480 lines
11 KiB
C++
Raw Normal View History

#include <tsdb.h>
#include <set>
/******************************************************************************
* SSimpleQuery *
* Classe per esecuzioni di query temporanee (wrapper semplice per SACommand) *
******************************************************************************/
const TDate SSimple_query::sq_get_date(const char * field)
{
const TDate app(_rec.get_date(field));
return app;
}
const real SSimple_query::sq_get_real(const char * field)
{
const real app(_rec.get(field));
return app;
}
TString SSimple_query::sq_get(const char* field, bool rtrim)
{
TString fld = _rec.get(field);
if (rtrim)
fld.rtrim();
return fld;
}
TString SSimple_query::sq_get(const string& field, const bool rtrim)
{
return sq_get(field.c_str(), rtrim);
}
TString SSimple_query::sq_get(TString& field, bool rtrim)
{
return sq_get(static_cast<const char*>(field), rtrim);
}
TString SSimple_query::sq_get(unsigned int column, bool rtrim)
{
return _rec.get(column);
}
unsigned SSimple_query::sq_get_num_fields() const
{
return _rec.get_num_fields();
}
TString SSimple_query::sq_get_name_field(const unsigned column) const
{
return _rec.get_name_field(column);
}
int SSimple_query::sq_get_width_field(const unsigned column) const
{
return _rec.get_width_field(column);
}
TFieldtypes SSimple_query::sq_get_type_field(const unsigned column) const
{
const TString type = _rec.get_type_field(column);
if (type == "dtUnknown")
return _nullfld;
if (type == "dtBool")
return _boolfld;
if (type == "dtShort")
return _intfld;
if (type == "dtULong")
return _longfld;
if (type == "dtDouble")
return _realfld;
if (type == "dtNumeric")
return _rec.get_scale_field(column) ? _realfld : _intfld;
if (type == "dtDateTime")
return _datefld;
if (type == "dtString")
return _alfafld;
if (type == "dtBytes")
return _intfld;
if (type == "dtLongBinary")
return _alfafld;
if (type == "dtLongChar")
return _alfafld;
if (type == "dtBLob")
return _alfafld;
if (type == "dtCLob")
return _alfafld;
if (type == "dtCursor")
return _nullfld;
if (type == "dtSpecificToDBMS")
return _nullfld;
return _nullfld;
}
const char* SSimple_query::sq_get_token_text_error(const int token, const bool erase)
{
TToken_string errors(sq_get_text_error(erase), '\n');
return errors.get(token);
}
void TDB_recordset::reset()
{
_current_row = -1;
_is_loaded = false;
_items = 0;
_row.destroy();
_column.destroy();
}
/* La query pu<70> iniziare con la stringa di connessione cos<6F> fatta:
* CONNECT(server, user, psw, driver = "MSSQL") il driver pu<EFBFBD> essere omesso.
* Se c'<EFBFBD> la estraggo, setto la connessione e prendo la vera query.
* Se no setto direttamente la query.
* Ritorno false se non mi sono mai connesso a niente e non passo
* la stringa di connessione.
*/
bool TDB_recordset::set(const char* sql)
{
bool ok;
TString real_query = "";
// Posso modificare oppure non posso ma _sql <20> vuota
if(!_freezed || _sql.empty())
{
if (_sql.empty() || !_freezed && !_sql.empty())
{
// Guardo se la query inizia con la stringa di connessione
if (TString(sql).starts_with("CONNECT(", true))
{
TString query(sql);
int pos_EOCon = query.find(')'); // End Of Conn
const TString& conn_str = query.sub(0, ++pos_EOCon);
ok = set_connection(conn_str);
if (!ok)
return false;
real_query << query.sub(pos_EOCon);
}
else if (!is_connected())
return false;
else
real_query << sql;
// Non sto facendo una select
if(real_query.find("SELECT") == -1 && real_query.find("select") == -1)
{
_sql.cut(0);
reset();
return false;
}
// Serve?
if (!_freezed || _sql != sql)
reset();
_sql.cut(0) << real_query;
if (_sql.find("SELECT") >= 0 || _sql.find("select") >= 0)
find_and_reset_vars();
bool is_set;
if ((is_set = _rec->sq_set(_sql))) {
unset_loaded();
}
return is_set;
}
}
return false;
}
/* Parso la stringa di connessione ed estraggo i dati.
* Se il numero di dati <EFBFBD> sufficiente eseguo la connessione.
* Ritorno false se non riesco a connettermi o il numero di dati <EFBFBD> sbagliato
*/
bool TDB_recordset::set_connection(const char* conn_str) const
{
TString pn(conn_str);
TString srv = "", usr = "", pwd = "", drv = "";
int first_pos = pn.find("(", 0);
int last_pos = pn.find(",", first_pos);
int i;
for (i = 0; last_pos != -1; i++) {
switch (i)
{
case 0:
srv = pn.sub(first_pos + 1, last_pos);
break;
case 1:
usr = pn.sub(first_pos + 1, last_pos);
break;
case 2:
pwd = pn.sub(first_pos + 1, last_pos);
break;
case 3:
drv = pn.sub(first_pos + 1, last_pos);
break;
default:
last_pos = -1;
break;
}
first_pos = last_pos;
last_pos = pn.find(",", first_pos + 1);
if( last_pos == -1 )
last_pos = pn.find(")", first_pos + 1);
}
// Guardo se ho valorizzato almeno i primi 3 elementi della connect
// Se non valorizzo l'ultimo come default: MSSQL Server
if (i == 3)
return connect(srv.ltrim(), usr.ltrim(), pwd.ltrim(), TSDB_MSSQL);
if(i == 4)
return connect(srv.ltrim(), usr.ltrim(), pwd.ltrim(), str_to_driver(drv.ltrim()));
return false;
}
// Ritorna true se si connette
bool TDB_recordset::connect(const char * db, const char * user, const char * pass, const TT_driver tipo_db) const
{
const bool connected = _rec->sq_connect(db, user, pass, tipo_db) == NOERR;
// Nel dubbio setto entrambi
_rec->sq_set_con_option("UseDynamicCursor", "True");
_rec->sq_set_con_option("Scrollable", "True");
return connected;
}
TT_driver TDB_recordset::str_to_driver(const char* tipo_db)
{
if (_stricmp(tipo_db, "") == 0)
return TSDB_undefined;
//! ODBC
if (_stricmp(tipo_db, "ODBC") == 0)
return TSDB_ODBC;
//! Oracle
if (_stricmp(tipo_db, "Oracle") == 0)
return TSDB_Oracle;
//! Microsoft SQL Server
if (_stricmp(tipo_db, "MSSQL") == 0)
return TSDB_MSSQL;
//! InterBase or Firebird
if (_stricmp(tipo_db, "InterBase") == 0)
return TSDB_InterBase;
//! SQLBase
if (_stricmp(tipo_db, "SQLBase") == 0)
return TSDB_SQLBase;
//! IBM DB2
if (_stricmp(tipo_db, "DB2") == 0)
return TSDB_DB2;
//! Informix
if (_stricmp(tipo_db, "Informix") == 0)
return TSDB_Informix;
//! Sybase ASE
if (_stricmp(tipo_db, "Sybase") == 0)
return TSDB_Sybase;
//! MySQL
if (_stricmp(tipo_db, "MySQL") == 0)
return TSDB_MySQL;
//! PostgreSQL
if (_stricmp(tipo_db, "PostgreSQL") == 0)
return TSDB_PostgreSQL;
//! SQLite
if (_stricmp(tipo_db, "SQLite") == 0)
return TSDB_SQLite;
//! SQL Anywere
if (_stricmp(tipo_db, "SQLAnywhere") == 0)
return TSDB_SQLAnywhere;
return TSDB_undefined;
}
bool TDB_recordset::set_loaded()
{
bool ok = false;
if (!_sql.empty() && _rec->sq_exec(false))
{
ok = _is_loaded = true;
_items = _rec->sq_items();
_ncolumns = _rec->sq_get_num_fields();
}
return ok;
}
void TDB_recordset::unset_loaded()
{
_is_loaded = false;
_items = 0;
_ncolumns = 0;
_current_row = 0;
}
void TDB_recordset::freeze(const bool on)
{
if (on)
_rec->freeze();
else
_rec->defrost();
_freezed = on;
}
bool TDB_recordset::connect(const char* db, const char* user, const char* pass, const char* tipo_db) const
{
return _rec->sq_connect(db, user, pass, str_to_driver(tipo_db)) == NOERR;
}
TRecnotype TDB_recordset::items() const
{
if (_is_loaded)
return _items;
return _rec->sq_items();
}
bool TDB_recordset::move_to(TRecnotype pos)
{
const TRecnotype tot = items();
TRecnotype row = pos;
bool ok = true;
if (pos < 0)
row = 0;
if (pos > tot)
row = tot;
if (!_is_loaded)
ok = set_loaded();
if( ok && ((ok = _rec->sq_go(row))) )
_current_row = pos;
return ok;
}
bool TDB_recordset::move_next()
{
bool ok = true;
if (!_is_loaded)
ok = set_loaded();
if (ok && _rec->sq_next())
{
_current_row = _rec->sq_pos();
return true;
}
return false;
}
const TString_array TDB_recordset::get_next_row()
{
if (move_next())
return get_row();
return TString_array();
}
const TString_array TDB_recordset::get_row(TRecnotype n)
{
bool ok = true;
// Get della riga attuale
if (n == -1)
n = current_row();
else if (_current_row != n)
ok = move_to(n); // Solo se non sono gi<67> su quella riga
if (ok)
{
const unsigned ncol = _rec->sq_get_num_fields();
_row.destroy();
for (unsigned i = 0; i < ncol; i++)
_row.add(TString(_rec->sq_get(i, false)));
return _row;
}
// else
_row.destroy();
return _row;
}
void TDB_recordset::requery()
{
_items = 0;
_current_row = -1;
_row.destroy();
_column.destroy();
}
unsigned TDB_recordset::columns() const
{
if (!_is_loaded)
{
TDB_recordset* my_self = const_cast<TDB_recordset*>(this);
my_self->set_loaded();
}
return _ncolumns;
}
const TRecordset_column_info& TDB_recordset::column_info(const unsigned column) const
{
static TRecordset_column_info info;
if (_is_loaded)
{
info._name = _rec->sq_get_name_field(column); // TString
info._width = _rec->sq_get_width_field(column); // int
info._type = _rec->sq_get_type_field(column); // TFieldtypes
info._pos = column;
}
else
{
info._name.cut(0); // TString
info._width = 0; // int
info._type = _alfafld; // TFieldtypes
info._pos = 0;
}
return info;
}
const TVariant& TDB_recordset::get(unsigned int column) const
{
static TVariant field = NULL_VARIANT;
static unsigned int last_get = 0;
if(!_freezed || column != last_get || field == NULL_VARIANT)
{
last_get = column;
field = _rec->sq_get(column);
}
return field;
}
const TVariant& TDB_recordset::get(const char* name) const
{
return TRecordset::get(name);
}
bool TDB_recordset::is_connected() const
{
return _rec->sq_is_connect();
}
const TVariant& TDB_recordset::active_connection() const
{
static TVariant conn = NULL_VARIANT;
conn.add(_dsn);
conn.add(_usr);
conn.add(_drv);
return conn;
}
bool TDB_recordset::exec(const char* sql)
{
bool exec = false;
if ((exec = _rec->sq_set_exec(sql))) {
_is_loaded = true;
_items = _rec->sq_items();
}
return exec;
}
bool TDB_recordset::commit() const
{
return _rec->sq_commit();
}
TDB_recordset::TDB_recordset(const char* sql, const bool freezed) : _freezed(freezed)
{
_current_row = -1;
_rec = new SSimple_query();
//_rec->sq_set_autocommit(true);
_sql.cut(0);
_is_loaded = false;
_items = 0;
_ncolumns = 0;
freeze(freezed);
set(sql);
}
TDB_recordset::~TDB_recordset()
{
delete _rec;
}