Files
MermsEmrWeb/mermsemr/src/core/pgsql_wrapper.cc
T
2019-02-19 22:35:27 +00:00

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;
}
//---------------------------------------------------------------------