Import database code from klay
authorSangwan Kwon <sangwan.kwon@samsung.com>
Fri, 29 Nov 2019 06:21:29 +0000 (15:21 +0900)
committer권상완/Security 2Lab(SR)/Engineer/삼성전자 <sangwan.kwon@samsung.com>
Mon, 2 Dec 2019 06:36:38 +0000 (15:36 +0900)
Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
src/vist/CMakeLists.txt
src/vist/database/CMakeLists.txt [new file with mode: 0644]
src/vist/database/column.cpp [new file with mode: 0644]
src/vist/database/column.hpp [new file with mode: 0644]
src/vist/database/connection.cpp [new file with mode: 0644]
src/vist/database/connection.hpp [new file with mode: 0644]
src/vist/database/statement.cpp [new file with mode: 0644]
src/vist/database/statement.hpp [new file with mode: 0644]
src/vist/database/tests/database.cpp [new file with mode: 0644]

index 4105a139908c36e63b73556ac1e21160462d2b6a..1406658d25c82d30daa9adc2c2bb03c81d047a83 100644 (file)
@@ -33,6 +33,7 @@ ADD_DEFINITIONS(-DDB_PATH="${DB_INSTALL_DIR}/.vist.db"
 
 # common
 ADD_SUBDIRECTORY(common)
+ADD_SUBDIRECTORY(database)
 ADD_SUBDIRECTORY(event)
 ADD_SUBDIRECTORY(klass)
 ADD_SUBDIRECTORY(logger)
diff --git a/src/vist/database/CMakeLists.txt b/src/vist/database/CMakeLists.txt
new file mode 100644 (file)
index 0000000..78568c1
--- /dev/null
@@ -0,0 +1,20 @@
+#  Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License
+
+ADD_VIST_COMMON_LIBRARY(vist_database column.cpp
+                                                                         connection.cpp
+                                                                         statement.cpp)
+
+FILE(GLOB DATABASE_TESTS "tests/*.cpp")
+ADD_VIST_TEST(${DATABASE_TESTS})
diff --git a/src/vist/database/column.cpp b/src/vist/database/column.cpp
new file mode 100644 (file)
index 0000000..45e830b
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  Copyright (c) 2015-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include "column.hpp"
+
+namespace vist {
+namespace database {
+
+Column::Column(::sqlite3_stmt* stmt, int idx) : statement(stmt), index(idx)
+{
+}
+
+std::string Column::getName() const
+{
+       return sqlite3_column_name(statement, index);
+}
+
+int Column::getInt() const
+{
+       return sqlite3_column_int(statement, index);
+}
+
+sqlite3_int64 Column::getInt64() const
+{
+       return sqlite3_column_int64(statement, index);
+}
+
+double Column::getDouble() const
+{
+       return sqlite3_column_double(statement, index);
+}
+
+const char* Column::getText() const
+{
+       return reinterpret_cast<const char *>(sqlite3_column_text(statement, index));
+}
+
+const void* Column::getBlob() const
+{
+       return sqlite3_column_blob(statement, index);
+}
+
+int Column::getType() const
+{
+       return sqlite3_column_type(statement, index);
+}
+
+int Column::getBytes() const
+{
+       return sqlite3_column_bytes(statement, index);
+}
+
+} // namespace database
+} // namespace vist
diff --git a/src/vist/database/column.hpp b/src/vist/database/column.hpp
new file mode 100644 (file)
index 0000000..49b640e
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *  Copyright (c) 2015-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file   connection.hpp
+ * @author Jaemin Ryu (jm77.ryu@samsung.com)
+ * @brief  Define Column of sqlite3 database.
+ */
+
+#pragma once
+
+#include <sqlite3.h>
+
+#include <string>
+
+namespace vist {
+namespace database {
+
+class Column final {
+public:
+       Column(::sqlite3_stmt* stmt, int idx);
+       ~Column() = default;
+
+       std::string getName() const;
+       sqlite3_int64 getInt64() const;
+       const char* getText() const;
+       double getDouble() const;
+       const void* getBlob() const;
+       int getInt() const;
+       int getType() const;
+       int getBytes() const;
+
+       int size() const
+       {
+               return getBytes();
+       }
+
+       operator int() const
+       {
+               return getInt();
+       }
+
+       operator sqlite3_int64() const
+       {
+               return getInt64();
+       }
+
+       operator double() const
+       {
+               return getDouble();
+       }
+
+       operator const char*() const
+       {
+               return getText();
+       }
+
+       operator const void*() const
+       {
+               return getBlob();
+       }
+
+private:
+       ::sqlite3_stmt* statement;
+       int index;
+};
+
+} // namespace database
+} // namespace vist
diff --git a/src/vist/database/connection.cpp b/src/vist/database/connection.cpp
new file mode 100644 (file)
index 0000000..43289e6
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2015-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include "connection.hpp"
+
+#include <vist/exception.hpp>
+
+#include <cstring>
+
+namespace vist {
+namespace database {
+
+Connection::Connection(const std::string& name, const int flags, bool integrityCheck) :
+       handle(nullptr), filename(name)
+{
+       if (::sqlite3_open_v2(filename.c_str(), &handle, flags, NULL))
+               THROW(ErrCode::RuntimeError) << "Failed to open: " << name
+                                                                        << ", log: " << this->getErrorMessage();
+
+       if (integrityCheck) {
+               bool verified = false;
+               sqlite3_stmt *integrity = NULL;
+               if (::sqlite3_prepare_v2(handle, "PRAGMA integrity_check;", -1, &integrity, NULL) == SQLITE_OK ) {
+                       while (::sqlite3_step(integrity) == SQLITE_ROW) {
+                               const unsigned char *result = ::sqlite3_column_text(integrity, 0);
+                               if (result && ::strcmp((const char *)result, (const char *)"ok") == 0) {
+                                       verified = true;
+                                       break;
+                               }
+                       }
+
+                       ::sqlite3_finalize(integrity);
+               }
+
+               if (!verified) {
+                       ::sqlite3_close(handle);
+                       THROW(ErrCode::RuntimeError) << this->getErrorMessage();
+               }
+       }
+}
+
+Connection::~Connection()
+{
+       ::sqlite3_close(handle);
+}
+
+int Connection::exec(const std::string& query)
+{
+       if (::sqlite3_exec(handle, query.c_str(), NULL, NULL, NULL) != SQLITE_OK)
+               THROW(ErrCode::RuntimeError) << "Failed to execute query: " << query
+                                                                        << ", log: " << this->getErrorMessage();
+
+       return ::sqlite3_changes(handle);
+}
+
+} // namespace database
+} // namespace vist
diff --git a/src/vist/database/connection.hpp b/src/vist/database/connection.hpp
new file mode 100644 (file)
index 0000000..b4a9eee
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  Copyright (c) 2015-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file   connection.hpp
+ * @author Jaemin Ryu (jm77.ryu@samsung.com)
+ * @brief  Define Connection of sqlite3 database.
+ */
+
+#pragma once
+
+#include <sqlite3.h>
+
+#include <string>
+
+namespace vist {
+namespace database {
+
+class Connection final {
+public:
+       enum Mode {
+               Create = SQLITE_OPEN_CREATE,
+               ReadWrite = SQLITE_OPEN_READWRITE
+       };
+
+       Connection(const std::string& name,
+                          const int flags = ReadWrite | Create,
+                          bool integrityCheck = true);
+       ~Connection();
+
+       int exec(const std::string& query);
+       bool isTableExists(const std::string& tableName);
+
+       long long getLastInsertRowId() const noexcept
+       {
+               return ::sqlite3_last_insert_rowid(handle);
+       }
+
+       const std::string& getName() const noexcept
+       {
+               return filename;
+       }
+
+       int getErrorCode() const
+       {
+               return ::sqlite3_errcode(handle);
+       }
+
+       int getExtendedErrorCode() const
+       {
+               return ::sqlite3_extended_errcode(handle);
+       }
+
+       std::string getErrorMessage() const
+       {
+               return ::sqlite3_errmsg(handle);
+       }
+
+       ::sqlite3* get() const noexcept
+       {
+               return handle;
+       }
+
+private:
+       ::sqlite3* handle;
+       std::string filename;
+};
+
+} // namespace database
+} // namespace vist
diff --git a/src/vist/database/statement.cpp b/src/vist/database/statement.cpp
new file mode 100644 (file)
index 0000000..b3f761b
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ *  Copyright (c) 2015-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include "statement.hpp"
+
+#include <vist/exception.hpp>
+
+#include <string>
+
+namespace vist {
+namespace database {
+
+Statement::Statement(const Connection& db, const std::string& query) :
+       statement(nullptr),
+       columnCount(0),
+       validRow(false)
+{
+       if (SQLITE_OK != ::sqlite3_prepare_v2(db.get(),
+                                                                                 query.c_str(),
+                                                                                 query.size(),
+                                                                                 &statement,
+                                                                                 NULL))
+               THROW(ErrCode::RuntimeError) << db.getErrorMessage();
+
+       columnCount = sqlite3_column_count(statement);
+}
+
+Statement::~Statement()
+{
+       ::sqlite3_finalize(statement);
+}
+
+void Statement::reset()
+{
+       if (::sqlite3_reset(statement) != SQLITE_OK)
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::clearBindings()
+{
+       if (::sqlite3_clear_bindings(statement) != SQLITE_OK)
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+std::string Statement::getErrorMessage() const
+{
+       return ::sqlite3_errmsg(::sqlite3_db_handle(statement));
+}
+
+std::string Statement::getErrorMessage(int errorCode) const
+{
+       return ::sqlite3_errstr(errorCode);
+}
+
+bool Statement::step()
+{
+       if (SQLITE_ROW == ::sqlite3_step(statement)) {
+               return (validRow = true);
+       }
+
+       return (validRow = false);
+}
+
+int Statement::exec()
+{
+       if (SQLITE_DONE == ::sqlite3_step(statement)) {
+               validRow = false;
+       }
+
+       return sqlite3_changes(sqlite3_db_handle(statement));
+}
+
+Column Statement::getColumn(const int index)
+{
+       if (!validRow || (index >= columnCount))
+               THROW(ErrCode::RuntimeError) << getErrorMessage(SQLITE_RANGE);
+
+       return Column(statement, index);
+}
+
+bool Statement::isNullColumn(const int index) const
+{
+       if (!validRow || (index >= columnCount))
+               THROW(ErrCode::RuntimeError) << getErrorMessage(SQLITE_RANGE);
+
+       return (SQLITE_NULL == sqlite3_column_type(statement, index));
+}
+
+std::string Statement::getColumnName(const int index) const
+{
+       if (index >= columnCount)
+               THROW(ErrCode::RuntimeError) << getErrorMessage(SQLITE_RANGE);
+
+       return sqlite3_column_name(statement, index);
+}
+
+
+void Statement::bind(const int index, const int& value)
+{
+       if (SQLITE_OK != ::sqlite3_bind_int(statement, index, value))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const int index, const sqlite3_int64& value)
+{
+       if (SQLITE_OK != ::sqlite3_bind_int64(statement, index, value))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const int index, const double& value)
+{
+       if (SQLITE_OK != ::sqlite3_bind_double(statement, index, value))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const int index, const char* value)
+{
+       if (SQLITE_OK != ::sqlite3_bind_text(statement, index, value, -1, SQLITE_TRANSIENT))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const int index, const std::string& value)
+{
+       if (SQLITE_OK != ::sqlite3_bind_text(statement, index, value.c_str(),
+                                                                                static_cast<int>(value.size()), SQLITE_TRANSIENT))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const int index, const void* value, const int size)
+{
+       if (SQLITE_OK != ::sqlite3_bind_blob(statement, index, value, size, SQLITE_TRANSIENT))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const int index)
+{
+       if (SQLITE_OK != ::sqlite3_bind_null(statement, index))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const std::string& name, const int& value)
+{
+       int index = sqlite3_bind_parameter_index(statement, name.c_str());
+       if (SQLITE_OK != sqlite3_bind_int(statement, index, value))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const std::string& name, const sqlite3_int64& value)
+{
+       int index = sqlite3_bind_parameter_index(statement, name.c_str());
+       if (SQLITE_OK != ::sqlite3_bind_int64(statement, index, value))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const std::string& name, const double& value)
+{
+       int index = sqlite3_bind_parameter_index(statement, name.c_str());
+       if (SQLITE_OK != ::sqlite3_bind_double(statement, index, value))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const std::string& name, const std::string& value)
+{
+       int index = sqlite3_bind_parameter_index(statement, name.c_str());
+       if (SQLITE_OK != ::sqlite3_bind_text(statement, index, value.c_str(),
+                                                                                static_cast<int>(value.size()), SQLITE_TRANSIENT))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const std::string& name, const char* value)
+{
+       int index = sqlite3_bind_parameter_index(statement, name.c_str());
+       if (SQLITE_OK != ::sqlite3_bind_text(statement, index, value, -1, SQLITE_TRANSIENT))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const std::string& name, const void* value, const int size)
+{
+       int index = sqlite3_bind_parameter_index(statement, name.c_str());
+       if (SQLITE_OK != ::sqlite3_bind_blob(statement, index, value, size, SQLITE_TRANSIENT))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+void Statement::bind(const std::string& name)
+{
+       int index = sqlite3_bind_parameter_index(statement, name.c_str());
+       if (SQLITE_OK != ::sqlite3_bind_null(statement, index))
+               THROW(ErrCode::RuntimeError) << getErrorMessage();
+}
+
+} // namespace database
+} // namespace vist
diff --git a/src/vist/database/statement.hpp b/src/vist/database/statement.hpp
new file mode 100644 (file)
index 0000000..a474e51
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  Copyright (c) 2015-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file   connection.hpp
+ * @author Jaemin Ryu (jm77.ryu@samsung.com)
+ * @brief  Define sqlite3 statement.
+ */
+
+
+#pragma once
+
+#include <vist/database/column.hpp>
+#include <vist/database/connection.hpp>
+
+#include <sqlite3.h>
+
+#include <map>
+#include <string>
+
+namespace vist {
+namespace database {
+
+class Statement final {
+public:
+       Statement(const Connection& db, const std::string& query);
+       virtual ~Statement();
+
+       int exec();
+       bool step();
+
+       void reset();
+       void clearBindings();
+       std::string getErrorMessage() const;
+       std::string getErrorMessage(int errorCode) const;
+
+       Column getColumn(const int index);
+       std::string getColumnName(const int index) const;
+       bool isNullColumn(const int index) const;
+
+       void bind(const int index, const int& value);
+       void bind(const int index, const sqlite3_int64& value);
+       void bind(const int index, const double& value);
+       void bind(const int index, const std::string& value);
+       void bind(const int index, const char* value);
+       void bind(const int index, const void* value, const int size);
+       void bind(const int index);
+
+       void bind(const std::string& name, const int& value);
+       void bind(const std::string& name, const sqlite3_int64& value);
+       void bind(const std::string& name, const double& value);
+       void bind(const std::string& name, const std::string& value);
+       void bind(const std::string& name, const char* value);
+       void bind(const std::string& name, const void* value, const int size);
+       void bind(const std::string& name);
+
+       int getColumnCount() const
+       {
+               return columnCount;
+       }
+
+       sqlite3_stmt* get() const noexcept
+       {
+               return statement;
+       }
+
+private:
+       typedef std::map<std::string, int> ColumnMap;
+
+       sqlite3_stmt* statement;
+       int columnCount;
+       int validRow;
+       ColumnMap columnNames;
+};
+
+} // namespace database
+} // namespace vist
diff --git a/src/vist/database/tests/database.cpp b/src/vist/database/tests/database.cpp
new file mode 100644 (file)
index 0000000..60159c8
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *  Copyright (c) 2015-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+#include <vist/exception.hpp>
+
+#include <vist/database/column.hpp>
+#include <vist/database/statement.hpp>
+#include <vist/database/connection.hpp>
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+namespace {
+
+const std::string TEST_DB_PATH = "/tmp/vist-test.db";
+
+} // anonymous namespace
+
+using namespace vist;
+
+TEST(DatabaseTests, database)
+{
+       std::string query = "CREATE TABLE IF NOT EXISTS CLIENT("     \
+                                               "ID INTEGER PRIMARY KEY AUTOINCREMENT,"  \
+                                               "PKG TEXT,"                              \
+                                               "KEY TEXT,"                              \
+                                               "IS_USED INTEGER,"                       \
+                                               "USER INTEGER)";
+
+       try {
+               database::Connection db(TEST_DB_PATH);
+               db.exec(query);
+       } catch (const vist::Exception<ErrCode>& e) {
+               EXPECT_TRUE(false) << e.what();
+       }
+}
+
+TEST(DatabaseTests, invalid_statement)
+{
+       bool raised = false;
+
+       try {
+               database::Connection db(TEST_DB_PATH);
+               database::Statement stmt(db, "INVALID STATEMENT");
+       } catch (const vist::Exception<ErrCode>&) {
+               raised = true;
+       }
+
+       EXPECT_TRUE(raised);
+}
+
+TEST(DatabaseTests, column_bind_index1)
+{
+       std::string query = "INSERT INTO CLIENT VALUES (NULL, ?, ?, ?, ?)";
+
+       bool raised = false;
+       try {
+               const char *str = "PACKAGE";
+               void *blob = (void *)str;
+               double user = 5001;
+               sqlite3_int64 used = 1;
+               std::string key = "test key";
+
+               database::Connection db(TEST_DB_PATH);
+               database::Statement stmt(db, query);
+               stmt.bind(1, blob, 8);
+               stmt.bind(2, key);
+               stmt.bind(3, used);
+               stmt.bind(4, user);
+               stmt.exec();
+               database::Statement select(db, "SELECT * FROM CLIENT");
+
+               EXPECT_EQ(5, select.getColumnCount());
+               stmt.clearBindings();
+               stmt.reset();
+       } catch (const vist::Exception<ErrCode>&) {
+               raised = true;
+       }
+
+       EXPECT_FALSE(raised);
+}
+
+TEST(DatabaseTests, column_bind_index2)
+{
+       std::string query = "INSERT INTO CLIENT VALUES (NULL, ?, ?, ?, ?)";
+
+       try {
+               database::Connection db(TEST_DB_PATH);
+               database::Statement stmt(db, query);
+               stmt.bind(1, "TEST PACKAGE");
+               stmt.bind(2, "TEST KEY");
+               stmt.bind(3, false);
+               stmt.bind(4, 5001);
+               stmt.exec();
+       } catch (const vist::Exception<ErrCode>& e) {
+               EXPECT_TRUE(false) << e.what();
+       }
+}
+
+TEST(DatabaseTests, column_bind_null)
+{
+       std::string query = "INSERT INTO CLIENT VALUES (NULL, :PKG, :KEY, :IS_USED, :USER)";
+
+       try {
+               database::Connection db(TEST_DB_PATH);
+               database::Statement stmt(db, query);
+               stmt.bind(":PKG");
+               stmt.bind(2);
+       } catch (const vist::Exception<ErrCode>& e) {
+               EXPECT_TRUE(false) << e.what();
+       }
+}
+
+TEST(DatabaseTests, column_bind_name1)
+{
+       std::string query = "INSERT INTO CLIENT VALUES (NULL, :PKG, :KEY, :IS_USED, :USER)";
+
+       try {
+               database::Connection db(TEST_DB_PATH);
+               database::Statement stmt(db, query);
+               stmt.bind(":PKG", "TEST PACKAGE");
+               stmt.bind(":KEY", "TEST KEY");
+               stmt.bind(":IS_USED", true);
+               stmt.bind(":USER", 5001);
+               stmt.exec();
+       } catch (const vist::Exception<ErrCode>& e) {
+               EXPECT_TRUE(false) << e.what();
+       }
+}
+
+TEST(DatabaseTests, column_bind_name2)
+{
+       std::string query = "INSERT INTO CLIENT VALUES (NULL, :PKG, :KEY, :IS_USED, :USER)";
+
+       try {
+               const char *str = "PACKAGE";
+               void *blob = (void *)str;
+               double user = 5001;
+               sqlite3_int64 used = 1;
+               std::string key = "test key";
+
+               database::Connection db(TEST_DB_PATH);
+               database::Statement stmt(db, query);
+               stmt.bind(":PKG", blob, 8);
+               stmt.bind(":KEY", key);
+               stmt.bind(":IS_USED", used);
+               stmt.bind(":USER", user);
+               stmt.exec();
+       } catch (const vist::Exception<ErrCode>& e) {
+               EXPECT_TRUE(false) << e.what();
+       }
+}
+
+TEST(DatabaseTests, column)
+{
+       try {
+               database::Connection db(TEST_DB_PATH);
+               database::Statement select(db, "SELECT * FROM CLIENT");
+               while (select.step()) {
+                       for (int  i = 0; i < select.getColumnCount(); i++) {
+                               if (select.isNullColumn(i)) {
+                                       continue;
+                               }
+                               select.getColumnName(i);
+                       }
+
+                       database::Column id = select.getColumn(0);
+                       database::Column pkg = select.getColumn(1);
+                       database::Column key = select.getColumn(2);
+                       database::Column used = select.getColumn(3);
+
+                       id.getInt();
+                       pkg.getText();
+                       key.getText();
+                       used.getInt();
+               }
+       } catch (const vist::Exception<ErrCode>& e) {
+               EXPECT_TRUE(false) << e.what();
+       }
+}