2017-10-26 10:28:19 +00:00
|
|
|
|
#include "xvtdb.h"
|
|
|
|
|
#include <sqlapi.h>
|
2018-02-09 13:29:55 +00:00
|
|
|
|
#include <string> // sprintf_s
|
2017-10-26 10:28:19 +00:00
|
|
|
|
|
|
|
|
|
#define _CON(a) ((SAConnection *)a)
|
|
|
|
|
#define _RCS(a) ((SACommand *)a)
|
|
|
|
|
#define _ERR(a) ((SAException *)a)
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
#define _CPY_STR(from,to) (to = _strdup(from));
|
2018-12-11 14:16:34 +01:00
|
|
|
|
#define _GET_ERROR(from,to) _CPY_STR(from,to)
|
|
|
|
|
|
2019-02-27 16:58:16 +01:00
|
|
|
|
#define CHECK_FREEZED if (is_freezed()) { return set_error_freezed(); }
|
2018-12-11 14:16:34 +01:00
|
|
|
|
|
2017-10-26 10:28:19 +00:00
|
|
|
|
/******************************************************************************
|
2018-02-09 13:29:55 +00:00
|
|
|
|
* TXvt_recordset *
|
2017-10-26 10:28:19 +00:00
|
|
|
|
* Classe per esecuzioni di query temporanee (wrapper semplice per SACommand) *
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
2018-07-06 16:30:37 +02:00
|
|
|
|
TXvt_recordset::TXvt_recordset() : _freezed(false)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
_con = new SAConnection;
|
|
|
|
|
_recset = new SACommand;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_RCS(_recset)->setConnection(_CON(_con));
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
TXvt_recordset::TXvt_recordset(const char* db, const char* user, const char* pass, const TT_driver tipo_db, const char * query, const bool ex, const bool freezed)
|
|
|
|
|
: _db(db), _usr(user), _psw(pass), _drv(tipo_db), _query(""), _recno(0), _freezed(false), _loaded(false)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
_con = new SAConnection;
|
2019-03-19 16:45:34 +01:00
|
|
|
|
if(connect(db, user, pass, tipo_db) == NOERR)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_recset = new SACommand;
|
|
|
|
|
_RCS(_recset)->setConnection(_CON(_con));
|
|
|
|
|
if (query && *query)
|
|
|
|
|
{
|
|
|
|
|
set(query);
|
|
|
|
|
if (ex)
|
|
|
|
|
{
|
|
|
|
|
exec();
|
|
|
|
|
// Terribile da vedere, ma ho fatto una funzione apposta e la voglio usare per Diana!
|
|
|
|
|
if(freezed)
|
|
|
|
|
freeze();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-12 17:38:18 +01:00
|
|
|
|
TT_driver TXvt_recordset::str_to_driver(const char* tipo_db)
|
|
|
|
|
{
|
|
|
|
|
TT_driver tipoDb_driver = TSDB_undefined;
|
|
|
|
|
//! DBMS client is not specified
|
|
|
|
|
if (_stricmp(tipo_db, "") != 0)
|
|
|
|
|
tipoDb_driver = TSDB_undefined;
|
|
|
|
|
//! ODBC
|
|
|
|
|
else if (_stricmp(tipo_db, "ODBC") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_ODBC;
|
|
|
|
|
//! Oracle
|
|
|
|
|
else if (_stricmp(tipo_db, "Oracle") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_Oracle;
|
|
|
|
|
//! Microsoft SQL Server
|
|
|
|
|
else if (_stricmp(tipo_db, "MSSQL") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_MSSQL;
|
|
|
|
|
//! InterBase or Firebird
|
|
|
|
|
else if (_stricmp(tipo_db, "InterBase") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_InterBase;
|
|
|
|
|
//! SQLBase
|
|
|
|
|
else if (_stricmp(tipo_db, "SQLBase") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_SQLBase;
|
|
|
|
|
//! IBM DB2
|
|
|
|
|
else if (_stricmp(tipo_db, "DB2") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_DB2;
|
|
|
|
|
//! Informix
|
|
|
|
|
else if (_stricmp(tipo_db, "Informix") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_Informix;
|
|
|
|
|
//! Sybase ASE
|
|
|
|
|
else if (_stricmp(tipo_db, "Sybase") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_Sybase;
|
|
|
|
|
//! MySQL
|
|
|
|
|
else if (_stricmp(tipo_db, "MySQL") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_MySQL;
|
|
|
|
|
//! PostgreSQL
|
|
|
|
|
else if (_stricmp(tipo_db, "PostgreSQL") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_PostgreSQL;
|
|
|
|
|
//! SQLite
|
|
|
|
|
else if (_stricmp(tipo_db, "SQLite") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_SQLite;
|
|
|
|
|
//! SQL Anywere
|
|
|
|
|
else if (_stricmp(tipo_db, "SQLAnywhere") == 0)
|
|
|
|
|
tipoDb_driver = TSDB_SQLAnywhere;
|
|
|
|
|
return tipoDb_driver;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
TXvt_recordset::TXvt_recordset(const char* db, const char* user, const char* pass, const char* tipo_db,
|
|
|
|
|
const char* query, const bool ex, const bool freezed) : TXvt_recordset(db, user, pass, str_to_driver(tipo_db), query, ex, freezed)
|
2019-03-12 17:38:18 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-26 10:28:19 +00:00
|
|
|
|
TXvt_recordset::~TXvt_recordset()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2018-07-06 16:30:37 +02:00
|
|
|
|
// Se non <20> connesso viene lanciata l'eccezione
|
2018-02-09 13:29:55 +00:00
|
|
|
|
if(_CON(_con)->isConnected())
|
2017-10-26 10:28:19 +00:00
|
|
|
|
_CON(_con)->Disconnect();
|
|
|
|
|
}
|
2018-02-09 13:29:55 +00:00
|
|
|
|
catch (...) {}
|
2018-07-06 16:30:37 +02:00
|
|
|
|
// Prima cancellare il recordset POI la connessione
|
|
|
|
|
delete _recset;
|
|
|
|
|
delete _con;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* PRIVATE FUNCTIONS **************************************************************************************************/
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
const bool TXvt_recordset::check_permission()
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
2019-03-19 16:45:34 +01:00
|
|
|
|
const bool err = is_freezed();
|
2018-02-09 13:29:55 +00:00
|
|
|
|
if (err)
|
2019-02-27 16:58:16 +01:00
|
|
|
|
set_error_freezed();
|
2017-10-26 10:28:19 +00:00
|
|
|
|
return !err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* PUBLIC FUNCTIONS **************************************************************************************************/
|
|
|
|
|
|
|
|
|
|
/**************************************************************************************************
|
|
|
|
|
* Gestione Connection *
|
|
|
|
|
**************************************************************************************************/
|
|
|
|
|
|
2019-02-27 16:58:16 +01:00
|
|
|
|
int TXvt_recordset::connect(const char* db, const char* user, const char* pass, TT_driver tipo_db)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
2019-03-19 16:45:34 +01:00
|
|
|
|
if (_con != nullptr)
|
2018-02-09 13:29:55 +00:00
|
|
|
|
{
|
|
|
|
|
// Se <20> gi<67> connesso lo scollego
|
|
|
|
|
if (_CON(_con)->isConnected())
|
|
|
|
|
_CON(_con)->Disconnect();
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
SAString db_address = db;
|
2018-02-09 13:29:55 +00:00
|
|
|
|
SAString usr = user;
|
2019-03-19 16:45:34 +01:00
|
|
|
|
const SAString psw = pass;
|
|
|
|
|
const SAClient_t db_driver = static_cast<SAClient_t>(tipo_db);
|
|
|
|
|
if (db_address.IsEmpty() || usr.IsEmpty())
|
2018-02-09 13:29:55 +00:00
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = NOT_INITIALIZED;
|
|
|
|
|
_string_error = NOT_INITIALIZEDS;
|
2018-02-09 13:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Mi collego
|
2019-03-19 16:45:34 +01:00
|
|
|
|
_CON(_con)->Connect(db_address, usr, psw, db_driver);
|
2018-02-09 13:29:55 +00:00
|
|
|
|
// Imposto che non si possono vedere i record non committati
|
|
|
|
|
_CON(_con)->setIsolationLevel(SA_ReadCommitted);
|
2019-03-19 12:37:55 +01:00
|
|
|
|
_CPY_STR(db, _db);
|
|
|
|
|
_CPY_STR(user, _usr);
|
|
|
|
|
_CPY_STR(pass, _psw);
|
|
|
|
|
_drv = tipo_db;
|
2018-02-09 13:29:55 +00:00
|
|
|
|
return NOERR;
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2018-02-09 13:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = NOT_INITIALIZED;
|
|
|
|
|
_string_error = NOT_INITIALIZEDS;
|
2018-02-09 13:29:55 +00:00
|
|
|
|
}
|
2019-02-11 14:47:45 +01:00
|
|
|
|
return _code_error;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TXvt_recordset::disconnect()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_CON(_con)->Disconnect();
|
|
|
|
|
}
|
|
|
|
|
catch(SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
bool TXvt_recordset::commit(const bool auto_roll)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
2018-02-09 13:29:55 +00:00
|
|
|
|
CHECK_FREEZED
|
2017-10-26 10:28:19 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_CON(_con)->Commit();
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-03-19 16:45:34 +01:00
|
|
|
|
if (auto_roll)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
rollback();
|
|
|
|
|
}
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TXvt_recordset::rollback()
|
|
|
|
|
{
|
2018-02-09 13:29:55 +00:00
|
|
|
|
CHECK_FREEZED
|
2017-10-26 10:28:19 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_CON(_con)->Rollback();
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
void TXvt_recordset::set_client(TT_driver client) const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
2019-03-19 16:45:34 +01:00
|
|
|
|
_CON(_con)->setClient(static_cast<SAClient_t>(client));
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-25 11:54:02 +01:00
|
|
|
|
void TXvt_recordset::set_con_option(const char* opt, const char* val) const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
2019-03-25 11:54:02 +01:00
|
|
|
|
_CON(_con)->setOption(opt) = val;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
void TXvt_recordset::set_autocommit(const bool ac) const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
_CON(_con)->setAutoCommit(ac ? SA_AutoCommitOn : SA_AutoCommitOff);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 16:58:16 +01:00
|
|
|
|
void TXvt_recordset::set_visibility(iso_lvl vis)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
/* La libreria attuale supporta diversi tipi di visibilit<69>, per mantenere una compatibilit<69> massima
|
|
|
|
|
* (evitando inutili seghe mentali) consiglio di usare i primi due, di default la classe imposta "Read committed"
|
|
|
|
|
* Tipi di isolazione:
|
|
|
|
|
* 0 -> Read uncommitted.
|
|
|
|
|
* 1 -> Read committed.
|
|
|
|
|
* 2 -> Repeatable read.
|
|
|
|
|
* 3 -> Serializable.
|
|
|
|
|
*/
|
2019-03-19 16:45:34 +01:00
|
|
|
|
_CON(_con)->setIsolationLevel(static_cast<SAIsolationLevel_t>(vis));
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 16:58:16 +01:00
|
|
|
|
const bool TXvt_recordset::is_connect() const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
return _CON(_con)->isConnected();
|
|
|
|
|
}
|
2019-02-27 16:58:16 +01:00
|
|
|
|
const bool TXvt_recordset::is_alive() const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
return _CON(_con)->isAlive();
|
|
|
|
|
}
|
2019-03-19 16:45:34 +01:00
|
|
|
|
int TXvt_recordset::get_visibility() const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
2019-03-19 16:45:34 +01:00
|
|
|
|
return static_cast<iso_lvl>(_CON(_con)->IsolationLevel());
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
2019-03-19 16:45:34 +01:00
|
|
|
|
bool TXvt_recordset::get_autocommit() const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
return _CON(_con)->AutoCommit() == SA_AutoCommitOn;
|
|
|
|
|
}
|
2019-03-19 16:45:34 +01:00
|
|
|
|
const char* TXvt_recordset::get_option(const char* opt) const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
return _CON(_con)->Option(opt);
|
|
|
|
|
}
|
2019-03-19 16:45:34 +01:00
|
|
|
|
long TXvt_recordset::get_client_v() const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
return _CON(_con)->ClientVersion();
|
|
|
|
|
}
|
2019-03-19 16:45:34 +01:00
|
|
|
|
const char* TXvt_recordset::get_server_v() const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
return _CON(_con)->ServerVersionString();
|
|
|
|
|
}
|
2019-03-19 16:45:34 +01:00
|
|
|
|
long TXvt_recordset::get_server_vn() const
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
return _CON(_con)->ServerVersion();
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 16:58:16 +01:00
|
|
|
|
bool TXvt_recordset::is_loaded() const
|
2018-02-09 13:29:55 +00:00
|
|
|
|
{
|
|
|
|
|
return _loaded;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long TXvt_recordset::items()
|
|
|
|
|
{
|
|
|
|
|
// Per non creare casini utilizzo una funzione apposita che mi ritorna il numero
|
|
|
|
|
P_CONN_VOID conn = new SAConnection;
|
2019-03-19 12:37:55 +01:00
|
|
|
|
SAString q;
|
2019-03-19 16:45:34 +01:00
|
|
|
|
long items = DEFAULT_ERR_NUMBER;
|
2018-02-09 13:29:55 +00:00
|
|
|
|
|
|
|
|
|
// Connetto la nuova istanza
|
2019-03-19 12:37:55 +01:00
|
|
|
|
try
|
|
|
|
|
{
|
2019-03-19 16:45:34 +01:00
|
|
|
|
_CON(conn)->Connect(_db, _usr, _psw, static_cast<SAClient_t>(_drv));
|
2019-03-19 12:37:55 +01:00
|
|
|
|
items = xvt_rcs_get_items(conn, _query);
|
|
|
|
|
if (conn != _con)
|
|
|
|
|
delete conn;
|
|
|
|
|
}
|
|
|
|
|
catch(SAException &x)
|
|
|
|
|
{
|
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 13:29:55 +00:00
|
|
|
|
return items;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long xvt_rcs_get_items(P_CONN_VOID con, const char* query)
|
|
|
|
|
{
|
|
|
|
|
P_COMM_VOID rcs = new SACommand(_CON(con));
|
|
|
|
|
_RCS(rcs)->setCommandText(query);
|
2019-03-19 12:37:55 +01:00
|
|
|
|
_RCS(rcs)->Execute();
|
2018-02-09 13:29:55 +00:00
|
|
|
|
long r = 0;
|
2019-03-19 12:37:55 +01:00
|
|
|
|
while(_RCS(rcs)->FetchNext())
|
2018-02-09 13:29:55 +00:00
|
|
|
|
r++;
|
|
|
|
|
delete rcs;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2017-10-26 10:28:19 +00:00
|
|
|
|
|
|
|
|
|
/**************************************************************************************************
|
|
|
|
|
* Gestione Recordset *
|
|
|
|
|
**************************************************************************************************/
|
|
|
|
|
bool TXvt_recordset::set(const char* query)
|
|
|
|
|
{
|
2018-02-09 13:29:55 +00:00
|
|
|
|
CHECK_FREEZED
|
2017-10-26 10:28:19 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
2018-02-09 13:29:55 +00:00
|
|
|
|
_query = query;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
_RCS(_recset)->setCommandText(query);
|
2019-03-19 12:37:55 +01:00
|
|
|
|
_loaded = false;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
bool TXvt_recordset::exec(const bool auto_f)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
2018-02-09 13:29:55 +00:00
|
|
|
|
CHECK_FREEZED
|
2018-07-06 16:30:37 +02:00
|
|
|
|
bool ok = false;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_RCS(_recset)->Execute();
|
2019-03-19 12:37:55 +01:00
|
|
|
|
_loaded = true;
|
2019-03-25 11:54:02 +01:00
|
|
|
|
_recno = -1;
|
2018-07-06 16:30:37 +02:00
|
|
|
|
// Se trovo almeno un "select" faccio l'autofetch
|
|
|
|
|
SAString s = _RCS(_recset)->CommandText(); s.MakeUpper();
|
2019-03-19 16:45:34 +01:00
|
|
|
|
ok = s.Find("SELECT") != SIZE_MAX && auto_f ? next() : true;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2018-07-06 16:30:37 +02:00
|
|
|
|
ok = false;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
2018-07-06 16:30:37 +02:00
|
|
|
|
return ok;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
bool TXvt_recordset::set_exec(const char* query, const bool auto_f)
|
2017-11-09 11:01:56 +00:00
|
|
|
|
{
|
|
|
|
|
set(query);
|
2019-02-27 16:58:16 +01:00
|
|
|
|
return exec(auto_f);
|
2017-11-09 11:01:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-26 10:28:19 +00:00
|
|
|
|
bool TXvt_recordset::next()
|
|
|
|
|
{
|
|
|
|
|
bool fetched = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if(_RCS(_recset)->FetchNext())
|
|
|
|
|
{
|
|
|
|
|
fetched = true;
|
|
|
|
|
_recno++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
return fetched;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TXvt_recordset::prev()
|
|
|
|
|
{
|
|
|
|
|
bool fetched = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_RCS(_recset)->FetchPrior())
|
|
|
|
|
{
|
|
|
|
|
fetched = true;
|
|
|
|
|
_recno--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
return fetched;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TXvt_recordset::first()
|
|
|
|
|
{
|
|
|
|
|
bool fetched = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_RCS(_recset)->FetchFirst())
|
|
|
|
|
{
|
|
|
|
|
fetched = true;
|
|
|
|
|
_recno = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
return fetched;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TXvt_recordset::last()
|
|
|
|
|
{
|
|
|
|
|
bool fetched = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_RCS(_recset)->FetchLast())
|
|
|
|
|
{
|
|
|
|
|
fetched = true;
|
|
|
|
|
_recno = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
return fetched;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
bool TXvt_recordset::go(const int new_pos)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
// Controllo che la nuova posizione non sia fuori dal limite inferiore (Non so quanto <20> grande il recordset)
|
2019-03-19 16:45:34 +01:00
|
|
|
|
bool result = new_pos >= 0;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
|
|
|
|
|
// Se la posizione <20> minore mi sposto indietro
|
2019-02-27 16:58:16 +01:00
|
|
|
|
while (new_pos < _recno && result)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
result = prev();
|
|
|
|
|
}
|
|
|
|
|
// Se la posizione <20> maggiore mi sposto in avanti
|
2019-02-27 16:58:16 +01:00
|
|
|
|
while (new_pos > _recno && result)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
result = next();
|
|
|
|
|
}
|
2019-03-19 16:45:34 +01:00
|
|
|
|
|
2017-10-26 10:28:19 +00:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 16:58:16 +01:00
|
|
|
|
const int TXvt_recordset::rows_affected() const
|
2018-02-09 13:29:55 +00:00
|
|
|
|
{
|
|
|
|
|
return _RCS(_recset)->RowsAffected();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-26 10:28:19 +00:00
|
|
|
|
int TXvt_recordset::get_int(const char* field)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return static_cast<int>(_RCS(_recset)->Field(field).asLong());
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2019-03-19 16:45:34 +01:00
|
|
|
|
return DEFAULT_ERR_NUMBER;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
short TXvt_recordset::get_short(const char* field)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return _RCS(_recset)->Field(field).asShort();
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2019-03-19 16:45:34 +01:00
|
|
|
|
return DEFAULT_ERR_NUMBER;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long TXvt_recordset::get_long(const char* field)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return _RCS(_recset)->Field(field).asLong();
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2019-03-19 16:45:34 +01:00
|
|
|
|
return DEFAULT_ERR_NUMBER;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double TXvt_recordset::get_double(const char* field)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return _RCS(_recset)->Field(field).asDouble();
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2019-03-19 16:45:34 +01:00
|
|
|
|
return DEFAULT_ERR_NUMBER;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TXvt_recordset::get_bool(const char* field)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return _RCS(_recset)->Field(field).asBool();
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-19 16:45:34 +01:00
|
|
|
|
|
2018-02-09 13:29:55 +00:00
|
|
|
|
const char* TXvt_recordset::get_date(const char * field)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
SADateTime app = _RCS(_recset)->Field(field).asDateTime();
|
2019-02-25 12:42:51 +01:00
|
|
|
|
static char date[9];
|
|
|
|
|
sprintf_s(date, sizeof(date), "%04d%02d%02d", app.GetYear(), app.GetMonth(), app.GetDay());
|
2017-10-26 10:28:19 +00:00
|
|
|
|
return date;
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2019-03-19 16:45:34 +01:00
|
|
|
|
return DEFAULT_ERR_STRING;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* TXvt_recordset::get(const char* field)
|
|
|
|
|
{
|
2019-02-25 16:02:34 +01:00
|
|
|
|
SACommand& pop = *static_cast<SACommand*>(_recset);
|
|
|
|
|
|
2017-10-26 10:28:19 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
2019-02-25 16:02:34 +01:00
|
|
|
|
static SAString fld;
|
|
|
|
|
fld = _RCS(_recset)->Field(field).asString();
|
|
|
|
|
return static_cast<const char *>(fld);
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2019-03-19 16:45:34 +01:00
|
|
|
|
return DEFAULT_ERR_STRING;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 18:00:13 +01:00
|
|
|
|
const char* TXvt_recordset::get(unsigned int field)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2019-03-19 12:37:55 +01:00
|
|
|
|
static SAString str;
|
|
|
|
|
str = _RCS(_recset)->Field(field + 1).asString();
|
|
|
|
|
return str;
|
2019-03-13 18:00:13 +01:00
|
|
|
|
}
|
|
|
|
|
catch(SAException &x)
|
|
|
|
|
{
|
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2019-03-19 16:45:34 +01:00
|
|
|
|
return DEFAULT_ERR_STRING;
|
2019-03-13 18:00:13 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-26 10:28:19 +00:00
|
|
|
|
char TXvt_recordset::get_char(const char* field)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return _RCS(_recset)->Field(field).asString()[0];
|
|
|
|
|
}
|
|
|
|
|
catch (SAException &x)
|
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = x.ErrNativeCode();
|
|
|
|
|
_GET_ERROR(x.ErrMessage(), _string_error);
|
|
|
|
|
_GET_ERROR(x.ErrText(), _string_error_full_text);
|
2019-03-19 16:45:34 +01:00
|
|
|
|
return DEFAULT_ERR_CHAR;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 18:00:13 +01:00
|
|
|
|
int TXvt_recordset::get_num_fields() const
|
|
|
|
|
{
|
|
|
|
|
return _RCS(_recset)->FieldCount();
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-15 10:51:50 +01:00
|
|
|
|
const char* TXvt_recordset::get_name_field(const unsigned column) const
|
|
|
|
|
{
|
2019-03-25 11:54:02 +01:00
|
|
|
|
SAField& f_name = _RCS(_recset)->Field(column + 1);
|
2019-03-15 10:51:50 +01:00
|
|
|
|
return static_cast<const char *>(f_name.Name());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int TXvt_recordset::get_width_field(const unsigned column) const
|
|
|
|
|
{
|
2019-03-25 11:54:02 +01:00
|
|
|
|
SAField& f_name = _RCS(_recset)->Field(column + 1);
|
2019-03-15 10:51:50 +01:00
|
|
|
|
return static_cast<int>(f_name.FieldSize());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* TXvt_recordset::get_type_field(const unsigned column) const
|
|
|
|
|
{
|
2019-03-25 11:54:02 +01:00
|
|
|
|
SAField& f_name = _RCS(_recset)->Field(column + 1);
|
2019-03-15 10:51:50 +01:00
|
|
|
|
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";
|
2019-03-19 12:37:55 +01:00
|
|
|
|
case SA_dtString:
|
|
|
|
|
return "dtString";
|
2019-03-15 10:51:50 +01:00
|
|
|
|
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";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-25 11:54:02 +01:00
|
|
|
|
int TXvt_recordset::get_precision_field(const unsigned column) const
|
|
|
|
|
{
|
|
|
|
|
SAField& f_name = _RCS(_recset)->Field(column + 1);
|
|
|
|
|
return f_name.FieldPrecision();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int TXvt_recordset::get_scale_field(const unsigned column) const
|
|
|
|
|
{
|
|
|
|
|
SAField& f_name = _RCS(_recset)->Field(column + 1);
|
|
|
|
|
return f_name.FieldScale();
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 16:45:34 +01:00
|
|
|
|
long TXvt_recordset::get_code_error(const bool erase)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
2019-03-19 16:45:34 +01:00
|
|
|
|
const long app = _code_error;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
if (erase)
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = NOERR;
|
2017-10-26 10:28:19 +00:00
|
|
|
|
return app;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-09 13:29:55 +00:00
|
|
|
|
const char* TXvt_recordset::get_string_error(bool erase)
|
2017-10-26 10:28:19 +00:00
|
|
|
|
{
|
2018-12-11 14:16:34 +01:00
|
|
|
|
static char* app;
|
|
|
|
|
|
|
|
|
|
if (app != nullptr)
|
|
|
|
|
delete app;
|
|
|
|
|
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_CPY_STR(_string_error, app);
|
|
|
|
|
|
|
|
|
|
if (erase)
|
|
|
|
|
_string_error = "";
|
|
|
|
|
return app;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* TXvt_recordset::get_text_error(bool erase)
|
|
|
|
|
{
|
|
|
|
|
static char* app;
|
|
|
|
|
|
|
|
|
|
if (app != nullptr)
|
|
|
|
|
delete app;
|
|
|
|
|
|
|
|
|
|
_CPY_STR(_string_error_full_text, app);
|
2018-12-11 14:16:34 +01:00
|
|
|
|
|
2017-10-26 10:28:19 +00:00
|
|
|
|
if (erase)
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_string_error_full_text = "";
|
2017-10-26 10:28:19 +00:00
|
|
|
|
return app;
|
2018-02-09 13:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 16:58:16 +01:00
|
|
|
|
const bool TXvt_recordset::set_error_freezed()
|
2018-02-09 13:29:55 +00:00
|
|
|
|
{
|
2019-02-11 14:47:45 +01:00
|
|
|
|
_code_error = ERROR_FREEZED;
|
|
|
|
|
_string_error = _string_error_full_text = ERROR_FREEZEDS;
|
2018-02-09 13:29:55 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|