mirror of
				https://github.com/Telecominfraproject/wlan-cloud-lib-poco.git
				synced 2025-11-03 20:18:01 +00:00 
			
		
		
		
	* Remaining Data2SQL fixes * Restore PocoDoc Signed-off-by: Francis ANDRE <francis.andre.kampbell@orange.fr>
		
			
				
	
	
		
			430 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			430 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
POCO SQL Connectors Developer Guide
 | 
						|
POCO SQL Library
 | 
						|
 | 
						|
!!!Overview
 | 
						|
Developing one's own <*SQL Connector*> implementation is rather straight-forward.
 | 
						|
Just implement the following interfaces:
 | 
						|
  * Poco::SQL::AbstractBinder
 | 
						|
  * Poco::SQL::AbstractExtractor
 | 
						|
  * Poco::SQL::StatementImpl
 | 
						|
  * Poco::SQL::SessionImpl
 | 
						|
  * Poco::SQL::Connector
 | 
						|
  * optional: Poco::SQL::AbstractPreparation
 | 
						|
 | 
						|
It is recommended to implement the classes from top to down (ie. start with Binder and Extractor) and to use a
 | 
						|
namespace that has <[ Poco::SQL ]> as parent, e.g.<[ Poco::SQL::SQLite ]>.
 | 
						|
 | 
						|
!!!AbstractBinder
 | 
						|
An <[AbstractBinder]> is a class that maps values to placeholders. It is also responsible to bind primitive C++ data types to database
 | 
						|
data types. The constructor of the subclass should receive everything needed to bind variables to
 | 
						|
placeholders by position. An example taken from the SQLite implementation would be:
 | 
						|
 | 
						|
    Binder::Binder(sqlite3_stmt* pStmt):
 | 
						|
        _pStmt(pStmt)
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    void Binder::bind(std::size_t pos, const Poco::Int32& val)
 | 
						|
    {
 | 
						|
        int rc = sqlite3_bind_int(_pStmt, (int)pos, val);
 | 
						|
        checkReturn(rc);
 | 
						|
    }
 | 
						|
 | 
						|
    void Binder::bind(std::size_t pos, const Poco::Int16& val)
 | 
						|
    {
 | 
						|
        Poco::Int32 tmp = val;
 | 
						|
        bind(pos, tmp);
 | 
						|
    }
 | 
						|
----
 | 
						|
SQLite only needs an <*sqlite3_stmt*> as internal state, Int32 is bound via <*sqlite3_bind_int*> and Int16 values are mapped to Int32 values.
 | 
						|
 | 
						|
!!Complete Interface
 | 
						|
All methods are public.
 | 
						|
 | 
						|
    AbstractBinder();
 | 
						|
        /// Creates the AbstractBinder.
 | 
						|
 | 
						|
    virtual ~AbstractBinder();
 | 
						|
        /// Destroys the AbstractBinder.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const Poco::Int8 &val) = 0;
 | 
						|
        /// Binds an Int8.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const Poco::UInt8 &val) = 0;
 | 
						|
        /// Binds an UInt8.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const Poco::Int16 &val) = 0;
 | 
						|
        /// Binds an Int16.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const Poco::UInt16 &val) = 0;
 | 
						|
        /// Binds an UInt16.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const Poco::Int32 &val) = 0;
 | 
						|
        /// Binds an Int32.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const Poco::UInt32 &val) = 0;
 | 
						|
        /// Binds an UInt32.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const Poco::Int64 &val) = 0;
 | 
						|
        /// Binds an Int64.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const Poco::UInt64 &val) = 0;
 | 
						|
        /// Binds an UInt64.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const bool &val) = 0;
 | 
						|
        /// Binds a boolean.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const float &val) = 0;
 | 
						|
        /// Binds a float.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const double &val) = 0;
 | 
						|
        /// Binds a double.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const char &val) = 0;
 | 
						|
        /// Binds a single character.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const char* const &pVal) = 0;
 | 
						|
        /// Binds a const char ptr.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const std::string& val) = 0;
 | 
						|
        /// Binds a string.
 | 
						|
 | 
						|
    virtual void bind(std::size_t pos, const BLOB& val) = 0;
 | 
						|
        /// Binds a BLOB.
 | 
						|
 | 
						|
    virtual void reset() = 0;
 | 
						|
        /// Resets the internal state, called before a rebind
 | 
						|
----
 | 
						|
 | 
						|
!!!AbstractExtractor
 | 
						|
An <[AbstractExtractor]> takes a result row and extracts from a given position one single value. It performs the reverse operation to the <[AbstractBinder]>,
 | 
						|
ie. it maps database types to primitive C++ types. An <[AbstractExtractor]> also has to handle null values. If it detects a null value, it is not allowed to modify
 | 
						|
the incoming value but will simply return false. An example taken from the SQLite implementation:
 | 
						|
 | 
						|
    Extractor::Extractor(sqlite3_stmt* pStmt):
 | 
						|
        _pStmt(pStmt)
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    bool Extractor::extract(std::size_t pos, Poco::Int32& val)
 | 
						|
    {
 | 
						|
        if (isNull(pos<[
 | 
						|
            return false;
 | 
						|
        val = sqlite3_column_int(_pStmt, (int)pos);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    bool Extractor::extract(std::size_t pos, Poco::Int16& val)
 | 
						|
    {
 | 
						|
        if (isNull(pos<[
 | 
						|
            return false;
 | 
						|
        val = sqlite3_column_int(_pStmt, (int)pos);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
----
 | 
						|
 | 
						|
!!Complete Interface
 | 
						|
All methods are public.
 | 
						|
 | 
						|
    AbstractExtractor();
 | 
						|
        /// Creates the AbstractExtractor.
 | 
						|
 | 
						|
    virtual ~AbstractExtractor();
 | 
						|
        /// Destroys the AbstractExtractor.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, Poco::Int8& val) = 0;
 | 
						|
        /// Extracts an Int8. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, Poco::UInt8& val) = 0;
 | 
						|
        /// Extracts an UInt8. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, Poco::Int16& val) = 0;
 | 
						|
        /// Extracts an Int16. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, Poco::UInt16& val) = 0;
 | 
						|
        /// Extracts an UInt16. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, Poco::Int32& val) = 0;
 | 
						|
        /// Extracts an Int32. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, Poco::UInt32& val) = 0;
 | 
						|
        /// Extracts an UInt32. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, Poco::Int64& val) = 0;
 | 
						|
        /// Extracts an Int64. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, Poco::UInt64& val) = 0;
 | 
						|
        /// Extracts an UInt64. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, bool& val) = 0;
 | 
						|
        /// Extracts a boolean. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, float& val) = 0;
 | 
						|
        /// Extracts a float. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, double& val) = 0;
 | 
						|
        /// Extracts a double. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, char& val) = 0;
 | 
						|
        /// Extracts a single character. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, std::string& val) = 0;
 | 
						|
        /// Extracts a string. Returns false if null was received.
 | 
						|
 | 
						|
    virtual bool extract(std::size_t pos, BLOB& val) = 0;
 | 
						|
        /// Extracts a BLOB. Returns false if null was received.
 | 
						|
----
 | 
						|
 | 
						|
!!!AbstractPreparation
 | 
						|
<[AbstractPreparation]> is an optional interface responsible for preparing an extract. If you need it depends on the <[SQLConnector]> you implement. For example, SQLite can do perfectly without it, ODBC instead requires it.
 | 
						|
SQLite doesn't need it because it works as follows:
 | 
						|
  * sendQuery
 | 
						|
  * getNextResult
 | 
						|
  * extract single row values from result set
 | 
						|
 | 
						|
This works because SQLites <*getNextResult*> provides the data as string, i.e. it doesn't need any type information.
 | 
						|
 | 
						|
The ODBC implementation is different:
 | 
						|
  * register/prepare for each column an output location
 | 
						|
  * getNextResult
 | 
						|
  * extract for each row the value by copying the content of the previously registered output location
 | 
						|
 | 
						|
<[AbstractPreparation]> is responsible for the first step. A typical prepare implementation will look like that:
 | 
						|
 | 
						|
    void prepare(std::size_t pos, Poco::Int32 val)
 | 
						|
    {
 | 
						|
       _myVec[pos] =  Poco::Any a(val);
 | 
						|
       int* i = AnyCast<int>(&_myVec[pos]);
 | 
						|
       //register int* i for output, Db specific
 | 
						|
    }
 | 
						|
----
 | 
						|
Extract now changes to:
 | 
						|
 | 
						|
    bool Extractor::extract(std::size_t pos, Poco::Int16& val)
 | 
						|
    {
 | 
						|
        if (isNull(pos))
 | 
						|
            return false;
 | 
						|
        val = AnyCast<int>(_myVec[pos]);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
----
 | 
						|
 | 
						|
!!Complete Interface
 | 
						|
 | 
						|
    AbstractPreparation();
 | 
						|
        /// Creates the AbstractPreparation.
 | 
						|
 | 
						|
    virtual ~AbstractPreparation();
 | 
						|
        /// Destroys the AbstractPreparation.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, Poco::Int8) = 0;
 | 
						|
        /// Prepares an Int8.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, Poco::UInt8) = 0;
 | 
						|
        /// Prepares an UInt8.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, Poco::Int16) = 0;
 | 
						|
        /// Prepares an Int16.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, Poco::UInt16) = 0;
 | 
						|
        /// Prepares an UInt16.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, Poco::Int32) = 0;
 | 
						|
        /// Prepares an Int32.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, Poco::UInt32) = 0;
 | 
						|
        /// Prepares an UInt32.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, Poco::Int64) = 0;
 | 
						|
        /// Prepares an Int64.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, Poco::UInt64) = 0;
 | 
						|
        /// Prepares an UInt64.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, bool) = 0;
 | 
						|
        /// Prepares a boolean.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, float) = 0;
 | 
						|
        /// Prepares a float.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, double) = 0;
 | 
						|
        /// Prepares a double.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, char) = 0;
 | 
						|
        /// Prepares a single character.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, const std::string& ) = 0;
 | 
						|
        /// Prepares a string.
 | 
						|
 | 
						|
    virtual void prepare(std::size_t pos, const BLOB&) = 0;
 | 
						|
----
 | 
						|
 | 
						|
Note that it is recommended to prepare a statement only once in the compileImpl of <[StatementImpl]>. The AbstractPreparator objects (which make use of <[AbstractPreparation]>
 | 
						|
can be created by iterating over the Extractor objects of the StatementImpl:
 | 
						|
 | 
						|
    Poco::SQL::AbstractExtractingVec::iterator it = extractings().begin();
 | 
						|
    Poco::SQL::AbstractExtractingVec::iterator itEnd = extractings().end();
 | 
						|
    std::size_t pos = 0; // sqlite starts with pos 0 for results! your DB maybe with 1
 | 
						|
    for (; it != itEnd; ++it)
 | 
						|
    {
 | 
						|
         AbstractPreparator* pPrep = (*it)->createPrepareObject(pPreparation, pos);
 | 
						|
        _prepareVec.push_back(pPrep);
 | 
						|
        (*it)->extract(pos);
 | 
						|
        pos += (*it)->numOfColumnsHandled();
 | 
						|
    }
 | 
						|
----
 | 
						|
!!!StatementImpl
 | 
						|
A <[StatementImpl]> stores as member a Binder and an Extractor (optional a Preparation object) and is responsible for compiling, binding, fetching single rows from the database and invoking the <*Extracting*> objects.
 | 
						|
The interface it has to implement is given as:
 | 
						|
 | 
						|
    public:
 | 
						|
        StatementImpl();
 | 
						|
            /// Creates the StatementImpl.
 | 
						|
 | 
						|
        virtual ~StatementImpl();
 | 
						|
            /// Destroys the StatementImpl.
 | 
						|
 | 
						|
    protected:
 | 
						|
        virtual bool hasNext() = 0;
 | 
						|
            /// Returns true if a call to next() will return data. Note that the
 | 
						|
            /// implementation must support several consecutive calls to hasNext
 | 
						|
            /// without data getting lost, ie. hasNext(); hasNext(); next() must
 | 
						|
            /// be equal to hasNext(); next();
 | 
						|
 | 
						|
        virtual void next() = 0;
 | 
						|
            /// Retrieves the next row from the resultset.
 | 
						|
            /// Will throw, if the resultset is empty.
 | 
						|
            /// Expects the statement to be compiled and bound
 | 
						|
 | 
						|
        virtual bool canBind() const = 0;
 | 
						|
            /// Returns if another bind is possible.
 | 
						|
 | 
						|
        virtual void compileImpl() = 0;
 | 
						|
            /// Compiles the statement, doesn't bind yet.
 | 
						|
            /// From now on AbstractBinder and AbstractExtractor
 | 
						|
            /// will be used
 | 
						|
 | 
						|
        virtual void bindImpl() = 0;
 | 
						|
            /// Binds parameters.
 | 
						|
 | 
						|
        virtual AbstractExtractor& extractor() = 0;
 | 
						|
            /// Returns the concrete extractor used by the statement.
 | 
						|
 | 
						|
        virtual AbstractBinder& binder() = 0;
 | 
						|
            /// Returns the concrete binder used by the statement.
 | 
						|
----
 | 
						|
 | 
						|
The Extracting and Binding objects can be accessed via the calls to the super-class methods <*extractings()*> and <*bindings()*>.
 | 
						|
A high-level <*bind*> implementation will look like this:
 | 
						|
 | 
						|
    [...]
 | 
						|
    Poco::SQL::AbstractBindingVec& binds = bindings();
 | 
						|
    std::size_t pos = 1; // or 0 depending on your database
 | 
						|
    Poco::SQL::AbstractBindingVec::iterator it = binds.begin();
 | 
						|
    Poco::SQL::AbstractBindingVec::iterator itEnd = binds.end();
 | 
						|
    for (; it != itEnd && (*it)->canBind(); ++it)
 | 
						|
    {
 | 
						|
        (*it)->bind(pos);
 | 
						|
        pos += (*it)->numOfColumnsHandled();
 | 
						|
    }
 | 
						|
----
 | 
						|
 | 
						|
A high-level <*next*> implementation:
 | 
						|
 | 
						|
    if (!hasNext())
 | 
						|
        throw Poco::SQL::SQLException("No data received");
 | 
						|
    int nCol = countColumnsInResult...;
 | 
						|
    poco_assert (columnsHandled() == nCol);
 | 
						|
    Poco::SQL::AbstractExtractingVec::iterator it = extractings().begin();
 | 
						|
    Poco::SQL::AbstractExtractingVec::iterator itEnd = extractings().end();
 | 
						|
    std::size_t pos = 0; // sqlite starts with pos 0 for results! your DB maybe with 1
 | 
						|
    for (; it != itEnd; ++it)
 | 
						|
    {
 | 
						|
        (*it)->extract(pos);
 | 
						|
        pos += (*it)->numOfColumnsHandled();
 | 
						|
    }
 | 
						|
    enableHasNext();
 | 
						|
----
 | 
						|
 | 
						|
A high-level <*hasNext*> implementation:
 | 
						|
 | 
						|
    if (enabledhasNext())
 | 
						|
    {
 | 
						|
        checkIfItHasMoreSQL
 | 
						|
        cacheResult
 | 
						|
        disablehasNext()
 | 
						|
    }
 | 
						|
 | 
						|
    return cachedResult;
 | 
						|
----
 | 
						|
 | 
						|
A high-level <*compileImpl*>:
 | 
						|
 | 
						|
    if (compiled)
 | 
						|
        return;
 | 
						|
 | 
						|
    std::string sqlStmt(toString());
 | 
						|
 | 
						|
   if database expects placeholders in different format than ":name", parse and replace them
 | 
						|
 | 
						|
    compile statement;
 | 
						|
 | 
						|
    create Binder;
 | 
						|
    create Extractor;
 | 
						|
----
 | 
						|
 | 
						|
A high-level <*canBind*>:
 | 
						|
 | 
						|
    bool ret = false;
 | 
						|
    if (!bindings().empty() && validCompiledStatement)
 | 
						|
        ret = (*bindings().begin())->canBind();
 | 
						|
 | 
						|
    return ret;
 | 
						|
----
 | 
						|
 | 
						|
!!!SessionImpl
 | 
						|
The purpose of the <[SessionImpl]> is simply to open/close a connection to the database, to act as factory for <[StatementImpl]> objects, and to handle transactions.
 | 
						|
The connection is opened in the constructor, and closed in the destructor.
 | 
						|
 | 
						|
    Poco::SQL::StatementImpl* createStatementImpl();
 | 
						|
        /// Returns an SQLite StatementImpl
 | 
						|
 | 
						|
    void begin();
 | 
						|
        /// Starts a transaction
 | 
						|
 | 
						|
    void commit();
 | 
						|
        /// Commits and ends a transaction
 | 
						|
 | 
						|
    void rollback();
 | 
						|
        /// Aborts a transaction
 | 
						|
----
 | 
						|
 | 
						|
!!!Connector
 | 
						|
Finally, one needs to implement the <[Connector]>.
 | 
						|
Each <[Connector]> should have a public static const string member named <*KEY*> and must have a factory method to <*create*> <[ Poco::AutoPtr ]> objects of type <[SessionImpl]>.
 | 
						|
It should also have a static <*addToFactory()*> and a static <*removeFromFactory()*> method:
 | 
						|
 | 
						|
    class My_API Connector: public Poco::SQL::Connector
 | 
						|
        /// Connector instantiates SessionImpl objects.
 | 
						|
    {
 | 
						|
    public:
 | 
						|
        static const std::string KEY;
 | 
						|
            /// Keyword for creating sessions
 | 
						|
 | 
						|
        Connector();
 | 
						|
            /// Creates the Connector.
 | 
						|
 | 
						|
        ~Connector();
 | 
						|
        /// Destroys the Connector.
 | 
						|
 | 
						|
        Poco::AutoPtr < Poco::SQL::SessionImpl > createSession(const std::string& connectionString);
 | 
						|
            /// Creates a SessionImpl object and initializes it with the given connectionString.
 | 
						|
 | 
						|
        static void registerConnector();
 | 
						|
            /// Registers the Connector under the Keyword Connector::KEY at the Poco::SQL::SessionFactory
 | 
						|
 | 
						|
        static void unregisterConnector();
 | 
						|
            /// Unregisters the Connector under the Keyword Connector::KEY at the Poco::SQL::SessionFactory
 | 
						|
    };
 | 
						|
----
 |