Mercurial > hg > orthanc
diff Core/SQLite/Statement.cpp @ 0:3959d33612cc
initial commit
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 19 Jul 2012 14:32:22 +0200 |
parents | |
children | db4d996ea264 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/SQLite/Statement.cpp Thu Jul 19 14:32:22 2012 +0200 @@ -0,0 +1,294 @@ +/** + * Palantir - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012 Medical Physics Department, CHU of Liege, + * Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "Statement.h" + +#include "Connection.h" +#include "../Toolbox.h" + +#include <boost/lexical_cast.hpp> +#include <sqlite3.h> +#include <string.h> + +namespace Palantir +{ + namespace SQLite + { + int Statement::CheckError(int err) const + { + bool succeeded = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE); + if (!succeeded) + { + throw PalantirException("SQLite error code " + boost::lexical_cast<std::string>(err)); + } + + return err; + } + + void Statement::CheckOk(int err) const + { + if (err == SQLITE_RANGE) + { + // Binding to a non-existent variable is evidence of a serious error. + throw PalantirException("Bind value out of range"); + } + else if (err != SQLITE_OK) + { + throw PalantirException("SQLite error code " + boost::lexical_cast<std::string>(err)); + } + } + + + Statement::Statement(Connection& database, + const StatementId& id, + const std::string& sql) : + reference_(database.GetCachedStatement(id, sql.c_str())) + { + Reset(true); + } + + + Statement::Statement(Connection& database, + const StatementId& id, + const char* sql) : + reference_(database.GetCachedStatement(id, sql)) + { + Reset(true); + } + + + Statement::Statement(Connection& database, + const std::string& sql) : + reference_(database.GetWrappedObject(), sql.c_str()) + { + } + + + Statement::Statement(Connection& database, + const char* sql) : + reference_(database.GetWrappedObject(), sql) + { + } + + + bool Statement::Run() + { + return CheckError(sqlite3_step(GetStatement())) == SQLITE_DONE; + } + + bool Statement::Step() + { + return CheckError(sqlite3_step(GetStatement())) == SQLITE_ROW; + } + + void Statement::Reset(bool clear_bound_vars) + { + // We don't call CheckError() here because sqlite3_reset() returns + // the last error that Step() caused thereby generating a second + // spurious error callback. + if (clear_bound_vars) + sqlite3_clear_bindings(GetStatement()); + sqlite3_reset(GetStatement()); + } + + std::string Statement::GetOriginalSQLStatement() + { + return std::string(sqlite3_sql(GetStatement())); + } + + + void Statement::BindNull(int col) + { + CheckOk(sqlite3_bind_null(GetStatement(), col + 1)); + } + + void Statement::BindBool(int col, bool val) + { + BindInt(col, val ? 1 : 0); + } + + void Statement::BindInt(int col, int val) + { + CheckOk(sqlite3_bind_int(GetStatement(), col + 1, val)); + } + + void Statement::BindInt64(int col, int64_t val) + { + CheckOk(sqlite3_bind_int64(GetStatement(), col + 1, val)); + } + + void Statement::BindDouble(int col, double val) + { + CheckOk(sqlite3_bind_double(GetStatement(), col + 1, val)); + } + + void Statement::BindCString(int col, const char* val) + { + CheckOk(sqlite3_bind_text(GetStatement(), col + 1, val, -1, SQLITE_TRANSIENT)); + } + + void Statement::BindString(int col, const std::string& val) + { + CheckOk(sqlite3_bind_text(GetStatement(), + col + 1, + val.data(), + val.size(), + SQLITE_TRANSIENT)); + } + + /*void Statement::BindString16(int col, const string16& value) + { + BindString(col, UTF16ToUTF8(value)); + }*/ + + void Statement::BindBlob(int col, const void* val, int val_len) + { + CheckOk(sqlite3_bind_blob(GetStatement(), col + 1, val, val_len, SQLITE_TRANSIENT)); + } + + + int Statement::ColumnCount() const + { + return sqlite3_column_count(GetStatement()); + } + + + ColumnType Statement::GetColumnType(int col) const + { + // Verify that our enum matches sqlite's values. + assert(COLUMN_TYPE_INTEGER == SQLITE_INTEGER); + assert(COLUMN_TYPE_FLOAT == SQLITE_FLOAT); + assert(COLUMN_TYPE_TEXT == SQLITE_TEXT); + assert(COLUMN_TYPE_BLOB == SQLITE_BLOB); + assert(COLUMN_TYPE_NULL == SQLITE_NULL); + + return static_cast<ColumnType>(sqlite3_column_type(GetStatement(), col)); + } + + ColumnType Statement::GetDeclaredColumnType(int col) const + { + std::string column_type(sqlite3_column_decltype(GetStatement(), col)); + Toolbox::ToLowerCase(column_type); + + if (column_type == "integer") + return COLUMN_TYPE_INTEGER; + else if (column_type == "float") + return COLUMN_TYPE_FLOAT; + else if (column_type == "text") + return COLUMN_TYPE_TEXT; + else if (column_type == "blob") + return COLUMN_TYPE_BLOB; + + return COLUMN_TYPE_NULL; + } + + bool Statement::ColumnBool(int col) const + { + return !!ColumnInt(col); + } + + int Statement::ColumnInt(int col) const + { + return sqlite3_column_int(GetStatement(), col); + } + + int64_t Statement::ColumnInt64(int col) const + { + return sqlite3_column_int64(GetStatement(), col); + } + + double Statement::ColumnDouble(int col) const + { + return sqlite3_column_double(GetStatement(), col); + } + + std::string Statement::ColumnString(int col) const + { + const char* str = reinterpret_cast<const char*>( + sqlite3_column_text(GetStatement(), col)); + int len = sqlite3_column_bytes(GetStatement(), col); + + std::string result; + if (str && len > 0) + result.assign(str, len); + return result; + } + + /*string16 Statement::ColumnString16(int col) const + { + std::string s = ColumnString(col); + return !s.empty() ? UTF8ToUTF16(s) : string16(); + }*/ + + int Statement::ColumnByteLength(int col) const + { + return sqlite3_column_bytes(GetStatement(), col); + } + + const void* Statement::ColumnBlob(int col) const + { + return sqlite3_column_blob(GetStatement(), col); + } + + bool Statement::ColumnBlobAsString(int col, std::string* blob) + { + const void* p = ColumnBlob(col); + size_t len = ColumnByteLength(col); + blob->resize(len); + if (blob->size() != len) { + return false; + } + blob->assign(reinterpret_cast<const char*>(p), len); + return true; + } + + /*bool Statement::ColumnBlobAsString16(int col, string16* val) const + { + const void* data = ColumnBlob(col); + size_t len = ColumnByteLength(col) / sizeof(char16); + val->resize(len); + if (val->size() != len) + return false; + val->assign(reinterpret_cast<const char16*>(data), len); + return true; + }*/ + + bool Statement::ColumnBlobAsVector(int col, std::vector<char>* val) const + { + val->clear(); + + const void* data = sqlite3_column_blob(GetStatement(), col); + int len = sqlite3_column_bytes(GetStatement(), col); + if (data && len > 0) { + val->resize(len); + memcpy(&(*val)[0], data, len); + } + return true; + } + + bool Statement::ColumnBlobAsVector( + int col, + std::vector<unsigned char>* val) const + { + return ColumnBlobAsVector(col, reinterpret_cast< std::vector<char>* >(val)); + } + + } +}