DPL: import DPL::SqlConnection and dependencies 62/23162/4
authorRafal Krypa <r.krypa@samsung.com>
Mon, 2 Jun 2014 17:00:44 +0000 (19:00 +0200)
committerRafal Krypa <r.krypa@samsung.com>
Mon, 23 Jun 2014 18:03:48 +0000 (20:03 +0200)
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>
src/server/dpl/core/include/dpl/availability.h [new file with mode: 0644]
src/server/dpl/core/include/dpl/char_traits.h [new file with mode: 0644]
src/server/dpl/core/include/dpl/errno_string.h [new file with mode: 0644]
src/server/dpl/core/include/dpl/free_deleter.h [new file with mode: 0644]
src/server/dpl/core/include/dpl/string.h [new file with mode: 0644]
src/server/dpl/core/src/errno_string.cpp [new file with mode: 0644]
src/server/dpl/core/src/string.cpp [new file with mode: 0644]
src/server/dpl/db/include/dpl/db/naive_synchronization_object.h [new file with mode: 0644]
src/server/dpl/db/include/dpl/db/sql_connection.h [new file with mode: 0644]
src/server/dpl/db/src/naive_synchronization_object.cpp [new file with mode: 0644]
src/server/dpl/db/src/sql_connection.cpp [new file with mode: 0644]

diff --git a/src/server/dpl/core/include/dpl/availability.h b/src/server/dpl/core/include/dpl/availability.h
new file mode 100644 (file)
index 0000000..0813892
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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
diff --git a/src/server/dpl/core/include/dpl/char_traits.h b/src/server/dpl/core/include/dpl/char_traits.h
new file mode 100644 (file)
index 0000000..eb2988f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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
diff --git a/src/server/dpl/core/include/dpl/errno_string.h b/src/server/dpl/core/include/dpl/errno_string.h
new file mode 100644 (file)
index 0000000..446dbc9
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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
diff --git a/src/server/dpl/core/include/dpl/free_deleter.h b/src/server/dpl/core/include/dpl/free_deleter.h
new file mode 100644 (file)
index 0000000..4a09904
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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
diff --git a/src/server/dpl/core/include/dpl/string.h b/src/server/dpl/core/include/dpl/string.h
new file mode 100644 (file)
index 0000000..e4dc923
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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
diff --git a/src/server/dpl/core/src/errno_string.cpp b/src/server/dpl/core/src/errno_string.cpp
new file mode 100644 (file)
index 0000000..6c59776
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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
diff --git a/src/server/dpl/core/src/string.cpp b/src/server/dpl/core/src/string.cpp
new file mode 100644 (file)
index 0000000..a642eaa
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * 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);
+}
diff --git a/src/server/dpl/db/include/dpl/db/naive_synchronization_object.h b/src/server/dpl/db/include/dpl/db/naive_synchronization_object.h
new file mode 100644 (file)
index 0000000..2f63a0f
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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
diff --git a/src/server/dpl/db/include/dpl/db/sql_connection.h b/src/server/dpl/db/include/dpl/db/sql_connection.h
new file mode 100644 (file)
index 0000000..18a5d3f
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * 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
diff --git a/src/server/dpl/db/src/naive_synchronization_object.cpp b/src/server/dpl/db/src/naive_synchronization_object.cpp
new file mode 100644 (file)
index 0000000..1ac71ca
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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
diff --git a/src/server/dpl/db/src/sql_connection.cpp b/src/server/dpl/db/src/sql_connection.cpp
new file mode 100644 (file)
index 0000000..57ea9b9
--- /dev/null
@@ -0,0 +1,866 @@
+/*
+ * 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