#ifndef __CONTEXT_DATABASE_H__
#define __CONTEXT_DATABASE_H__
+#include <utility>
#include <string>
#include <vector>
#include <ContextTypes.h>
#define COL_STRING "s"
struct sqlite3;
+struct sqlite3_stmt;
namespace ctx {
class EXPORT_API Database {
public:
+ class Insertions {
+ public:
+ Insertions(Database* database, const std::string& tableName, const std::string& columns);
+ ~Insertions();
+
+ bool add(Tuple* tuple, Tuple* tupleExt = NULL);
+
+ private:
+ int __bind(Tuple* tuple, int idx);
+ bool __execute();
+
+ sqlite3* __dbHandle;
+ sqlite3_stmt* __stmt;
+ std::vector<std::pair<Tuple*, Tuple*>> __values;
+ int __dimension;
+
+ friend class Database;
+ };
+
Database(const std::string& dbPath);
virtual ~Database();
bool execute(const std::string& query, const std::string& columnTypes, std::vector<std::string>* columnNames, std::vector<Tuple*>* queryResult);
bool execute(const std::string& query, std::vector<Tuple*>* queryResult);
+ // insert() does not consume the input tuples
+ bool insert(const std::string& tableName, const std::string& columns, Tuple* tuple, Tuple* tupleExt = NULL);
+ bool insert(const std::string& tableName, const std::string& columns, std::vector<Tuple*>& tuples);
+ bool insert(Insertions& insertions);
+
void beginTransaction();
void endTransaction();
* limitations under the License.
*/
+#include <algorithm>
#include <sqlite3.h>
#include <Tuple.h>
#include <Database.h>
bool Database::execute(const std::string& query, std::vector<Tuple*>* result)
{
- return execute(query, "", NULL, result);
+ return execute(query, EMPTY_STR, NULL, result);
+}
+
+bool Database::insert(const std::string& tableName, const std::string& columns, Tuple* tuple, Tuple* tupleExt)
+{
+ Insertions insertions(this, tableName, columns);
+ insertions.add(tuple, tupleExt);
+ return insertions.__execute();
+}
+
+bool Database::insert(const std::string& tableName, const std::string& columns, std::vector<Tuple*>& tuples)
+{
+ Insertions insertions(this, tableName, columns);
+ for (auto& tuple : tuples) {
+ if (!insertions.add(tuple, NULL))
+ return false;
+ }
+ return insert(insertions);
+}
+
+bool Database::insert(Insertions& insertions)
+{
+ IF_FAIL_RETURN(insertions.__dbHandle == this->__dbHandle, false);
+ beginTransaction();
+ bool success = insertions.__execute();
+ endTransaction();
+ return success;
}
void Database::beginTransaction()
sqlite3_exec(__dbHandle, endQuery, NULL, NULL, NULL);
__transactionOn = false;
}
+
+Database::Insertions::Insertions(Database* database, const std::string& tableName, const std::string& columns) :
+ __dbHandle(database->__dbHandle),
+ __stmt(NULL),
+ __dimension(0)
+{
+ IF_FAIL_VOID_TAG(database && !tableName.empty() && !columns.empty(), _E, "Invalid parameter");
+
+ size_t columnCnt = std::count(columns.begin(), columns.end(), ',') + 1;
+ __dimension = columnCnt;
+
+ std::string query = "INSERT INTO [" + tableName + "] (" + columns + ") VALUES (";
+
+ for (size_t i = 0; i < columnCnt; ++i) {
+ query += "?,";
+ }
+
+ query.back() = ')';
+
+ int error = sqlite3_prepare_v2(__dbHandle, query.c_str(), -1, &__stmt, NULL);
+ IF_FAIL_VOID_TAG(error == SQLITE_OK, _E, "Preparation failed");
+}
+
+Database::Insertions::~Insertions()
+{
+ sqlite3_finalize(__stmt);
+}
+
+bool Database::Insertions::add(Tuple* tuple, Tuple* tupleExt)
+{
+ IF_FAIL_RETURN(tuple, false);
+ __values.push_back(std::make_pair(tuple, tupleExt));
+ return true;
+}
+
+int Database::Insertions::__bind(Tuple* tuple, int idx)
+{
+ IF_FAIL_RETURN(tuple && idx >= 0, idx);
+
+ const char* str = NULL;
+ int64_t i64 = 0;
+ double dbl = 0;
+
+ for (unsigned int i = 0; i < tuple->size(); ++i) {
+ if (tuple->getAt(i, &str)) {
+ if (sqlite3_bind_text(__stmt, idx, str, -1, SQLITE_STATIC) != SQLITE_OK)
+ return E_FAILED;
+ } else if (tuple->getAt(i, &i64)) {
+ if (sqlite3_bind_int64(__stmt, idx, i64) != SQLITE_OK)
+ return E_FAILED;
+ } else if (tuple->getAt(i, &dbl)) {
+ if (sqlite3_bind_double(__stmt, idx, dbl) != SQLITE_OK)
+ return E_FAILED;
+ } else {
+ _W("Unknown attribute type");
+ return E_FAILED;
+ }
+ ++idx;
+ }
+
+ return idx;
+}
+
+bool Database::Insertions::__execute()
+{
+ for (auto& iter : __values) {
+ Tuple* tuple = iter.first;
+ Tuple* tupleExt = iter.second;
+
+ if (__bind(tupleExt, __bind(tuple, 0)) != __dimension) {
+ _E("Binding failed");
+ sqlite3_reset(__stmt);
+ return false;
+ }
+
+ if (sqlite3_step(__stmt) != SQLITE_DONE) {
+ _E("Execution failed");
+ return false;
+ }
+ }
+
+ return true;
+}
return true;
}
+unsigned int Tuple::size()
+{
+ IF_FAIL_RETURN_TAG(__gVar, 0, _W, "Consumed");
+ IF_FAIL_RETURN_TAG(__parse(), 0, _E, "Parsing failed");
+ return static_cast<unsigned int>(__numElements);
+}
+
bool Tuple::getAt(unsigned int idx, int64_t* val)
{
IF_FAIL_RETURN(__verify(idx, G_VARIANT_TYPE_INT64), false);
bool Tuple::getAt(unsigned int idx, std::string* val)
{
+ const char* str = NULL;
+ IF_FAIL_RETURN(getAt(idx, &str), false);
+
+ *val = str;
+ return true;
+}
+
+bool Tuple::getAt(unsigned int idx, const char** val)
+{
IF_FAIL_RETURN(__verify(idx, G_VARIANT_TYPE_STRING), false);
const gchar* str = g_variant_get_string(__elements[idx], NULL);
IF_FAIL_RETURN_TAG(str, false, _E, "NULL string");
- *val = str;
+ *val = reinterpret_cast<const char*>(str);
return true;
}