diff --git a/framework/areg/persist/IEDatabaseEngine.hpp b/framework/areg/persist/IEDatabaseEngine.hpp
index 89d108a22..51e2189e1 100644
--- a/framework/areg/persist/IEDatabaseEngine.hpp
+++ b/framework/areg/persist/IEDatabaseEngine.hpp
@@ -87,6 +87,11 @@ class AREG_API IEDatabaseEngine
**/
virtual bool commit(bool doCommit) = 0;
+ /**
+ * \brief Rolls back the database changes and returns true if succeeded.
+ **/
+ virtual bool rollback(void) = 0;
+
//////////////////////////////////////////////////////////////////////////
// Forbidden calls.
//////////////////////////////////////////////////////////////////////////
diff --git a/framework/aregextend.vcxproj b/framework/aregextend.vcxproj
index 271a3f20c..a9e2e1752 100644
--- a/framework/aregextend.vcxproj
+++ b/framework/aregextend.vcxproj
@@ -47,6 +47,8 @@
+
+
@@ -70,6 +72,8 @@
+
+
diff --git a/framework/aregextend.vcxproj.filters b/framework/aregextend.vcxproj.filters
index b2c1b6d68..90546d8d9 100644
--- a/framework/aregextend.vcxproj.filters
+++ b/framework/aregextend.vcxproj.filters
@@ -72,6 +72,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
@@ -133,6 +139,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
diff --git a/framework/aregextend/db/LogSqliteDatabase.hpp b/framework/aregextend/db/LogSqliteDatabase.hpp
index c047254ba..48d325630 100644
--- a/framework/aregextend/db/LogSqliteDatabase.hpp
+++ b/framework/aregextend/db/LogSqliteDatabase.hpp
@@ -21,6 +21,30 @@
#include "areg/logging/IELogDatabaseEngine.hpp"
#include "areg/base/String.hpp"
+#if 0
+#include
+
+enum eLogItemType
+{
+ ItemUnknown = 0 //!< Unknown log item type
+ , ItemInstance //!< Log instance item
+ , ItemThread //!< Log thread item
+ , ItemScope //!< Log scope item
+ , ItemPriority //!< Log priority item
+};
+
+struct sLogItem
+{
+ ITEM_ID itemId { 0 }; // itemList{ }; //!< The list of log items
+};
+#endif
//////////////////////////////////////////////////////////////////////////
// LogSqliteDatabase class declaration
//////////////////////////////////////////////////////////////////////////
@@ -199,6 +223,39 @@ class LogSqliteDatabase : public IELogDatabaseEngine
**/
virtual bool logScopeDeactivate(const ITEM_ID & cookie, unsigned int scopeId, const DateTime & timestamp) override;
+ /**
+ * \brief Rolls back the database changes and returns true if succeeded.
+ **/
+ virtual bool rollback(void) override;
+
+//////////////////////////////////////////////////////////////////////////
+// Attributes and operations
+//////////////////////////////////////////////////////////////////////////
+#if 0
+ std::vector getLogInstanceNames(void) const;
+
+ std::vector getLogInstances(void) const;
+
+ std::vector getLogThreadNames(void) const;
+
+ std::vector getLogThreads(void) const;
+
+ std::vector getLogScopeNames(void) const;
+
+ std::vector getLogScopes(void) const;
+
+ std::vector getPriorityNames(void) const;
+
+ std::vector getLogInstScopes(ITEM_ID instId) const;
+
+ std::vector getLodMessages(void) const;
+
+ std::vector getLodInstMessages(ITEM_ID instId) const;
+
+ std::vector getLodScopeMessages(ITEM_ID instId, uint32_t scopeId) const;
+
+#endif
+
//////////////////////////////////////////////////////////////////////////
// Hidden methods
//////////////////////////////////////////////////////////////////////////
diff --git a/framework/aregextend/db/SqliteDatabase.hpp b/framework/aregextend/db/SqliteDatabase.hpp
index 8c79f7229..44ac01520 100644
--- a/framework/aregextend/db/SqliteDatabase.hpp
+++ b/framework/aregextend/db/SqliteDatabase.hpp
@@ -29,6 +29,7 @@
**/
class SqliteDatabase : public IEDatabaseEngine
{
+ friend class SqliteStatement;
//////////////////////////////////////////////////////////////////////////
// Constructors / Destructor
//////////////////////////////////////////////////////////////////////////
@@ -111,6 +112,11 @@ class SqliteDatabase : public IEDatabaseEngine
**/
virtual bool commit(bool doCommit) override;
+ /**
+ * \brief Rolls back the database changes and returns true if succeeded.
+ **/
+ virtual bool rollback(void) override;
+
//////////////////////////////////////////////////////////////////////////
// Hidden methods
//////////////////////////////////////////////////////////////////////////
diff --git a/framework/aregextend/db/SqliteRow.hpp b/framework/aregextend/db/SqliteRow.hpp
new file mode 100644
index 000000000..9b673bd7e
--- /dev/null
+++ b/framework/aregextend/db/SqliteRow.hpp
@@ -0,0 +1,204 @@
+#ifndef AREG_AREGEXTEND_DB_SQLITEROW_HPP
+#define AREG_AREGEXTEND_DB_SQLITEROW_HPP
+/************************************************************************
+ * This file is part of the AREG SDK core engine.
+ * AREG SDK is dual-licensed under Free open source (Apache version 2.0
+ * License) and Commercial (with various pricing models) licenses, depending
+ * on the nature of the project (commercial, research, academic or free).
+ * You should have received a copy of the AREG SDK license description in LICENSE.txt.
+ * If not, please contact to info[at]aregtech.com
+ *
+ * \copyright (c) 2017-2023 Aregtech UG. All rights reserved.
+ * \file aregextend/db/SqliteRow.hpp
+ * \author Artak Avetyan
+ * \ingroup AREG platform, extended library, SQLite row object to get results.
+ ************************************************************************/
+
+/************************************************************************
+ * Include files.
+ ************************************************************************/
+#include "areg/base/GEGlobal.h"
+#include "areg/base/String.hpp"
+
+/************************************************************************
+ * Dependencies
+ ************************************************************************/
+class SqliteStatement;
+
+//////////////////////////////////////////////////////////////////////////
+// SqliteRow class declaration
+//////////////////////////////////////////////////////////////////////////
+/**
+ * \brief Represents a single row of results from a SQLite query.
+ * Provides access to column values and metadata for the current row.
+ **/
+class SqliteRow
+{
+//////////////////////////////////////////////////////////////////////////
+// Constructors / operators.
+//////////////////////////////////////////////////////////////////////////
+public:
+ /**
+ * \brief Default constructor. Initializes an invalid row.
+ */
+ SqliteRow(void);
+
+ /**
+ * \brief Constructs a SqliteRow from a SqliteStatement.
+ * \param statement Reference to the SqliteStatement object.
+ */
+ SqliteRow(SqliteStatement& statement);
+
+ /**
+ * \brief Constructs a SqliteRow from a raw statement pointer.
+ * \param statement Pointer to the underlying SQLite statement.
+ */
+ SqliteRow(void* statement);
+
+ /**
+ * \brief Copy constructor.
+ * \param src The source SqliteRow to copy from.
+ */
+ SqliteRow(const SqliteRow& src);
+
+ /**
+ * \brief Move constructor.
+ * \param src The source SqliteRow to move from.
+ */
+ SqliteRow(SqliteRow&& src);
+
+ /**
+ * \brief Destructor. Defaulted.
+ */
+ ~SqliteRow(void) = default;
+
+ /**
+ * \brief Copy assignment operator.
+ * \param src The source SqliteRow to copy from.
+ * \return Reference to this object.
+ */
+ SqliteRow& operator = (const SqliteRow& src);
+
+ /**
+ * \brief Move assignment operator.
+ * \param src The source SqliteRow to move from.
+ * \return Reference to this object.
+ */
+ SqliteRow& operator = (SqliteRow&& src);
+
+//////////////////////////////////////////////////////////////////////////
+// Attributes and operations
+//////////////////////////////////////////////////////////////////////////
+public:
+ /**
+ * \brief Checks if the row is valid (i.e., associated with a statement).
+ * \return True if valid, false otherwise.
+ */
+ inline bool isValid(void) const;
+
+ /**
+ * \brief Retrieves the integer value of the specified column.
+ * \param column The 0-based column index.
+ * \return The integer value of the column.
+ */
+ int getInt(int column) const;
+
+ /**
+ * \brief Retrieves the 64-bit integer value of the specified column.
+ * \param column The 0-based column index.
+ * \return The 64-bit integer value of the column.
+ */
+ int64_t getInt64(int column) const;
+
+ /**
+ * \brief Retrieves the double value of the specified column.
+ * \param column The 0-based column index.
+ * \return The double value of the column.
+ */
+ double getDouble(int column) const;
+
+ /**
+ * \brief Retrieves the text value of the specified column.
+ * \param column The 0-based column index.
+ * \return The string value of the column.
+ */
+ String getText(int column) const;
+
+ /**
+ * \brief Checks if the specified column is NULL.
+ * \param column The 0-based column index.
+ * \return True if the column is NULL, false otherwise.
+ */
+ bool isNull(int column) const;
+
+ /**
+ * \brief Checks if the specified column index is valid.
+ * \param column The 0-based column index.
+ * \return True if the column index is valid, false otherwise.
+ */
+ bool isColumnValid(int column) const;
+
+ /**
+ * \brief Checks if the specified column contains a string value.
+ * \param column The 0-based column index.
+ * \return True if the column is a string, false otherwise.
+ */
+ bool isString(int column) const;
+
+ /**
+ * \brief Checks if the specified column contains a 32-bit integer value.
+ * \param column The 0-based column index.
+ * \return True if the column is a 32-bit integer, false otherwise.
+ */
+ bool isInteger(int column) const;
+
+ /**
+ * \brief Checks if the specified column contains a 64-bit integer value.
+ * \param column The 0-based column index.
+ * \return True if the column is a 64-bit integer, false otherwise.
+ */
+ bool isInteger64(int column) const;
+
+ /**
+ * \brief Checks if the specified column contains a double value.
+ * \param column The 0-based column index.
+ * \return True if the column is a double, false otherwise.
+ */
+ bool isDouble(int column) const;
+
+ /**
+ * \brief Returns the number of columns in the row.
+ * \return The number of columns.
+ */
+ int getColumnCount(void) const;
+
+ /**
+ * \brief Returns the name of the specified column.
+ * \param column The 0-based column index.
+ * \return The name of the column.
+ */
+ String getColumnName(int column) const;
+
+ /**
+ * \brief Returns the index of the column with the specified name.
+ * \param columnName The name of the column.
+ * \return The 0-based index of the column, or -1 if not found.
+ */
+ int getColumnIndex(const String& columnName) const;
+
+//////////////////////////////////////////////////////////////////////////
+// Member variables
+//////////////////////////////////////////////////////////////////////////
+protected:
+ /**
+ * \brief Pointer to the underlying SQLite statement.
+ */
+ void* mStatement;
+};
+
+inline bool SqliteRow::isValid(void) const
+{
+ return (mStatement != nullptr);
+}
+
+#endif // AREG_AREGEXTEND_DB_SQLITEROW_HPP
diff --git a/framework/aregextend/db/SqliteStatement.hpp b/framework/aregextend/db/SqliteStatement.hpp
new file mode 100644
index 000000000..e7d1c612a
--- /dev/null
+++ b/framework/aregextend/db/SqliteStatement.hpp
@@ -0,0 +1,308 @@
+#ifndef AREG_AREGEXTEND_DB_SQLITESTATEMENT_HPP
+#define AREG_AREGEXTEND_DB_SQLITESTATEMENT_HPP
+/************************************************************************
+ * This file is part of the AREG SDK core engine.
+ * AREG SDK is dual-licensed under Free open source (Apache version 2.0
+ * License) and Commercial (with various pricing models) licenses, depending
+ * on the nature of the project (commercial, research, academic or free).
+ * You should have received a copy of the AREG SDK license description in LICENSE.txt.
+ * If not, please contact to info[at]aregtech.com
+ *
+ * \copyright (c) 2017-2023 Aregtech UG. All rights reserved.
+ * \file aregextend/db/SqliteStatement.hpp
+ * \author Artak Avetyan
+ * \ingroup AREG platform, extended library, SQLite statement object.
+ ************************************************************************/
+
+/************************************************************************
+ * Include files.
+ ************************************************************************/
+#include "areg/base/GEGlobal.h"
+#include "areg/base/String.hpp"
+#include "aregextend/db/SqliteRow.hpp"
+
+class SqliteDatabase;
+
+//////////////////////////////////////////////////////////////////////////
+// SqliteStatement class declaration
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * /brief This class represents a prepared SQL statement that can be executed against a SqliteDatabase.
+ **/
+class SqliteStatement
+{
+ friend class SqliteRow;
+
+//////////////////////////////////////////////////////////////////////////
+// Internal types and constants
+//////////////////////////////////////////////////////////////////////////
+public:
+ /**
+ * \brief Enum representing the type of a column in the result set.
+ */
+ enum class eColumnType
+ {
+ ColumnUnknown = 0 //!< Unknown column type.
+ , ColumnInteger //!< 32-bit integer column.
+ , ColumnInteger64 //!< 64-bit integer column.
+ , ColumnDouble //!< Double-precision floating point column.
+ , ColumnText //!< Text (string) column.
+ , ColumnBlob //!< Binary large object column.
+ , ColumnNull //!< Null column.
+ };
+
+//////////////////////////////////////////////////////////////////////////
+// Constructors / Destructor
+//////////////////////////////////////////////////////////////////////////
+public:
+ /**
+ * \brief Constructs a SqliteStatement and prepares the given SQL statement.
+ * \param db Reference to the SqliteDatabase object.
+ * \param sql The SQL statement to prepare.
+ */
+ SqliteStatement(SqliteDatabase& db, const String& sql);
+
+ /**
+ * \brief Constructs a SqliteStatement associated with the given database.
+ * The statement is not prepared until prepare() is called.
+ * \param db Reference to the SqliteDatabase object.
+ */
+ SqliteStatement(SqliteDatabase& db);
+
+ /**
+ * \brief Destructor. Finalizes the statement and releases resources.
+ */
+ ~SqliteStatement(void);
+
+//////////////////////////////////////////////////////////////////////////
+// Attributes and operations
+//////////////////////////////////////////////////////////////////////////
+public:
+ /**
+ * \brief Prepares the SQL statement for execution.
+ * \param sql The SQL statement to prepare.
+ * \return True if the statement was prepared successfully, false otherwise.
+ */
+ bool prepare(const String& sql);
+
+ /**
+ * \brief Executes the prepared statement (for non-SELECT statements).
+ * \return True if execution was successful, false otherwise.
+ */
+ bool execute(void);
+
+ /**
+ * \brief Advances to the next row in the result set.
+ * \return True if a new row is available, false if there are no more rows.
+ */
+ bool next(void);
+
+ /**
+ * \brief Resets the statement to its initial state, ready for re-execution.
+ */
+ void reset(void);
+
+ /**
+ * \brief Finalizes the statement and releases associated resources.
+ */
+ void finalize(void);
+
+ /**
+ * \brief Checks if the statement is prepared and ready for execution.
+ * \return True if the statement is prepared, false otherwise.
+ */
+ inline bool isValid(void) const;
+
+ /**
+ * \brief Returns the current row position in the result set.
+ * The first row starts with 1. Return 0 if SQL statement is not prepared yet.
+ **/
+ inline uint32_t getRowPos(void) const;
+
+ /**
+ * \brief Binds an integer value to the specified parameter index.
+ * \param index The 1-based parameter index.
+ * \param value The integer value to bind.
+ * \return True if binding was successful, false otherwise.
+ */
+ bool bindInt(int index, int value);
+
+ /**
+ * \brief Binds a 64-bit integer value to the specified parameter index.
+ * \param index The 1-based parameter index.
+ * \param value The 64-bit integer value to bind.
+ * \return True if binding was successful, false otherwise.
+ */
+ bool bindInt64(int index, int64_t value);
+
+ /**
+ * \brief Binds a double value to the specified parameter index.
+ * \param index The 1-based parameter index.
+ * \param value The double value to bind.
+ * \return True if binding was successful, false otherwise.
+ */
+ bool bindDouble(int index, double value);
+
+ /**
+ * \brief Binds a text value to the specified parameter index.
+ * \param index The 1-based parameter index.
+ * \param value The string value to bind.
+ * \return True if binding was successful, false otherwise.
+ */
+ bool bindText(int index, const String& value);
+
+ /**
+ * \brief Binds a NULL value to the specified parameter index.
+ * \param index The 1-based parameter index.
+ * \return True if binding was successful, false otherwise.
+ */
+ bool bindNull(int index);
+
+ /**
+ * \brief Clears all parameter bindings for the prepared statement.
+ */
+ void clearBindings(void);
+
+ /**
+ * \brief Retrieves the integer value of the specified column in the current row.
+ * \param column The 0-based column index.
+ * \return The integer value of the column.
+ */
+ int getInt(int column) const;
+
+ /**
+ * \brief Retrieves the 64-bit integer value of the specified column in the current row.
+ * \param column The 0-based column index.
+ * \return The 64-bit integer value of the column.
+ */
+ int64_t getInt64(int column) const;
+
+ /**
+ * \brief Retrieves the double value of the specified column in the current row.
+ * \param column The 0-based column index.
+ * \return The double value of the column.
+ */
+ double getDouble(int column) const;
+
+ /**
+ * \brief Retrieves the text value of the specified column in the current row.
+ * \param column The 0-based column index.
+ * \return The string value of the column.
+ */
+ String getText(int column) const;
+
+ /**
+ * \brief Checks if the specified column in the current row is NULL.
+ * \param column The 0-based column index.
+ * \return True if the column is NULL, false otherwise.
+ */
+ bool isNull(int column) const;
+
+ /**
+ * \brief Checks if the specified column index is valid for the current result set.
+ * \param column The 0-based column index.
+ * \return True if the column index is valid, false otherwise.
+ */
+ bool isColumnValid(int column) const;
+
+ /**
+ * \brief Checks if the specified column contains a string value.
+ * \param column The 0-based column index.
+ * \return True if the column is a string, false otherwise.
+ */
+ bool isString(int column) const;
+
+ /**
+ * \brief Checks if the specified column contains a 32-bit integer value.
+ * \param column The 0-based column index.
+ * \return True if the column is a 32-bit integer, false otherwise.
+ */
+ bool isInteger(int column) const;
+
+ /**
+ * \brief Checks if the specified column contains a 64-bit integer value.
+ * \param column The 0-based column index.
+ * \return True if the column is a 64-bit integer, false otherwise.
+ */
+ bool isInteger64(int column) const;
+
+ /**
+ * \brief Checks if the specified column contains a double value.
+ * \param column The 0-based column index.
+ * \return True if the column is a double, false otherwise.
+ */
+ bool isDouble(int column) const;
+
+ /**
+ * \brief Returns the number of columns in the result set.
+ * \return The number of columns.
+ */
+ int getColumnCount(void) const;
+
+ /**
+ * \brief Returns the name of the specified column.
+ * \param column The 0-based column index.
+ * \return The name of the column.
+ */
+ String getColumnName(int column) const;
+
+ /**
+ * \brief Returns the index of the column with the specified name.
+ * \param columnName The name of the column.
+ * \return The 0-based index of the column, or -1 if not found.
+ */
+ int getColumnIndex(const String& columnName) const;
+
+ /**
+ * \brief Returns the type of the specified column.
+ * \param column The 0-based column index.
+ * \return The column type as eColumnType.
+ */
+ SqliteStatement::eColumnType getColumnType(int column) const;
+
+ /**
+ * \brief Returns a SqliteRow object representing the current row.
+ * \return The current SqliteRow.
+ */
+ SqliteRow row() const;
+
+ /**
+ * \brief Advances to the next row and returns a SqliteRow object for it.
+ * \return The next SqliteRow.
+ */
+ SqliteRow nextRow(void) const;
+
+ /**
+ * \brief Advances to the next row in the result set (const overload).
+ * \return True if a new row is available, false otherwise.
+ */
+ bool next(void) const;
+
+//////////////////////////////////////////////////////////////////////////
+// Member variables
+//////////////////////////////////////////////////////////////////////////
+protected:
+ SqliteDatabase& mDatabase; //!< The SQLite database object, which owns this statement.
+ void * mStatement; //!< The SQLite statement object.
+ uint32_t mRowPos; //!< The current row position.
+
+//////////////////////////////////////////////////////////////////////////
+// Forbidden calls
+//////////////////////////////////////////////////////////////////////////
+ SqliteStatement(void) = delete; //!< Default constructor is not allowed.
+ DECLARE_NOCOPY_NOMOVE(SqliteStatement); //!< No copy or move allowed.
+};
+
+inline bool SqliteStatement::isValid(void) const
+{
+ return (mStatement != nullptr);
+}
+
+
+inline uint32_t SqliteStatement::getRowPos(void) const
+{
+ return mRowPos;
+}
+
+#endif // AREG_AREGEXTEND_DB_SQLITESTATEMENT_HPP
diff --git a/framework/aregextend/db/private/CMakeLists.txt b/framework/aregextend/db/private/CMakeLists.txt
index 7e3985d04..5ef04a3b0 100644
--- a/framework/aregextend/db/private/CMakeLists.txt
+++ b/framework/aregextend/db/private/CMakeLists.txt
@@ -1,4 +1,6 @@
macro_add_source(aregextend_SRC "${AREG_FRAMEWORK}"
aregextend/db/private/LogSqliteDatabase.cpp
aregextend/db/private/SqliteDatabase.cpp
+ aregextend/db/private/SqliteRow.cpp
+ aregextend/db/private/SqliteStatement.cpp
)
diff --git a/framework/aregextend/db/private/LogSqliteDatabase.cpp b/framework/aregextend/db/private/LogSqliteDatabase.cpp
index 0104621c6..083480108 100644
--- a/framework/aregextend/db/private/LogSqliteDatabase.cpp
+++ b/framework/aregextend/db/private/LogSqliteDatabase.cpp
@@ -584,3 +584,65 @@ bool LogSqliteDatabase::logScopeDeactivate(const ITEM_ID& cookie, unsigned int s
);
return _execute(sql);
}
+
+bool LogSqliteDatabase::rollback(void)
+{
+ return commit(false);
+}
+
+#if 0
+std::vector LogSqliteDatabase::getLogInstanceNames(void) const
+{
+ return std::vector();
+}
+
+std::vector LogSqliteDatabase::getLogInstances(void) const
+{
+ return std::vector();
+}
+
+std::vector LogSqliteDatabase::getLogThreadNames(void) const
+{
+ return std::vector();
+}
+
+std::vector LogSqliteDatabase::getLogThreads(void) const
+{
+ return std::vector();
+}
+
+std::vector LogSqliteDatabase::getLogScopeNames(void) const
+{
+ return std::vector();
+}
+
+std::vector LogSqliteDatabase::getLogScopes(void) const
+{
+ return std::vector();
+}
+
+std::vector LogSqliteDatabase::getPriorityNames(void) const
+{
+ return std::vector();
+}
+
+std::vector LogSqliteDatabase::getLogInstScopes(ITEM_ID instId) const
+{
+ return std::vector();
+}
+
+std::vector LogSqliteDatabase::getLodMessages(void) const
+{
+ return std::vector();
+}
+
+std::vector LogSqliteDatabase::getLodInstMessages(ITEM_ID instId) const
+{
+ return std::vector();
+}
+
+std::vector LogSqliteDatabase::getLodScopeMessages(ITEM_ID instId, uint32_t scopeId) const
+{
+ return std::vector();
+}
+#endif
diff --git a/framework/aregextend/db/private/SqliteDatabase.cpp b/framework/aregextend/db/private/SqliteDatabase.cpp
index 4b4ef9b0a..55661a08a 100644
--- a/framework/aregextend/db/private/SqliteDatabase.cpp
+++ b/framework/aregextend/db/private/SqliteDatabase.cpp
@@ -27,7 +27,18 @@
#include "sqlite3/amalgamation/sqlite3.h"
#endif // defined(USE_SQLITE_PACKAGE) && (USE_SQLITE_PACKAGE != 0)
+namespace
+{
+ inline sqlite3* _sqlite(void* dbObject)
+ {
+ return reinterpret_cast(dbObject);
+ }
+ inline sqlite3** _sqlite(void** dbObject)
+ {
+ return reinterpret_cast(dbObject);
+ }
+}
SqliteDatabase::SqliteDatabase(void)
: IEDatabaseEngine ( )
@@ -43,7 +54,7 @@ SqliteDatabase::SqliteDatabase(const String& dbPath, bool open)
{
if (open && (mDbPath.isEmpty() == false))
{
- if (::sqlite3_open(mDbPath.getString(), reinterpret_cast(&mDbObject)) != SQLITE_OK)
+ if (::sqlite3_open(mDbPath.getString(), _sqlite(&mDbObject)) != SQLITE_OK)
{
_close();
}
@@ -60,7 +71,7 @@ inline bool SqliteDatabase::_open(const String& dbPath)
bool result{ true };
_close();
mDbPath = dbPath.isEmpty() == false ? File::normalizePath(dbPath) : mDbPath;
- if (SQLITE_OK != ::sqlite3_open(mDbPath.getString(), reinterpret_cast(&mDbObject)))
+ if (SQLITE_OK != ::sqlite3_open(mDbPath.getString(), _sqlite(&mDbObject)))
{
_close();
result = false;
@@ -73,7 +84,7 @@ inline void SqliteDatabase::_close(void)
{
if (mDbObject != nullptr)
{
- ::sqlite3_close(reinterpret_cast(mDbObject));
+ ::sqlite3_close(_sqlite(mDbObject));
mDbObject = nullptr;
}
}
@@ -98,7 +109,7 @@ bool SqliteDatabase::execute(const String& sql)
bool result{ false };
if (mDbObject != nullptr)
{
- result = SQLITE_OK == ::sqlite3_exec(reinterpret_cast(mDbObject), sql.getString(), nullptr, nullptr, nullptr);
+ result = SQLITE_OK == ::sqlite3_exec(_sqlite(mDbObject), sql.getString(), nullptr, nullptr, nullptr);
}
return result;
@@ -108,7 +119,7 @@ bool SqliteDatabase::begin(void)
{
constexpr std::string_view sqlBegin{ "BEGIN TRANSACTION;" };
- return (mDbObject != nullptr ? SQLITE_OK == ::sqlite3_exec(reinterpret_cast(mDbObject), sqlBegin.data(), nullptr, nullptr, nullptr) : false);
+ return (mDbObject != nullptr ? SQLITE_OK == ::sqlite3_exec(_sqlite(mDbObject), sqlBegin.data(), nullptr, nullptr, nullptr) : false);
}
bool SqliteDatabase::commit(bool doCommit)
@@ -116,5 +127,10 @@ bool SqliteDatabase::commit(bool doCommit)
constexpr std::string_view sqlCommit{ "COMMIT;" };
constexpr std::string_view sqlRoolback{ "ROLLBACK;" };
- return (mDbObject != nullptr ? SQLITE_OK == ::sqlite3_exec(reinterpret_cast(mDbObject), doCommit ? sqlCommit.data() : sqlRoolback.data(), nullptr, nullptr, nullptr) : false);
+ return (mDbObject != nullptr ? SQLITE_OK == ::sqlite3_exec(_sqlite(mDbObject), doCommit ? sqlCommit.data() : sqlRoolback.data(), nullptr, nullptr, nullptr) : false);
+}
+
+bool SqliteDatabase::rollback(void)
+{
+ return commit(false);
}
diff --git a/framework/aregextend/db/private/SqliteRow.cpp b/framework/aregextend/db/private/SqliteRow.cpp
new file mode 100644
index 000000000..2dc45118a
--- /dev/null
+++ b/framework/aregextend/db/private/SqliteRow.cpp
@@ -0,0 +1,167 @@
+/************************************************************************
+ * This file is part of the AREG SDK core engine.
+ * AREG SDK is dual-licensed under Free open source (Apache version 2.0
+ * License) and Commercial (with various pricing models) licenses, depending
+ * on the nature of the project (commercial, research, academic or free).
+ * You should have received a copy of the AREG SDK license description in LICENSE.txt.
+ * If not, please contact to info[at]aregtech.com
+ *
+ * \copyright (c) 2017-2023 Aregtech UG. All rights reserved.
+ * \file aregextend/db/SqliteRow.cpp
+ * \author Artak Avetyan
+ * \ingroup AREG platform, extended library, SQLite row object to get results.
+ ************************************************************************/
+
+#include "aregextend/db/SqliteRow.hpp"
+#include "aregextend/db/SqliteStatement.hpp"
+
+#if defined(USE_SQLITE_PACKAGE) && (USE_SQLITE_PACKAGE != 0)
+ #include
+#else // defined(USE_SQLITE_PACKAGE) && (USE_SQLITE_PACKAGE != 0)
+ #include "sqlite3/amalgamation/sqlite3.h"
+#endif // defined(USE_SQLITE_PACKAGE) && (USE_SQLITE_PACKAGE != 0)
+
+namespace
+{
+ inline sqlite3_stmt* _sqlite_stmt(void* stmtObject)
+ {
+ return reinterpret_cast(stmtObject);
+ }
+}
+
+SqliteRow::SqliteRow(void)
+ : mStatement(nullptr)
+{
+}
+
+SqliteRow::SqliteRow(SqliteStatement& statement)
+ : mStatement(statement.mStatement)
+{
+}
+
+SqliteRow::SqliteRow(void* statement)
+ : mStatement(statement)
+{
+}
+
+SqliteRow::SqliteRow(const SqliteRow& src)
+ : mStatement(src.mStatement)
+{
+}
+
+SqliteRow::SqliteRow(SqliteRow&& src)
+ : mStatement(src.mStatement)
+{
+ src.mStatement = nullptr; // Transfer ownership
+}
+
+SqliteRow& SqliteRow::operator = (const SqliteRow& src)
+{
+ mStatement = src.mStatement;
+ return (*this);
+}
+
+SqliteRow& SqliteRow::operator = (SqliteRow&& src)
+{
+ mStatement = src.mStatement;
+ src.mStatement = nullptr; // Transfer ownership
+ return (*this);
+}
+
+int SqliteRow::getInt(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return sqlite3_column_int(_sqlite_stmt(mStatement), column);
+}
+
+int64_t SqliteRow::getInt64(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return sqlite3_column_int64(_sqlite_stmt(mStatement), column);
+}
+
+double SqliteRow::getDouble(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return sqlite3_column_double(_sqlite_stmt(mStatement), column);
+}
+
+String SqliteRow::getText(int column) const
+{
+ return String(reinterpret_cast(sqlite3_column_text(_sqlite_stmt(mStatement), column)));
+}
+
+bool SqliteRow::isNull(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_NULL);
+}
+
+bool SqliteRow::isColumnValid(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) != SQLITE_NULL);
+}
+
+bool SqliteRow::isString(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_TEXT);
+}
+
+bool SqliteRow::isInteger(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_INTEGER);
+}
+
+bool SqliteRow::isInteger64(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_INTEGER);
+}
+
+bool SqliteRow::isDouble(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_FLOAT);
+}
+
+int SqliteRow::getColumnCount(void) const
+{
+ ASSERT(isValid());
+ return sqlite3_column_count(_sqlite_stmt(mStatement));
+}
+
+String SqliteRow::getColumnName(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ const char* columnName = sqlite3_column_name(_sqlite_stmt(mStatement), column);
+ return String((columnName != nullptr) ? columnName : String::EmptyString);
+}
+
+int SqliteRow::getColumnIndex(const String& columnName) const
+{
+ ASSERT(isValid());
+ ASSERT(!columnName.isEmpty());
+ int columnCount = getColumnCount();
+ for (int index = 0; index < columnCount; ++index)
+ {
+ if (getColumnName(index) == columnName)
+ {
+ return index;
+ }
+ }
+
+ return NECommon::INVALID_INDEX; // Column not found
+}
diff --git a/framework/aregextend/db/private/SqliteStatement.cpp b/framework/aregextend/db/private/SqliteStatement.cpp
new file mode 100644
index 000000000..980bf2c7b
--- /dev/null
+++ b/framework/aregextend/db/private/SqliteStatement.cpp
@@ -0,0 +1,253 @@
+/************************************************************************
+ * This file is part of the AREG SDK core engine.
+ * AREG SDK is dual-licensed under Free open source (Apache version 2.0
+ * License) and Commercial (with various pricing models) licenses, depending
+ * on the nature of the project (commercial, research, academic or free).
+ * You should have received a copy of the AREG SDK license description in LICENSE.txt.
+ * If not, please contact to info[at]aregtech.com
+ *
+ * \copyright (c) 2017-2023 Aregtech UG. All rights reserved.
+ * \file aregextend/db/SqliteStatement.cpp
+ * \author Artak Avetyan
+ * \ingroup AREG platform, extended library, SQLite statement object.
+ ************************************************************************/
+#include "aregextend/db/SqliteStatement.hpp"
+#include "aregextend/db/SqliteDatabase.hpp"
+
+#if defined(USE_SQLITE_PACKAGE) && (USE_SQLITE_PACKAGE != 0)
+ #include
+#else // defined(USE_SQLITE_PACKAGE) && (USE_SQLITE_PACKAGE != 0)
+ #include "sqlite3/amalgamation/sqlite3.h"
+#endif // defined(USE_SQLITE_PACKAGE) && (USE_SQLITE_PACKAGE != 0)
+
+namespace
+{
+ inline sqlite3* _sqlite(void* dbObject)
+ {
+ return reinterpret_cast(dbObject);
+ }
+
+ inline sqlite3** _sqlite(void** dbObject)
+ {
+ return reinterpret_cast(dbObject);
+ }
+
+ inline sqlite3_stmt* _sqlite_stmt(void* stmtObject)
+ {
+ return reinterpret_cast(stmtObject);
+ }
+
+ inline sqlite3_stmt** _sqlite_stmt(void** stmtObject)
+ {
+ return reinterpret_cast(stmtObject);
+ }
+}
+
+SqliteStatement::SqliteStatement(SqliteDatabase& db, const String& sql)
+ : mDatabase (db)
+ , mStatement(nullptr)
+ , mRowPos (0)
+{
+ if (db.isOperable())
+ {
+ prepare(sql);
+ }
+}
+
+SqliteStatement::SqliteStatement(SqliteDatabase& db)
+ : mDatabase (db)
+ , mStatement(nullptr)
+ , mRowPos (0)
+{
+}
+
+SqliteStatement::~SqliteStatement(void)
+{
+ finalize();
+}
+
+bool SqliteStatement::prepare(const String& sql)
+{
+ bool result{ (mDatabase.isOperable() && !sql.isEmpty() && (SQLITE_OK == ::sqlite3_prepare_v2(_sqlite(mDatabase.mDbObject), sql.getString(), -1, _sqlite_stmt(&mStatement), nullptr))) };
+ mRowPos = result ? 1 : 0; // Reset row position
+ return result;
+}
+
+bool SqliteStatement::execute()
+{
+ return isValid() && (sqlite3_step(_sqlite_stmt(mStatement)) == SQLITE_DONE);
+}
+
+bool SqliteStatement::next()
+{
+ bool result{ isValid() && (sqlite3_step(_sqlite_stmt(mStatement)) == SQLITE_ROW) };
+ mRowPos += result ? 1 : 0; // Increment row position if a new row is available
+ return result;
+}
+
+void SqliteStatement::reset()
+{
+ mRowPos = 0; // Reset row position
+ sqlite3_reset(_sqlite_stmt(mStatement));
+}
+
+void SqliteStatement::finalize()
+{
+ if (mStatement != nullptr)
+ {
+ sqlite3_finalize(_sqlite_stmt(mStatement));
+ mStatement = nullptr;
+ mRowPos = 0; // Reset row position
+ }
+}
+
+bool SqliteStatement::bindInt(int index, int value)
+{
+ return isValid() && (sqlite3_bind_int(_sqlite_stmt(mStatement), index, value) == SQLITE_OK);
+}
+
+bool SqliteStatement::bindInt64(int index, int64_t value)
+{
+ return isValid() && (sqlite3_bind_int64(_sqlite_stmt(mStatement), index, value) == SQLITE_OK);
+}
+
+bool SqliteStatement::bindDouble(int index, double value)
+{
+ return isValid() && (sqlite3_bind_double(_sqlite_stmt(mStatement), index, value) == SQLITE_OK);
+}
+
+bool SqliteStatement::bindText(int index, const String& value)
+{
+ return isValid() && (sqlite3_bind_text(_sqlite_stmt(mStatement), index, value.getString(), -1, SQLITE_TRANSIENT) == SQLITE_OK);
+}
+
+bool SqliteStatement::bindNull(int index)
+{
+ return isValid() && (sqlite3_bind_null(_sqlite_stmt(mStatement), index) == SQLITE_OK);
+}
+
+void SqliteStatement::clearBindings(void)
+{
+ ASSERT(isValid());
+ sqlite3_clear_bindings(_sqlite_stmt(mStatement));
+}
+
+int SqliteStatement::getInt(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return sqlite3_column_int(_sqlite_stmt(mStatement), column);
+}
+
+int64_t SqliteStatement::getInt64(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return sqlite3_column_int64(_sqlite_stmt(mStatement), column);
+}
+
+double SqliteStatement::getDouble(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return sqlite3_column_double(_sqlite_stmt(mStatement), column);
+}
+
+String SqliteStatement::getText(int column) const
+{
+ return String(reinterpret_cast(sqlite3_column_text(_sqlite_stmt(mStatement), column)));
+}
+
+bool SqliteStatement::isNull(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_NULL);
+}
+
+bool SqliteStatement::isColumnValid(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) != SQLITE_NULL);
+}
+
+bool SqliteStatement::isString(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_TEXT);
+}
+
+bool SqliteStatement::isInteger(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_INTEGER);
+}
+
+bool SqliteStatement::isInteger64(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_INTEGER);
+}
+
+bool SqliteStatement::isDouble(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ return (sqlite3_column_type(_sqlite_stmt(mStatement), column) == SQLITE_FLOAT);
+}
+
+int SqliteStatement::getColumnCount(void) const
+{
+ ASSERT(isValid());
+ return sqlite3_column_count(_sqlite_stmt(mStatement));
+}
+
+String SqliteStatement::getColumnName(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ const char* columnName = sqlite3_column_name(_sqlite_stmt(mStatement), column);
+ return String((columnName != nullptr) ? columnName : String::EmptyString);
+}
+
+int SqliteStatement::getColumnIndex(const String& columnName) const
+{
+ ASSERT(isValid());
+ ASSERT(!columnName.isEmpty());
+ int columnCount = getColumnCount();
+ for (int index = 0; index < columnCount; ++index)
+ {
+ if (getColumnName(index) == columnName)
+ {
+ return index;
+ }
+ }
+
+ return NECommon::INVALID_INDEX; // Column not found
+}
+
+SqliteStatement::eColumnType SqliteStatement::getColumnType(int column) const
+{
+ ASSERT(isValid());
+ ASSERT(column >= 0);
+ int type = sqlite3_column_type(_sqlite_stmt(mStatement), column);
+ switch (type)
+ {
+ case SQLITE_INTEGER:
+ return eColumnType::ColumnInteger;
+ case SQLITE_FLOAT:
+ return eColumnType::ColumnDouble;
+ case SQLITE_TEXT:
+ return eColumnType::ColumnText;
+ case SQLITE_BLOB:
+ return eColumnType::ColumnBlob;
+ case SQLITE_NULL:
+ return eColumnType::ColumnNull;
+ default:
+ return eColumnType::ColumnUnknown;
+ }
+}