Import SQLite wrapper class from wrt-commons 0.2.210.
Several dependencies from DPL common imported as needed. Dependency DPL::Thread
has been omitted on purpose, because it caused too many other dependencies.
It will be substituded in a separate patch.
These classes will be used by security-manager. When security-manager gets its
own repository, SqlConnection will be removed from security-server.
Change-Id: I090f73d6912f4ef6b85b313e7b12d20a7fd758a1
Signed-off-by: Rafal Krypa <r.krypa@samsung.com>
--- /dev/null
+/*
+ * Copyright (c) 2013 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 availability.h
+ * @author Jihoon Chung (jihoon.chung@samsung.com)
+ * @version 1.0
+ */
+#ifndef DPL_AVAILABILITY_H
+#define DPL_AVAILABILITY_H
+
+#define DPL_DEPRECATED __attribute__((deprecated))
+#define DPL_DEPRECATED_WITH_MESSAGE(msg) __attribute__((deprecated(msg)))
+
+#define DPL_UNUSED __attribute__((unused))
+#define DPL_UNUSED_PARAM(variable) (void)variable
+
+#endif // DPL_AVAILABILITY_H
--- /dev/null
+/*
+ * Copyright (c) 2011 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 char_traits.h
+ * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com)
+ * @version 1.0
+ * @brief Char traits are used to create basic_string extended with
+ * additional features
+ * Current char traits could be extended in feature to boost
+ * performance
+ */
+#ifndef DPL_CHAR_TRAITS
+#define DPL_CHAR_TRAITS
+
+#include <cstring>
+#include <string>
+#include <ostream>
+#include <algorithm>
+#include <dpl/exception.h>
+
+namespace DPL {
+typedef std::char_traits<wchar_t> CharTraits;
+} // namespace DPL
+
+#endif // DPL_CHAR_TRAITS
--- /dev/null
+/*
+ * Copyright (c) 2011 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 errno_string.h
+ * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
+ * @version 1.0
+ * @brief This file is the implementation file of errno string
+ */
+#ifndef DPL_ERRNO_STRING_H
+#define DPL_ERRNO_STRING_H
+
+#include <dpl/exception.h>
+#include <string>
+#include <cerrno>
+
+namespace DPL {
+DECLARE_EXCEPTION_TYPE(DPL::Exception, InvalidErrnoValue)
+
+std::string GetErrnoString(int error = errno);
+} // namespace DPL
+
+#endif // DPL_ERRNO_STRING_H
--- /dev/null
+/*
+ * Copyright (c) 2014 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 free_deleter.h
+ * @author Pawel Czajkowski (p.czajkowski@samsung.com)
+ * @version 1.0
+ * @brief This file is the implementation file deleter with use std::free()
+ */
+#ifndef FREE_DELETER_H
+#define FREE_DELETER_H
+
+#include <cstdlib>
+namespace DPL
+{
+struct free_deleter
+{
+ void operator()(void *p) { std::free(p); }
+};
+}// DPL
+#endif // FREE_DELETER_H
--- /dev/null
+/*
+ * Copyright (c) 2011 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 string.h
+ * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com)
+ * @version 1.0
+ */
+#ifndef DPL_STRING
+#define DPL_STRING
+
+#include <dpl/exception.h>
+#include <dpl/char_traits.h>
+#include <string>
+#include <ostream>
+#include <numeric>
+
+namespace DPL {
+// @brief DPL string
+typedef std::basic_string<wchar_t, CharTraits> String;
+
+// @brief String exception class
+class StringException
+{
+ public:
+ DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
+
+ // @brief Invalid init for UTF8 to UTF32 converter
+ DECLARE_EXCEPTION_TYPE(Base, IconvInitErrorUTF8ToUTF32)
+
+ // @brief Invalid taStdContainerinit for UTF32 to UTF32 converter
+ DECLARE_EXCEPTION_TYPE(Base, IconvInitErrorUTF32ToUTF8)
+
+ // @brief Invalid conversion for UTF8 to UTF32 converter
+ DECLARE_EXCEPTION_TYPE(Base, IconvConvertErrorUTF8ToUTF32)
+
+ // @brief Invalid conversion for UTF8 to UTF32 converter
+ DECLARE_EXCEPTION_TYPE(Base, IconvConvertErrorUTF32ToUTF8)
+
+ // @brief Invalid ASCII character detected in FromASCII
+ DECLARE_EXCEPTION_TYPE(Base, InvalidASCIICharacter)
+
+ // @brief Invalid ASCII character detected in FromASCII
+ DECLARE_EXCEPTION_TYPE(Base, ICUInvalidCharacterFound)
+};
+
+//!\brief convert ASCII string to DPL::String
+String FromASCIIString(const std::string& aString);
+
+//!\brief convert UTF32 string to DPL::String
+String FromUTF32String(const std::wstring& aString);
+
+//@brief Returns String object created from UTF8 string
+//@param[in] aString input UTF-8 string
+String FromUTF8String(const std::string& aString);
+
+//@brief Returns String content as std::string
+std::string ToUTF8String(const String& aString);
+
+//@brief Compare two unicode strings
+int StringCompare(const String &left,
+ const String &right,
+ bool caseInsensitive = false);
+
+//@brief Splits the string into substrings.
+//@param[in] str Input string
+//@param[in] delimiters array or string containing a sequence of substring
+// delimiters. Can be also a single delimiter character.
+//@param[in] it InserterIterator that is used to save the generated substrings.
+template<typename StringType, typename Delimiters, typename InserterIterator>
+void Tokenize(const StringType& str,
+ const Delimiters& delimiters,
+ InserterIterator it,
+ bool ignoreEmpty = false)
+{
+ typename StringType::size_type nextSearchStart = 0;
+ typename StringType::size_type pos;
+ typename StringType::size_type length;
+
+ while (true) {
+ pos = str.find_first_of(delimiters, nextSearchStart);
+ length =
+ ((pos == StringType::npos) ? str.length() : pos) - nextSearchStart;
+
+ if (!ignoreEmpty || length > 0) {
+ *it = str.substr(nextSearchStart, length);
+ it++;
+ }
+
+ if (pos == StringType::npos) {
+ return;
+ }
+
+ nextSearchStart = pos + 1;
+ }
+}
+
+namespace Utils {
+
+template<typename T> class ConcatFunc : public std::binary_function<T, T, T>
+{
+public:
+ explicit ConcatFunc(const T & val) : m_delim(val) {}
+ T operator()(const T & arg1, const T & arg2) const
+ {
+ return arg1 + m_delim + arg2;
+ }
+private:
+ T m_delim;
+};
+
+}
+
+template<typename ForwardIterator>
+typename ForwardIterator::value_type Join(ForwardIterator begin, ForwardIterator end, typename ForwardIterator::value_type delim)
+{
+ typedef typename ForwardIterator::value_type value;
+ if(begin == end) return value();
+ Utils::ConcatFunc<value> func(delim);
+ ForwardIterator init = begin;
+ return std::accumulate(++begin, end, *init, func);
+}
+
+template<class StringType> void TrimLeft(StringType & obj, typename StringType::const_pointer separators)
+{
+ obj.erase(0, obj.find_first_not_of(separators));
+}
+
+template<class StringType> void TrimRight(StringType & obj, typename StringType::const_pointer separators)
+{
+ obj.erase(obj.find_last_not_of(separators)+1);
+}
+
+template<class StringType> void Trim(StringType & obj, typename StringType::const_pointer separators)
+{
+ TrimLeft(obj, separators);
+ TrimRight(obj, separators);
+}
+
+
+} //namespace DPL
+
+std::ostream& operator<<(std::ostream& aStream, const DPL::String& aString);
+
+#endif // DPL_STRING
--- /dev/null
+/*
+ * Copyright (c) 2011 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 errno_string.h
+ * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
+ * @version 1.0
+ * @brief This file is the implementation file of errno string
+ */
+#include <stddef.h>
+#include <dpl/errno_string.h>
+#include <dpl/assert.h>
+#include <dpl/exception.h>
+#include <dpl/assert.h>
+#include <dpl/free_deleter.h>
+#include <memory>
+#include <string>
+#include <cstddef>
+#include <cstring>
+#include <malloc.h>
+#include <cerrno>
+#include <stdexcept>
+
+namespace DPL {
+namespace // anonymous
+{
+const size_t DEFAULT_ERRNO_STRING_SIZE = 32;
+} // namespace anonymous
+
+std::string GetErrnoString(int error)
+{
+ size_t size = DEFAULT_ERRNO_STRING_SIZE;
+ char *buffer = NULL;
+
+ for (;;) {
+ // Add one extra characted for end of string null value
+ char *newBuffer = static_cast<char *>(::realloc(buffer, size + 1));
+
+ if (!newBuffer) {
+ // Failed to realloc
+ ::free(buffer);
+ throw std::bad_alloc();
+ }
+
+ // Setup reallocated buffer
+ buffer = newBuffer;
+ ::memset(buffer, 0, size + 1);
+
+ // Try to retrieve error string
+#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE
+ // The XSI-compliant version of strerror_r() is provided if:
+ int result = ::strerror_r(error, buffer, size);
+
+ if (result == 0) {
+ std::unique_ptr<char[],free_deleter> scopedBufferFree(buffer);
+ return std::string(buffer);
+ }
+#else
+ errno = 0;
+
+ // Otherwise, the GNU-specific version is provided.
+ char *result = ::strerror_r(error, buffer, size);
+
+ if (result != NULL) {
+ std::unique_ptr<char[],free_deleter> scopedBufferFree(buffer);
+ return std::string(result);
+ }
+#endif
+
+ // Interpret errors
+ switch (errno) {
+ case EINVAL:
+ // We got an invalid errno value
+ ::free(buffer);
+ ThrowMsg(InvalidErrnoValue, "Invalid errno value: " << error);
+
+ case ERANGE:
+ // Incease buffer size and retry
+ size <<= 1;
+ continue;
+
+ default:
+ AssertMsg(0, "Invalid errno value after call to strerror_r!");
+ }
+ }
+}
+} // namespace DPL
--- /dev/null
+/*
+ * Copyright (c) 2011 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 string.cpp
+ * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com)
+ * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
+ * @version 1.0
+ */
+#include <stddef.h>
+#include <memory>
+#include <dpl/string.h>
+#include <dpl/char_traits.h>
+#include <dpl/errno_string.h>
+#include <dpl/exception.h>
+#include <dpl/log/log.h>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <cstring>
+#include <errno.h>
+#include <iconv.h>
+#include <unicode/ustring.h>
+
+// TODO: Completely move to ICU
+namespace DPL {
+namespace //anonymous
+{
+class ASCIIValidator
+{
+ const std::string& m_TestedString;
+
+ public:
+ ASCIIValidator(const std::string& aTestedString);
+
+ void operator()(char aCharacter) const;
+};
+
+ASCIIValidator::ASCIIValidator(const std::string& aTestedString) :
+ m_TestedString(aTestedString)
+{}
+
+void ASCIIValidator::operator()(char aCharacter) const
+{
+ // Check for ASCII data range
+ if (aCharacter <= 0) {
+ ThrowMsg(
+ StringException::InvalidASCIICharacter,
+ "invalid character code " << static_cast<int>(aCharacter)
+ << " from string [" <<
+ m_TestedString
+ << "] passed as ASCII");
+ }
+}
+
+const iconv_t gc_IconvOperError = reinterpret_cast<iconv_t>(-1);
+const size_t gc_IconvConvertError = static_cast<size_t>(-1);
+} // namespace anonymous
+
+String FromUTF8String(const std::string& aIn)
+{
+ if (aIn.empty()) {
+ return String();
+ }
+
+ size_t inbytes = aIn.size();
+
+ // Default iconv UTF-32 module adds BOM (4 bytes) in from of string
+ // The worst case is when 8bit UTF-8 char converts to 32bit UTF-32
+ // newsize = oldsize * 4 + end + bom
+ // newsize - bytes for UTF-32 string
+ // oldsize - letters in UTF-8 string
+ // end - end character for UTF-32 (\0)
+ // bom - Unicode header in front of string (0xfeff)
+ size_t outbytes = sizeof(wchar_t) * (inbytes + 2);
+ std::vector<wchar_t> output(inbytes + 2, 0);
+
+ size_t outbytesleft = outbytes;
+ char* inbuf = const_cast<char*>(aIn.c_str());
+
+ // vector is used to provide buffer for iconv which expects char* buffer
+ // but during conversion from UTF32 uses internaly wchar_t
+ char* outbuf = reinterpret_cast<char*>(&output[0]);
+
+ iconv_t iconvHandle = iconv_open("UTF-32", "UTF-8");
+
+ if (gc_IconvOperError == iconvHandle) {
+ int error = errno;
+
+ ThrowMsg(StringException::IconvInitErrorUTF8ToUTF32,
+ "iconv_open failed for " << "UTF-32 <- UTF-8" <<
+ "error: " << GetErrnoString(error));
+ }
+
+ size_t iconvRet = iconv(iconvHandle,
+ &inbuf,
+ &inbytes,
+ &outbuf,
+ &outbytesleft);
+
+ iconv_close(iconvHandle);
+
+ if (gc_IconvConvertError == iconvRet) {
+ ThrowMsg(StringException::IconvConvertErrorUTF8ToUTF32,
+ "iconv failed for " << "UTF-32 <- UTF-8" << "error: "
+ << GetErrnoString());
+ }
+
+ // Ignore BOM in front of UTF-32
+ return &output[1];
+}
+
+std::string ToUTF8String(const DPL::String& aIn)
+{
+ if (aIn.empty()) {
+ return std::string();
+ }
+
+ size_t inbytes = aIn.size() * sizeof(wchar_t);
+ size_t outbytes = inbytes + sizeof(char);
+
+ // wstring returns wchar_t but iconv expects char*
+ // iconv internally is processing input as wchar_t
+ char* inbuf = reinterpret_cast<char*>(const_cast<wchar_t*>(aIn.c_str()));
+ std::vector<char> output(inbytes, 0);
+ char* outbuf = &output[0];
+
+ size_t outbytesleft = outbytes;
+
+ iconv_t iconvHandle = iconv_open("UTF-8", "UTF-32");
+
+ if (gc_IconvOperError == iconvHandle) {
+ ThrowMsg(StringException::IconvInitErrorUTF32ToUTF8,
+ "iconv_open failed for " << "UTF-8 <- UTF-32"
+ << "error: " << GetErrnoString());
+ }
+
+ size_t iconvRet = iconv(iconvHandle,
+ &inbuf,
+ &inbytes,
+ &outbuf,
+ &outbytesleft);
+
+ iconv_close(iconvHandle);
+
+ if (gc_IconvConvertError == iconvRet) {
+ ThrowMsg(StringException::IconvConvertErrorUTF32ToUTF8,
+ "iconv failed for " << "UTF-8 <- UTF-32"
+ << "error: " << GetErrnoString());
+ }
+
+ return &output[0];
+}
+
+String FromASCIIString(const std::string& aString)
+{
+ String output;
+
+ std::for_each(aString.begin(), aString.end(), ASCIIValidator(aString));
+ std::copy(aString.begin(), aString.end(), std::back_inserter<String>(output));
+
+ return output;
+}
+
+String FromUTF32String(const std::wstring& aString)
+{
+ return String(&aString[0]);
+}
+
+static UChar *ConvertToICU(const String &inputString)
+{
+ std::unique_ptr<UChar[]> outputString;
+ int32_t size = 0;
+ int32_t convertedSize = 0;
+ UErrorCode error = U_ZERO_ERROR;
+
+ // Calculate size of output string
+ ::u_strFromWCS(NULL,
+ 0,
+ &size,
+ inputString.c_str(),
+ -1,
+ &error);
+
+ if (error == U_ZERO_ERROR ||
+ error == U_BUFFER_OVERFLOW_ERROR)
+ {
+ // What buffer size is ok ?
+ LogPedantic("ICU: Output buffer size: " << size);
+ } else {
+ ThrowMsg(StringException::ICUInvalidCharacterFound,
+ "ICU: Failed to retrieve output string size. Error: "
+ << error);
+ }
+
+ // Allocate proper buffer
+ outputString.reset(new UChar[size + 1]);
+ ::memset(outputString.get(), 0, sizeof(UChar) * (size + 1));
+
+ error = U_ZERO_ERROR;
+
+ // Do conversion
+ ::u_strFromWCS(outputString.get(),
+ size + 1,
+ &convertedSize,
+ inputString.c_str(),
+ -1,
+ &error);
+
+ if (!U_SUCCESS(error)) {
+ ThrowMsg(StringException::ICUInvalidCharacterFound,
+ "ICU: Failed to convert string. Error: " << error);
+ }
+
+ // Done
+ return outputString.release();
+}
+
+int StringCompare(const String &left,
+ const String &right,
+ bool caseInsensitive)
+{
+ // Convert input strings
+ std::unique_ptr<UChar[]> leftICU(ConvertToICU(left));
+ std::unique_ptr<UChar[]> rightICU(ConvertToICU(right));
+
+ if (caseInsensitive) {
+ return static_cast<int>(u_strcasecmp(leftICU.get(), rightICU.get(), 0));
+ } else {
+ return static_cast<int>(u_strcmp(leftICU.get(), rightICU.get()));
+ }
+}
+} //namespace DPL
+
+std::ostream& operator<<(std::ostream& aStream, const DPL::String& aString)
+{
+ return aStream << DPL::ToUTF8String(aString);
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 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 naive_synchronization_object.h
+ * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
+ * @version 1.0
+ * @brief This file is the implementation file of SQL naive
+ * synchronization object
+ */
+#ifndef DPL_NAIVE_SYNCHRONIZATION_OBJECT_H
+#define DPL_NAIVE_SYNCHRONIZATION_OBJECT_H
+
+#include <dpl/db/sql_connection.h>
+
+namespace DPL {
+namespace DB {
+/**
+ * Naive synchronization object used to synchronize SQL connection
+ * to the same database across different threads and processes
+ */
+class NaiveSynchronizationObject :
+ public SqlConnection::SynchronizationObject
+{
+ public:
+ // [SqlConnection::SynchronizationObject]
+ virtual void Synchronize();
+ virtual void NotifyAll();
+};
+} // namespace DB
+} // namespace DPL
+
+#endif // DPL_NAIVE_SYNCHRONIZATION_OBJECT_H
--- /dev/null
+/*
+ * Copyright (c) 2011 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 sql_connection.h
+ * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
+ * @version 1.0
+ * @brief This file is the implementation file of SQL connection
+ */
+#ifndef DPL_SQL_CONNECTION_H
+#define DPL_SQL_CONNECTION_H
+
+#include <dpl/noncopyable.h>
+#include <dpl/exception.h>
+#include <dpl/availability.h>
+#include <memory>
+#include <boost/optional.hpp>
+#include <dpl/string.h>
+#include <dpl/log/log.h>
+#include <sqlite3.h>
+#include <string>
+#include <dpl/assert.h>
+#include <memory>
+#include <stdint.h>
+
+namespace DPL {
+namespace DB {
+/**
+ * SQL connection class
+ */
+class SqlConnection
+{
+ public:
+ /**
+ * SQL Exception classes
+ */
+ class Exception
+ {
+ public:
+ DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
+ DECLARE_EXCEPTION_TYPE(Base, SyntaxError)
+ DECLARE_EXCEPTION_TYPE(Base, ConnectionBroken)
+ DECLARE_EXCEPTION_TYPE(Base, InternalError)
+ DECLARE_EXCEPTION_TYPE(Base, InvalidColumn)
+ };
+
+ typedef int ColumnIndex;
+ typedef int ArgumentIndex;
+
+ /*
+ * SQL processed data command
+ */
+ class DataCommand :
+ private Noncopyable
+ {
+ private:
+ SqlConnection *m_masterConnection;
+ sqlite3_stmt *m_stmt;
+
+ void CheckBindResult(int result);
+ void CheckColumnIndex(SqlConnection::ColumnIndex column);
+
+ DataCommand(SqlConnection *connection, const char *buffer);
+
+ friend class SqlConnection;
+
+ public:
+ virtual ~DataCommand();
+
+ /**
+ * Bind null to the prepared statement argument
+ *
+ * @param position Index of argument to bind value to
+ */
+ void BindNull(ArgumentIndex position);
+
+ /**
+ * Bind int to the prepared statement argument
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindInteger(ArgumentIndex position, int value);
+
+ /**
+ * Bind int8_t to the prepared statement argument
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindInt8(ArgumentIndex position, int8_t value);
+
+ /**
+ * Bind int16 to the prepared statement argument
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindInt16(ArgumentIndex position, int16_t value);
+
+ /**
+ * Bind int32 to the prepared statement argument
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindInt32(ArgumentIndex position, int32_t value);
+
+ /**
+ * Bind int64 to the prepared statement argument
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindInt64(ArgumentIndex position, int64_t value);
+
+ /**
+ * Bind float to the prepared statement argument
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindFloat(ArgumentIndex position, float value);
+
+ /**
+ * Bind double to the prepared statement argument
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindDouble(ArgumentIndex position, double value);
+
+ /**
+ * Bind string to the prepared statement argument
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindString(ArgumentIndex position, const char *value);
+
+ /**
+ * Bind string to the prepared statement argument
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindString(ArgumentIndex position, const String& value);
+
+ /**
+ * Bind optional int to the prepared statement argument.
+ * If optional is not set null will be bound
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindInteger(ArgumentIndex position, const boost::optional<int> &value);
+
+ /**
+ * Bind optional int8 to the prepared statement argument.
+ * If optional is not set null will be bound
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindInt8(ArgumentIndex position, const boost::optional<int8_t> &value);
+
+ /**
+ * Bind optional int16 to the prepared statement argument.
+ * If optional is not set null will be bound
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindInt16(ArgumentIndex position, const boost::optional<int16_t> &value);
+
+ /**
+ * Bind optional int32 to the prepared statement argument.
+ * If optional is not set null will be bound
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindInt32(ArgumentIndex position, const boost::optional<int32_t> &value);
+
+ /**
+ * Bind optional int64 to the prepared statement argument.
+ * If optional is not set null will be bound
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindInt64(ArgumentIndex position, const boost::optional<int64_t> &value);
+
+ /**
+ * Bind optional float to the prepared statement argument.
+ * If optional is not set null will be bound
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindFloat(ArgumentIndex position, const boost::optional<float> &value);
+
+ /**
+ * Bind optional double to the prepared statement argument.
+ * If optional is not set null will be bound
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindDouble(ArgumentIndex position, const boost::optional<double> &value);
+
+ /**
+ * Bind optional string to the prepared statement argument.
+ * If optional is not set null will be bound
+ *
+ * @param position Index of argument to bind value to
+ * @param value Value to bind
+ */
+ void BindString(ArgumentIndex position, const boost::optional<String> &value);
+
+ /**
+ * Execute the prepared statement and/or move
+ * to the next row of the result
+ *
+ * @return True when there was a row returned
+ */
+ bool Step();
+
+ /**
+ * Reset prepared statement's arguments
+ * All parameters will become null
+ */
+ void Reset();
+
+ /**
+ * Checks whether column value is null
+ *
+ * @throw Exception::InvalidColumn
+ */
+ bool IsColumnNull(ColumnIndex column);
+
+ /**
+ * Get integer value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ int GetColumnInteger(ColumnIndex column);
+
+ /**
+ * Get int8 value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ int8_t GetColumnInt8(ColumnIndex column);
+
+ /**
+ * Get int16 value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ int16_t GetColumnInt16(ColumnIndex column);
+ /**
+ * Get int32 value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ int32_t GetColumnInt32(ColumnIndex column);
+
+ /**
+ * Get int64 value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ int64_t GetColumnInt64(ColumnIndex column);
+
+ /**
+ * Get float value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ float GetColumnFloat(ColumnIndex column);
+
+ /**
+ * Get double value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ double GetColumnDouble(ColumnIndex column);
+
+ /**
+ * Get string value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ std::string GetColumnString(ColumnIndex column);
+
+ /**
+ * Get optional integer value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ boost::optional<int> GetColumnOptionalInteger(ColumnIndex column);
+
+ /**
+ * Get optional int8 value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ boost::optional<int8_t> GetColumnOptionalInt8(ColumnIndex column);
+
+ /**
+ * Get optional int16value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ boost::optional<int16_t> GetColumnOptionalInt16(ColumnIndex column);
+
+ /**
+ * Get optional int32 value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ boost::optional<int32_t> GetColumnOptionalInt32(ColumnIndex column);
+
+ /**
+ * Get optional int64 value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ boost::optional<int64_t> GetColumnOptionalInt64(ColumnIndex column);
+
+ /**
+ * Get optional float value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ boost::optional<float> GetColumnOptionalFloat(ColumnIndex column);
+
+ /**
+ * Get optional double value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ boost::optional<double> GetColumnOptionalDouble(ColumnIndex column);
+
+ /**
+ * Get optional string value from column in current row.
+ *
+ * @throw Exception::InvalidColumn
+ */
+ boost::optional<String> GetColumnOptionalString(ColumnIndex column);
+ };
+
+ // Move on copy semantics
+ typedef std::auto_ptr<DataCommand> DataCommandAutoPtr;
+
+ // Open flags
+ class Flag
+ {
+ public:
+ enum Type
+ {
+ None = 1 << 0,
+ UseLucene = 1 << 1
+ };
+
+ enum Option
+ {
+ RO = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY,
+ /**
+ * *TODO: please remove CREATE option from RW flag when all places
+ * that need that switched do CRW
+ */
+ RW = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE |
+ SQLITE_OPEN_CREATE,
+ CRW = RW | SQLITE_OPEN_CREATE
+ };
+ };
+
+ // RowID
+ typedef sqlite3_int64 RowID;
+
+ /**
+ * Synchronization object used to synchronize SQL connection
+ * to the same database across different threads and processes
+ */
+ class SynchronizationObject
+ {
+ public:
+ virtual ~SynchronizationObject() {}
+
+ /**
+ * Synchronizes SQL connection for multiple clients.
+ */
+ virtual void Synchronize() = 0;
+
+ /**
+ * Notify all waiting clients that the connection is no longer locked.
+ */
+ virtual void NotifyAll() = 0;
+ };
+
+ protected:
+ sqlite3 *m_connection;
+
+ // Options
+ bool m_usingLucene;
+
+ // Stored data procedures
+ int m_dataCommandsCount;
+
+ // Synchronization object
+ std::unique_ptr<SynchronizationObject> m_synchronizationObject;
+
+ virtual void Connect(const std::string &address,
+ Flag::Type = Flag::None, Flag::Option = Flag::RO);
+ virtual void Disconnect();
+
+ void TurnOnForeignKeys();
+
+ static SynchronizationObject *AllocDefaultSynchronizationObject();
+
+ public:
+ /**
+ * Open SQL connection
+ *
+ * Synchronization is archieved by using provided asynchronization object.
+ * If synchronizationObject is set to NULL, so synchronization is performed.
+ * Ownership of the synchronization object is transfered to sql connection
+ * object.
+ *
+ * @param address Database file name
+ * @param flags Open flags
+ * @param synchronizationObject A synchronization object to use.
+ */
+ explicit SqlConnection(const std::string &address = std::string(),
+ Flag::Type flags = Flag::None,
+ Flag::Option options = Flag::RO,
+ SynchronizationObject *synchronizationObject =
+ AllocDefaultSynchronizationObject());
+
+ /**
+ * Destructor
+ */
+ virtual ~SqlConnection();
+
+ /**
+ * Execute SQL command without result
+ *
+ * @param format
+ * @param ...
+ */
+ void ExecCommand(const char *format, ...) DPL_DEPRECATED_WITH_MESSAGE(
+ "To prevent sql injection do not use this \
+ method for direct sql execution");
+
+ /**
+ * Execute BEGIN; command to start new transaction
+ *
+ */
+ void BeginTransaction();
+
+ /**
+ * Execute ROLLBACK; command to discard changes made
+ *
+ */
+ void RollbackTransaction();
+
+ /**
+ * Execute COMMIT; command to commit changes in database
+ *
+ */
+ void CommitTransaction();
+
+ /**
+ * Prepare stored procedure
+ *
+ * @param format SQL statement
+ * @return Data command representing stored procedure
+ */
+ DataCommandAutoPtr PrepareDataCommand(const char *format, ...);
+
+ /**
+ * Check whether given table exists
+ *
+ * @param tableName Name of the table to check
+ * @return True if given table name exists
+ */
+ bool CheckTableExist(const char *tableName);
+
+ /**
+ * Get last insert operation new row id
+ *
+ * @return Row ID
+ */
+ RowID GetLastInsertRowID() const;
+};
+} // namespace DB
+} // namespace DPL
+
+#endif // DPL_SQL_CONNECTION_H
--- /dev/null
+/*
+ * Copyright (c) 2011 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 naive_synchronization_object.cpp
+ * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
+ * @version 1.0
+ * @brief This file is the implementation file of SQL naive
+ * synchronization object
+ */
+#include <stddef.h>
+#include <dpl/db/naive_synchronization_object.h>
+#include <dpl/thread.h>
+
+namespace {
+ unsigned int seed = time(NULL);
+}
+
+namespace DPL {
+namespace DB {
+void NaiveSynchronizationObject::Synchronize()
+{
+ // Sleep for about 10ms - 30ms
+ Thread::MiliSleep(10 + rand_r(&seed) % 20);
+}
+
+void NaiveSynchronizationObject::NotifyAll()
+{
+ // No need to inform about anything
+}
+} // namespace DB
+} // namespace DPL
--- /dev/null
+/*
+ * Copyright (c) 2011 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 sql_connection.cpp
+ * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
+ * @version 1.0
+ * @brief This file is the implementation file of SQL connection
+ */
+#include <stddef.h>
+#include <dpl/db/sql_connection.h>
+#include <dpl/db/naive_synchronization_object.h>
+#include <dpl/free_deleter.h>
+#include <memory>
+#include <dpl/noncopyable.h>
+#include <dpl/assert.h>
+#include <db-util.h>
+#include <unistd.h>
+#include <cstdio>
+#include <cstdarg>
+
+namespace DPL {
+namespace DB {
+namespace // anonymous
+{
+class ScopedNotifyAll :
+ public Noncopyable
+{
+ private:
+ SqlConnection::SynchronizationObject *m_synchronizationObject;
+
+ public:
+ explicit ScopedNotifyAll(
+ SqlConnection::SynchronizationObject *synchronizationObject) :
+ m_synchronizationObject(synchronizationObject)
+ {}
+
+ ~ScopedNotifyAll()
+ {
+ if (!m_synchronizationObject) {
+ return;
+ }
+
+ LogPedantic("Notifying after successful synchronize");
+ m_synchronizationObject->NotifyAll();
+ }
+};
+} // namespace anonymous
+
+SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
+ const char *buffer) :
+ m_masterConnection(connection),
+ m_stmt(NULL)
+{
+ Assert(connection != NULL);
+
+ // Notify all after potentially synchronized database connection access
+ ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
+
+ for (;;) {
+ int ret = sqlite3_prepare_v2(connection->m_connection,
+ buffer, strlen(buffer),
+ &m_stmt, NULL);
+
+ if (ret == SQLITE_OK) {
+ LogPedantic("Data command prepared successfuly");
+ break;
+ } else if (ret == SQLITE_BUSY) {
+ LogPedantic("Collision occurred while preparing SQL command");
+
+ // Synchronize if synchronization object is available
+ if (connection->m_synchronizationObject) {
+ LogPedantic("Performing synchronization");
+ connection->m_synchronizationObject->Synchronize();
+ continue;
+ }
+
+ // No synchronization object defined. Fail.
+ }
+
+ // Fatal error
+ const char *error = sqlite3_errmsg(m_masterConnection->m_connection);
+
+ LogPedantic("SQL prepare data command failed");
+ LogPedantic(" Statement: " << buffer);
+ LogPedantic(" Error: " << error);
+
+ ThrowMsg(Exception::SyntaxError, error);
+ }
+
+ LogPedantic("Prepared data command: " << buffer);
+
+ // Increment stored data command count
+ ++m_masterConnection->m_dataCommandsCount;
+}
+
+SqlConnection::DataCommand::~DataCommand()
+{
+ LogPedantic("SQL data command finalizing");
+
+ if (sqlite3_finalize(m_stmt) != SQLITE_OK) {
+ LogPedantic("Failed to finalize data command");
+ }
+
+ // Decrement stored data command count
+ --m_masterConnection->m_dataCommandsCount;
+}
+
+void SqlConnection::DataCommand::CheckBindResult(int result)
+{
+ if (result != SQLITE_OK) {
+ const char *error = sqlite3_errmsg(
+ m_masterConnection->m_connection);
+
+ LogPedantic("Failed to bind SQL statement parameter");
+ LogPedantic(" Error: " << error);
+
+ ThrowMsg(Exception::SyntaxError, error);
+ }
+}
+
+void SqlConnection::DataCommand::BindNull(
+ SqlConnection::ArgumentIndex position)
+{
+ CheckBindResult(sqlite3_bind_null(m_stmt, position));
+ LogPedantic("SQL data command bind null: ["
+ << position << "]");
+}
+
+void SqlConnection::DataCommand::BindInteger(
+ SqlConnection::ArgumentIndex position,
+ int value)
+{
+ CheckBindResult(sqlite3_bind_int(m_stmt, position, value));
+ LogPedantic("SQL data command bind integer: ["
+ << position << "] -> " << value);
+}
+
+void SqlConnection::DataCommand::BindInt8(
+ SqlConnection::ArgumentIndex position,
+ int8_t value)
+{
+ CheckBindResult(sqlite3_bind_int(m_stmt, position,
+ static_cast<int>(value)));
+ LogPedantic("SQL data command bind int8: ["
+ << position << "] -> " << value);
+}
+
+void SqlConnection::DataCommand::BindInt16(
+ SqlConnection::ArgumentIndex position,
+ int16_t value)
+{
+ CheckBindResult(sqlite3_bind_int(m_stmt, position,
+ static_cast<int>(value)));
+ LogPedantic("SQL data command bind int16: ["
+ << position << "] -> " << value);
+}
+
+void SqlConnection::DataCommand::BindInt32(
+ SqlConnection::ArgumentIndex position,
+ int32_t value)
+{
+ CheckBindResult(sqlite3_bind_int(m_stmt, position,
+ static_cast<int>(value)));
+ LogPedantic("SQL data command bind int32: ["
+ << position << "] -> " << value);
+}
+
+void SqlConnection::DataCommand::BindInt64(
+ SqlConnection::ArgumentIndex position,
+ int64_t value)
+{
+ CheckBindResult(sqlite3_bind_int64(m_stmt, position,
+ static_cast<sqlite3_int64>(value)));
+ LogPedantic("SQL data command bind int64: ["
+ << position << "] -> " << value);
+}
+
+void SqlConnection::DataCommand::BindFloat(
+ SqlConnection::ArgumentIndex position,
+ float value)
+{
+ CheckBindResult(sqlite3_bind_double(m_stmt, position,
+ static_cast<double>(value)));
+ LogPedantic("SQL data command bind float: ["
+ << position << "] -> " << value);
+}
+
+void SqlConnection::DataCommand::BindDouble(
+ SqlConnection::ArgumentIndex position,
+ double value)
+{
+ CheckBindResult(sqlite3_bind_double(m_stmt, position, value));
+ LogPedantic("SQL data command bind double: ["
+ << position << "] -> " << value);
+}
+
+void SqlConnection::DataCommand::BindString(
+ SqlConnection::ArgumentIndex position,
+ const char *value)
+{
+ if (!value) {
+ BindNull(position);
+ return;
+ }
+
+ // Assume that text may disappear
+ CheckBindResult(sqlite3_bind_text(m_stmt, position,
+ value, strlen(value),
+ SQLITE_TRANSIENT));
+
+ LogPedantic("SQL data command bind string: ["
+ << position << "] -> " << value);
+}
+
+void SqlConnection::DataCommand::BindString(
+ SqlConnection::ArgumentIndex position,
+ const String &value)
+{
+ BindString(position, ToUTF8String(value).c_str());
+}
+
+void SqlConnection::DataCommand::BindInteger(
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<int> &value)
+{
+ if (!value) {
+ BindNull(position);
+ } else {
+ BindInteger(position, *value);
+ }
+}
+
+void SqlConnection::DataCommand::BindInt8(
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<int8_t> &value)
+{
+ if (!value) {
+ BindNull(position);
+ } else {
+ BindInt8(position, *value);
+ }
+}
+
+void SqlConnection::DataCommand::BindInt16(
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<int16_t> &value)
+{
+ if (!value) {
+ BindNull(position);
+ } else {
+ BindInt16(position, *value);
+ }
+}
+
+void SqlConnection::DataCommand::BindInt32(
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<int32_t> &value)
+{
+ if (!value) {
+ BindNull(position);
+ } else {
+ BindInt32(position, *value);
+ }
+}
+
+void SqlConnection::DataCommand::BindInt64(
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<int64_t> &value)
+{
+ if (!value) {
+ BindNull(position);
+ } else {
+ BindInt64(position, *value);
+ }
+}
+
+void SqlConnection::DataCommand::BindFloat(
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<float> &value)
+{
+ if (!value) {
+ BindNull(position);
+ } else {
+ BindFloat(position, *value);
+ }
+}
+
+void SqlConnection::DataCommand::BindDouble(
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<double> &value)
+{
+ if (!value) {
+ BindNull(position);
+ } else {
+ BindDouble(position, *value);
+ }
+}
+
+void SqlConnection::DataCommand::BindString(
+ SqlConnection::ArgumentIndex position,
+ const boost::optional<String> &value)
+{
+ if (!!value) {
+ BindString(position, ToUTF8String(*value).c_str());
+ } else {
+ BindNull(position);
+ }
+}
+
+bool SqlConnection::DataCommand::Step()
+{
+ // Notify all after potentially synchronized database connection access
+ ScopedNotifyAll notifyAll(
+ m_masterConnection->m_synchronizationObject.get());
+
+ for (;;) {
+ int ret = sqlite3_step(m_stmt);
+
+ if (ret == SQLITE_ROW) {
+ LogPedantic("SQL data command step ROW");
+ return true;
+ } else if (ret == SQLITE_DONE) {
+ LogPedantic("SQL data command step DONE");
+ return false;
+ } else if (ret == SQLITE_BUSY) {
+ LogPedantic("Collision occurred while executing SQL command");
+
+ // Synchronize if synchronization object is available
+ if (m_masterConnection->m_synchronizationObject) {
+ LogPedantic("Performing synchronization");
+
+ m_masterConnection->
+ m_synchronizationObject->Synchronize();
+
+ continue;
+ }
+
+ // No synchronization object defined. Fail.
+ }
+
+ // Fatal error
+ const char *error = sqlite3_errmsg(m_masterConnection->m_connection);
+
+ LogPedantic("SQL step data command failed");
+ LogPedantic(" Error: " << error);
+
+ ThrowMsg(Exception::InternalError, error);
+ }
+}
+
+void SqlConnection::DataCommand::Reset()
+{
+ /*
+ * According to:
+ * http://www.sqlite.org/c3ref/stmt.html
+ *
+ * if last sqlite3_step command on this stmt returned an error,
+ * then sqlite3_reset will return that error, althought it is not an error.
+ * So sqlite3_reset allways succedes.
+ */
+ sqlite3_reset(m_stmt);
+
+ LogPedantic("SQL data command reset");
+}
+
+void SqlConnection::DataCommand::CheckColumnIndex(
+ SqlConnection::ColumnIndex column)
+{
+ if (column < 0 || column >= sqlite3_column_count(m_stmt)) {
+ ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
+ }
+}
+
+bool SqlConnection::DataCommand::IsColumnNull(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column type: [" << column << "]");
+ CheckColumnIndex(column);
+ return sqlite3_column_type(m_stmt, column) == SQLITE_NULL;
+}
+
+int SqlConnection::DataCommand::GetColumnInteger(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column integer: [" << column << "]");
+ CheckColumnIndex(column);
+ int value = sqlite3_column_int(m_stmt, column);
+ LogPedantic(" Value: " << value);
+ return value;
+}
+
+int8_t SqlConnection::DataCommand::GetColumnInt8(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column int8: [" << column << "]");
+ CheckColumnIndex(column);
+ int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return value;
+}
+
+int16_t SqlConnection::DataCommand::GetColumnInt16(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column int16: [" << column << "]");
+ CheckColumnIndex(column);
+ int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return value;
+}
+
+int32_t SqlConnection::DataCommand::GetColumnInt32(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column int32: [" << column << "]");
+ CheckColumnIndex(column);
+ int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return value;
+}
+
+int64_t SqlConnection::DataCommand::GetColumnInt64(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column int64: [" << column << "]");
+ CheckColumnIndex(column);
+ int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return value;
+}
+
+float SqlConnection::DataCommand::GetColumnFloat(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column float: [" << column << "]");
+ CheckColumnIndex(column);
+ float value = static_cast<float>(sqlite3_column_double(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return value;
+}
+
+double SqlConnection::DataCommand::GetColumnDouble(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column double: [" << column << "]");
+ CheckColumnIndex(column);
+ double value = sqlite3_column_double(m_stmt, column);
+ LogPedantic(" Value: " << value);
+ return value;
+}
+
+std::string SqlConnection::DataCommand::GetColumnString(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column string: [" << column << "]");
+ CheckColumnIndex(column);
+
+ const char *value = reinterpret_cast<const char *>(
+ sqlite3_column_text(m_stmt, column));
+
+ LogPedantic("Value: " << (value ? value : "NULL"));
+
+ if (value == NULL) {
+ return std::string();
+ }
+
+ return std::string(value);
+}
+
+boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column optional integer: ["
+ << column << "]");
+ CheckColumnIndex(column);
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) {
+ return boost::optional<int>();
+ }
+ int value = sqlite3_column_int(m_stmt, column);
+ LogPedantic(" Value: " << value);
+ return boost::optional<int>(value);
+}
+
+boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column optional int8: ["
+ << column << "]");
+ CheckColumnIndex(column);
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) {
+ return boost::optional<int8_t>();
+ }
+ int8_t value = static_cast<int8_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return boost::optional<int8_t>(value);
+}
+
+boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column optional int16: ["
+ << column << "]");
+ CheckColumnIndex(column);
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) {
+ return boost::optional<int16_t>();
+ }
+ int16_t value = static_cast<int16_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return boost::optional<int16_t>(value);
+}
+
+boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column optional int32: ["
+ << column << "]");
+ CheckColumnIndex(column);
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) {
+ return boost::optional<int32_t>();
+ }
+ int32_t value = static_cast<int32_t>(sqlite3_column_int(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return boost::optional<int32_t>(value);
+}
+
+boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column optional int64: ["
+ << column << "]");
+ CheckColumnIndex(column);
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) {
+ return boost::optional<int64_t>();
+ }
+ int64_t value = static_cast<int64_t>(sqlite3_column_int64(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return boost::optional<int64_t>(value);
+}
+
+boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column optional float: ["
+ << column << "]");
+ CheckColumnIndex(column);
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) {
+ return boost::optional<float>();
+ }
+ float value = static_cast<float>(sqlite3_column_double(m_stmt, column));
+ LogPedantic(" Value: " << value);
+ return boost::optional<float>(value);
+}
+
+boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column optional double: ["
+ << column << "]");
+ CheckColumnIndex(column);
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) {
+ return boost::optional<double>();
+ }
+ double value = sqlite3_column_double(m_stmt, column);
+ LogPedantic(" Value: " << value);
+ return boost::optional<double>(value);
+}
+
+boost::optional<String> SqlConnection::DataCommand::GetColumnOptionalString(
+ SqlConnection::ColumnIndex column)
+{
+ LogPedantic("SQL data command get column optional string: ["
+ << column << "]");
+ CheckColumnIndex(column);
+ if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) {
+ return boost::optional<String>();
+ }
+ const char *value = reinterpret_cast<const char *>(
+ sqlite3_column_text(m_stmt, column));
+ LogPedantic("Value: " << value);
+ String s = FromUTF8String(value);
+ return boost::optional<String>(s);
+}
+
+void SqlConnection::Connect(const std::string &address,
+ Flag::Type type,
+ Flag::Option flag)
+{
+ if (m_connection != NULL) {
+ LogPedantic("Already connected.");
+ return;
+ }
+ LogPedantic("Connecting to DB: " << address << "...");
+
+ // Connect to database
+ int result;
+ if (type & Flag::UseLucene) {
+ result = db_util_open_with_options(
+ address.c_str(),
+ &m_connection,
+ flag,
+ NULL);
+
+ m_usingLucene = true;
+ LogPedantic("Lucene index enabled");
+ } else {
+ result = sqlite3_open_v2(
+ address.c_str(),
+ &m_connection,
+ flag,
+ NULL);
+
+ m_usingLucene = false;
+ LogPedantic("Lucene index disabled");
+ }
+
+ if (result == SQLITE_OK) {
+ LogPedantic("Connected to DB");
+ } else {
+ LogPedantic("Failed to connect to DB!");
+ ThrowMsg(Exception::ConnectionBroken, address);
+ }
+
+ // Enable foreign keys
+ TurnOnForeignKeys();
+}
+
+void SqlConnection::Disconnect()
+{
+ if (m_connection == NULL) {
+ LogPedantic("Already disconnected.");
+ return;
+ }
+
+ LogPedantic("Disconnecting from DB...");
+
+ // All stored data commands must be deleted before disconnect
+ AssertMsg(m_dataCommandsCount == 0,
+ "All stored procedures must be deleted"
+ " before disconnecting SqlConnection");
+
+ int result;
+
+ if (m_usingLucene) {
+ result = db_util_close(m_connection);
+ } else {
+ result = sqlite3_close(m_connection);
+ }
+
+ if (result != SQLITE_OK) {
+ const char *error = sqlite3_errmsg(m_connection);
+ LogPedantic("SQL close failed");
+ LogPedantic(" Error: " << error);
+ Throw(Exception::InternalError);
+ }
+
+ m_connection = NULL;
+
+ LogPedantic("Disconnected from DB");
+}
+
+bool SqlConnection::CheckTableExist(const char *tableName)
+{
+ if (m_connection == NULL) {
+ LogPedantic("Cannot execute command. Not connected to DB!");
+ return false;
+ }
+
+ DataCommandAutoPtr command =
+ PrepareDataCommand("select tbl_name from sqlite_master where name=?;");
+
+ command->BindString(1, tableName);
+
+ if (!command->Step()) {
+ LogPedantic("No matching records in table");
+ return false;
+ }
+
+ return command->GetColumnString(0) == tableName;
+}
+
+SqlConnection::SqlConnection(const std::string &address,
+ Flag::Type flag,
+ Flag::Option option,
+ SynchronizationObject *synchronizationObject) :
+ m_connection(NULL),
+ m_usingLucene(false),
+ m_dataCommandsCount(0),
+ m_synchronizationObject(synchronizationObject)
+{
+ LogPedantic("Opening database connection to: " << address);
+
+ // Connect to DB
+ SqlConnection::Connect(address, flag, option);
+
+ if (!m_synchronizationObject) {
+ LogPedantic("No synchronization object defined");
+ }
+}
+
+SqlConnection::~SqlConnection()
+{
+ LogPedantic("Closing database connection");
+
+ // Disconnect from DB
+ Try
+ {
+ SqlConnection::Disconnect();
+ }
+ Catch(Exception::Base)
+ {
+ LogPedantic("Failed to disconnect from database");
+ }
+}
+
+void SqlConnection::ExecCommand(const char *format, ...)
+{
+ if (m_connection == NULL) {
+ LogPedantic("Cannot execute command. Not connected to DB!");
+ return;
+ }
+
+ if (format == NULL) {
+ LogPedantic("Null query!");
+ ThrowMsg(Exception::SyntaxError, "Null statement");
+ }
+
+ char *rawBuffer;
+
+ va_list args;
+ va_start(args, format);
+
+ if (vasprintf(&rawBuffer, format, args) == -1) {
+ rawBuffer = NULL;
+ }
+
+ va_end(args);
+
+ std::unique_ptr<char[],free_deleter> buffer(rawBuffer);
+
+ if (!buffer) {
+ LogPedantic("Failed to allocate statement string");
+ return;
+ }
+
+ LogPedantic("Executing SQL command: " << buffer.get());
+
+ // Notify all after potentially synchronized database connection access
+ ScopedNotifyAll notifyAll(m_synchronizationObject.get());
+
+ for (;;) {
+ char *errorBuffer;
+
+ int ret = sqlite3_exec(m_connection,
+ buffer.get(),
+ NULL,
+ NULL,
+ &errorBuffer);
+
+ std::string errorMsg;
+
+ // Take allocated error buffer
+ if (errorBuffer != NULL) {
+ errorMsg = errorBuffer;
+ sqlite3_free(errorBuffer);
+ }
+
+ if (ret == SQLITE_OK) {
+ return;
+ }
+
+ if (ret == SQLITE_BUSY) {
+ LogPedantic("Collision occurred while executing SQL command");
+
+ // Synchronize if synchronization object is available
+ if (m_synchronizationObject) {
+ LogPedantic("Performing synchronization");
+ m_synchronizationObject->Synchronize();
+ continue;
+ }
+
+ // No synchronization object defined. Fail.
+ }
+
+ // Fatal error
+ LogPedantic("Failed to execute SQL command. Error: " << errorMsg);
+ ThrowMsg(Exception::SyntaxError, errorMsg);
+ }
+}
+
+SqlConnection::DataCommandAutoPtr SqlConnection::PrepareDataCommand(
+ const char *format,
+ ...)
+{
+ if (m_connection == NULL) {
+ LogPedantic("Cannot execute data command. Not connected to DB!");
+ return DataCommandAutoPtr();
+ }
+
+ char *rawBuffer;
+
+ va_list args;
+ va_start(args, format);
+
+ if (vasprintf(&rawBuffer, format, args) == -1) {
+ rawBuffer = NULL;
+ }
+
+ va_end(args);
+
+ std::unique_ptr<char[],free_deleter> buffer(rawBuffer);
+
+ if (!buffer) {
+ LogPedantic("Failed to allocate statement string");
+ return DataCommandAutoPtr();
+ }
+
+ LogPedantic("Executing SQL data command: " << buffer.get());
+
+ return DataCommandAutoPtr(new DataCommand(this, buffer.get()));
+}
+
+SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
+{
+ return static_cast<RowID>(sqlite3_last_insert_rowid(m_connection));
+}
+
+void SqlConnection::TurnOnForeignKeys()
+{
+ ExecCommand("PRAGMA foreign_keys = ON;");
+}
+
+void SqlConnection::BeginTransaction()
+{
+ ExecCommand("BEGIN;");
+}
+
+void SqlConnection::RollbackTransaction()
+{
+ ExecCommand("ROLLBACK;");
+}
+
+void SqlConnection::CommitTransaction()
+{
+ ExecCommand("COMMIT;");
+}
+
+SqlConnection::SynchronizationObject *
+SqlConnection::AllocDefaultSynchronizationObject()
+{
+ return new NaiveSynchronizationObject();
+}
+} // namespace DB
+} // namespace DPL