diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(SetKDbCMakePolicies NO_POLICY_SCOPE) -project(KDb VERSION 3.0.90) # Update this +project(KDb VERSION 3.0.91) # Update this # CMake include(CMakePackageConfigHelpers) diff --git a/src/KDb.h b/src/KDb.h --- a/src/KDb.h +++ b/src/KDb.h @@ -112,32 +112,39 @@ return KDb::deleteAllRecords(conn, table.name()); } -/*! @return autoincrement field's @a autoIncrementFieldName value - of last inserted record for result @a result. - - Simply, method internally fetches values of the last inserted record and returns selected - field's value. The field belong to @a tableName table. - Requirements: the field must be of integer type, there must be a record inserted using query - for which the @a result is returned. - On error std::numeric_limits::max() is returned. - Last inserted record is identified by a magical record identifier, usually called ROWID - (PostgreSQL has it as well as SQLite; see KDbDriverBehavior::ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE). - ROWID's value will be assigned back to @a recordId if this pointer is not null. -*/ -KDB_EXPORT quint64 lastInsertedAutoIncValue(KDbSqlResult *result, - const QString& autoIncrementFieldName, const QString& tableName, quint64* recordId = nullptr); +/** + * Returns value of last inserted record for an autoincrement field + * + * This method internally fetches values of the last inserted record for which @a result was + * returned and returns selected field's value. The field belong to @a tableName table. + * The field must be of integer type, there must be a record inserted using query for which the @a + * result is returned. + * std::numeric_limits::max() is returned on error or if @a result is null. + * The last inserted record is identified by a magical record identifier, usually called ROWID + * (PostgreSQL has it as well as SQLite; + * see KDbDriverBehavior::ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE). + * ROWID's value will be assigned back to @a recordId if this pointer is not @c nullptr. + */ +KDB_EXPORT quint64 lastInsertedAutoIncValue(QSharedPointer result, + const QString &autoIncrementFieldName, + const QString &tableName, quint64 *recordId = nullptr); -/*! @overload int lastInsertedAutoIncValue(KDbSqlResult *, const QString&, const QString&, quint64*) +/** + * @overload + * * Accepts @a recordId that can be obtained from KDbPreparedStatement::lastInsertRecordId() * or KDbSqlResult::lastInsertRecordId(). */ KDB_EXPORT quint64 lastInsertedAutoIncValue(KDbConnection *conn, const quint64 recordId, - const QString& autoIncrementFieldName, const QString& tableName); + const QString &autoIncrementFieldName, + const QString &tableName); -/*! @overload int lastInsertedAutoIncValue(KDbSqlResult *, const QString&, const QString&, quint64*) +/** +@overload */ -inline quint64 lastInsertedAutoIncValue(KDbSqlResult *result, - const QString& autoIncrementFieldName, const KDbTableSchema& table, quint64* recordId = nullptr) +inline quint64 lastInsertedAutoIncValue(QSharedPointer result, + const QString &autoIncrementFieldName, + const KDbTableSchema &table, quint64 *recordId = nullptr) { return lastInsertedAutoIncValue(result, autoIncrementFieldName, table.name(), recordId); } diff --git a/src/KDb.cpp b/src/KDb.cpp --- a/src/KDb.cpp +++ b/src/KDb.cpp @@ -323,7 +323,7 @@ const QString &keyname, KDbField::Type keytype, const QVariant &keyval) { Q_ASSERT(conn); - return conn->executeVoidSQL(KDbEscapedString("DELETE FROM %1 WHERE %2=%3") + return conn->executeSql(KDbEscapedString("DELETE FROM %1 WHERE %2=%3") .arg(conn->escapeIdentifier(tableName)) .arg(conn->escapeIdentifier(keyname)) .arg(conn->driver()->valueToSQL(keytype, keyval))); @@ -334,7 +334,7 @@ const QString &keyname2, KDbField::Type keytype2, const QVariant& keyval2) { Q_ASSERT(conn); - return conn->executeVoidSQL(KDbEscapedString("DELETE FROM %1 WHERE %2=%3 AND %4=%5") + return conn->executeSql(KDbEscapedString("DELETE FROM %1 WHERE %2=%3 AND %4=%5") .arg(conn->escapeIdentifier(tableName)) .arg(conn->escapeIdentifier(keyname1)) .arg(conn->driver()->valueToSQL(keytype1, keyval1)) @@ -348,7 +348,7 @@ const QString &keyname3, KDbField::Type keytype3, const QVariant& keyval3) { Q_ASSERT(conn); - return conn->executeVoidSQL(KDbEscapedString("DELETE FROM %1 WHERE %2=%3 AND %4=%5 AND %6=%7") + return conn->executeSql(KDbEscapedString("DELETE FROM %1 WHERE %2=%3 AND %4=%5 AND %6=%7") .arg(conn->escapeIdentifier(tableName)) .arg(conn->escapeIdentifier(keyname1)) .arg(conn->driver()->valueToSQL(keytype1, keyval1)) @@ -361,14 +361,17 @@ bool KDb::deleteAllRecords(KDbConnection* conn, const QString &tableName) { Q_ASSERT(conn); - return conn->executeVoidSQL(KDbEscapedString("DELETE FROM %1") + return conn->executeSql(KDbEscapedString("DELETE FROM %1") .arg(conn->escapeIdentifier(tableName))); } -KDB_EXPORT quint64 KDb::lastInsertedAutoIncValue(KDbSqlResult *result, - const QString& autoIncrementFieldName, const QString& tableName, quint64* recordId) +KDB_EXPORT quint64 KDb::lastInsertedAutoIncValue(QSharedPointer result, + const QString &autoIncrementFieldName, + const QString &tableName, quint64 *recordId) { - Q_ASSERT(result); + if (!result) { + return std::numeric_limits::max(); + } const quint64 foundRecordId = result->lastInsertRecordId(); if (recordId) { *recordId = foundRecordId; @@ -378,7 +381,8 @@ } KDB_EXPORT quint64 KDb::lastInsertedAutoIncValue(KDbConnection *conn, const quint64 recordId, - const QString& autoIncrementFieldName, const QString& tableName) + const QString &autoIncrementFieldName, + const QString &tableName) { const KDbDriverBehavior *behavior = KDbDriverBehavior::get(conn->driver()); if (behavior->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE) { @@ -493,18 +497,18 @@ if (!result.serverMessage().isEmpty()) *details += QLatin1String("

") + kdb::tr("Message from server:") + QLatin1String(" ") + result.serverMessage(); - if (!result.recentSQLString().isEmpty()) + if (!result.recentSqlString().isEmpty()) *details += QLatin1String("

") + kdb::tr("SQL statement:") - + QString::fromLatin1(" %1").arg(result.recentSQLString().toString()); + + QString::fromLatin1(" %1").arg(result.recentSqlString().toString()); int serverErrorCode = 0; QString serverResultName; if (result.isError()) { serverErrorCode = result.serverErrorCode(); serverResultName = resultable.serverResultName(); } if ( !details->isEmpty() && ( !result.serverMessage().isEmpty() - || !result.recentSQLString().isEmpty() + || !result.recentSqlString().isEmpty() || !serverResultName.isEmpty() || serverErrorCode != 0) ) diff --git a/src/KDbAlter.cpp b/src/KDbAlter.cpp --- a/src/KDbAlter.cpp +++ b/src/KDbAlter.cpp @@ -1074,7 +1074,7 @@ } sql += (") SELECT " + sourceFields + " FROM " + oldTable->name()); kdbDebug() << " ** " << sql; - if (!d->conn->executeVoidSQL(sql)) { + if (!d->conn->executeSql(sql)) { m_result = d->conn->result(); //! @todo delete newTable... args->result = false; diff --git a/src/KDbConnection.h b/src/KDbConnection.h --- a/src/KDbConnection.h +++ b/src/KDbConnection.h @@ -87,7 +87,7 @@ KDbConnectionOptions *options(); /*! Reimplemented, also clears sql string. - @sa recentSQLString() */ + @sa recentSqlString() */ void clearResult(); /*! @brief Disconnects from driver with given parameters. @@ -320,11 +320,9 @@ /*! @return true if "auto commit" option is on. - When auto commit is on (the default on for any new KDbConnection object), - every sql functional statement (statement that changes - data in the database implicitly starts a new transaction. - This transaction is automatically committed - after successful statement execution or rolled back on error. + When auto commit is on (the default on for any new KDbConnection object), every SQL statement + that manipulates data in the database implicitly starts a new transaction. This transaction is + automatically committed after successful statement execution or rolled back on error. For drivers that do not support transactions (see KDbDriver::features()) this method shouldn't be called because it does nothing ans always returns false. @@ -334,7 +332,7 @@ transaction per connection (see KDbDriver::SingleTransactions), use this single connection for autocommiting, so if there is already transaction started by the KDb user program (with beginTransaction()), this transaction - is committed before any sql functional statement execution. In this situation + is committed before any statement that manipulates data. In this situation default transaction is also affected (see defaultTransaction()). Only for drivers that support nested transactions (KDbDriver::NestedTransactions), @@ -565,11 +563,11 @@ /*! @return true if there is at least one record in @a table. */ tristate isEmpty(KDbTableSchema* table); - virtual KDbEscapedString recentSQLString() const; + virtual KDbEscapedString recentSqlString() const; //PROTOTYPE: #define A , const QVariant& -#define H_INS_REC(args) bool insertRecord(KDbTableSchema* tableSchema args, KDbSqlResult** result = 0) +#define H_INS_REC(args) QSharedPointer insertRecord(KDbTableSchema* tableSchema args) #define H_INS_REC_ALL \ H_INS_REC(A); \ H_INS_REC(A A); \ @@ -582,16 +580,17 @@ H_INS_REC_ALL; #undef H_INS_REC -#define H_INS_REC(args) bool insertRecord(KDbFieldList* fields args, KDbSqlResult** result = 0) +#define H_INS_REC(args) QSharedPointer insertRecord(KDbFieldList* fields args) H_INS_REC_ALL; #undef H_INS_REC_ALL #undef H_INS_REC #undef A - bool insertRecord(KDbTableSchema* tableSchema, const QList& values, KDbSqlResult** result = nullptr); + QSharedPointer insertRecord(KDbTableSchema *tableSchema, + const QList &values); - bool insertRecord(KDbFieldList* fields, const QList& values, KDbSqlResult** result = nullptr); + QSharedPointer insertRecord(KDbFieldList *fields, const QList &values); /*! Creates table defined by @a tableSchema. Schema information is also added into kexi system tables, for later reuse. @@ -740,28 +739,45 @@ */ bool useTemporaryDatabaseIfNeeded(QString* name); - /*! Executes a new native (raw, backend-specific) SQL query for statement @a sql. - * Only use this method in cases if a non-portable raw query is required. - * Access to results can be obtained using the returned KDbSqlResult object. - * @c nullptr is returned on failure. Use result() to obtain detailed status information. - * The KDbConnection object is owner of the returned object. Before closing, the - * connection object deletes all its owned KDbSqlResult objects. It is also possible - * and recommended that caller deletes the KDbSqlResult object as soon as the result - * is not needed. - * If the query is not supposed to return records (e.g. is a functional query) - * or the caller is not interested in the records, the returned object can be just deleted. - * In this case executeVoidSQL() can be a better choice. - * Using QScopedPointer construct may simplify memory management of the - * returned object. + /** + * Prepares execution of a new native (raw, backend-specific) SQL query. + * + * The query is described by a raw statement @a sql which should be is valid and properly + * escaped. Access to results can be obtained using + * the returned KDbSqlResult object. The object is guarded with a shared pointer to facilitate + * transfer of ownership and memory management. A null pointer is returned if preparation of + * the query fails. Use KDbConnection::result() immediately after calling prepareSql() to + * obtain detailed result information about the preparation. + * + * The returned object should be deleted before the database connection is closed. + * Connection object does not deletes the KDbSqlResult objects. It is also possible and + * recommended that caller deletes the KDbSqlResult object as soon as the result is not needed. + * + * The returned object can be ignored if the query is not supposed to return records (e.g. + * manipulates data through INSERT, UPDATE, DELETE, ...) or the caller is not interested in the + * records. Thanks to the use of the shared pointer the object will be immediately deleted and + * execution will be finalized prior to that. However to execute queries that return no + * results, executeSql() is a better choice because of performance and easier reporting to + * results. + * + * @note Only use this method if a non-portable raw query is required. + * In other cases use prepareQuery() or executeQuery() and the KDbCursor object. */ - KDbSqlResult* executeSQL(const KDbEscapedString& sql) Q_REQUIRED_RESULT; - - /*! Executes a new native (raw, backend-specific) SQL query for statement @a sql. - * This method is equivalent of executeSQL() useful for cases when the query is not - * supposed to return records (e.g. is a functional query) or if the caller is not - * interested in the records. + QSharedPointer prepareSql(const KDbEscapedString& sql) Q_REQUIRED_RESULT; + + /** + * Executes a new native (raw, backend-specific) SQL query + * + * The query is described by a raw statement @a sql which should be is valid and properly + * escaped. This method is a convenience version of prepareSql() that immediately starts and + * finalizes execution of a raw query in one step and provides a result. Use it for queries + * that do not return records, i.e. for queries that manipulate data (INSERT, UPDATE, DELETE, + * ...) or if the caller is not interested in the returned records. + * + * @note Only use this method if a non-portable raw query is required. + * In other cases use prepareQuery() or executeQuery() and the KDbCursor object. */ - bool executeVoidSQL(const KDbEscapedString& sql); + bool executeSql(const KDbEscapedString& sql); /*! Stores object (id, name, caption, description) described by @a object on the backend. It is expected that entry on the @@ -874,11 +890,15 @@ The lookup is case insensitive. */ virtual tristate drv_containsTable(const QString &tableName) = 0; - /*! Creates table using @a tableSchema information. - @return true on success. Default implementation - builds a statement using createTableStatement() and calls drv_executeSQL() - Note for driver developers: reimplement this only if you want do to - this in other way. */ + /** + * Creates table using @a tableSchema information. + * + * @return true on success. + * + * Default implementation builds a statement using createTableStatement() and calls + * executeSql(). Note for driver developers: reimplement this only to perform creation in other + * way. + */ virtual bool drv_createTable(const KDbTableSchema& tableSchema); /*! Alters table's described @a tableSchema name to @a newName. @@ -918,33 +938,30 @@ Used internally by tableSchema(). */ KDbField* setupField(const KDbRecordData& data) Q_REQUIRED_RESULT; - /*! Executes query for a raw SQL statement @a sql with possibility of returning records. - - It is useful mostly for functional (SELECT) queries. While INSERT queries do not - return records, the KDbSqlResult object offers KDbSqlResult::lastInsertRecordId(). - The @sql should be is valid and properly escaped. Only use this method if you really - need. For low-level access to the results (without cursors). The result may be not - stored (not buffered) yet. Use KDbSqlResult::fetchRecord() to fetch each record. - @return @c nullptr if there is no proper result. Ownership of the returned object is - passed to the caller. - @see executeSQL */ - virtual KDbSqlResult* drv_executeSQL(const KDbEscapedString& sql) Q_REQUIRED_RESULT = 0; - - /*! Executes query for a raw SQL statement @a sql without returning resulting records. - - It is useful mostly for INSERT queries but it is possible to execute SELECT queries - when returned records can be ignored. The @sql should be is valid and properly escaped. - Only use this method if you really need. - @see executeVoidSQL */ - virtual bool drv_executeVoidSQL(const KDbEscapedString& sql) = 0; - - /*! Uses result of execution of raw SQL query using drv_executeSQL(). - For low-level access to the results (without cursors). - The result may be not stored (not buffered) yet. - Use KDbSqlResult::fetchRecord() to fetch each record. - @return @c nullptr if there is no proper result. - Ownership of the returned object is passed to the caller. */ - //virtual KDbSqlResult* drv_getSqlResult() Q_REQUIRED_RESULT = 0; + /** + * Prepares query for a raw SQL statement @a sql with possibility of returning records. + * + * It is useful mostly for SELECT queries. While INSERT queries do not return records, the + * KDbSqlResult object offers KDbSqlResult::lastInsertRecordId(). The @sql should be is valid + * and properly escaped. Only use this method if you really need. For low-level access to the + * results (without cursors). The result may be not stored (not buffered) yet. Use + * KDbSqlResult::fetchRecord() to fetch each record. @return Null pointer if there is no proper + * result or error. Ownership of the returned object is passed to the caller. + * + * @see prepareSql + */ + virtual KDbSqlResult* drv_prepareSql(const KDbEscapedString &sql) Q_REQUIRED_RESULT = 0; + + /** + * Executes query for a raw SQL statement @a sql without returning resulting records. + * + * It is useful mostly for INSERT queries but it is possible to execute SELECT queries when + * returned records can be ignored. The @sql should be is valid and properly escaped. + * + * @note Only use this method if you really need. + * @see executeSql + */ + virtual bool drv_executeSql(const KDbEscapedString& sql) = 0; /*! For reimplementation: loads list of databases' names available for this connection and adds these names to @a list. If your server is not able to offer such a list, @@ -1189,8 +1206,9 @@ bool checkIfColumnExists(KDbCursor *cursor, int column); /*! @internal used by insertRecord() methods. */ - bool insertRecordInternal(const QString &tableSchemaName, KDbFieldList* fields, - const KDbEscapedString &sql, KDbSqlResult** result); + QSharedPointer insertRecordInternal(const QString &tableSchemaName, + KDbFieldList *fields, + const KDbEscapedString &sql); /*! @internal used by querySingleRecord() methods. Note: "LIMIT 1" is appended to @a sql statement if @a addLimitTo1 is true (the default). */ diff --git a/src/KDbConnection.cpp b/src/KDbConnection.cpp --- a/src/KDbConnection.cpp +++ b/src/KDbConnection.cpp @@ -992,41 +992,41 @@ // escapeIdentifier(tableSchema->name()) + // " VALUES (" + vals + ")"; -bool KDbConnection::insertRecordInternal(const QString &tableSchemaName, KDbFieldList* fields, - const KDbEscapedString &sql, KDbSqlResult** result = nullptr) +QSharedPointer KDbConnection::insertRecordInternal(const QString &tableSchemaName, + KDbFieldList *fields, + const KDbEscapedString &sql) { + QSharedPointer res; if (!drv_beforeInsert(tableSchemaName,fields )) { - return false; + return res; } - QScopedPointer res(executeSQL(sql)); + res = prepareSql(sql); if (!res || res->lastResult().isError()) { - return false; + res.clear(); + return res; } if (!drv_afterInsert(tableSchemaName, fields)) { - return false; + res.clear(); + return res; } { - // Fetching is needed to performs real execution, at least for some backends. - // Also we're not expecting record but let's delete if there's any. - QScopedPointer record(res->fetchRecord()); + // Fetching is needed to perform real execution at least for some backends. + // Also we are not expecting record but let's delete if there's any. + (void)res->fetchRecord(); } - if (!res->lastResult().isError()) { - if (result) { - *result = res.take(); - } - return true; + if (res->lastResult().isError()) { + res.clear(); } - return false; + return res; } #define C_INS_REC(args, vals) \ - bool KDbConnection::insertRecord(KDbTableSchema* tableSchema args, KDbSqlResult** result) {\ + QSharedPointer KDbConnection::insertRecord(KDbTableSchema* tableSchema args) { \ return insertRecordInternal(tableSchema->name(), tableSchema, \ KDbEscapedString("INSERT INTO ") + escapeIdentifier(tableSchema->name()) \ + " (" \ + tableSchema->sqlFieldsList(this) \ - + ") VALUES (" + vals + ")", \ - result); \ + + ") VALUES (" + vals + ')'); \ } #define C_INS_REC_ALL \ @@ -1049,7 +1049,7 @@ #define V_A( a ) value += (',' + d->driver->valueToSQL( it.next(), c ## a )); #define C_INS_REC(args, vals) \ - bool KDbConnection::insertRecord(KDbFieldList* fields args, KDbSqlResult** result) \ + QSharedPointer KDbConnection::insertRecord(KDbFieldList* fields args) \ { \ KDbEscapedString value; \ const KDbField::List *flist = fields->fields(); \ @@ -1060,8 +1060,7 @@ return insertRecordInternal(tableName, fields, \ KDbEscapedString(QLatin1String("INSERT INTO ") + escapeIdentifier(tableName)) \ + " (" + fields->sqlFieldsList(this) \ - + ") VALUES (" + value + ')', \ - result); \ + + ") VALUES (" + value + ')'); \ } C_INS_REC_ALL @@ -1072,13 +1071,14 @@ #undef C_INS_REC #undef C_INS_REC_ALL -bool KDbConnection::insertRecord(KDbTableSchema* tableSchema, const QList& values, - KDbSqlResult** result) +QSharedPointer KDbConnection::insertRecord(KDbTableSchema *tableSchema, + const QList &values) { // Each SQL identifier needs to be escaped in the generated query. + QSharedPointer res; const KDbField::List *flist = tableSchema->fields(); if (flist->isEmpty()) { - return false; + return res; } KDbField::ListIterator fieldsIt(flist->constBegin()); QList::ConstIterator it = values.constBegin(); @@ -1100,16 +1100,18 @@ } sql += ')'; m_result.setSql(sql); - return insertRecordInternal(tableSchema->name(), tableSchema, sql, result); + res = insertRecordInternal(tableSchema->name(), tableSchema, sql); + return res; } -bool KDbConnection::insertRecord(KDbFieldList* fields, const QList& values, - KDbSqlResult** result) +QSharedPointer KDbConnection::insertRecord(KDbFieldList *fields, + const QList &values) { // Each SQL identifier needs to be escaped in the generated query. + QSharedPointer res; const KDbField::List *flist = fields->fields(); if (flist->isEmpty()) { - return false; + return res; } KDbField::ListIterator fieldsIt(flist->constBegin()); KDbEscapedString sql; @@ -1134,7 +1136,8 @@ } sql += ')'; m_result.setSql(sql); - return insertRecordInternal(tableName, fields, sql, result); + res = insertRecordInternal(tableName, fields, sql); + return res; } inline static bool checkSql(const KDbEscapedString& sql, KDbResult* result) @@ -1149,19 +1152,19 @@ return true; } -KDbSqlResult* KDbConnection::executeSQL(const KDbEscapedString& sql) +QSharedPointer KDbConnection::prepareSql(const KDbEscapedString& sql) { m_result.setSql(sql); - return drv_executeSQL(sql); + return QSharedPointer(drv_prepareSql(sql)); } -bool KDbConnection::executeVoidSQL(const KDbEscapedString& sql) +bool KDbConnection::executeSql(const KDbEscapedString& sql) { m_result.setSql(sql); if (!checkSql(sql, &m_result)) { return false; } - if (!drv_executeVoidSQL(sql)) { + if (!drv_executeSql(sql)) { m_result.setMessage(QString()); //clear as this could be most probably just "Unknown error" string. m_result.setErrorSql(sql); m_result.prependMessage(ERR_SQL_EXECUTION_ERROR, @@ -1257,7 +1260,7 @@ sql.append(KDbEscapedString(" WHERE t_id=%1 AND f_name=%2") .arg(d->driver->valueToSQL(KDbField::Integer, field->table()->id())) .arg(escapeString(field->name()))); - return executeVoidSQL(sql); + return executeSql(sql); } #define createTable_ERR \ @@ -1432,7 +1435,7 @@ KDbEscapedString sql = KDbEscapedString("INSERT INTO %1 SELECT * FROM %2") .arg(escapeIdentifier(destinationTableSchema.name())) .arg(escapeIdentifier(tableSchema.name())); - return executeVoidSQL(sql); + return executeSql(sql); } bool KDbConnection::removeObject(int objId) @@ -1454,7 +1457,7 @@ bool KDbConnection::drv_dropTable(const QString& tableName) { - return executeVoidSQL(KDbEscapedString("DROP TABLE %1").arg(escapeIdentifier(tableName))); + return executeSql(KDbEscapedString("DROP TABLE %1").arg(escapeIdentifier(tableName))); } tristate KDbConnection::dropTable(KDbTableSchema* tableSchema) @@ -1614,15 +1617,15 @@ } // the new table owns the previous table's id: - if (!executeVoidSQL( + if (!executeSql( KDbEscapedString("UPDATE kexi__objects SET o_id=%1 WHERE o_id=%2 AND o_type=%3") .arg(d->driver->valueToSQL(KDbField::Integer, origID)) .arg(d->driver->valueToSQL(KDbField::Integer, tableSchema->id())) .arg(d->driver->valueToSQL(KDbField::Integer, int(KDb::TableObjectType))))) { return false; } - if (!executeVoidSQL(KDbEscapedString("UPDATE kexi__fields SET t_id=%1 WHERE t_id=%2") + if (!executeSql(KDbEscapedString("UPDATE kexi__fields SET t_id=%1 WHERE t_id=%2") .arg(d->driver->valueToSQL(KDbField::Integer, origID)) .arg(d->driver->valueToSQL(KDbField::Integer, tableSchema->id())))) { @@ -1641,7 +1644,7 @@ // Update kexi__objects //! @todo - if (!executeVoidSQL(KDbEscapedString("UPDATE kexi__objects SET o_name=%1 WHERE o_id=%2") + if (!executeSql(KDbEscapedString("UPDATE kexi__objects SET o_name=%1 WHERE o_id=%2") .arg(escapeString(tableSchema->name())) .arg(d->driver->valueToSQL(KDbField::Integer, tableSchema->id())))) { @@ -1668,7 +1671,7 @@ const QString oldTableName = tableSchema->name(); tableSchema->setName(newName); - if (!executeVoidSQL(KDbEscapedString("ALTER TABLE %1 RENAME TO %2") + if (!executeSql(KDbEscapedString("ALTER TABLE %1 RENAME TO %2") .arg(KDbEscapedString(escapeIdentifier(oldTableName)), KDbEscapedString(escapeIdentifier(newName))))) { @@ -1718,7 +1721,7 @@ return false; } //kdbDebug() << "******** " << sql; - return executeVoidSQL(sql); + return executeSql(sql); } bool KDbConnection::drv_createTable(const QString& tableName) @@ -1944,19 +1947,19 @@ KDbTransactionData* KDbConnection::drv_beginTransaction() { - if (!executeVoidSQL(KDbEscapedString("BEGIN"))) + if (!executeSql(KDbEscapedString("BEGIN"))) return nullptr; return new KDbTransactionData(this); } bool KDbConnection::drv_commitTransaction(KDbTransactionData *) { - return executeVoidSQL(KDbEscapedString("COMMIT")); + return executeSql(KDbEscapedString("COMMIT")); } bool KDbConnection::drv_rollbackTransaction(KDbTransactionData *) { - return executeVoidSQL(KDbEscapedString("ROLLBACK")); + return executeSql(KDbEscapedString("ROLLBACK")); } bool KDbConnection::drv_setAutoCommit(bool /*on*/) @@ -2109,13 +2112,12 @@ if (!fl) { return false; } - KDbSqlResult* result; - if (!insertRecord(fl.data(), QVariant(object->type()), QVariant(object->name()), - QVariant(object->caption()), QVariant(object->description()), &result)) - { + QSharedPointer result + = insertRecord(fl.data(), QVariant(object->type()), QVariant(object->name()), + QVariant(object->caption()), QVariant(object->description())); + if (!result) { return false; } - QScopedPointer resultGuard(result); //fetch newly assigned ID //! @todo safe to cast it? quint64 obj_id = KDb::lastInsertedAutoIncValue(result, QLatin1String("o_id"), *ts); @@ -2134,7 +2136,7 @@ } } //existing object: - return executeVoidSQL( + return executeSql( KDbEscapedString("UPDATE kexi__objects SET o_type=%2, o_caption=%3, o_desc=%4 WHERE o_id=%1") .arg(d->driver->valueToSQL(KDbField::Integer, object->id())) .arg(d->driver->valueToSQL(KDbField::Integer, object->type())) @@ -2853,12 +2855,12 @@ return false; } if (result == true) { - return executeVoidSQL(KDbEscapedString("UPDATE kexi__objectdata SET o_data=%1 WHERE o_id=%2 AND ") + return executeSql(KDbEscapedString("UPDATE kexi__objectdata SET o_data=%1 WHERE o_id=%2 AND ") .arg(d->driver->valueToSQL(KDbField::LongText, dataString)) .arg(d->driver->valueToSQL(KDbField::Integer, objectID)) + sql_sub); } - return executeVoidSQL( + return executeSql( KDbEscapedString("INSERT INTO kexi__objectdata (o_id, o_data, o_sub_id) VALUES (") + KDbEscapedString::number(objectID) + ',' + d->driver->valueToSQL(KDbField::LongText, dataString) + ',' + d->driver->valueToSQL(KDbField::Text, dataID) + ')'); @@ -2881,7 +2883,7 @@ sql += KDbEscapedString(" AND ") + KDb::sqlWhere(d->driver, KDbField::Text, QLatin1String("o_sub_id"), dataID); } - return executeVoidSQL(sql); + return executeSql(sql); } bool KDbConnection::removeDataBlock(int objectID, const QString& dataID) @@ -3114,7 +3116,7 @@ if (!drv_beforeUpdate(mt->name(), &affectedFields)) return false; - bool res = executeVoidSQL(sql); + bool res = executeSql(sql); // postprocessing after update if (!drv_afterUpdate(mt->name(), &affectedFields)) @@ -3232,14 +3234,13 @@ // kdbDebug() << " -- SQL == " << sql; // low-level insert - KDbSqlResult* result; - if (!insertRecordInternal(mt->name(), &affectedFields, sql, &result)) { + QSharedPointer result = insertRecordInternal(mt->name(), &affectedFields, sql); + if (!result) { m_result = KDbResult(ERR_INSERT_SERVER_ERROR, tr("Record inserting on the server failed.")); return false; } //success: now also assign a new value in memory: - QScopedPointer resultGuard(result); QHash columnsOrderExpanded; updateRecordDataWithNewValues(query, data, b, &columnsOrderExpanded); @@ -3249,9 +3250,10 @@ if (pkey && !aif_list->isEmpty()) { //! @todo now only if PKEY is present, this should also work when there's no PKEY KDbQueryColumnInfo *id_columnInfo = aif_list->first(); -//! @todo safe to cast it? - quint64 last_id = KDb::lastInsertedAutoIncValue(result, - id_columnInfo->field()->name(), id_columnInfo->field()->table()->name(), &recordId); + //! @todo safe to cast it? + quint64 last_id + = KDb::lastInsertedAutoIncValue(result, id_columnInfo->field()->name(), + id_columnInfo->field()->table()->name(), &recordId); if (last_id == std::numeric_limits::max()) { //! @todo show error //! @todo remove just inserted record. How? Using ROLLBACK? @@ -3350,7 +3352,7 @@ sql += sqlwhere; //kdbDebug() << " -- SQL == " << sql; - if (!executeVoidSQL(sql)) { + if (!executeSql(sql)) { m_result = KDbResult(ERR_DELETE_SERVER_ERROR, tr("Record deletion on the server failed.")); return false; @@ -3373,7 +3375,7 @@ KDbEscapedString sql = KDbEscapedString("DELETE FROM ") + escapeIdentifier(mt->name()); //kdbDebug() << "-- SQL == " << sql; - if (!executeVoidSQL(sql)) { + if (!executeSql(sql)) { m_result = KDbResult(ERR_DELETE_SERVER_ERROR, tr("Record deletion on the server failed.")); return false; @@ -3408,7 +3410,7 @@ return KDbPreparedStatement(iface, type, fields, whereFieldNames); } -KDbEscapedString KDbConnection::recentSQLString() const { +KDbEscapedString KDbConnection::recentSqlString() const { return result().errorSql().isEmpty() ? m_result.sql() : result().errorSql(); } diff --git a/src/KDbConnectionProxy.h b/src/KDbConnectionProxy.h --- a/src/KDbConnectionProxy.h +++ b/src/KDbConnectionProxy.h @@ -197,7 +197,7 @@ tristate isEmpty(KDbTableSchema* table); - KDbEscapedString recentSQLString() const override; + KDbEscapedString recentSqlString() const override; //PROTOTYPE: #define A , const QVariant& @@ -253,9 +253,9 @@ bool useTemporaryDatabaseIfNeeded(QString* name); - KDbSqlResult* executeSQL(const KDbEscapedString& sql) Q_REQUIRED_RESULT; + QSharedPointer prepareSql(const KDbEscapedString& sql) Q_REQUIRED_RESULT; - bool executeVoidSQL(const KDbEscapedString& sql); + bool executeSql(const KDbEscapedString& sql); bool storeObjectData(KDbObject* object); @@ -304,9 +304,9 @@ KDbField* setupField(const KDbRecordData& data); - KDbSqlResult* drv_executeSQL(const KDbEscapedString& sql) override Q_REQUIRED_RESULT; + KDbSqlResult* drv_prepareSql(const KDbEscapedString& sql) override Q_REQUIRED_RESULT; - bool drv_executeVoidSQL(const KDbEscapedString& sql) override; + bool drv_executeSql(const KDbEscapedString& sql) override; bool drv_getDatabasesList(QStringList* list) override; diff --git a/src/KDbConnectionProxy.cpp b/src/KDbConnectionProxy.cpp --- a/src/KDbConnectionProxy.cpp +++ b/src/KDbConnectionProxy.cpp @@ -391,9 +391,9 @@ return d->connection->isEmpty(table); } -KDbEscapedString KDbConnectionProxy::recentSQLString() const +KDbEscapedString KDbConnectionProxy::recentSqlString() const { - return d->connection->recentSQLString(); + return d->connection->recentSqlString(); } //PROTOTYPE: @@ -504,14 +504,14 @@ return d->connection->useTemporaryDatabaseIfNeeded(name); } -KDbSqlResult* KDbConnectionProxy::executeSQL(const KDbEscapedString& sql) +QSharedPointer KDbConnectionProxy::prepareSql(const KDbEscapedString& sql) { - return d->connection->executeSQL(sql); + return d->connection->prepareSql(sql); } -bool KDbConnectionProxy::executeVoidSQL(const KDbEscapedString& sql) +bool KDbConnectionProxy::executeSql(const KDbEscapedString& sql) { - return d->connection->executeVoidSQL(sql); + return d->connection->executeSql(sql); } bool KDbConnectionProxy::storeObjectData(KDbObject* object) @@ -627,14 +627,14 @@ return d->connection->setupField(data); } -KDbSqlResult* KDbConnectionProxy::drv_executeSQL(const KDbEscapedString& sql) +KDbSqlResult* KDbConnectionProxy::drv_prepareSql(const KDbEscapedString& sql) { - return d->connection->drv_executeSQL(sql); + return d->connection->drv_prepareSql(sql); } -bool KDbConnectionProxy::drv_executeVoidSQL(const KDbEscapedString& sql) +bool KDbConnectionProxy::drv_executeSql(const KDbEscapedString& sql) { - return d->connection->drv_executeVoidSQL(sql); + return d->connection->drv_executeSql(sql); } bool KDbConnectionProxy::drv_getDatabasesList(QStringList* list) diff --git a/src/KDbError.h b/src/KDbError.h --- a/src/KDbError.h +++ b/src/KDbError.h @@ -102,7 +102,7 @@ //! errors related to queries #define ERR_SQL_EXECUTION_ERROR 260 //!< general server error for sql statement execution -//!< usually returned by KDbConnection::executeSQL() +//!< usually returned by KDbConnection::executeSql() #define ERR_SQL_PARSE_ERROR 270 //!< Parse error coming from arser::parse() #define ERR_OTHER 0xffff //!< use this if you have not (yet?) the name for given error diff --git a/src/KDbPreparedStatement.cpp b/src/KDbPreparedStatement.cpp --- a/src/KDbPreparedStatement.cpp +++ b/src/KDbPreparedStatement.cpp @@ -78,16 +78,12 @@ } d->dirty = false; } - bool resultOwned = true; - QScopedPointer result(d->iface->execute(d->type, *d->fieldsForParameters, - d->fields, parameters, &resultOwned)); + QSharedPointer result + = d->iface->execute(d->type, *d->fieldsForParameters, d->fields, parameters); if (!result) { return false; } d->lastInsertRecordId = result->lastInsertRecordId(); - if (resultOwned) { - result.take(); - } return true; } diff --git a/src/KDbProperties.cpp b/src/KDbProperties.cpp --- a/src/KDbProperties.cpp +++ b/src/KDbProperties.cpp @@ -44,7 +44,7 @@ } if (result == true) { - if (!m_conn->executeVoidSQL( + if (!m_conn->executeSql( KDbEscapedString("UPDATE kexi__db SET db_value=%1 WHERE db_property=%2") .arg(m_conn->escapeString(value.toString())) .arg(m_conn->escapeString(name)))) @@ -56,7 +56,7 @@ return true; } - if (!m_conn->executeVoidSQL( + if (!m_conn->executeSql( KDbEscapedString("INSERT INTO kexi__db (db_property, db_value) VALUES (%1, %2)") .arg(m_conn->escapeString(name)) .arg(m_conn->escapeString(value.toString())))) @@ -84,7 +84,7 @@ } if (result == true) { - if (!m_conn->executeVoidSQL( + if (!m_conn->executeSql( KDbEscapedString("UPDATE kexi__db SET db_value=%1 WHERE db_property=%2") .arg(m_conn->escapeString(caption)) .arg(m_conn->escapeString(name)))) { @@ -95,7 +95,7 @@ return true; } - if (!m_conn->executeVoidSQL( + if (!m_conn->executeSql( KDbEscapedString("INSERT INTO kexi__db (db_property, db_value) VALUES (%1, %2)") .arg(m_conn->escapeString(name)) .arg(m_conn->escapeString(caption)))) { diff --git a/src/KDbResult.shared.h b/src/KDbResult.shared.h --- a/src/KDbResult.shared.h +++ b/src/KDbResult.shared.h @@ -112,9 +112,9 @@ } /*! @return sql string of actually executed SQL statement, - usually using drv_executeSQL(). If there was error during executing SQL statement, + usually using drv_executeSql(). If there was error during executing SQL statement, before, that string is returned instead. */ - virtual inline KDbEscapedString recentSQLString() const { + virtual inline KDbEscapedString recentSqlString() const { return d->errorSql; } diff --git a/src/drivers/mysql/MysqlConnection.h b/src/drivers/mysql/MysqlConnection.h --- a/src/drivers/mysql/MysqlConnection.h +++ b/src/drivers/mysql/MysqlConnection.h @@ -59,8 +59,8 @@ KDbMessageHandler* msgHandler = nullptr) override; bool drv_closeDatabase() override; bool drv_dropDatabase(const QString &dbName = QString()) override; - KDbSqlResult* drv_executeSQL(const KDbEscapedString& sql) override Q_REQUIRED_RESULT; - bool drv_executeVoidSQL(const KDbEscapedString& sql) override; + KDbSqlResult* drv_prepareSql(const KDbEscapedString& sql) override Q_REQUIRED_RESULT; + bool drv_executeSql(const KDbEscapedString& sql) override; //! Implemented for KDbResultable QString serverResultName() const override; diff --git a/src/drivers/mysql/MysqlConnection.cpp b/src/drivers/mysql/MysqlConnection.cpp --- a/src/drivers/mysql/MysqlConnection.cpp +++ b/src/drivers/mysql/MysqlConnection.cpp @@ -141,7 +141,7 @@ mysqlDebug() << storedDbName; // mysql_create_db deprecated, use SQL here. // db names are lower case in mysql - return drv_executeVoidSQL(KDbEscapedString("CREATE DATABASE %1").arg(escapeIdentifier(storedDbName))); + return drv_executeSql(KDbEscapedString("CREATE DATABASE %1").arg(escapeIdentifier(storedDbName))); } bool MysqlConnection::drv_useDatabase(const QString &dbName, bool *cancelled, KDbMessageHandler* msgHandler) @@ -167,22 +167,22 @@ { //! @todo is here escaping needed? const QString storedDbName(d->lowerCaseTableNames ? dbName.toLower() : dbName); - return drv_executeVoidSQL(KDbEscapedString("DROP DATABASE %1").arg(escapeIdentifier(storedDbName))); + return drv_executeSql(KDbEscapedString("DROP DATABASE %1").arg(escapeIdentifier(storedDbName))); } -KDbSqlResult* MysqlConnection::drv_executeSQL(const KDbEscapedString& sql) +KDbSqlResult* MysqlConnection::drv_prepareSql(const KDbEscapedString& sql) { - if (!drv_executeVoidSQL(sql)) { + if (!drv_executeSql(sql)) { return nullptr; } MYSQL_RES *data = mysql_use_result(d->mysql); // more optimal than mysql_store_result //! @todo use mysql_error() return new MysqlSqlResult(this, data); } -bool MysqlConnection::drv_executeVoidSQL(const KDbEscapedString& sql) +bool MysqlConnection::drv_executeSql(const KDbEscapedString& sql) { - if (!d->executeVoidSQL(sql)) { + if (!d->executeSql(sql)) { storeResult(); return false; } diff --git a/src/drivers/mysql/MysqlConnection_p.h b/src/drivers/mysql/MysqlConnection_p.h --- a/src/drivers/mysql/MysqlConnection_p.h +++ b/src/drivers/mysql/MysqlConnection_p.h @@ -63,7 +63,7 @@ bool useDatabase(const QString &dbName = QString()); //! Executes query for a raw SQL statement @a sql using mysql_real_query() - bool executeVoidSQL(const KDbEscapedString& sql); + bool executeSql(const KDbEscapedString& sql); static QString serverResultName(MYSQL *mysql); @@ -179,13 +179,15 @@ KDbField *createField(const QString &tableName, int index) override Q_REQUIRED_RESULT; - inline KDbSqlRecord* fetchRecord() override Q_REQUIRED_RESULT { + inline QSharedPointer fetchRecord() override Q_REQUIRED_RESULT { + QSharedPointer record; MYSQL_ROW row = data ? mysql_fetch_row(data) : nullptr; if (!row) { - return nullptr; + return record; } unsigned long* lengths = mysql_fetch_lengths(data); - return new MysqlSqlRecord(row, lengths); + record.reset(new MysqlSqlRecord(row, lengths)); + return record; } inline KDbResult lastResult() override { diff --git a/src/drivers/mysql/MysqlConnection_p.cpp b/src/drivers/mysql/MysqlConnection_p.cpp --- a/src/drivers/mysql/MysqlConnection_p.cpp +++ b/src/drivers/mysql/MysqlConnection_p.cpp @@ -113,17 +113,17 @@ bool MysqlConnectionInternal::useDatabase(const QString &dbName) { //! @todo is here escaping needed? - if (!executeVoidSQL(KDbEscapedString("USE ") + escapeIdentifier(dbName))) { + if (!executeSql(KDbEscapedString("USE ") + escapeIdentifier(dbName))) { return false; } - if (!executeVoidSQL(KDbEscapedString("SET SESSION sql_mode='TRADITIONAL'"))) { + if (!executeSql(KDbEscapedString("SET SESSION sql_mode='TRADITIONAL'"))) { // needed to turn warnings about trimming string values into SQL errors return false; } return true; } -bool MysqlConnectionInternal::executeVoidSQL(const KDbEscapedString& sql) +bool MysqlConnectionInternal::executeSql(const KDbEscapedString& sql) { return 0 == mysql_real_query(mysql, sql.constData(), sql.length()); } @@ -160,13 +160,13 @@ //-------------------------------------- -static inline KDbSqlString mysqlTypeName(MysqlSqlResult *result, QScopedPointer *recordPtr) +static inline KDbSqlString mysqlTypeName(MysqlSqlResult *result) { KDbSqlString name; if (result && result->fieldsCount() >= 2) { - recordPtr->reset(static_cast(result->fetchRecord())); - if (*recordPtr) { - name = (*recordPtr)->cstringValue(1); + QSharedPointer record = result->fetchRecord(); + if (record) { + name = static_cast(record.data())->cstringValue(1); } } return name; @@ -189,7 +189,7 @@ = KDbEscapedString("SHOW COLUMNS FROM `") + conn->escapeIdentifier(table) + "` LIKE '" + conn->escapeIdentifier(fld->name) + '\''; - if (!conn->executeVoidSQL(query)) + if (!conn->executeSql(query)) // Huh? MySQL wont tell us what values it can take. return QStringList(); @@ -252,10 +252,10 @@ const KDbEscapedString sql = KDbEscapedString("SHOW COLUMNS FROM %1 LIKE '%2'") .arg(escapeIdentifier(tableName)).arg(field->name()); //! @todo this conflicts with active query - QScopedPointer result(static_cast(conn->executeSQL(sql))); + QSharedPointer result = conn->prepareSql(sql); if (result) { - QScopedPointer record; - const KDbSqlString typeName(mysqlTypeName(result.data(), &record)); + MysqlSqlResult* mysqlResult = static_cast(result.data()); + const KDbSqlString typeName(mysqlTypeName(mysqlResult)); if (typeName.rawDataToByteArray().toLower().contains("blob")) { // Doesn't matter how big it is, it's binary kdbType = KDbField::BLOB; diff --git a/src/drivers/mysql/MysqlPreparedStatement.h b/src/drivers/mysql/MysqlPreparedStatement.h --- a/src/drivers/mysql/MysqlPreparedStatement.h +++ b/src/drivers/mysql/MysqlPreparedStatement.h @@ -36,10 +36,10 @@ private: bool prepare(const KDbEscapedString& sql) override; - KDbSqlResult *execute(KDbPreparedStatement::Type type, const KDbField::List &selectFieldList, - KDbFieldList *insertFieldList, - const KDbPreparedStatementParameters ¶meters, - bool *resultOwned) override Q_REQUIRED_RESULT; + QSharedPointer execute(KDbPreparedStatement::Type type, + const KDbField::List &selectFieldList, + KDbFieldList *insertFieldList, + const KDbPreparedStatementParameters ¶meters) override Q_REQUIRED_RESULT; bool init(); void done(); diff --git a/src/drivers/mysql/MysqlPreparedStatement.cpp b/src/drivers/mysql/MysqlPreparedStatement.cpp --- a/src/drivers/mysql/MysqlPreparedStatement.cpp +++ b/src/drivers/mysql/MysqlPreparedStatement.cpp @@ -232,13 +232,13 @@ } #endif -KDbSqlResult* MysqlPreparedStatement::execute( - KDbPreparedStatement::Type type, - const KDbField::List& selectFieldList, - KDbFieldList* insertFieldList, - const KDbPreparedStatementParameters& parameters, bool *resultOwned) +QSharedPointer MysqlPreparedStatement::execute(KDbPreparedStatement::Type type, + const KDbField::List &selectFieldList, + KDbFieldList *insertFieldList, + const KDbPreparedStatementParameters ¶meters) { Q_UNUSED(selectFieldList); + QSharedPointer result; #ifdef KDB_USE_MYSQL_STMT if (!m_statement || m_realParamCount <= 0) return false; @@ -305,14 +305,9 @@ myParameters.append(QVariant()); } } - KDbSqlResult* result; - if (connection->insertRecord(insertFieldList, myParameters, &result)) { - *resultOwned = false; - return result; - } - return nullptr; + result = connection->insertRecord(insertFieldList, myParameters); } //! @todo support select #endif // !KDB_USE_MYSQL_STMT - return nullptr; + return result; } diff --git a/src/drivers/postgresql/PostgresqlConnection.h b/src/drivers/postgresql/PostgresqlConnection.h --- a/src/drivers/postgresql/PostgresqlConnection.h +++ b/src/drivers/postgresql/PostgresqlConnection.h @@ -82,8 +82,8 @@ //! Drops the given database bool drv_dropDatabase(const QString &dbName = QString()) override; //! Executes an SQL statement - KDbSqlResult* drv_executeSQL(const KDbEscapedString& sql) override Q_REQUIRED_RESULT; - bool drv_executeVoidSQL(const KDbEscapedString& sql) override; + KDbSqlResult* drv_prepareSql(const KDbEscapedString& sql) override Q_REQUIRED_RESULT; + bool drv_executeSql(const KDbEscapedString& sql) override; //! Implemented for KDbResultable QString serverResultName() const override; diff --git a/src/drivers/postgresql/PostgresqlConnection.cpp b/src/drivers/postgresql/PostgresqlConnection.cpp --- a/src/drivers/postgresql/PostgresqlConnection.cpp +++ b/src/drivers/postgresql/PostgresqlConnection.cpp @@ -113,7 +113,7 @@ bool PostgresqlConnection::drv_createDatabase(const QString &dbName) { - return executeVoidSQL(KDbEscapedString("CREATE DATABASE ") + escapeIdentifier(dbName)); + return executeSql(KDbEscapedString("CREATE DATABASE ") + escapeIdentifier(dbName)); } QByteArray buildConnParameter(const QByteArray& key, const QVariant& value) @@ -200,7 +200,7 @@ //! it's not possible now because we don't have connection context in KDbFunctionExpressionData if (!d->fuzzystrmatchExtensionCreated) { d->fuzzystrmatchExtensionCreated - = drv_executeVoidSQL(KDbEscapedString("CREATE EXTENSION IF NOT EXISTS fuzzystrmatch")); + = drv_executeSql(KDbEscapedString("CREATE EXTENSION IF NOT EXISTS fuzzystrmatch")); } PQclear(result); return true; @@ -218,26 +218,26 @@ //postgresqlDebug() << dbName; //! @todo Maybe should check that dbname is no the currentdb - if (executeVoidSQL(KDbEscapedString("DROP DATABASE ") + escapeIdentifier(dbName))) + if (executeSql(KDbEscapedString("DROP DATABASE ") + escapeIdentifier(dbName))) return true; return false; } -KDbSqlResult* PostgresqlConnection::drv_executeSQL(const KDbEscapedString& sql) +KDbSqlResult* PostgresqlConnection::drv_prepareSql(const KDbEscapedString& sql) { - PGresult* result = d->executeSQL(sql); + PGresult* result = d->executeSql(sql); const ExecStatusType status = PQresultStatus(result); if (status == PGRES_TUPLES_OK || status == PGRES_COMMAND_OK) { return new PostgresqlSqlResult(this, result, status); } storeResult(result, status); return nullptr; } -bool PostgresqlConnection::drv_executeVoidSQL(const KDbEscapedString& sql) +bool PostgresqlConnection::drv_executeSql(const KDbEscapedString& sql) { - PGresult* result = d->executeSQL(sql); + PGresult* result = d->executeSql(sql); const ExecStatusType status = PQresultStatus(result); d->storeResultAndClear(&m_result, &result, status); return status == PGRES_TUPLES_OK || status == PGRES_COMMAND_OK; diff --git a/src/drivers/postgresql/PostgresqlConnection_p.h b/src/drivers/postgresql/PostgresqlConnection_p.h --- a/src/drivers/postgresql/PostgresqlConnection_p.h +++ b/src/drivers/postgresql/PostgresqlConnection_p.h @@ -44,7 +44,7 @@ virtual ~PostgresqlConnectionInternal(); //! Executes query for a raw SQL statement @a sql on the database - PGresult* executeSQL(const KDbEscapedString& sql); + PGresult* executeSql(const KDbEscapedString& sql); static QString serverResultName(int resultCode); @@ -161,10 +161,11 @@ KDbField *createField(const QString &tableName, int index) override Q_REQUIRED_RESULT; - inline KDbSqlRecord* fetchRecord() override Q_REQUIRED_RESULT { - return recordToFetch < recordsCount - ? new PostgresqlSqlRecord(result, recordToFetch++) - : nullptr; + inline QSharedPointer fetchRecord() override Q_REQUIRED_RESULT + { + return QSharedPointer(recordToFetch < recordsCount + ? new PostgresqlSqlRecord(result, recordToFetch++) + : nullptr); } inline KDbResult lastResult() override { diff --git a/src/drivers/postgresql/PostgresqlConnection_p.cpp b/src/drivers/postgresql/PostgresqlConnection_p.cpp --- a/src/drivers/postgresql/PostgresqlConnection_p.cpp +++ b/src/drivers/postgresql/PostgresqlConnection_p.cpp @@ -62,7 +62,7 @@ result->setServerMessage(QString::fromLatin1(msg)); } -PGresult* PostgresqlConnectionInternal::executeSQL(const KDbEscapedString& sql) +PGresult* PostgresqlConnectionInternal::executeSql(const KDbEscapedString& sql) { //! @todo consider using binary mode with PQexecParams() return PQexec(conn, sql.toByteArray().constData()); diff --git a/src/drivers/postgresql/PostgresqlCursor.cpp b/src/drivers/postgresql/PostgresqlCursor.cpp --- a/src/drivers/postgresql/PostgresqlCursor.cpp +++ b/src/drivers/postgresql/PostgresqlCursor.cpp @@ -59,7 +59,7 @@ //Create a cursor result set bool PostgresqlCursor::drv_open(const KDbEscapedString& sql) { - d->res = d->executeSQL(sql); + d->res = d->executeSql(sql); d->resultStatus = PQresultStatus(d->res); if (d->resultStatus != PGRES_TUPLES_OK && d->resultStatus != PGRES_COMMAND_OK) { storeResultAndClear(&d->res, d->resultStatus); diff --git a/src/drivers/postgresql/PostgresqlPreparedStatement.h b/src/drivers/postgresql/PostgresqlPreparedStatement.h --- a/src/drivers/postgresql/PostgresqlPreparedStatement.h +++ b/src/drivers/postgresql/PostgresqlPreparedStatement.h @@ -33,12 +33,10 @@ bool prepare(const KDbEscapedString& sql) override; - KDbSqlResult* execute( - KDbPreparedStatement::Type type, - const KDbField::List& selectFieldList, - KDbFieldList* insertFieldList, - const KDbPreparedStatementParameters& parameters, - bool *resultOwned) override Q_REQUIRED_RESULT; + QSharedPointer execute(KDbPreparedStatement::Type type, + const KDbField::List &selectFieldList, + KDbFieldList *insertFieldList, + const KDbPreparedStatementParameters ¶meters) override Q_REQUIRED_RESULT; private: Q_DISABLE_COPY(PostgresqlPreparedStatement) diff --git a/src/drivers/postgresql/PostgresqlPreparedStatement.cpp b/src/drivers/postgresql/PostgresqlPreparedStatement.cpp --- a/src/drivers/postgresql/PostgresqlPreparedStatement.cpp +++ b/src/drivers/postgresql/PostgresqlPreparedStatement.cpp @@ -38,13 +38,12 @@ return true; } -KDbSqlResult* PostgresqlPreparedStatement::execute( - KDbPreparedStatement::Type type, - const KDbField::List& selectFieldList, - KDbFieldList* insertFieldList, - const KDbPreparedStatementParameters& parameters, bool *resultOwned) +QSharedPointer PostgresqlPreparedStatement::execute( + KDbPreparedStatement::Type type, const KDbField::List &selectFieldList, + KDbFieldList *insertFieldList, const KDbPreparedStatementParameters ¶meters) { Q_UNUSED(selectFieldList); + QSharedPointer result; if (type == KDbPreparedStatement::InsertStatement) { const int missingValues = insertFieldList->fieldCount() - parameters.count(); KDbPreparedStatementParameters myParameters(parameters); @@ -54,13 +53,8 @@ myParameters.append(QVariant()); } } - KDbSqlResult* result; - if (connection->insertRecord(insertFieldList, myParameters, &result)) { - *resultOwned = false; - return result; - } - return nullptr; + result = connection->insertRecord(insertFieldList, myParameters); } //! @todo support select - return nullptr; + return result; } diff --git a/src/drivers/sqlite/SqliteConnection.h b/src/drivers/sqlite/SqliteConnection.h --- a/src/drivers/sqlite/SqliteConnection.h +++ b/src/drivers/sqlite/SqliteConnection.h @@ -83,8 +83,9 @@ anymore, so database file is just removed. See note from drv_useDatabase(). */ bool drv_dropDatabase(const QString &dbName = QString()) override; - KDbSqlResult* drv_executeSQL(const KDbEscapedString& sql) override; - bool drv_executeVoidSQL(const KDbEscapedString& sql) override; + KDbSqlResult* drv_prepareSql(const KDbEscapedString& sql) override; + + bool drv_executeSql(const KDbEscapedString& sql) override; //! Implemented for KDbResultable QString serverResultName() const override; diff --git a/src/drivers/sqlite/SqliteConnection.cpp b/src/drivers/sqlite/SqliteConnection.cpp --- a/src/drivers/sqlite/SqliteConnection.cpp +++ b/src/drivers/sqlite/SqliteConnection.cpp @@ -171,7 +171,7 @@ // Works with 3.6.23. Earlier version just ignore this pragma. // See http://www.sqlite.org/pragma.html#pragma_secure_delete //! @todo add connection flags to the driver and global setting to control the "secure delete" pragma - if (!drv_executeVoidSQL(KDbEscapedString("PRAGMA secure_delete = on"))) { + if (!drv_executeSql(KDbEscapedString("PRAGMA secure_delete = on"))) { drv_closeDatabaseSilently(); return false; } @@ -181,7 +181,7 @@ return false; } // load ROOT collation for use as default collation - if (!drv_executeVoidSQL(KDbEscapedString("SELECT icu_load_collation('', '')"))) { + if (!drv_executeSql(KDbEscapedString("SELECT icu_load_collation('', '')"))) { drv_closeDatabaseSilently(); return false; } @@ -289,10 +289,10 @@ return new SqliteCursor(this, query, options); } -KDbSqlResult* SqliteConnection::drv_executeSQL(const KDbEscapedString& sql) +KDbSqlResult* SqliteConnection::drv_prepareSql(const KDbEscapedString& sql) { #ifdef KDB_DEBUG_GUI - KDb::debugGUI(QLatin1String("ExecuteSQL (SQLite): ") + sql.toString()); + KDb::debugGUI(QLatin1String("PrepareSQL (SQLite): ") + sql.toString()); #endif sqlite3_stmt *prepared_st = nullptr; @@ -318,10 +318,10 @@ return new SqliteSqlResult(this, prepared_st); } -bool SqliteConnection::drv_executeVoidSQL(const KDbEscapedString& sql) +bool SqliteConnection::drv_executeSql(const KDbEscapedString& sql) { #ifdef KDB_DEBUG_GUI - KDb::debugGUI(QLatin1String("ExecuteVoidSQL (SQLite): ") + sql.toString()); + KDb::debugGUI(QLatin1String("ExecuteSQL (SQLite): ") + sql.toString()); #endif char *errmsg_p = nullptr; diff --git a/src/drivers/sqlite/SqliteConnection_p.h b/src/drivers/sqlite/SqliteConnection_p.h --- a/src/drivers/sqlite/SqliteConnection_p.h +++ b/src/drivers/sqlite/SqliteConnection_p.h @@ -146,15 +146,15 @@ KDbField *createField(const QString &tableName, int index) override Q_REQUIRED_RESULT; - inline KDbSqlRecord* fetchRecord() override Q_REQUIRED_RESULT { + inline QSharedPointer fetchRecord() override Q_REQUIRED_RESULT { SqliteSqlRecord *record; const int res = sqlite3_step(prepared_st); if (res == SQLITE_ROW) { record = new SqliteSqlRecord(prepared_st); } else { record = nullptr; } - return record; + return QSharedPointer(record); } inline KDbResult lastResult() override { diff --git a/src/drivers/sqlite/SqliteConnection_p.cpp b/src/drivers/sqlite/SqliteConnection_p.cpp --- a/src/drivers/sqlite/SqliteConnection_p.cpp +++ b/src/drivers/sqlite/SqliteConnection_p.cpp @@ -139,8 +139,8 @@ if (!cachedFieldInfos.isEmpty()) { return true; } - QScopedPointer tableInfoResult(conn->executeSQL( - KDbEscapedString("PRAGMA table_info(%1)").arg(conn->escapeIdentifier(tableName)))); + QSharedPointer tableInfoResult = conn->prepareSql( + KDbEscapedString("PRAGMA table_info(%1)").arg(conn->escapeIdentifier(tableName))); if (!tableInfoResult) { return false; } @@ -179,7 +179,7 @@ bool ok = true; Q_FOREVER { - QScopedPointer record(tableInfoResult->fetchRecord()); + QSharedPointer record = tableInfoResult->fetchRecord(); if (!record) { ok = !tableInfoResult->lastResult().isError(); break; diff --git a/src/drivers/sqlite/SqlitePreparedStatement.h b/src/drivers/sqlite/SqlitePreparedStatement.h --- a/src/drivers/sqlite/SqlitePreparedStatement.h +++ b/src/drivers/sqlite/SqlitePreparedStatement.h @@ -36,16 +36,15 @@ protected: bool prepare(const KDbEscapedString& sql) override; - KDbSqlResult* execute( - KDbPreparedStatement::Type type, - const KDbField::List& selectFieldList, - KDbFieldList* insertFieldList, - const KDbPreparedStatementParameters& parameters, - bool *resultOwned) override Q_REQUIRED_RESULT; + QSharedPointer execute(KDbPreparedStatement::Type type, + const KDbField::List &selectFieldList, KDbFieldList *insertFieldList, + const KDbPreparedStatementParameters ¶meters) override Q_REQUIRED_RESULT; bool bindValue(KDbField *field, const QVariant& value, int arg); - QScopedPointer m_sqlResult; + inline SqliteSqlResult *sqlResult() { return static_cast(m_sqlResult.data()); } + + QSharedPointer m_sqlResult; private: Q_DISABLE_COPY(SqlitePreparedStatement) }; diff --git a/src/drivers/sqlite/SqlitePreparedStatement.cpp b/src/drivers/sqlite/SqlitePreparedStatement.cpp --- a/src/drivers/sqlite/SqlitePreparedStatement.cpp +++ b/src/drivers/sqlite/SqlitePreparedStatement.cpp @@ -35,16 +35,16 @@ bool SqlitePreparedStatement::prepare(const KDbEscapedString& sql) { - m_sqlResult.reset(static_cast(connection->executeSQL(sql))); + m_sqlResult = connection->prepareSql(sql); m_result = connection->result(); return m_sqlResult && !m_result.isError(); } bool SqlitePreparedStatement::bindValue(KDbField *field, const QVariant& value, int par) { if (value.isNull()) { //no value to bind or the value is null: bind NULL - int res = sqlite3_bind_null(m_sqlResult->prepared_st, par); + int res = sqlite3_bind_null(sqlResult()->prepared_st, par); if (res != SQLITE_OK) { m_result.setServerErrorCode(res); storeResult(&m_result); @@ -55,7 +55,7 @@ if (field->isTextType()) { //! @todo optimize: make a static copy so SQLITE_STATIC can be used const QByteArray utf8String(value.toString().toUtf8()); - int res = sqlite3_bind_text(m_sqlResult->prepared_st, par, + int res = sqlite3_bind_text(sqlResult()->prepared_st, par, utf8String.constData(), utf8String.length(), SQLITE_TRANSIENT /*??*/); if (res != SQLITE_OK) { m_result.setServerErrorCode(res); @@ -73,14 +73,14 @@ bool ok; const int intValue = value.toInt(&ok); if (ok) { - int res = sqlite3_bind_int(m_sqlResult->prepared_st, par, intValue); + int res = sqlite3_bind_int(sqlResult()->prepared_st, par, intValue); if (res != SQLITE_OK) { m_result.setServerErrorCode(res); storeResult(&m_result); return false; } } else { - int res = sqlite3_bind_null(m_sqlResult->prepared_st, par); + int res = sqlite3_bind_null(sqlResult()->prepared_st, par); if (res != SQLITE_OK) { m_result.setServerErrorCode(res); storeResult(&m_result); @@ -91,7 +91,7 @@ } case KDbField::Float: case KDbField::Double: { - int res = sqlite3_bind_double(m_sqlResult->prepared_st, par, value.toDouble()); + int res = sqlite3_bind_double(sqlResult()->prepared_st, par, value.toDouble()); if (res != SQLITE_OK) { m_result.setServerErrorCode(res); storeResult(&m_result); @@ -104,14 +104,14 @@ bool ok; const qint64 int64Value = value.toLongLong(&ok); if (ok) { - int res = sqlite3_bind_int64(m_sqlResult->prepared_st, par, int64Value); + int res = sqlite3_bind_int64(sqlResult()->prepared_st, par, int64Value); if (res != SQLITE_OK) { m_result.setServerErrorCode(res); storeResult(&m_result); return false; } } else { - int res = sqlite3_bind_null(m_sqlResult->prepared_st, par); + int res = sqlite3_bind_null(sqlResult()->prepared_st, par); if (res != SQLITE_OK) { m_result.setServerErrorCode(res); storeResult(&m_result); @@ -121,7 +121,7 @@ break; } case KDbField::Boolean: { - int res = sqlite3_bind_text(m_sqlResult->prepared_st, par, value.toBool() ? "1" : "0", + int res = sqlite3_bind_text(sqlResult()->prepared_st, par, value.toBool() ? "1" : "0", 1, SQLITE_TRANSIENT /*??*/); if (res != SQLITE_OK) { m_result.setServerErrorCode(res); @@ -131,7 +131,7 @@ break; } case KDbField::Time: { - int res = sqlite3_bind_text(m_sqlResult->prepared_st, par, + int res = sqlite3_bind_text(sqlResult()->prepared_st, par, qPrintable(value.toTime().toString(Qt::ISODate)), QLatin1String("HH:MM:SS").size(), SQLITE_TRANSIENT /*??*/); if (res != SQLITE_OK) { @@ -142,7 +142,7 @@ break; } case KDbField::Date: { - int res = sqlite3_bind_text(m_sqlResult->prepared_st, par, + int res = sqlite3_bind_text(sqlResult()->prepared_st, par, qPrintable(value.toDate().toString(Qt::ISODate)), QLatin1String("YYYY-MM-DD").size(), SQLITE_TRANSIENT /*??*/); if (res != SQLITE_OK) { @@ -153,7 +153,7 @@ break; } case KDbField::DateTime: { - int res = sqlite3_bind_text(m_sqlResult->prepared_st, par, + int res = sqlite3_bind_text(sqlResult()->prepared_st, par, qPrintable(value.toDateTime().toString(Qt::ISODate)), QLatin1String("YYYY-MM-DDTHH:MM:SS").size(), SQLITE_TRANSIENT /*??*/); if (res != SQLITE_OK) { @@ -165,7 +165,7 @@ } case KDbField::BLOB: { const QByteArray byteArray(value.toByteArray()); - int res = sqlite3_bind_blob(m_sqlResult->prepared_st, par, + int res = sqlite3_bind_blob(sqlResult()->prepared_st, par, byteArray.constData(), byteArray.size(), SQLITE_TRANSIENT /*??*/); if (res != SQLITE_OK) { m_result.setServerErrorCode(res); @@ -177,7 +177,7 @@ default: { sqliteWarning() << "unsupported field type:" << field->type() << "- NULL value bound to column #" << par; - int res = sqlite3_bind_null(m_sqlResult->prepared_st, par); + int res = sqlite3_bind_null(sqlResult()->prepared_st, par); if (res != SQLITE_OK) { m_result.setServerErrorCode(res); storeResult(&m_result); @@ -188,16 +188,15 @@ return true; } -KDbSqlResult* SqlitePreparedStatement::execute( +QSharedPointer SqlitePreparedStatement::execute( KDbPreparedStatement::Type type, const KDbField::List& selectFieldList, KDbFieldList* insertFieldList, - const KDbPreparedStatementParameters& parameters, bool *resultOwned) + const KDbPreparedStatementParameters& parameters) { Q_UNUSED(insertFieldList); - Q_UNUSED(resultOwned); - if (!m_sqlResult->prepared_st) { - return nullptr; + if (!sqlResult()->prepared_st) { + return QSharedPointer(); } int par = 1; // par.index counted from 1 @@ -207,22 +206,22 @@ it += (it == parameters.constEnd() ? 0 : 1), ++itFields, par++) { if (!bindValue(*itFields, it == parameters.constEnd() ? QVariant() : *it, par)) - return nullptr; + return QSharedPointer(); } //real execution - const int res = sqlite3_step(m_sqlResult->prepared_st); + const int res = sqlite3_step(sqlResult()->prepared_st); if (type == KDbPreparedStatement::InsertStatement) { const bool ok = res == SQLITE_DONE; if (ok) { m_result = KDbResult(); } else { m_result.setServerErrorCode(res); storeResult(&m_result); - sqliteWarning() << m_result << QString::fromLatin1(sqlite3_sql(m_sqlResult->prepared_st)); + sqliteWarning() << m_result << QString::fromLatin1(sqlite3_sql(sqlResult()->prepared_st)); } - (void)sqlite3_reset(m_sqlResult->prepared_st); - return m_sqlResult.data(); + (void)sqlite3_reset(sqlResult()->prepared_st); + return m_sqlResult; } else if (type == KDbPreparedStatement::SelectStatement) { //! @todo fetch result @@ -233,10 +232,10 @@ } else { m_result.setServerErrorCode(res); storeResult(&m_result); - sqliteWarning() << m_result << QString::fromLatin1(sqlite3_sql(m_sqlResult->prepared_st)); + sqliteWarning() << m_result << QString::fromLatin1(sqlite3_sql(sqlResult()->prepared_st)); } - (void)sqlite3_reset(m_sqlResult->prepared_st); - return m_sqlResult.data(); + (void)sqlite3_reset(sqlResult()->prepared_st); + return m_sqlResult; } - return nullptr; + return QSharedPointer(); } diff --git a/src/drivers/sybase/SybaseConnection.h b/src/drivers/sybase/SybaseConnection.h --- a/src/drivers/sybase/SybaseConnection.h +++ b/src/drivers/sybase/SybaseConnection.h @@ -55,7 +55,7 @@ KDbMessageHandler* msgHandler = 0); virtual bool drv_closeDatabase(); virtual bool drv_dropDatabase(const QString &dbName = QString()); - virtual bool drv_executeSQL(const KDbEscapedString& sql); + virtual bool drv_executeSql(const KDbEscapedString& sql); virtual quint64 drv_lastInsertRecordId(); //! Implemented for KDbResultable diff --git a/src/drivers/sybase/SybaseConnection.cpp b/src/drivers/sybase/SybaseConnection.cpp --- a/src/drivers/sybase/SybaseConnection.cpp +++ b/src/drivers/sybase/SybaseConnection.cpp @@ -95,10 +95,10 @@ { //sybaseDebug() << dbName; // mysql_create_db deprecated, use SQL here. - if (drv_executeVoidSQL(KDbEscapedString("CREATE DATABASE ") + dbName)) { + if (drv_executeSql(KDbEscapedString("CREATE DATABASE ") + dbName)) { // set allow_nulls_by_default option to true KDbEscapedString allowNullsQuery = KDbEscapedString("sp_dboption %1, allow_nulls_by_default, true").arg(dbName); - if (drv_executeVoidSQL(allowNullsQuery.data())) + if (drv_executeSql(allowNullsQuery.data())) return true; } d->storeResult(); @@ -123,12 +123,12 @@ bool SybaseConnection::drv_dropDatabase(const QString &dbName) { - return drv_executeVoidSQL(KDbEscapedString("DROP DATABASE ") + escapeString(dbName)); + return drv_executeSql(KDbEscapedString("DROP DATABASE ") + escapeString(dbName)); } -bool SybaseConnection::drv_executeSQL(const KDbEscapedString& sql) +bool SybaseConnection::drv_executeSql(const KDbEscapedString& sql) { - return d->executeSQL(sql); + return d->executeSql(sql); } quint64 SybaseConnection::drv_lastInsertRecordId() @@ -179,7 +179,7 @@ return true; // explicit insertion into IDENTITY fields !! - return drv_executeVoidSQL(KDbEscapedString("SET IDENTITY_INSERT %1 ON").arg(escapeIdentifier(table))); + return drv_executeSql(KDbEscapedString("SET IDENTITY_INSERT %1 ON").arg(escapeIdentifier(table))); } @@ -192,7 +192,7 @@ return true; // explicit insertion into IDENTITY fields has taken place. Turn off IDENTITY_INSERT - return drv_executeVoidSQL(KDbEscapedString("SET IDENTITY_INSERT %1 OFF").arg(escapeIdentifier(table))); + return drv_executeSql(KDbEscapedString("SET IDENTITY_INSERT %1 OFF").arg(escapeIdentifier(table))); } @@ -202,7 +202,7 @@ return true; // explicit update of IDENTITY fields has taken place. - return drv_executeVoidSQL(KDbEscapedString("SET IDENTITY_UPDATE %1 ON").arg(escapeIdentifier(table))); + return drv_executeSql(KDbEscapedString("SET IDENTITY_UPDATE %1 ON").arg(escapeIdentifier(table))); } bool KDbSybaseConnection::drv_afterUpdate(const QString& table, KDbFieldList& fields) @@ -214,5 +214,5 @@ return true; // explicit insertion into IDENTITY fields has taken place. Turn off IDENTITY_INSERT - return drv_executeVoidSQL(KDbEscapedString("SET IDENTITY_UPDATE %1 OFF").arg(escapeIdentifier(table))); + return drv_executeSql(KDbEscapedString("SET IDENTITY_UPDATE %1 OFF").arg(escapeIdentifier(table))); } diff --git a/src/drivers/sybase/SybaseConnection_p.h b/src/drivers/sybase/SybaseConnection_p.h --- a/src/drivers/sybase/SybaseConnection_p.h +++ b/src/drivers/sybase/SybaseConnection_p.h @@ -58,7 +58,7 @@ bool useDatabase(const QString &dbName = QString()); //! Executes query for a raw SQL statement @a sql on the database - bool executeSQL(const KDbEscapedString& sql); + bool executeSql(const KDbEscapedString& sql); //! Stores last operation's result virtual void storeResult(); diff --git a/src/drivers/sybase/SybaseConnection_p.cpp b/src/drivers/sybase/SybaseConnection_p.cpp --- a/src/drivers/sybase/SybaseConnection_p.cpp +++ b/src/drivers/sybase/SybaseConnection_p.cpp @@ -210,7 +210,7 @@ return false; } -bool SybaseConnectionInternal::executeSQL(const KDbEscapedString& sql) +bool SybaseConnectionInternal::executeSql(const KDbEscapedString& sql) { // remove queries in buffer if any. flush existing results if any dbcancel(dbProcess); diff --git a/src/drivers/xbase/XbaseConnection.h b/src/drivers/xbase/XbaseConnection.h --- a/src/drivers/xbase/XbaseConnection.h +++ b/src/drivers/xbase/XbaseConnection.h @@ -55,7 +55,7 @@ KDbMessageHandler* msgHandler = 0 ); virtual bool drv_closeDatabase(); virtual bool drv_dropDatabase(const QString &dbName = QString()); - virtual bool drv_executeSQL(const KDbEscapedString& sql); + virtual bool drv_executeSql(const KDbEscapedString& sql); virtual quint64 drv_lastInsertRecordId(); //! Implemented for KDbResultable diff --git a/src/drivers/xbase/XbaseConnection.cpp b/src/drivers/xbase/XbaseConnection.cpp --- a/src/drivers/xbase/XbaseConnection.cpp +++ b/src/drivers/xbase/XbaseConnection.cpp @@ -105,8 +105,8 @@ return true; } -bool xBaseConnection::drv_executeSQL( const KDbEscapedString& sql ) { - return d->executeSQL(sql); +bool xBaseConnection::drv_executeSql( const KDbEscapedString& sql ) { + return d->executeSql(sql); } quint64 xBaseConnection::drv_lastInsertRecordId() diff --git a/src/drivers/xbase/XbaseConnection_p.h b/src/drivers/xbase/XbaseConnection_p.h --- a/src/drivers/xbase/XbaseConnection_p.h +++ b/src/drivers/xbase/XbaseConnection_p.h @@ -47,7 +47,7 @@ bool useDatabase(const QString &dbName = QString()); //! Execute SQL statement on the database - bool executeSQL(const KDbEscapedString& sql); + bool executeSql(const KDbEscapedString& sql); //! Stores last operation's result virtual void storeResult(); diff --git a/src/drivers/xbase/XbaseConnection_p.cpp b/src/drivers/xbase/XbaseConnection_p.cpp --- a/src/drivers/xbase/XbaseConnection_p.cpp +++ b/src/drivers/xbase/XbaseConnection_p.cpp @@ -163,11 +163,11 @@ return internalConn->useDatabase(dbMap[dbName]); } -bool xBaseConnectionInternal::executeSQL(const KDbEscapedString& sql) +bool xBaseConnectionInternal::executeSql(const KDbEscapedString& sql) { //xbaseDebug() << statement; if ( !internalConn ) { return false; } - return internalConn->executeSQL(sql); + return internalConn->executeSql(sql); } diff --git a/src/expression/KDbFunctionExpression.cpp b/src/expression/KDbFunctionExpression.cpp --- a/src/expression/KDbFunctionExpression.cpp +++ b/src/expression/KDbFunctionExpression.cpp @@ -706,7 +706,7 @@ alphabetic characters. */ // See also https://dev.mysql.com/doc/refman/5.1/en/string-functions.html#function_soundex // See also http://www.postgresql.org/docs/9.5/static/fuzzystrmatch.html#AEN165853 - //! @todo we call drv_executeVoidSQL("CREATE EXTENSION IF NOT EXISTS fuzzystrmatch") on connection, + //! @todo we call drv_executeSql("CREATE EXTENSION IF NOT EXISTS fuzzystrmatch") on connection, //! do that on first use of SOUNDEX() // example: SELECT SOUNDEX("John") // result: "J500" diff --git a/src/interfaces/KDbPreparedStatementInterface.h b/src/interfaces/KDbPreparedStatementInterface.h --- a/src/interfaces/KDbPreparedStatementInterface.h +++ b/src/interfaces/KDbPreparedStatementInterface.h @@ -47,15 +47,11 @@ //! @a selectFieldList specifies fields for SELECT statement. //! @a insertFieldList is set to list of fields in INSERT statement. //! Parameters @a parameters are passed to the statement, usually using binding. - //! The value pointed by @a resultOwned is set to true if the returned SQL result is owned - //! by the prepared statement object. This is expected and the default behaviour. - //! If the value pointed by @a resultOwned is set to @c false, the KDbSqlResult object - //! will be deleted by the KDbPreparedStatement object before returning. - virtual KDbSqlResult* execute( + virtual QSharedPointer execute( KDbPreparedStatement::Type type, const KDbField::List& selectFieldList, KDbFieldList* insertFieldList, - const KDbPreparedStatementParameters& parameters, bool *resultOwned) Q_REQUIRED_RESULT = 0; + const KDbPreparedStatementParameters& parameters) Q_REQUIRED_RESULT = 0; friend class KDbConnection; friend class KDbPreparedStatement; diff --git a/src/sql/KDbSqlResult.h b/src/sql/KDbSqlResult.h --- a/src/sql/KDbSqlResult.h +++ b/src/sql/KDbSqlResult.h @@ -21,6 +21,7 @@ #define KDB_SQLRESULT_H #include "kdb_export.h" +#include #include class KDbConnection; @@ -30,10 +31,15 @@ class KDbSqlField; class KDbSqlRecord; -//! The KDbSqlResult class abstracts result of execution of raw SQL query executed using KDbConnection::executeSQL() /** - * KDbSqlResult allows to return low-level information about fields of the result - * and fetch records. + * The KDbSqlResult class abstracts result of a raw SQL query preparation by KDbConnection::prepareSql() + * + * The KDbSqlResult object provides low-level access to information about fields of the result and + * can fetch records by actual execution of the prepared query. + * + * @note the KDbSqlResult object should be deleted before closing the database connection that + * created it. This is needed because the connection is used by the object to retrieve data or to + * obtain status information. */ class KDB_EXPORT KDbSqlResult { @@ -57,9 +63,14 @@ //! be ignored as well if the KDbSqlResult already has field metadata available. virtual KDbField* createField(const QString &tableName, int index) Q_REQUIRED_RESULT = 0; - //! Fetches one record and returns it. @return nullptr if there is no record to fetch or on error. - //! Check lastResult() for errors. - virtual KDbSqlRecord* fetchRecord() Q_REQUIRED_RESULT = 0; + /** + * Fetches one record. + * + * @return a shared pointer to the record or a null pointer if there is no record to fetch or + * on error. + * Check lastResult() for detailed result. Ownership is transferred to the caller. + */ + virtual QSharedPointer fetchRecord() Q_REQUIRED_RESULT = 0; //! Convenience method. Fetches one record and all values into @a data. //! @return record data object and passes its ownership diff --git a/src/sql/KDbSqlResult.cpp b/src/sql/KDbSqlResult.cpp --- a/src/sql/KDbSqlResult.cpp +++ b/src/sql/KDbSqlResult.cpp @@ -33,14 +33,13 @@ KDbRecordData* KDbSqlResult::fetchRecordData() { - QScopedPointer record(fetchRecord()); + QSharedPointer record = fetchRecord(); if (!record) { return nullptr; } - QScopedPointer data(new KDbRecordData(fieldsCount())); + KDbRecordData *data = new KDbRecordData(fieldsCount()); for(int i = 0; i < data->count(); ++i) { (*data)[i] = record->toByteArray(i); } - return data.take(); + return data; } - diff --git a/tests/features/main.cpp b/tests/features/main.cpp --- a/tests/features/main.cpp +++ b/tests/features/main.cpp @@ -338,7 +338,7 @@ #endif if (r) - qDebug() << "RECENT SQL STATEMENT: " << conn->recentSQLString(); + qDebug() << "RECENT SQL STATEMENT: " << conn->recentSqlString(); if (conn && !conn->disconnect()) r = 1;