wallet/src/ISqlite3.h
2022-06-30 16:55:37 +10:00

96 lines
4.8 KiB
C++

#pragma once
#include "ILog.h"
// this is pure virtual interface base class between sqlite3, which speaks only C and utf8 char[]
// and wxWidgets which speaks only C++ and unicode strings.
// Usage: Call the factory function std::shared_ptr<ISqlite3> sqlite3_open(const char *) to get a shared
// pointer to the // Sqlite3 database object. Then call the factory function
// sqlite3_prepare(std::shared_ptr<ISqlite3>, const char *) to get a unique pointer to
// a compiled SQL statement
// Its primary purpose is to avoid code that needs both the wxWidgets header files,
// and the sqlite3.h header file.
//
// It speaks only utf8 char[], and needs to be called in wxWidgets code using
// wxString.utf8_str() and its return values need to be interpreted in wxWidgets code
// using wxString::FromUTF8().
//
// This header file can be included in code that has the sqlite3.h header file
// and in code that has the wxWidgets header file, for it has no dependencies on either one
//
// In code that has wxWidgets headers, we call members of this interface class,
// rather than directly calling sqlite3 functions.
//
// I originally implemented the pimpl idiom, but it turns out that pimpl has become
// substantially more difficult in C++14, because one is effectively rolling one's own
// unique pointer.
//
// It is therefore easier to implement a pure virtual base class with a virtual destructor and
// factory function that returns a smart pointer to a member of the derived implementation
//
/* This code is at a low level abstraction, because it provides low level C++ interface to inherently low level C
It is intended to be wrapped in higher level code that does not know about the nuts and bolts of sqlite3, but which supports throwing, templated functions, and all that.*/
//
//___________________________________
// This class wraps a compiled sql statement.
class Icompiled_sql
{
protected:
Icompiled_sql() = default; // needed for derived constructor
public:
virtual ~Icompiled_sql() = default; // needed for derived destructor
// Bind is used when writing stuff into the database. These objects should continue to exist until the write is finalized or reset.
virtual void Isqlite3_bind( int, const std::span<const uint8_t>) = 0; // https://sqlite.org/c3ref/bind.html
virtual void Isqlite3_bind(int, int) = 0;
virtual void Isqlite3_bind(int, int64_t) = 0;
virtual void Isqlite3_bind(int) = 0;
virtual void Isqlite3_bind(int, const char*) = 0;
enum sql_result { DONE, ROW, BUSY, SQL_ERROR, MISUSE };
virtual sql_result Isqlite3_step() = 0;
// when reading, you don't use bind. Sqlite creates a temporary in the memory that it manages. If you want the object to live beyond the next step operation, need to make a copy
// When writing objects, we reinterpret a pointer to a typed object as a blob pointer, when reading them, we need a typed copy, otherwise calling the destructor could be bad.
// We don't want Sqlite3 calling destructors on our objects, hence write them as static, and create them from raw bytes on reading.
virtual std::span<const uint8_t> Isqlite3_column_blob (int) const = 0; // returns the null pointer and zero length if null.
virtual int Isqlite3_column_int (int) const = 0;
virtual int64_t Isqlite3_column_int64 (int) const = 0;
virtual char* Isqlite3_column_text (int) const = 0; // returns pointer to zero length
// string if null. If we need to distinguish betweem zero length strings and nulls, need the
// type function.
// We can store any type in any column, and read any type from any column, but if something
// unexpected is in a column, it gets coerced to the expected type on being read back.
// Thus something stored as a number and read back as blob will come back as the decimal character string.
// It is very rarely valid to store different types in the same column, except that
// null is permissible. The difference between null and zero matters, but the case of
// null is usually dealt with by sql code, not C code.
virtual void Isqlite3_reset() = 0; // https://sqlite.org/c3ref/reset.html
};
//___________________________________
// This class wraps a database. Its derived implementation will hold an old type C pointer
// to an opened database object, which is destroyed when the class object is destroyed
class ISqlite3
{
protected:
ISqlite3() = default; // needed for derived constructor
public:
virtual ~ISqlite3() = default; // needed for derived destructor
virtual void exec(const char*) = 0;
};
// Factory method to open a database and produce a shared object wrapping the database
ISqlite3* Sqlite3_open(const char*);
// Factory method to create a database and produce a shared object wrapping the database
ISqlite3* Sqlite3_create(const char*);
// Factory method to prepare a compiled sql statement
Icompiled_sql* sqlite3_prepare(ISqlite3*, const char *);
void sqlite3_init();
extern "C" {
int sqlite3_shutdown(void);
}