Files correlati : agalib Ricompilazione Demo : [ ] Commento : Implementato di meccanismo generico di blocco degli inserimenti, attivabile nelle singole applicazioni (cg2 e ve0) git-svn-id: svn://10.65.10.50/branches/R_10_00@22420 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			429 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			429 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
#include <diction.h>
 | 
						|
#include <odbcrset.h>
 | 
						|
#include <sqlset.h>
 | 
						|
#include <textset.h>
 | 
						|
#include <utility.h>
 | 
						|
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
// TODBC_connections
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
 | 
						|
class TODBC_connections
 | 
						|
{
 | 
						|
  TString _dsn, _usr;
 | 
						|
  XVT_ODBC _odbc;
 | 
						|
 | 
						|
protected:
 | 
						|
  void close();
 | 
						|
 | 
						|
public:
 | 
						|
  XVT_ODBC get(const char* dsn, const char* usr, const char* pwd, const char* dir);
 | 
						|
  TODBC_connections();
 | 
						|
  ~TODBC_connections();
 | 
						|
};
 | 
						|
 | 
						|
TODBC_connections _connections;
 | 
						|
 | 
						|
void TODBC_connections::close()
 | 
						|
{
 | 
						|
  if (_odbc != NULL)
 | 
						|
  {
 | 
						|
    xvt_odbc_free_connection(_odbc);
 | 
						|
    _odbc = NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
XVT_ODBC TODBC_connections::get(const char* dsn, const char* usr, const char* pwd, const char* dir)
 | 
						|
{
 | 
						|
  if (_odbc == NULL || _dsn != dsn || _usr != usr)
 | 
						|
  {
 | 
						|
    close();
 | 
						|
    if (dsn && *dsn)
 | 
						|
      _odbc = xvt_odbc_get_connection(_dsn = dsn, _usr = usr, pwd, dir);
 | 
						|
  }
 | 
						|
  return _odbc;
 | 
						|
}
 | 
						|
 | 
						|
TODBC_connections::TODBC_connections() : _odbc(NULL)
 | 
						|
{}
 | 
						|
 | 
						|
TODBC_connections::~TODBC_connections()
 | 
						|
{
 | 
						|
  close();
 | 
						|
}
 | 
						|
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
// TODBC_recordset
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
 | 
						|
XVT_ODBC TODBC_recordset::connection() const
 | 
						|
{ return _connections.get(_dsn, _usr, _pwd, _dir); }
 | 
						|
 | 
						|
bool TODBC_recordset::connect(const char* dsn, const char* usr, const char* pwd, const char* dir)
 | 
						|
{
 | 
						|
  _dsn = dsn; _usr = usr; _pwd = pwd; _dir = dir;
 | 
						|
  return connection() != NULL;
 | 
						|
}
 | 
						|
 | 
						|
const TString& TODBC_recordset::query_text() const
 | 
						|
{ return _sql; }
 | 
						|
 | 
						|
const TString& TODBC_recordset::driver_version() const
 | 
						|
{
 | 
						|
  TString& tmp = get_tmp_string(50);
 | 
						|
  xvt_odbc_driver(connection(), tmp.get_buffer(), tmp.size());
 | 
						|
  return tmp;
 | 
						|
}
 | 
						|
 | 
						|
void TODBC_recordset::reset()
 | 
						|
{
 | 
						|
  _first_row = 0;
 | 
						|
  _items = 0;
 | 
						|
  _current_row = -1;
 | 
						|
  _pagesize = 512;
 | 
						|
  _page.destroy();
 | 
						|
  _column.destroy();
 | 
						|
  _columns_loaded = false;
 | 
						|
}
 | 
						|
 | 
						|
int TODBC_recordset::on_get_columns(int argc, char** values, char** columns)
 | 
						|
{
 | 
						|
  static unsigned long _counter = 0;
 | 
						|
 | 
						|
  if (_column.empty())
 | 
						|
  {
 | 
						|
    _counter = 0;
 | 
						|
    for (int i = 0; i < argc; i++)
 | 
						|
    {
 | 
						|
      const char* fldtype = NULL;
 | 
						|
      TRecordset_column_info* info = new TRecordset_column_info;
 | 
						|
      info->_width = 1;
 | 
						|
      info->_type = _alfafld;
 | 
						|
 | 
						|
      if (columns != NULL)
 | 
						|
      {
 | 
						|
        info->_name = columns[i];
 | 
						|
        fldtype = columns[argc+i];
 | 
						|
      }
 | 
						|
      else
 | 
						|
        info->_name.format("FIELD%d", i+1);
 | 
						|
      
 | 
						|
      if (fldtype != NULL)
 | 
						|
      {
 | 
						|
        if (xvt_str_compare_ignoring_case(fldtype, "DATE") == 0)
 | 
						|
        {
 | 
						|
          info->_type = _datefld; 
 | 
						|
          info->_width = 10;
 | 
						|
        } else
 | 
						|
        if (xvt_str_compare_ignoring_case(fldtype, "NUMERIC") == 0)
 | 
						|
        {
 | 
						|
          info->_type = _realfld;
 | 
						|
        } else
 | 
						|
        if (xvt_str_compare_ignoring_case(fldtype, "BLOB") == 0)
 | 
						|
        {
 | 
						|
          info->_type = _memofld;
 | 
						|
          info->_width = 50;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      _column.add(info);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  const bool processed = _counter++ < 128;
 | 
						|
  if (processed)
 | 
						|
  {
 | 
						|
    for (int i = 0; i < argc; i++) if (values[i] && *values[i])
 | 
						|
    {
 | 
						|
      TRecordset_column_info& info = (TRecordset_column_info&)_column[i];
 | 
						|
      if (info._type == _alfafld || info._type == _realfld)
 | 
						|
      {
 | 
						|
        const int len = strlen(values[i]);
 | 
						|
        if (len > info._width)
 | 
						|
          info._width = len;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return processed ? 0 : -1;  
 | 
						|
}
 | 
						|
 | 
						|
static int query_get_columns(void* jolly, int argc, char** values, char** columns)
 | 
						|
{
 | 
						|
  TODBC_recordset* q = (TODBC_recordset*)jolly;
 | 
						|
  return q->on_get_columns(argc, values, columns);
 | 
						|
}
 | 
						|
 | 
						|
void TODBC_recordset::requery()
 | 
						|
{
 | 
						|
  _items = 0;
 | 
						|
  _current_row = -1;
 | 
						|
  _page.destroy();
 | 
						|
}
 | 
						|
 | 
						|
int TODBC_recordset::on_get_items(int argc, char** values, char** columns)
 | 
						|
{
 | 
						|
  if (!_columns_loaded)
 | 
						|
    on_get_rows(argc, values, columns);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
static int query_get_items(void* jolly, int argc, char** values, char** columns)
 | 
						|
{
 | 
						|
  TODBC_recordset* q = (TODBC_recordset*)jolly;
 | 
						|
  return q->on_get_items(argc, values, columns);
 | 
						|
}
 | 
						|
 | 
						|
TRecnotype TODBC_recordset::items() const
 | 
						|
{
 | 
						|
  if (_items == 0)
 | 
						|
  {
 | 
						|
    TString sql; parsed_text(sql);
 | 
						|
    XVT_ODBC oc = connection();
 | 
						|
    if (oc != NULL)
 | 
						|
    {
 | 
						|
      TPerformance_profiler prof("ODBC count");
 | 
						|
      TRecnotype& i = (TRecnotype&)_items;
 | 
						|
      if (!_columns_loaded)
 | 
						|
      {
 | 
						|
        TODBC_recordset* myself = (TODBC_recordset*)this;
 | 
						|
        myself->_page.destroy();
 | 
						|
        myself->_cursor_pos = 0;
 | 
						|
        i = xvt_odbc_execute(oc, sql, query_get_items, (void*)this);
 | 
						|
        myself->_columns_loaded = true;
 | 
						|
      }
 | 
						|
      else
 | 
						|
        i = xvt_odbc_execute(oc, sql, NULL, NULL);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return _items;
 | 
						|
}
 | 
						|
 | 
						|
unsigned int TODBC_recordset::columns() const
 | 
						|
{
 | 
						|
  if (!_columns_loaded && _column.items() == 0)
 | 
						|
  {
 | 
						|
    XVT_ODBC oc = connection();
 | 
						|
    if (oc != NULL)
 | 
						|
    {
 | 
						|
      TODBC_recordset* myself = (TODBC_recordset*)this;
 | 
						|
      TString sql; parsed_text(sql);
 | 
						|
      TPerformance_profiler prof("ODBC info");
 | 
						|
      myself->_cursor_pos = 0;
 | 
						|
      xvt_odbc_execute(oc, sql, query_get_columns, (void*)this);
 | 
						|
      myself->_columns_loaded = true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return _column.items();
 | 
						|
}
 | 
						|
 
 | 
						|
const TRecordset_column_info& TODBC_recordset::column_info(unsigned int c) const
 | 
						|
{
 | 
						|
  if (c >= columns())  // Generare column infos if needed
 | 
						|
    c = 0;
 | 
						|
  return (const TRecordset_column_info&)_column[c];
 | 
						|
}
 | 
						|
 | 
						|
// Funzione chiamata per riempire la pagina corrente delle righe della query
 | 
						|
int TODBC_recordset::on_get_rows(int argc, char** values, char** columns)
 | 
						|
{
 | 
						|
  if (!_columns_loaded)
 | 
						|
    on_get_columns(argc, values, columns);
 | 
						|
 | 
						|
  if (_page.items() >= _pagesize)
 | 
						|
    return -1;
 | 
						|
 | 
						|
  if (_cursor_pos++ < _first_row)
 | 
						|
    return 0; // Ignora le righe prima del LIMIT
 | 
						|
  
 | 
						|
  TArray* a = new TArray;
 | 
						|
  for (int c = 0; c < argc; c++)
 | 
						|
  {
 | 
						|
    TVariant* var = new TVariant;
 | 
						|
    switch (column_info(c)._type)
 | 
						|
    {
 | 
						|
    case _alfafld: 
 | 
						|
      var->set(values[c]);
 | 
						|
      break;
 | 
						|
    case _memofld: 
 | 
						|
      if (values[c])
 | 
						|
      {
 | 
						|
        TFixed_string memo(values[c]);
 | 
						|
        memo.replace(char(0xB6), '\n');
 | 
						|
        var->set(memo); 
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case _datefld: 
 | 
						|
      var->set(TDate(values[c])); 
 | 
						|
      break;
 | 
						|
    default: 
 | 
						|
      var->set(real(values[c]));
 | 
						|
      break;
 | 
						|
    }      
 | 
						|
    a->add(var, c);
 | 
						|
  }
 | 
						|
  _page.add(a);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int query_get_rows(void* jolly, int argc, char** values, char** columns)
 | 
						|
{
 | 
						|
  TODBC_recordset* rs = (TODBC_recordset*)jolly;
 | 
						|
  return rs->on_get_rows(argc, values, columns);
 | 
						|
}
 | 
						|
 | 
						|
bool TODBC_recordset::move_to(TRecnotype n)
 | 
						|
{
 | 
						|
  const TRecnotype tot = items();
 | 
						|
  _current_row = n;
 | 
						|
  if (n < 0 || n >= tot)
 | 
						|
  {
 | 
						|
    _page.destroy(); // Forza rilettura la prossima volta
 | 
						|
    _first_row = 0;
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (n < _first_row || n >= _first_row+_page.items())
 | 
						|
  {
 | 
						|
    TString sql; parsed_text(sql);
 | 
						|
    XVT_ODBC oc = connection();
 | 
						|
    if (oc == NULL)
 | 
						|
      return false;
 | 
						|
 | 
						|
    if (tot > _pagesize && sql.find("LIMIT ") < 0)
 | 
						|
    {
 | 
						|
      const int semicolon = sql.rfind(';');
 | 
						|
      if (semicolon >= 0)
 | 
						|
        sql.cut(semicolon);
 | 
						|
      sql.trim();
 | 
						|
      _page.destroy();
 | 
						|
      if (n >= _pagesize)
 | 
						|
        _first_row = n-32; // Prendo qualche riga dalla pagina precedente, per velocizzare il pagina su
 | 
						|
      else
 | 
						|
        _first_row = n;
 | 
						|
    }
 | 
						|
 | 
						|
    TPerformance_profiler prof("ODBC query");
 | 
						|
    _cursor_pos = 0;
 | 
						|
    xvt_odbc_execute(oc, sql, query_get_rows, this);
 | 
						|
    
 | 
						|
    if (!_columns_loaded)
 | 
						|
      _columns_loaded = true;  // Brutto posto ma necessario
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
long TODBC_recordset::exec(const char* sql)
 | 
						|
{
 | 
						|
  long err = -1;
 | 
						|
 | 
						|
  TString cmd; 
 | 
						|
 | 
						|
  // Se la stringa "sql" non contiene parametri di connessione ma essi sono in "_sql"
 | 
						|
  // allora cerco di effetture la connessione in base a quella
 | 
						|
  if (_dsn.empty() && strncmp(sql, "ODBC(", 5) != 0 && _sql.starts_with("ODBC("))
 | 
						|
    parsed_text(cmd);
 | 
						|
 | 
						|
  XVT_ODBC oc = connection();
 | 
						|
  if (oc != NULL)
 | 
						|
  {
 | 
						|
    set(sql);
 | 
						|
    parsed_text(cmd);
 | 
						|
    TPerformance_profiler prof("ODBC command");
 | 
						|
    err = xvt_odbc_execute(oc, cmd, NULL, NULL);
 | 
						|
  }
 | 
						|
  
 | 
						|
  return err;
 | 
						|
}
 | 
						|
 | 
						|
TRecnotype TODBC_recordset::current_row() const
 | 
						|
{
 | 
						|
  return _current_row;
 | 
						|
}
 | 
						|
 | 
						|
const TArray* TODBC_recordset::row(TRecnotype n)
 | 
						|
{
 | 
						|
  const TArray* a = NULL;
 | 
						|
  if (move_to(n))
 | 
						|
    a = (const TArray*)_page.objptr(n-_first_row);
 | 
						|
  return a;
 | 
						|
}
 | 
						|
 | 
						|
const TVariant& TODBC_recordset::get(unsigned int c) const
 | 
						|
{
 | 
						|
  const TArray* a = (const TArray*)_page.objptr(_current_row-_first_row);
 | 
						|
  if (a != NULL)
 | 
						|
  {
 | 
						|
    const TVariant* s = (const TVariant*)a->objptr(c);
 | 
						|
    if (s != NULL)
 | 
						|
      return *s;
 | 
						|
  }
 | 
						|
  return NULL_VARIANT;
 | 
						|
}
 | 
						|
 | 
						|
const TVariant& TODBC_recordset::get(const char* name) const
 | 
						|
{
 | 
						|
  return TRecordset::get(name);
 | 
						|
}
 | 
						|
 | 
						|
void TODBC_recordset::parsed_text(TString& sql) const
 | 
						|
{
 | 
						|
  TRecordset::parsed_text(sql);
 | 
						|
 | 
						|
  if (sql.starts_with("ODBC(", true))
 | 
						|
  {
 | 
						|
    const int par = sql.find(')');
 | 
						|
    if (par > 0)
 | 
						|
    {
 | 
						|
      TToken_string conn(sql.sub(5, par), ',');
 | 
						|
      sql.ltrim(par+1);
 | 
						|
      sql.trim();
 | 
						|
 | 
						|
      TString dsn = conn.get(); dsn.strip("\"");
 | 
						|
      TString usr = conn.get(); usr.strip("\"");
 | 
						|
      TString pwd = conn.get(); pwd.strip("\"");
 | 
						|
      TString dir = conn.get(); dir.strip("\"");
 | 
						|
      if (!((TODBC_recordset*)this)->connect(dsn, usr, pwd, dir))
 | 
						|
        error_box(FR("Impossibile connettersi al DSN %s"), (const char*)dsn);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void TODBC_recordset::set(const char* sql) 
 | 
						|
{ 
 | 
						|
  reset(); 
 | 
						|
  _sql = sql;
 | 
						|
  if (_sql.find("SELECT") >= 0 || _sql.find("select") >= 0)
 | 
						|
    find_and_reset_vars();
 | 
						|
}
 | 
						|
 | 
						|
TODBC_recordset::TODBC_recordset(const char* sql)
 | 
						|
{
 | 
						|
  set(sql);
 | 
						|
}
 | 
						|
 | 
						|
TODBC_recordset::~TODBC_recordset()
 | 
						|
{ }
 | 
						|
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
// Creazione "intelligente" del recordset appropriato in base alla query
 | 
						|
///////////////////////////////////////////////////////////
 | 
						|
 | 
						|
TRecordset* create_recordset(const TString& sql)
 | 
						|
{
 | 
						|
  TRecordset* rex = NULL;
 | 
						|
  if (sql.full())
 | 
						|
  {
 | 
						|
    if (sql.starts_with("US", true))
 | 
						|
      rex = new TISAM_recordset(sql); else
 | 
						|
    if (sql.starts_with("ODBC", true))
 | 
						|
      rex = new TODBC_recordset(sql); else
 | 
						|
    if (sql.starts_with("CSV", true))
 | 
						|
      rex = new TCSV_recordset(sql); else
 | 
						|
    if (sql.starts_with("AS400", true)) 
 | 
						|
      rex = new TAS400_recordset(sql);
 | 
						|
		else
 | 
						|
      rex = new TSQL_recordset(sql);
 | 
						|
  }
 | 
						|
  return rex;
 | 
						|
}
 |