Add insert() helper functions to the class Database 33/118433/2
authorMu-Woong Lee <muwoong.lee@samsung.com>
Fri, 10 Mar 2017 09:38:19 +0000 (18:38 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Mon, 13 Mar 2017 07:55:48 +0000 (16:55 +0900)
Change-Id: Id3e1bef3239974fca51102d07a809f00c7d6729f
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
include/Database.h
include/Tuple.h
src/database/Database.cpp
src/shared/Tuple.cpp

index d784fec..f8e9c8a 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef __CONTEXT_DATABASE_H__
 #define __CONTEXT_DATABASE_H__
 
+#include <utility>
 #include <string>
 #include <vector>
 #include <ContextTypes.h>
@@ -26,6 +27,7 @@
 #define COL_STRING     "s"
 
 struct sqlite3;
+struct sqlite3_stmt;
 
 namespace ctx {
 
@@ -33,6 +35,25 @@ 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();
@@ -43,6 +64,11 @@ namespace ctx {
                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();
 
index 2bcce6a..e63caaa 100644 (file)
@@ -27,9 +27,12 @@ namespace ctx {
        public:
                ~Tuple();
 
+               unsigned int size();
+
                bool getAt(unsigned int idx, int64_t* val);
                bool getAt(unsigned int idx, double* val);
                bool getAt(unsigned int idx, std::string* val);
+               bool getAt(unsigned int idx, const char** val);
 
                static Tuple* duplicate(Tuple& tuple);
 
index e8e63ca..5bec68e 100644 (file)
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <algorithm>
 #include <sqlite3.h>
 #include <Tuple.h>
 #include <Database.h>
@@ -170,7 +171,33 @@ bool Database::execute(const std::string& query, const std::string& columnTypes,
 
 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()
@@ -195,3 +222,86 @@ void Database::endTransaction()
        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;
+}
index db61a59..a8e2f16 100644 (file)
@@ -77,6 +77,13 @@ bool Tuple::__verify(unsigned int idx, const GVariantType* type)
        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);
@@ -93,12 +100,21 @@ bool Tuple::getAt(unsigned int idx, double* val)
 
 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;
 }