campo-sirio/src/xvtdb/xvtdb.cpp
Tolla cb7551773d Patch level : 12.0 no-patch
Files correlati     :
Commento            :
Aggiunte funzioni per leggere colonne (andavano già messe da tempo)
- Aggiunta colonna natura in TCodiceIVA
- Aggiunta causale 770 come recordset
- Aggiunta colonne cassa previdenziale, soggetto a ritenuta e spesa calcolo ritenuta
- Aggiunto nuovo tipo di errore da SQLAPI in TXvt_recordset
2019-02-11 14:47:45 +01:00

629 lines
14 KiB
C++

#include "xvtdb.h"
#include <sqlapi.h>
#include <string> // sprintf_s
#define _CON(a) ((SAConnection *)a)
#define _RCS(a) ((SACommand *)a)
#define _ERR(a) ((SAException *)a)
#define _CPY_STR(from,to) (to = strdup(from));
#define _GET_ERROR(from,to) _CPY_STR(from,to)
/******************************************************************************
* TXvt_recordset *
* Classe per esecuzioni di query temporanee (wrapper semplice per SACommand) *
******************************************************************************/
TXvt_recordset::TXvt_recordset() : _freezed(false)
{
_con = new SAConnection;
_recset = new SACommand;
try
{
_RCS(_recset)->setConnection(_CON(_con));
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
}
}
TXvt_recordset::TXvt_recordset(const char* db, const char* user, const char* pass, TT_driver tipoDb, const char * query, const bool ex, const bool freezed)
: _db(db), _usr(user), _psw(pass), _drv(tipoDb), _freezed(false)
{
_con = new SAConnection;
if(connect(db, user, pass, tipoDb) == NOERR)
{
try
{
_recset = new SACommand;
_RCS(_recset)->setConnection(_CON(_con));
// if (query[0] != '\0')
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)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
}
}
}
TXvt_recordset::~TXvt_recordset()
{
try
{
// Se non è connesso viene lanciata l'eccezione
if(_CON(_con)->isConnected())
_CON(_con)->Disconnect();
}
catch (...) {}
// Prima cancellare il recordset POI la connessione
delete _recset;
delete _con;
}
/* PRIVATE FUNCTIONS **************************************************************************************************/
const bool TXvt_recordset::checkPermission()
{
bool err = is_freezed();
if (err)
setErrorFreezed();
return !err;
}
/* PUBLIC FUNCTIONS **************************************************************************************************/
/**************************************************************************************************
* Gestione Connection *
**************************************************************************************************/
int TXvt_recordset::connect(const char* db, const char* user, const char* pass, TT_driver tipoDb)
{
if (_con != NULL)
{
// Se è già connesso lo scollego
if (_CON(_con)->isConnected())
_CON(_con)->Disconnect();
SAString dbAddress = db;
SAString usr = user;
SAString psw = pass;
SAClient_t dbDriver = (SAClient_t)tipoDb;
if (dbAddress.IsEmpty() || usr.IsEmpty())
{
_code_error = NOT_INITIALIZED;
_string_error = NOT_INITIALIZEDS;
}
else
{
try
{
// Mi collego
_CON(_con)->Connect(dbAddress, usr, psw, dbDriver);
// Imposto che non si possono vedere i record non committati
_CON(_con)->setIsolationLevel(SA_ReadCommitted);
return NOERR;
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
}
}
}
else
{
_code_error = NOT_INITIALIZED;
_string_error = NOT_INITIALIZEDS;
}
return _code_error;
}
void TXvt_recordset::disconnect()
{
try
{
_CON(_con)->Disconnect();
}
catch(SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
}
}
bool TXvt_recordset::commit(bool autoRoll)
{
CHECK_FREEZED
try
{
_CON(_con)->Commit();
}
catch (SAException &x)
{
if (autoRoll)
{
rollback();
}
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return false;
}
return true;
}
bool TXvt_recordset::rollback()
{
CHECK_FREEZED
try
{
_CON(_con)->Rollback();
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return false;
}
return true;
}
void TXvt_recordset::setClient(TT_driver client)
{
_CON(_con)->setClient((SAClient_t) client);
}
void TXvt_recordset::setConOption(const char* opt)
{
_CON(_con)->setOption(opt);
}
void TXvt_recordset::setAutocommit(bool ac)
{
_CON(_con)->setAutoCommit(ac ? SA_AutoCommitOn : SA_AutoCommitOff);
}
void TXvt_recordset::setVisibility(isoLvl vis)
{
/* La libreria attuale supporta diversi tipi di visibilità, per mantenere una compatibilità 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.
*/
_CON(_con)->setIsolationLevel((SAIsolationLevel_t)vis);
}
const bool TXvt_recordset::isConnect() const
{
return _CON(_con)->isConnected();
}
const bool TXvt_recordset::isAlive() const
{
return _CON(_con)->isAlive();
}
int TXvt_recordset::getVisibility()
{
return (isoLvl)_CON(_con)->IsolationLevel();
}
bool TXvt_recordset::getAutocommit()
{
return _CON(_con)->AutoCommit() == SA_AutoCommitOn;
}
const char* TXvt_recordset::getOption(const char* opt)
{
return _CON(_con)->Option(opt);
}
long TXvt_recordset::getClientV()
{
return _CON(_con)->ClientVersion();
}
const char* TXvt_recordset::getServerV()
{
return _CON(_con)->ServerVersionString();
}
long TXvt_recordset::getServerVN()
{
return _CON(_con)->ServerVersion();
}
bool TXvt_recordset::isLoaded() const
{
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;
char q[500];
long items;
// Connetto la nuova istanza
_CON(conn)->Connect(_db, _usr, _psw, (SAClient_t)_drv);
// Controllo sia tutto a posto
// Creo la query
strcat_s(q, sizeof(q), "SELECT COUNT(*) ");
strcat_s(q, sizeof(q), (strstr(_query, "FROM") != NULL ? strstr(_query, "FROM") : strstr(_query, "from"))); // Serve?
items = xvt_rcs_get_items(conn, q);
if(conn != _con)
delete conn;
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);
long r = 0;
for(bool ok = _RCS(rcs)->FetchFirst(); ok; ok = _RCS(rcs)->FetchNext())
r++;
delete rcs;
return r;
}
/**************************************************************************************************
* Gestione Recordset *
**************************************************************************************************/
bool TXvt_recordset::set(const char* query)
{
CHECK_FREEZED
try
{
_query = query;
_RCS(_recset)->setCommandText(query);
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return false;
}
return true;
}
bool TXvt_recordset::exec(bool autoF)
{
CHECK_FREEZED
bool ok = false;
try
{
_RCS(_recset)->Execute();
_recno = -1;
// Se trovo almeno un "select" faccio l'autofetch
SAString s = _RCS(_recset)->CommandText(); s.MakeUpper();
ok = s.Find("SELECT") != SIZE_MAX && autoF ? next() : true;
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
ok = false;
}
return ok;
}
bool TXvt_recordset::setExec(const char* query, bool autoF)
{
set(query);
return exec(autoF);
}
bool TXvt_recordset::next()
{
bool fetched = false;
try
{
if(_RCS(_recset)->FetchNext())
{
fetched = true;
_recno++;
}
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
}
return fetched;
}
bool TXvt_recordset::prev()
{
bool fetched = false;
try
{
if (_RCS(_recset)->FetchPrior())
{
fetched = true;
_recno--;
}
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
}
return fetched;
}
bool TXvt_recordset::first()
{
bool fetched = false;
try
{
if (_RCS(_recset)->FetchFirst())
{
fetched = true;
_recno = 0;
}
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
}
return fetched;
}
bool TXvt_recordset::last()
{
/* La vita sarebbe molto bella se potessi chiamare la funzione FetchLast(),
// siccome non so la posizione del record eseguo ciclicamente Next
// _RCS(_recset)->FetchLast();
while (Next())
{
_recno++;
}
*/
bool fetched = false;
try
{
if (_RCS(_recset)->FetchLast())
{
fetched = true;
_recno = 0;
}
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
}
return fetched;
}
bool TXvt_recordset::go(int newPos)
{
// Controllo che la nuova posizione non sia fuori dal limite inferiore (Non so quanto è grande il recordset)
bool result = newPos >= 0 ? true : false;
// Se la posizione è minore mi sposto indietro
while (newPos < _recno && result)
{
result = prev();
}
// Se la posizione è maggiore mi sposto in avanti
while (newPos > _recno && result)
{
result = next();
}
/*
// Controllo finale per prevenire errori
if (newPos == _recno)
return true;
else
return false;
*/
return result;
}
const int TXvt_recordset::rowsAffected()
{
return _RCS(_recset)->RowsAffected();
}
int TXvt_recordset::get_int(const char* field)
{
try
{
return static_cast<int>(_RCS(_recset)->Field(field).asLong());
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return -1;
}
}
short TXvt_recordset::get_short(const char* field)
{
try
{
return _RCS(_recset)->Field(field).asShort();
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return -1;
}
}
long TXvt_recordset::get_long(const char* field)
{
try
{
return _RCS(_recset)->Field(field).asLong();
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return -1;
}
}
double TXvt_recordset::get_double(const char* field)
{
try
{
return _RCS(_recset)->Field(field).asDouble();
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return -1;
}
}
bool TXvt_recordset::get_bool(const char* field)
{
try
{
return _RCS(_recset)->Field(field).asBool();
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return false;
}
}
/*
real TXvt_recordset::GetReal(const char * field)
{
return Get(field);
}
*/
const char* TXvt_recordset::get_date(const char * field)
{
try
{
SADateTime app = _RCS(_recset)->Field(field).asDateTime();
static char date[8];
sprintf_s(date, sizeof(date), "%d%d%d", app.GetYear(), app.GetMonth(), app.GetDay());
return date;
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return NULL;
}
}
const char* TXvt_recordset::get(const char* field)
{
try
{
return static_cast<const char *>(_RCS(_recset)->Field(field).asString());
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return "";
}
}
char TXvt_recordset::get_char(const char* field)
{
try
{
return _RCS(_recset)->Field(field).asString()[0];
}
catch (SAException &x)
{
_code_error = x.ErrNativeCode();
_GET_ERROR(x.ErrMessage(), _string_error);
_GET_ERROR(x.ErrText(), _string_error_full_text);
return '\0';
}
}
long TXvt_recordset::get_code_error(bool erase)
{
long app = _code_error;
if (erase)
_code_error = NOERR;
return app;
}
const char* TXvt_recordset::get_string_error(bool erase)
{
static char* app;
if (app != nullptr)
delete app;
_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);
if (erase)
_string_error_full_text = "";
return app;
}
const bool TXvt_recordset::setErrorFreezed()
{
_code_error = ERROR_FREEZED;
_string_error = _string_error_full_text = ERROR_FREEZEDS;
return false;
}