<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2022.  All rights reserved
 */
#include "../../StroikaPreComp.h"

#include <system_error>

#include "../../Characters/Format.h"
#include "../../Characters/StringBuilder.h"
#include "../../Characters/ToString.h"
#include "../../Debug/Trace.h"
#include "../../Time/Duration.h"

#include "SQLite.h"

using std::byte;

using namespace Stroika::Foundation;

using namespace Characters;
using namespace Debug;
using namespace Database;
using namespace Database::SQL::SQLite;
using namespace Execution;
using namespace Time;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

#if qHasFeature_sqlite && defined(_MSC_VER)
// Use #pragma comment lib instead of explicit entry in the lib entry of the project file
#pragma comment(lib, "sqlite.lib")
#endif

#if qHasFeature_sqlite
namespace {
    struct ModuleShutdown_ {
        ~ModuleShutdown_ ()
        {
            Verify (::sqlite3_shutdown () == SQLITE_OK); // mostly pointless but avoids memory leak complaints
        }
    } sModuleShutdown_;
    [[noreturn]] void ThrowSQLiteError_ (int errCode, sqlite3* sqliteConnection = nullptr)
    {
        Require (errCode != SQLITE_OK);
        optional<String> errMsgDetails;
        if (sqliteConnection != nullptr) {
            errMsgDetails = String::FromUTF8 (::sqlite3_errmsg (sqliteConnection));
        }
        switch (errCode) {
            case SQLITE_BUSY: {
                DbgTrace (L"SQLITE_BUSY");
                Execution::Throw (system_error{make_error_code (errc::device_or_resource_busy)});
            } break;
            case SQLITE_CONSTRAINT: {
                if (errMsgDetails) {
                    Execution::Throw (Exception{Characters::Format (L"SQLITE_CONSTRAINT: %s", errMsgDetails->c_str ())});
                }
                else {
                    Execution::Throw (Exception{L"SQLITE_CONSTRAINT"sv});
                }
            } break;
            case SQLITE_TOOBIG: {
                Execution::Throw (Exception{L"SQLITE_TOOBIG"sv});
            } break;
            case SQLITE_FULL: {
                DbgTrace (L"SQLITE_FULL");
                Execution::Throw (system_error{make_error_code (errc::no_space_on_device)});
            } break;
            case SQLITE_READONLY: {
                Execution::Throw (Exception{L"SQLITE_READONLY"sv});
            } break;
            case SQLITE_MISUSE: {
                if (errMsgDetails) {
                    Execution::Throw (Exception{Characters::Format (L"SQLITE_MISUSE: %s", errMsgDetails->c_str ())});
                }
                else {
                    Execution::Throw (Exception{L"SQLITE_MISUSE"sv});
                }
            } break;
            case SQLITE_ERROR: {
                if (errMsgDetails) {
                    Execution::Throw (Exception{Characters::Format (L"SQLITE_ERROR: %s", errMsgDetails->c_str ())});
                }
                else {
                    Execution::Throw (Exception{L"SQLITE_ERROR"sv});
                }
            } break;
            case SQLITE_NOMEM: {
                DbgTrace (L"SQLITE_NOMEM translated to bad_alloc");
                Execution::Throw (bad_alloc{});
            } break;
        }
        if (errMsgDetails) {
            Execution::Throw (Exception{Characters::Format (L"SQLite Error: %s (code %d)", errMsgDetails->c_str (), errCode)});
        }
        else {
            Execution::Throw (Exception{Characters::Format (L"SQLite Error: %d", errCode)});
        }
    }
    void ThrowSQLiteErrorIfNotOK_ (int errCode, sqlite3* sqliteConnection = nullptr)
    {
        static_assert (SQLITE_OK == 0);
        if (errCode != SQLITE_OK) [[UNLIKELY_ATTR]] {
            ThrowSQLiteError_ (errCode, sqliteConnection);
        }
    }
}

/*
 ********************************************************************************
 *************************** SQLite::CompiledOptions ****************************
 ********************************************************************************
 */
namespace {
    struct VerifyFlags_ {
        VerifyFlags_ ()
        {
            Assert (CompiledOptions::kThe.ENABLE_NORMALIZE == !!::sqlite3_compileoption_used ("ENABLE_NORMALIZE"));
            Assert (CompiledOptions::kThe.THREADSAFE == !!::sqlite3_compileoption_used ("THREADSAFE"));
            #if SQLITE_VERSION_NUMBER < 3038000
            Assert (CompiledOptions::kThe.ENABLE_JSON1 == !!::sqlite3_compileoption_used ("ENABLE_JSON1"));
            #else
            Assert (CompiledOptions::kThe.ENABLE_JSON1 == !::sqlite3_compileoption_used ("OMIT_JSON1"));
            #endif
        }
    } sVerifyFlags_;
}

/*
 ********************************************************************************
 *************************** SQLite::Connection::Rep_ ***************************
 ********************************************************************************
 */
struct Connection::Rep_ final : IRep {
    Rep_ (const Options& options)
    {
        TraceContextBumper ctx{"SQLite::Connection::Rep_::Rep_"};

        int flags = 0;
        if (options.fThreadingMode) {
            switch (*options.fThreadingMode) {
                case Options::ThreadingMode::eSingleThread:
                    break;
                case Options::ThreadingMode::eMultiThread:
                    Require (CompiledOptions::kThe.THREADSAFE);
                    Require (::sqlite3_threadsafe ());<commit_msg>cosmetic<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2022.  All rights reserved
 */
#include "../../StroikaPreComp.h"

#include <system_error>

#include "../../Characters/Format.h"
#include "../../Characters/StringBuilder.h"
#include "../../Characters/ToString.h"
#include "../../Debug/Trace.h"
#include "../../Time/Duration.h"

#include "SQLite.h"

using std::byte;

using namespace Stroika::Foundation;

using namespace Characters;
using namespace Debug;
using namespace Database;
using namespace Database::SQL::SQLite;
using namespace Execution;
using namespace Time;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

#if qHasFeature_sqlite && defined(_MSC_VER)
// Use #pragma comment lib instead of explicit entry in the lib entry of the project file
#pragma comment(lib, "sqlite.lib")
#endif

#if qHasFeature_sqlite
namespace {
    struct ModuleShutdown_ {
        ~ModuleShutdown_ ()
        {
            Verify (::sqlite3_shutdown () == SQLITE_OK); // mostly pointless but avoids memory leak complaints
        }
    } sModuleShutdown_;
    [[noreturn]] void ThrowSQLiteError_ (int errCode, sqlite3* sqliteConnection = nullptr)
    {
        Require (errCode != SQLITE_OK);
        optional<String> errMsgDetails;
        if (sqliteConnection != nullptr) {
            errMsgDetails = String::FromUTF8 (::sqlite3_errmsg (sqliteConnection));
        }
        switch (errCode) {
            case SQLITE_BUSY: {
                DbgTrace (L"SQLITE_BUSY");
                Execution::Throw (system_error{make_error_code (errc::device_or_resource_busy)});
            } break;
            case SQLITE_CONSTRAINT: {
                if (errMsgDetails) {
                    Execution::Throw (Exception{Characters::Format (L"SQLITE_CONSTRAINT: %s", errMsgDetails->c_str ())});
                }
                else {
                    Execution::Throw (Exception{L"SQLITE_CONSTRAINT"sv});
                }
            } break;
            case SQLITE_TOOBIG: {
                Execution::Throw (Exception{L"SQLITE_TOOBIG"sv});
            } break;
            case SQLITE_FULL: {
                DbgTrace (L"SQLITE_FULL");
                Execution::Throw (system_error{make_error_code (errc::no_space_on_device)});
            } break;
            case SQLITE_READONLY: {
                Execution::Throw (Exception{L"SQLITE_READONLY"sv});
            } break;
            case SQLITE_MISUSE: {
                if (errMsgDetails) {
                    Execution::Throw (Exception{Characters::Format (L"SQLITE_MISUSE: %s", errMsgDetails->c_str ())});
                }
                else {
                    Execution::Throw (Exception{L"SQLITE_MISUSE"sv});
                }
            } break;
            case SQLITE_ERROR: {
                if (errMsgDetails) {
                    Execution::Throw (Exception{Characters::Format (L"SQLITE_ERROR: %s", errMsgDetails->c_str ())});
                }
                else {
                    Execution::Throw (Exception{L"SQLITE_ERROR"sv});
                }
            } break;
            case SQLITE_NOMEM: {
                DbgTrace (L"SQLITE_NOMEM translated to bad_alloc");
                Execution::Throw (bad_alloc{});
            } break;
        }
        if (errMsgDetails) {
            Execution::Throw (Exception{Characters::Format (L"SQLite Error: %s (code %d)", errMsgDetails->c_str (), errCode)});
        }
        else {
            Execution::Throw (Exception{Characters::Format (L"SQLite Error: %d", errCode)});
        }
    }
    void ThrowSQLiteErrorIfNotOK_ (int errCode, sqlite3* sqliteConnection = nullptr)
    {
        static_assert (SQLITE_OK == 0);
        if (errCode != SQLITE_OK) [[UNLIKELY_ATTR]] {
            ThrowSQLiteError_ (errCode, sqliteConnection);
        }
    }
}

/*
 ********************************************************************************
 *************************** SQLite::CompiledOptions ****************************
 ********************************************************************************
 */
namespace {
    struct VerifyFlags_ {
        VerifyFlags_ ()
        {
            Assert (CompiledOptions::kThe.ENABLE_NORMALIZE == !!::sqlite3_compileoption_used ("ENABLE_NORMALIZE"));
            Assert (CompiledOptions::kThe.THREADSAFE == !!::sqlite3_compileoption_used ("THREADSAFE"));
#if SQLITE_VERSION_NUMBER < 3038000
            Assert (CompiledOptions::kThe.ENABLE_JSON1 == !!::sqlite3_compileoption_used ("ENABLE_JSON1"));
#else
            Assert (CompiledOptions::kThe.ENABLE_JSON1 == !::sqlite3_compileoption_used ("OMIT_JSON1"));
#endif
        }
    } sVerifyFlags_;
}

/*
 ********************************************************************************
 *************************** SQLite::Connection::Rep_ ***************************
 ********************************************************************************
 */
struct Connection::Rep_ final : IRep {
    Rep_ (const Options& options)
    {
        TraceContextBumper ctx{"SQLite::Connection::Rep_::Rep_"};

        int flags = 0;
        if (options.fThreadingMode) {
            switch (*options.fThreadingMode) {
                case Options::ThreadingMode::eSingleThread:
                    break;
                case Options::ThreadingMode::eMultiThread:
                    Require (CompiledOptions::kThe.THREADSAFE);
                    Require (::sqlite3_threadsafe ());
{'fraction_non_alphanumeric': 0.18692608418947176, 'fraction_numerical': 0.005818710791890172, 'mean_word_length': 2.4777110338286437, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3519554', 'n_tokens_mistral': 3085, 'n_tokens_neox': 2931, 'n_words': 578}