363 lines
8.9 KiB
C++
363 lines
8.9 KiB
C++
#include "pgsql.h"
|
|
#include "pgsql_wrapper.h"
|
|
#include "clog.h"
|
|
#include <safestring.h>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <cassert>
|
|
#include <cstdarg>
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
|
|
void map_to_cvars(map<const char *,const char *>f, CVars &rec)
|
|
{
|
|
map<const char *,const char *>::iterator it;
|
|
for(it = f.begin(); it != f.end(); it++) {
|
|
logfmt( logINFO, "f[%s] = %s", it->first, it->second );
|
|
rec[it->first] = it->second;
|
|
}
|
|
}
|
|
|
|
void load_db_record( const char * table, CVars &rec, const char * where, ... )
|
|
{
|
|
logfmt( FLOG_MAX, "void load_db_record( const char * table, CVars &rec, const char * where, ... )");
|
|
|
|
size_t buf_size = 512;
|
|
char *buffer = new char[buf_size];
|
|
|
|
va_list argPtr;
|
|
size_t length;
|
|
std::string cmd;
|
|
|
|
while (true) {
|
|
if (!buffer) {
|
|
assert(buffer); // to stop when debugging
|
|
cmd = std::string("<alloc problem>", 16);
|
|
break;
|
|
}
|
|
va_start(argPtr, where);
|
|
length = vsnprintf(buffer, buf_size, where, argPtr);
|
|
va_end(argPtr);
|
|
|
|
if (length >= 0 && length < buf_size - 1) {
|
|
// string fits into current buffer
|
|
cmd = std::string(buffer, length);
|
|
break;
|
|
}
|
|
// otherwise resize buffer :
|
|
buf_size *= 2;
|
|
// fprintf(stderr, "Reallocating vstrf-buffer to size=%u\n", buf_size);
|
|
delete [] buffer;
|
|
buffer = new char[buf_size];
|
|
}
|
|
|
|
const PGresult* res = pgsql_query("SELECT * FROM %s WHERE %s", table, cmd.c_str() );
|
|
|
|
if( buffer ) delete [] buffer;
|
|
|
|
if (!res || pgsql_num_rows(res)!=1) return;
|
|
|
|
map<const char*,const char*>f = pgsql_fetch_assoc(res, 0);
|
|
logfmt( FLOG_MAX, "load_db_record(%s) num_cols=%d", table, f.size() );
|
|
if (f.empty()) {
|
|
return;
|
|
}
|
|
|
|
map<const char *,const char *>::iterator it;
|
|
for(it = f.begin(); it != f.end(); it++) {
|
|
rec[ it->first ] = it->second;
|
|
}
|
|
}
|
|
|
|
// This function now supports binary data
|
|
long load_db_record( CVars &rec, const char * query, ... )
|
|
{
|
|
logfmt( FLOG_MAX, "long load_db_record( CVars &rec, const char * query, ... )");
|
|
|
|
size_t buf_size = 512;
|
|
char *buffer = new char[buf_size];
|
|
|
|
va_list argPtr;
|
|
size_t length;
|
|
std::string cmd;
|
|
|
|
while (true) {
|
|
if (!buffer) {
|
|
assert(buffer); // to stop when debugging
|
|
cmd = std::string("<alloc problem>", 16);
|
|
break;
|
|
}
|
|
va_start(argPtr, query);
|
|
length = vsnprintf(buffer, buf_size, query, argPtr);
|
|
va_end(argPtr);
|
|
|
|
if (length >= 0 && length < buf_size - 1) {
|
|
// string fits into current buffer
|
|
cmd = std::string(buffer, length);
|
|
break;
|
|
}
|
|
// otherwise resize buffer :
|
|
buf_size *= 2;
|
|
// fprintf(stderr, "Reallocating vstrf-buffer to size=%u\n", buf_size);
|
|
delete [] buffer;
|
|
buffer = new char[buf_size];
|
|
}
|
|
|
|
const PGresult* res = pgsql_query("%s", cmd.c_str() );
|
|
|
|
if( buffer ) delete [] buffer;
|
|
|
|
if (!res || pgsql_num_rows(res)!=1) return -1l;
|
|
|
|
map<const char*,const char*>f = pgsql_fetch_assoc(res, 0);
|
|
logfmt( FLOG_MAX, "load_db_record(%s) num_cols=%d", cmd.c_str(), f.size() );
|
|
if (f.empty()) {
|
|
return 0l;
|
|
}
|
|
|
|
map<const char *,const char *>::iterator it;
|
|
for(it = f.begin(); it != f.end(); it++) {
|
|
rec[ it->first ] = it->second;
|
|
}
|
|
return 1l;
|
|
}
|
|
|
|
|
|
#define MAX_BINARY_PARS 20
|
|
|
|
long insert_db_record( int mode, const char *table, const char *seq, CVars &rec )
|
|
{
|
|
CVars::const_iterator i;
|
|
char cmd[128]; /*cols[1024], vals[1024]; cols[0] = 0; vals[0] = 0;*/
|
|
bool first = true;
|
|
string cols, vals;
|
|
int bind_i = 0;
|
|
long int sz[MAX_BINARY_PARS]; bzero( sz, sizeof(sz) ); // provides binding for all binary columns simultaneously
|
|
int binary_i = 0;
|
|
|
|
logfmt( FLOG_MAX, "insert_db_record()" );
|
|
|
|
snprintf( cmd, sizeof(cmd), "INSERT INTO %s (%%s) VALUES (%%s)", table );
|
|
|
|
for ( i=rec.begin(); i != rec.end(); i++ )
|
|
{
|
|
NEED_ESC;
|
|
// logfmt( FLOG_MAX, "'%s': i->second.valid()=%d, db()=%d", i->first.c_str(), i->second.valid(), i->second.db() );
|
|
|
|
if ( (DBS_VALID & mode) && !i->second.valid() ) continue;
|
|
if ( (DBS_STREAM & mode ) && !i->second.db() ) continue;
|
|
//logfmt( FLOG_MAX, "insert_db_record(): %s = %s", i->first.c_str(), i->second.c_str() );
|
|
|
|
cols += string(first?"":",") + i->first;
|
|
if ( !first ) vals += ",";
|
|
|
|
if ( i->second.binary() )
|
|
{
|
|
/*
|
|
vals += '?';
|
|
sz[binary_i] = i->second.size();
|
|
char *data = (char*)i->second.data();
|
|
|
|
//logfmt( FLOG_MAX, "saving binary parameter '%s', len = %d", i->first.c_str(), i->second.size() );
|
|
|
|
SQLBindParameter( st.hstmt, ++bind_i, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, sz[binary_i], 0, data, sz[binary_i], &sz[binary_i] );
|
|
|
|
if ( binary_i++ == MAX_BINARY_PARS )
|
|
{
|
|
logfmt( FLOG_MAX, "Exceeded maximum allowed binary parameters" );
|
|
return 0;
|
|
}
|
|
*/
|
|
throw err("Binary parameters are not supported");
|
|
}
|
|
else
|
|
vals += string("E'") + esc(i->second.c_str()) + "'";
|
|
|
|
/*strcatf( cols, sizeof(cols), "%s%s", first?"":",", i->first.c_str() );
|
|
strcatf( vals, sizeof(vals), "%s'%s'", first?"":",", i->second.c_str() );*/
|
|
|
|
first = false;
|
|
}
|
|
|
|
int res = pgsql_exec( cmd, cols.c_str(), vals.c_str() );
|
|
|
|
return curr_val( seq );
|
|
}
|
|
|
|
|
|
void update_db_record( int mode, const char * table, CVars &rec, long id, const char * where, ... ) throw ( bad_parameter )
|
|
{
|
|
va_list ap;
|
|
va_start( ap, where );
|
|
v_update_db_record( mode, table, rec, "id", id, where, ap );
|
|
va_end( ap );
|
|
}
|
|
|
|
|
|
void update_db_record( int mode, const char * table, CVars &rec, const char *index, long id, const char * where, ... ) throw ( bad_parameter )
|
|
{
|
|
va_list ap;
|
|
va_start( ap, where );
|
|
v_update_db_record( mode, table, rec, index, id, where, ap );
|
|
va_end( ap );
|
|
}
|
|
|
|
void v_update_db_record( int mode, const char * table, CVars &rec, const char *index, long id, const char * where, va_list ap ) throw ( bad_parameter )
|
|
{
|
|
logfmt( FLOG_MAX, "update_db_record()" );
|
|
int bind_i = 0;
|
|
|
|
if ( !id ) throw bad_parameter( rec, "id" );
|
|
|
|
CVars::const_iterator i;
|
|
char cmd[128];
|
|
bool first = true;
|
|
string cols;
|
|
char * wherestr;
|
|
|
|
snprintf( cmd, sizeof(cmd), "UPDATE %s SET %%s WHERE %s=%lu AND %%s", table, index, id );
|
|
|
|
for ( i=rec.begin(); i != rec.end(); i++ )
|
|
{
|
|
NEED_ESC;
|
|
if ( !i->second.valid() ) continue;
|
|
if ( (DBS_STREAM & mode) && !i->second.db() ) continue;
|
|
|
|
cols += string(first?"":",") + i->first + "=";
|
|
|
|
if ( ! i->second.binary() )
|
|
cols += string("E'") + esc(i->second.c_str()) + "'";
|
|
else
|
|
{
|
|
/*
|
|
cols += "?";
|
|
long int sz = i->second.size();
|
|
char *data = (char*)i->second.data();
|
|
|
|
SQLBindParameter( st.hstmt, ++bind_i, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, sz, 0, data, sz, &sz );
|
|
*/
|
|
throw err("Binary data is not supported");
|
|
}
|
|
|
|
first = false;
|
|
}
|
|
|
|
if ( where )
|
|
{
|
|
int size = vsnprintf( NULL, 0, where, ap ) + 1;
|
|
wherestr = (char*)malloc( size );
|
|
if ( !wherestr ) throw err("malloc() error");
|
|
vsnprintf( wherestr, size, where, ap );
|
|
}
|
|
|
|
int rows = pgsql_exec( cmd, cols.c_str(), where?wherestr:"true" );
|
|
if ( where )
|
|
free( wherestr );
|
|
|
|
if ( rows!=1 ) throw bad_parameter( rec, "id" );
|
|
}
|
|
|
|
long curr_val( const char *seq )
|
|
{
|
|
long size = 20+strlen(seq);
|
|
char cmd[size];
|
|
snprintf( cmd, size, "SELECT currval('%s')", seq );
|
|
logfmt( FLOG_MAX, "%s", cmd);
|
|
const PGresult* res = pgsql_query( cmd );
|
|
if (res && pgsql_num_rows(res)>0) {
|
|
vector<const char *>f = pgsql_fetch_row(res,0);
|
|
if (!f.empty() && f.size()>0) {
|
|
return atol(f[0]);
|
|
}
|
|
}
|
|
logfmt( FLOG_MAX, "SQL error" );
|
|
return -1l;
|
|
}
|
|
|
|
//---------------------------- class CEscape ----------------
|
|
|
|
char * CEscape::New( int sz )
|
|
{
|
|
if ( ESCAPE_MAX_VARS==n )
|
|
{
|
|
logfmt( FLOG_MAX, "CEscape::New() Maximum number of variables reached" );
|
|
return NULL;
|
|
}
|
|
|
|
vars[n] = new char[sz];
|
|
n++;
|
|
|
|
return vars[n-1];
|
|
}
|
|
|
|
CEscape::CEscape( char * st )
|
|
{
|
|
n = 0;
|
|
this->st = st;
|
|
}
|
|
|
|
CEscape::~CEscape()
|
|
{
|
|
for ( int i=0; i<n; i++ )
|
|
delete vars[i];
|
|
n = 0;
|
|
}
|
|
|
|
char * CEscape::Escape( const char * param )
|
|
{
|
|
if ( !param ) return NULL;
|
|
int len = this->EscapeLength(param);
|
|
return this->EscapeReal( param, New(len), len );
|
|
}
|
|
|
|
int CEscape::EscapeLength( const char * par )
|
|
{
|
|
if ( !par ) return 0;
|
|
|
|
int i, len = strlen(par), extra = 0;
|
|
|
|
for ( i=0; i<len; i++ )
|
|
if ( par[i]=='\'' || par[i]=='\\' )
|
|
extra++;
|
|
|
|
return len+extra+1;
|
|
}
|
|
|
|
char * CEscape::EscapeReal( const char * cmd, char * _esc, int sz )
|
|
{
|
|
char * c, * c1, * d, *dend;
|
|
char * esc = _esc?_esc:this->esc;
|
|
|
|
if (!sz) sz = sizeof(this->esc);
|
|
|
|
c = (char*)cmd; esc[0] = 0; d = esc; dend = d+sz;
|
|
|
|
if ( !cmd ) return esc;
|
|
|
|
// LOG( cmd, LOG_MAX );
|
|
|
|
while ( c<cmd+strlen(cmd) )
|
|
{
|
|
c1 = c + strcspn( c, "'\\" ); // apostrophe and backslash
|
|
|
|
if ( !*c1 )
|
|
{
|
|
strsafecpy( d, c, dend-d );
|
|
break;
|
|
}
|
|
|
|
strnsafecpy( d, c, c1-c, dend-d );
|
|
d += strlen(d);
|
|
//if (*(c1+0)=='\'') strcatf( d, dend-d, "'%c", *c1 );
|
|
strcatf( d, dend-d, "\\%c", *c1 );
|
|
d += strlen(d);
|
|
c = c1+1;
|
|
}
|
|
|
|
// LOG( esc, LOG_MAX );
|
|
|
|
return esc;
|
|
}
|
|
//---------------------------------------------------------------------
|
|
|