# common
ADD_SUBDIRECTORY(common)
+ADD_SUBDIRECTORY(database)
ADD_SUBDIRECTORY(event)
ADD_SUBDIRECTORY(klass)
ADD_SUBDIRECTORY(logger)
--- /dev/null
+# 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})
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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();
+ }
+}