Patch level : 12.0 732

Files correlati     : agalib, xvtdb
Commento            :
- Implementazione TDb_recordset
- Aggiunte funzioni a XVTRecordset per wrap SQLAPI++
This commit is contained in:
Simone Palacino 2019-03-15 10:51:50 +01:00
parent 4e44d78df6
commit e62c56d572
5 changed files with 273 additions and 83 deletions

View File

@ -741,8 +741,8 @@ TRecordset* create_recordset(const TString& sql)
rex = new TCSV_recordset(sql); else
if (sql.starts_with("AS400", true))
rex = new TAS400_recordset(sql);
//if (sql.starts_with("CONNECT", true))
//rex = new TDB_recordset(sql);
if (sql.starts_with("CONNECT", true))
rex = new TDB_recordset(sql);
else
rex = new TSQL_recordset(sql);
}

View File

@ -48,44 +48,110 @@ 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 _realfld;
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;
}
void TDB_recordset::reset()
{
_items = 0;
_current_row = -1;
_columns_loaded = false;
}
/* La query può iniziare con la stringa di connessione così fatta:
* CONNECT(server, user, psw, driver = "MSSQL") il driver può essere omesso
* Se c'è la estraggo, setto la connessione e prendo la vera query
* Se no setto direttamente la query
* CONNECT(server, user, psw, driver = "MSSQL") il driver può essere omesso.
* Se c'è 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.
*/
void TDB_recordset::set(const char* sql)
bool TDB_recordset::set(const char* sql)
{
bool ok;
TString real_query = "";
// Guardo se la query inizia con la stringa di connessione
if(TString(sql).starts_with("CONNECT(", true))
// Posso modificare oppure non posso ma _sql è vuota
if(!_freezed || _sql.empty())
{
TString query(sql);
int pos_EOCon = query.find(')'); // End Of Conn
const TString conn_str = query.sub(0, ++pos_EOCon);
set_connection(conn_str);
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 (!_connected)
return false;
else
real_query << sql;
real_query << query.sub(pos_EOCon);
// Serve?
if (!_freezed || _sql != sql)
reset();
_sql.cut(0) << real_query;
if (_sql.find("SELECT") >= 0 || _sql.find("select") >= 0)
find_and_reset_vars();
return _rec->sq_set(_sql);
}
}
else
real_query << sql;
if (!_freezed || _sql != sql)
reset();
_sql.cut(0) << real_query;
if (_sql.find("SELECT") >= 0 || _sql.find("select") >= 0)
find_and_reset_vars();
_rec->sq_set(_sql);
return false;
}
void TDB_recordset::set_connection(const char* conn_str) const
/* Parso la stringa di connessione ed estraggo i dati.
* Se il numero di dati è sufficiente eseguo la connessione.
* Ritorno false se non riesco a connettermi o il numero di dati è sbagliato
*/
bool TDB_recordset::set_connection(const char* conn_str) const
{
TString pn(conn_str);
TString srv = "", usr = "", pwd = "", drv = "";
@ -112,19 +178,22 @@ void TDB_recordset::set_connection(const char* conn_str) const
break;
}
first_pos = last_pos;
}
}
// Guardo se ho valorizzato almeno i primi 3 elementi della connect
// Se non valorizzo l'ultimo metto come default MSSQL Server
// Se non valorizzo l'ultimo come default: MSSQL Server
if (i == 2)
connect(srv.ltrim(), usr.ltrim(), pwd.ltrim(), TSDB_MSSQL);
else if(i == 3)
connect(srv.ltrim(), usr.ltrim(), pwd.ltrim(), str_to_driver(drv.ltrim()));
return connect(srv.ltrim(), usr.ltrim(), pwd.ltrim(), TSDB_MSSQL);
if(i == 3)
return connect(srv.ltrim(), usr.ltrim(), pwd.ltrim(), str_to_driver(drv.ltrim()));
return false;
}
int TDB_recordset::connect(const char * db, const char * user, const char * pass, const TT_driver tipo_db) const
// Ritorna true se si connette
bool TDB_recordset::connect(const char * db, const char * user, const char * pass, const TT_driver tipo_db) const
{
return _rec->sq_connect(db, user, pass, tipo_db);
return _rec->sq_connect(db, user, pass, tipo_db) == NOERR;
}
TT_driver TDB_recordset::str_to_driver(const char* tipo_db)
@ -170,64 +239,78 @@ TT_driver TDB_recordset::str_to_driver(const char* tipo_db)
return TSDB_undefined;
}
int TDB_recordset::connect(const char* db, const char* user, const char* pass, const char* tipo_db) const
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));
return _rec->sq_connect(db, user, pass, str_to_driver(tipo_db)) == NOERR;
}
TRecnotype TDB_recordset::items() const
{
if(!_rec->sq_is_loaded() && _items == 0)
_rec->sq_exec();
auto& i = const_cast<TRecnotype&>(_items);
i = _rec->sq_items();
return i;
return static_cast<TRecnotype>(_rec->sq_items());
}
bool TDB_recordset::move_to(TRecnotype pos)
{
const TRecnotype tot = items();
_current_row = pos;
TRecnotype row = pos;
bool ok;
if (_freezed && _loaded)
{
if (pos < 0)
_current_row = 0;
if (pos > tot)
_current_row = tot;
return true;
}
return _rec->sq_go(pos);
if (pos < 0)
row = 0;
if (pos > tot)
row = tot;
if( (ok = _rec->sq_go(row)) )
_current_row = pos;
return ok;
}
const TArray* TDB_recordset::row(TRecnotype n)
bool TDB_recordset::move_next()
{
static TRecnotype last_n = -1;
if(n >= 0 && n < _rec->sq_items())
if (_rec->sq_next())
{
if (n == last_n && !_row.empty()) // Richiedo sempre la stessa riga
return &_row;
if (move_to(n))
{
const unsigned ncol = _rec->sq_get_num_fields();
last_n = n;
for (unsigned i = 0; i < ncol; i++)
_row.add(_rec->sq_get(i, false));
return &_row;
}
_current_row = _rec->sq_pos();
return true;
}
return false;
}
const TArray TDB_recordset::get_next_row()
{
if (move_next())
return get_row();
return TArray().destroy();
}
const TArray TDB_recordset::get_row(TRecnotype n)
{
bool ok;
// Get della riga attuale
if(n == -1)
{
n = current_row();
ok = true;
}
else
ok = _rec->sq_is_loaded() && move_to(n); // Non faccio la move se non e` caricato
if (_rec->sq_is_loaded() && ok)
{
const unsigned ncol = _rec->sq_get_num_fields();
_row.destroy();
for (unsigned i = 0; i < ncol; i++)
_row.add(_rec->sq_get(i, false));
return _row;
}
// else
_row.destroy();
return &_row;
return _row;
}
void TDB_recordset::requery()
{
_items = 0;
}
unsigned TDB_recordset::columns() const
@ -235,11 +318,20 @@ unsigned TDB_recordset::columns() const
return _rec->sq_get_num_fields();
}
const TRecordset_column_info& TDB_recordset::column_info(const unsigned column) const
{
static TRecordset_column_info* info = new TRecordset_column_info;
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
return *info;
}
const TVariant& TDB_recordset::get(unsigned int column) const
{
static TVariant field = NULL_VARIANT;
static unsigned int last_get = 0;
if(column != last_get || field == NULL_VARIANT)
if(!_freezed || column != last_get || field == NULL_VARIANT)
{
last_get = column;
field = _rec->sq_get(column);
@ -248,11 +340,35 @@ const TVariant& TDB_recordset::get(unsigned int column) const
return field;
}
TDB_recordset::TDB_recordset(const char* sql, const bool freezed) : _freezed(freezed), _loaded(false)
const TVariant& TDB_recordset::active_connection() const
{
static TVariant conn = NULL_VARIANT;
conn.add(_dsn);
conn.add(_usr);
conn.add(_drv);
return conn;
}
const bool TDB_recordset::exec(const char* sql) const
{
return _rec->sq_set_exec(sql);
}
const bool TDB_recordset::commit() const
{
return _rec->sq_commit();
}
TDB_recordset::TDB_recordset(const char* sql, const bool freezed) : _freezed(freezed)
{
set(sql);
_current_row = -1;
_rec = new SSimple_query();
_items = 0;
_rec->sq_set_autocommit(true);
_sql.cut(0);
set(sql);
}
TDB_recordset::~TDB_recordset()
{
delete _rec;
}

View File

@ -171,6 +171,12 @@ public:
const char sq_get_char(const char* field) { return _rec.get_char(field); }
/**< Ritorna il numero di campi dopo l'ultimo comando di esecuzione effettuato; se il risultato esiste */
unsigned int sq_get_num_fields() const;
/**< Ritorna il nome del campo numero (column) in formato (TString= */
TString sq_get_name_field(unsigned column) const;
/**< Ritorna la grandezza del campo numero (column) */
int sq_get_width_field(unsigned column) const;
/**< Ritorna il tipo del campo numero (column) in formato (TFieldtypes) */
TFieldtypes sq_get_type_field(unsigned column) const;
/**< Ritorna la posizione attuale */
const long sq_pos() const { return _rec.pos(); }
@ -205,32 +211,40 @@ class TDB_recordset : public TRecordset
TString _sql;
TString _dsn, _usr, _pwd, _drv;
bool _freezed, _loaded, _columns_loaded{};
TRecnotype _items, _current_row;
bool _freezed{}, _columns_loaded{}, _auto_commit{}, _connected{};
TRecnotype _current_row;
TArray _row, _column;
protected:
void reset();
void set(const char* sql);
bool set(const char* sql);
// Parsa la stringa di connessione contenuta nella query
void set_connection(const char * conn_str) const;
int connect(const char * db, const char * user, const char * pass, const TT_driver tipo_db) const;
int connect(const char * db, const char * user, const char * pass, const char * tipo_db) const;
bool set_connection(const char * conn_str) const;
bool connect(const char * db, const char * user, const char * pass, const TT_driver tipo_db) const;
bool connect(const char * db, const char * user, const char * pass, const char * tipo_db) const;
static TT_driver str_to_driver(const char* tipo_db);
public:
TRecnotype items() const override; // Pure
bool move_to(TRecnotype pos) override; // Pure
bool move_next() override;
TRecnotype current_row() const override { return _current_row; } // Pure
const TArray* row(TRecnotype n);
const TArray get_next_row();
// Con il valore di default viene restituita la riga alla pos. attuale
const TArray get_row(TRecnotype n = -1);
void requery() override; // da impl. Pure
const TString& query_text() const override { return _sql; };
const TString& query_text() const override { return _sql; }
unsigned int columns() const override; // Pure
//virtual const TRecordset_column_info& column_info(unsigned int column) const; // Pure
unsigned int columns() const override; // Pure
const TRecordset_column_info& column_info(unsigned int column) const override; // Pure
const TVariant& get(unsigned int column) const override; // Pure
const TVariant& active_connection() const;
const bool exec(const char* sql) const;
const bool commit() const;
TDB_recordset(const char * sql, bool freezed = false);
~TDB_recordset();
};
#endif

View File

@ -684,6 +684,60 @@ int TXvt_recordset::get_num_fields() const
return _RCS(_recset)->FieldCount();
}
const char* TXvt_recordset::get_name_field(const unsigned column) const
{
auto& f_name = _RCS(_recset)->Field(column);
return static_cast<const char *>(f_name.Name());
}
int TXvt_recordset::get_width_field(const unsigned column) const
{
auto& f_name = _RCS(_recset)->Field(column);
return static_cast<int>(f_name.FieldSize());
}
const char* TXvt_recordset::get_type_field(const unsigned column) const
{
auto& f_name = _RCS(_recset)->Field(column);
const auto type = f_name.FieldType();
switch(type)
{
case SA_dtUnknown:
return "dtUnknown";
case SA_dtBool:
return "dtBool";
case SA_dtShort:
return "dtShort";
case SA_dtUShort:
return "dtLong";
case SA_dtULong:
return "dtDouble";
case SA_dtNumeric:
return "dtNumeric";
case SA_dtDateTime:
return "dtDateTime";
case SA_dtInterval:
return "dtString";
case SA_dtBytes:
return "dtBytes";
case SA_dtLongBinary:
return "dtLongBinary";
case SA_dtLongChar:
return "dtLongChar";
case SA_dtBLob:
return "dtBLob";
case SA_dtCLob:
return "dtCLob";
case SA_dtCursor:
return "dtCursor";
case SA_dtSpecificToDBMS:
return "dtSpecificToDBMS";
default:
return "dtUnknown";
}
}
long TXvt_recordset::get_code_error(bool erase)
{
long app = _code_error;

View File

@ -201,6 +201,12 @@ public:
char get_char(const char* field);
/**< Ritorna il numero di campi dopo l'ultimo comando di esecuzione effettuato; se il risultato esiste */
int get_num_fields() const;
/**< Ritorna il nome del campo numero (column) */
const char* get_name_field(unsigned column) const;
/**< Ritorna la grandezza del campo numero (column) */
int get_width_field(unsigned column) const;
/**< Ritorna il tipo del campo numero (column) */
const char* get_type_field(unsigned column) const;
/**< Ritorna la posizione attuale */
long pos() const { return _recno; }