diff --git a/src/include/odbcrset.cpp b/src/include/odbcrset.cpp index 0518bcf56..a1073d141 100755 --- a/src/include/odbcrset.cpp +++ b/src/include/odbcrset.cpp @@ -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); } diff --git a/src/include/tsdb.cpp b/src/include/tsdb.cpp index 895c21a7b..46454e1ed 100644 --- a/src/include/tsdb.cpp +++ b/src/include/tsdb.cpp @@ -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(_items); - i = _rec->sq_items(); - return i; - + return static_cast(_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; +} diff --git a/src/include/tsdb.h b/src/include/tsdb.h index ecbe4e667..8ac37d619 100644 --- a/src/include/tsdb.h +++ b/src/include/tsdb.h @@ -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 \ No newline at end of file diff --git a/src/xvtdb/xvtdb.cpp b/src/xvtdb/xvtdb.cpp index eaf8ee46d..d7d4997b0 100644 --- a/src/xvtdb/xvtdb.cpp +++ b/src/xvtdb/xvtdb.cpp @@ -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(f_name.Name()); +} + +int TXvt_recordset::get_width_field(const unsigned column) const +{ + auto& f_name = _RCS(_recset)->Field(column); + return static_cast(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; diff --git a/src/xvtdb/xvtdb.h b/src/xvtdb/xvtdb.h index a93187255..f1ce0014c 100644 --- a/src/xvtdb/xvtdb.h +++ b/src/xvtdb/xvtdb.h @@ -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; }