diff --git a/src/include/odbcrset.cpp b/src/include/odbcrset.cpp index f9055b815..699a33361 100755 --- a/src/include/odbcrset.cpp +++ b/src/include/odbcrset.cpp @@ -724,6 +724,387 @@ TODBC_recordset::TODBC_recordset(const char* sql, const bool freezed) : _freezed TODBC_recordset::~TODBC_recordset() { } +/////////////////////////////////////////////////////////// +// TDB_recordset +/////////////////////////////////////////////////////////// + +void TDB_recordset::reset() +{ + _current_row = -1; + _is_loaded = false; + _items = 0; + _row.destroy(); + _column.destroy(); +} + +/* 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. + * 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 è 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 è 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 = ""; + + 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à 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(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; +} + /////////////////////////////////////////////////////////// // Creazione "intelligente" del recordset appropriato in base alla query /////////////////////////////////////////////////////////// diff --git a/src/include/odbcrset.h b/src/include/odbcrset.h index 5e83dd507..0595bed45 100755 --- a/src/include/odbcrset.h +++ b/src/include/odbcrset.h @@ -5,6 +5,10 @@ #include #endif +#ifndef __TSDB_H +#include +#endif + enum TODBC_driver { ODBC_generic, ODBC_mssql, @@ -72,4 +76,55 @@ public: virtual ~TODBC_recordset(); }; +class TDB_recordset : public TRecordset +{ + SSimple_query * _rec; + TString _sql; + TString _dsn, _usr, _pwd, _drv; + + bool _freezed; + TRecnotype _current_row; + TString_array _row, _column; + bool _is_loaded; + TRecnotype _items; + unsigned _ncolumns; + +protected: + // Parsa la stringa di connessione contenuta nella query + 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); + bool set_loaded(); + void unset_loaded(); + +public: + void freeze(const bool on = true); + void reset(); + bool set(const char* sql); + bool move_to(TRecnotype pos) override; // Pure + bool move_next() override; + void requery() override; // da impl. Pure + bool is_connected() const; + unsigned columns() const override; // Pure + TRecnotype items() const override; // Pure + TRecnotype current_row() const override { return _current_row; } // Pure + // Con il valore di default viene restituita la riga alla pos. attuale + const TString_array get_row(TRecnotype n = -1); + const TString_array get_next_row(); + const TString& query_text() const override { return _sql; } + const TString& driver_version() const override { return _rec->sq_get_client_v(); }; + const TVariant& get(unsigned int column) const override; // Pure + const TVariant& get(const char* name) const override; // Pure + const TRecordset_column_info& column_info(unsigned int column) const override; // Pure + + // Ritorna la connessione attuale + const TVariant& active_connection() const; + bool exec(const char* sql); + bool commit() const; + + TDB_recordset(const char * sql, bool freezed = false); + ~TDB_recordset(); +}; + #endif diff --git a/src/include/tsdb.cpp b/src/include/tsdb.cpp index b0df08595..76cd1df5f 100644 --- a/src/include/tsdb.cpp +++ b/src/include/tsdb.cpp @@ -107,380 +107,3 @@ const char* SSimple_query::sq_get_token_text_error(const int token, const bool e 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ò 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. - * 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 è 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 è 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 = ""; - - 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à 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(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; -} diff --git a/src/include/tsdb.h b/src/include/tsdb.h index 5b1f14d96..c739d6429 100644 --- a/src/include/tsdb.h +++ b/src/include/tsdb.h @@ -206,55 +206,4 @@ public: virtual ~SSimple_query() = default; }; -class TDB_recordset : public TRecordset -{ - SSimple_query * _rec; - TString _sql; - TString _dsn, _usr, _pwd, _drv; - - bool _freezed; - TRecnotype _current_row; - TString_array _row, _column; - bool _is_loaded; - TRecnotype _items; - unsigned _ncolumns; - -protected: - // Parsa la stringa di connessione contenuta nella query - 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); - bool set_loaded(); - void unset_loaded(); - -public: - void freeze(const bool on = true); - void reset(); - bool set(const char* sql); - bool move_to(TRecnotype pos) override; // Pure - bool move_next() override; - void requery() override; // da impl. Pure - bool is_connected() const; - unsigned columns() const override; // Pure - TRecnotype items() const override; // Pure - TRecnotype current_row() const override { return _current_row; } // Pure - // Con il valore di default viene restituita la riga alla pos. attuale - const TString_array get_row(TRecnotype n = -1); - const TString_array get_next_row(); - const TString& query_text() const override { return _sql; } - const TString& driver_version() const override { return _rec->sq_get_client_v(); }; - const TVariant& get(unsigned int column) const override; // Pure - const TVariant& get(const char* name) const override; // Pure - const TRecordset_column_info& column_info(unsigned int column) const override; // Pure - - // Ritorna la connessione attuale - const TVariant& active_connection() const; - bool exec(const char* sql); - bool commit() const; - - TDB_recordset(const char * sql, bool freezed = false); - ~TDB_recordset(); -}; - #endif \ No newline at end of file