monotone-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Monotone-devel] Typesafe VA_ARGS replacement for database::execute/fetc


From: Vinzenz 'evilissimo' Feenstra
Subject: [Monotone-devel] Typesafe VA_ARGS replacement for database::execute/fetch
Date: Thu, 19 Jan 2006 09:57:54 +0100
User-agent: Thunderbird 1.5 (Windows/20051201)

Hi,

I've attached the class query_args which can be used as VA_ARGS replacement for the methods database::execute and database::fetch

a possible signature of database::execute
void database::execute( query_args & args );

Thinkable usage will be something like this: ( db is a object of database ) db.execute( db.query("INSERT INTO TEST VALUES( ? , ? , ? , ? )") % value1 % value2 % value 3 % value 4);



Some kind of tests:

       {
query_args qa(handle,"CREATE TABLE TEST( ID INTEGER PRIMARY KEY , NAME TEXT , CURRENCY REAL , NUMBER INTEGER )");
           int rescode = sqlite3_step(qa.get_statement(false));
           if(rescode != SQLITE_OK)
std::cout << "Insert failed with errcode = " << sqlite3_errcode(handle) << " And erromsg: " << sqlite3_errmsg(handle) << std::endl;
       }
{ query_args qa(handle,"INSERT INTO TEST VALUES( ? , ? , ? , ? )"); qa % query_args::null() % "evilissimo" % 12.95 % 4325 ; int rescode = 0;
           sqlite3_step(qa.get_statement(false));
           if(SQLITE_DONE != sqlite3_errcode(handle))
std::cout << "Insert failed with errcode = " << sqlite3_errcode(handle) << " And erromsg: " << sqlite3_errmsg(handle) << std::endl;
       }


I will implement query_args into database.cc/.hh asap


Let me know what you're thinking about it.

BR

Vinzenz

#ifndef __QUERY_ARGS_HH__
#define __QUERY_ARGS_HH__ 1
// copyright (C) 2006 vinzenz feenstra <address@hidden>
// all rights reserved.
// licensed to the public under the terms of the GNU GPL (>= 2)
// see the file COPYING for details
#include <string>
#include <utility>
struct sqlite3_stmt;
struct sqlite3;

struct query_args
{
    // represents NULL  will be passed like this    %  query_args::null() 
    struct null{ null(){} };

    struct binary
    {
        binary( void const * data , size_t size ); 
        void const * get_data() const; 
        size_t const get_size() const;
    private:
        void const * data_p;
        size_t data_size;
    };

    explicit query_args( sqlite3 * db_handle , std::string const & sql_query );
    ~query_args();

    template< typename ArgumentType >
    query_args & operator%( ArgumentType const & arg )
    {
        bind_arg(arg);
        // Error check
        internal_assert();
        return *this;
    }    

    // Retrieving the statement 
    // If release is true we don't care anymore whether 
    // the statement will be cleared anywhere else
    sqlite3_stmt * get_statement(bool release = true);
    std::string const & get_query() const;

private:

    // bind_arg() binds an argument to a sqlite3 statement
    // as TEXT
    void bind_arg( std::string  const & text );
    // as TEXT specializing for char const* to avoid copies
    void bind_arg( char const * text );
    // as BINARY
    void bind_arg( binary const & bin );
    // as BINARY
    void bind_arg( void const * binary , size_t size );
    // as INTEGER
    void bind_arg( int const integer );
    // as INTEGER64
    void bind_arg( long long const integer64 );
    // as NULL
    void bind_arg( null const & );
    // as REAL
    void bind_arg( double const & real );
    // as REAL
    void bind_arg( float const & real );

    template< typename Type1 , typename Type2 >
    void bind_arg( std::pair< Type1 , Type2 > const & pair_arg )
    {
        bind_arg(pair_arg.first);
        bind_arg(pair_arg.second);
    }    
    // Needs to be tested, if it works
    template< typename ArgType >
    void bind_arg( ArgType const & arg )
    {
        bind_arg(arg());
    }

    void internal_assert();
protected:
    sqlite3_stmt * stmt;
    int params_needed;
    int last_param_nr;
    std::string query;
};

#endif // __QUERY_ARGS_HH__
// -*- mode: C++; c-file-style: "gnu"; indent-tabs-mode: nil -*-
// copyright (C) 2006 vinzenz feenstra <address@hidden>
// all rights reserved.
// licensed to the public under the terms of the GNU GPL (>= 2)
// see the file COPYING for details

#include "sanity.hh"
#include "sqlite3.h"
#include "query_args.hh"



query_args::binary::binary( void const * data , size_t size )
:data_p(data),data_size(size)
{}

void const * query_args::binary::get_data() const
{
    return data_p;
}

size_t const query_args::binary::get_size() const
{
    return data_size;
}


query_args::query_args( sqlite3 * db_handle , std::string const & sql_query )
:stmt(0),
 params_needed(0),
 last_param_nr(1),
 query(sql_query)
{
    char const * tail = 0;
    sqlite3_prepare(db_handle, query.c_str() , -1, &stmt , &tail);
    internal_assert();

    L(F("prepared statement %s\n") % query);

    // no support for multiple statements here
    E(*tail == 0, 
        F("multiple statements in query: %s\n") % query);

    params_needed = sqlite3_bind_parameter_count(stmt);
}

query_args::~query_args()
{
    // if the statement still exists we're cleaning it
    // since the database can't be closed properly if it
    // is still opened
    if(stmt)
    {
        L("Resetting sqlite3_statement");
        sqlite3_reset(stmt);
        internal_assert();
        L("Finalizing sqlite3_statement");
        if(sqlite3_finalize(stmt) != SQLITE_OK)
            internal_assert();
    }
}

std::string const & query_args::get_query() const
{
    return query;
}

sqlite3_stmt * query_args::get_statement( bool release )
{
    // Ensure that we have all params needed, otherwise 
    I( params_needed == last_param_nr );

    // Retrieving the statement 
    // If release is true we don't care anymore whether 
    // the statement will be cleared anywhere else
    if(release)
    {        
        L("Returning statement and releasing the ownership of the sqlite3_stmt 
pointer");
        sqlite3_stmt * tmp = stmt;
        stmt = 0;
        return tmp;
    }
    // returning the statement and keep ownership of the 
    // statement
    L("Returning statement and keeping the ownership of the sqlite3_stmt 
pointer");
    return stmt;
}

// as TEXT
void query_args::bind_arg( std::string  const & text )
{
    L( F("Binding argument %d of %d as TEXT, with Value %s") % last_param_nr % 
params_needed % text );
    if(stmt)
        
sqlite3_bind_text(stmt,last_param_nr++,text.c_str(),int(text.size()),SQLITE_TRANSIENT);
}
// as TEXT specializing for char const* to avoid copies
void query_args::bind_arg( char const * text )
{
    L( F("Binding argument %d of %d as TEXT, with Value %s") % last_param_nr % 
params_needed % text );
    if( text && stmt )
    {
        int size = strlen(text);
        sqlite3_bind_text(stmt,last_param_nr++,text,size,SQLITE_TRANSIENT);
    }
}
// as BINARY
void query_args::bind_arg( binary const & bin )
{
    bind_arg(bin.get_data(),bin.get_size());
}
// as BINARY
void query_args::bind_arg( void const * binary , size_t size )
{
    L( F("Binding argument %d of %d as BINARY") % last_param_nr % params_needed 
);
    if(stmt && binary)
        
sqlite3_bind_blob(stmt,last_param_nr++,binary,int(size),SQLITE_TRANSIENT);
}
// as INTEGER
void query_args::bind_arg( int const integer )
{
    L( F("Binding argument %d of %d as INTEGER with value %d") % last_param_nr 
% params_needed % integer );
    if(stmt)
        sqlite3_bind_int(stmt,last_param_nr++,integer);
}
// as INTEGER64
void query_args::bind_arg( long long const integer64 )
{
    L( F("Binding argument %d of %d as INTEGER64 with value %d") % 
last_param_nr % params_needed % integer64 );
    if(stmt)
        sqlite3_bind_int64(stmt,last_param_nr++,integer64);
}
// as NULL
void query_args::bind_arg( null const &)
{
    L( F("Binding argument %d of %d as NULL") % last_param_nr % params_needed );
    if(stmt)
        sqlite3_bind_null(stmt,last_param_nr++);
}
// as REAL
void query_args::bind_arg( double const & real )
{
    L( F("Binding argument %d of %d as REAL with value %d") % last_param_nr % 
params_needed % real );
    if(stmt)
        sqlite3_bind_double(stmt,last_param_nr++,real);
}
// as REAL
void query_args::bind_arg( float const & real )
{
    L( F("Binding argument %d of %d as REAL with value %d") % last_param_nr % 
params_needed % real );
    if(stmt)
        sqlite3_bind_double(stmt,last_param_nr++,double(real));
}


void query_args::internal_assert()
{
    sqlite3 * s = sqlite3_db_handle(stmt);

    int errcode = sqlite3_errcode(s);

    if (errcode == SQLITE_OK) return;

    const char * errmsg = sqlite3_errmsg(s);

    // sometimes sqlite is not very helpful
    // so we keep a table of errors people have gotten and more helpful versions
    if (errcode != SQLITE_OK)
    {
        // first log the code so we can find _out_ what the confusing code
        // was... note that code does not uniquely identify the errmsg, unlike
        // errno's.
        L(F("sqlite error: %d: %s") % errcode % errmsg);
    }
    std::string auxiliary_message = "";
    if (errcode == SQLITE_ERROR)
    {
        auxiliary_message = _("make sure database and containing directory are 
writeable");
    }
    // if the last message is empty, the \n will be stripped off too
    E(errcode == SQLITE_OK,
        // kind of string surgery to avoid ~duplicate strings
        boost::format("%s\n%s")
        % (F("sqlite error: %d: %s") % errcode % errmsg).str()
        % auxiliary_message);
}


reply via email to

[Prev in Thread] Current Thread [Next in Thread]