[Top][All Lists]
[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);
}
- [Monotone-devel] Typesafe VA_ARGS replacement for database::execute/fetch,
Vinzenz 'evilissimo' Feenstra <=
- Re: [Monotone-devel] Typesafe VA_ARGS replacement for database::execute/fetch, Christof Petig, 2006/01/19
- Message not available
- Re: [Monotone-devel] Typesafe VA_ARGS replacement for database::execute/fetch, Christof Petig, 2006/01/20
- Re: [Monotone-devel] Typesafe VA_ARGS replacement for database::execute/fetch, Nathaniel Smith, 2006/01/20
- Re: [Monotone-devel] Typesafe VA_ARGS replacement for database::execute/fetch, Timothy Brownawell, 2006/01/21
- Re: [Monotone-devel] Typesafe VA_ARGS replacement for database::execute/fetch, Richard Levitte - VMS Whacker, 2006/01/21
- Re: [Monotone-devel] Typesafe VA_ARGS replacement for database::execute/fetch, Nathaniel Smith, 2006/01/22
- [Monotone-devel] Copy-on-write not mandated! (Was: Typesafe VA_ARGS replacement for database::execute/fetch), Clemens Hintze, 2006/01/22
- Re: [Monotone-devel] Copy-on-write not mandated! (Was: Typesafe VA_ARGS replacement for database::execute/fetch), Nathaniel Smith, 2006/01/22
- Re: [Monotone-devel] Copy-on-write not mandated! (Was: Typesafe VA_ARGS replacement for database::execute/fetch), Patrick Mauritz, 2006/01/23
- Re: [Monotone-devel] Copy-on-write not mandated!, Petr Ovtchenkov, 2006/01/24