Files correlati : ba7.exe ba7100a.mak Commento : Invio postino con ODBC
1102 lines
29 KiB
C++
1102 lines
29 KiB
C++
#include <applicat.h>
|
||
#include <automask.h>
|
||
#include <progind.h>
|
||
#include <odbcrset.h>
|
||
#include <relation.h>
|
||
#include <utility.h>
|
||
#include <extcdecl.h>
|
||
#include <real.h>
|
||
|
||
#include "ba2900.h"
|
||
#include <xvtdb.h>
|
||
//#include "tsdb.h"
|
||
#include "codeb.h"
|
||
#include "reputils.h"
|
||
|
||
#define TABELLE_CAMPO 171
|
||
|
||
void check_range_tab(TMask& msk)
|
||
{
|
||
if (msk.get_int(F_FROMTAB) == 7466)
|
||
{
|
||
msk.show(F_MYRANGE);
|
||
msk.set(F_FROMTAB, 2);
|
||
}
|
||
else
|
||
{
|
||
if (msk.get_int(F_FROMTAB) < 2)
|
||
msk.set(F_FROMTAB, 2);
|
||
if (msk.get_int(F_FROMTAB) > prefix().items())
|
||
msk.set(F_FROMTAB, prefix().items());
|
||
if (msk.get_int(F_TOTAB) < msk.get_int(F_FROMTAB))
|
||
msk.set(F_TOTAB, msk.get_int(F_FROMTAB));
|
||
if (msk.get_int(F_TOTAB) > prefix().items())
|
||
msk.set(F_TOTAB, prefix().items());
|
||
}
|
||
}
|
||
|
||
class TMSSQLExport_msk : public TAutomask
|
||
{
|
||
protected:
|
||
virtual long handler(WINDOW task, EVENT* ep);
|
||
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
|
||
public:
|
||
TMSSQLExport_msk();
|
||
~TMSSQLExport_msk();
|
||
};
|
||
|
||
long TMSSQLExport_msk::handler(WINDOW task, EVENT* ep)
|
||
{
|
||
if (ep->type == E_TIMER)
|
||
{
|
||
if (is_running())
|
||
stop_run(K_ENTER);
|
||
}
|
||
return TAutomask::handler(task, ep);
|
||
}
|
||
|
||
bool TMSSQLExport_msk::on_field_event(TOperable_field& o, TField_event e, long jolly)
|
||
{
|
||
switch (o.dlg())
|
||
{
|
||
case 1:
|
||
/*
|
||
case F_FILES:
|
||
if (e == se_query_add || e == se_query_del)
|
||
return false;
|
||
*/
|
||
case CHK_ONLYTAB:
|
||
if (e == fe_modify)
|
||
{
|
||
get_bool(CHK_ONLYTAB) ? enable(F_FROMTAB) : disable(F_FROMTAB);
|
||
get_bool(CHK_ONLYTAB) ? enable(F_TOTAB) : disable(F_TOTAB);
|
||
}
|
||
break;
|
||
case CHK_EXPORTTABLES:
|
||
if (e == fe_modify)
|
||
{
|
||
get_bool(CHK_EXPORTTABLES) ? enable(CHK_ONLYTAB) : disable(CHK_ONLYTAB);
|
||
break;
|
||
}
|
||
default:
|
||
check_range_tab(*this);
|
||
break;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
TMSSQLExport_msk::TMSSQLExport_msk() : TAutomask("ba2900a")
|
||
{
|
||
set(F_DSN, ini_get_string(CONFIG_DITTA, "Campo_MSSQL_Export", "DSN"));
|
||
set(F_USR, ini_get_string(CONFIG_DITTA, "Campo_MSSQL_Export", "User"));
|
||
set(F_PWD, ini_get_string(CONFIG_DITTA, "Campo_MSSQL_Export", "Password"));
|
||
//set(CHK_CREATEGEN, "X");
|
||
set(CHK_CREATETABLES, "X");
|
||
//set(CHK_EXPORTGEN, "X");
|
||
set(CHK_EXPORTTABLES, "X");
|
||
set(F_FROMTAB, 2);
|
||
set(F_TOTAB, prefix().items());
|
||
}
|
||
|
||
TMSSQLExport_msk::~TMSSQLExport_msk()
|
||
{
|
||
ini_set_string(CONFIG_DITTA, "Campo_MSSQL_Export", "DSN", TMask::get(F_DSN));
|
||
ini_set_string(CONFIG_DITTA, "Campo_MSSQL_Export", "User", TMask::get(F_USR));
|
||
ini_set_string(CONFIG_DITTA, "Campo_MSSQL_Export", "Password", TMask::get(F_PWD));
|
||
}
|
||
|
||
class TMSSQLExport_app : public TSkeleton_application
|
||
{
|
||
protected:
|
||
TToken_string _tables;
|
||
TString _DSN, _usr, _psw;
|
||
SSimple_query* _db;
|
||
TMSSQLExport_msk* _msk;
|
||
TLog_report* _log;
|
||
TString _logstr;
|
||
|
||
bool _visual;
|
||
const TString toEscape (TString val) const; // Prende una stringa e sistema i caratteri di escape
|
||
const TString toDate (TString val) const; // Prende una stringa e la trasforma in una data di mssql
|
||
const TString queryToNull (TString val) const; // Da una query sostituisce tutti i valori vuoti ('') con null
|
||
//*****************************************************************
|
||
bool empty_tables() const;
|
||
bool rko_gen() const;
|
||
bool expor_gen() const;
|
||
bool file_valid(int logicnum) const;
|
||
int export_tables();
|
||
bool create_gen() const;
|
||
static TString tab_name(int logicnum, TString& ditta_name);
|
||
void set_range_tab(int& logicnum, int& endtab) const;
|
||
bool create_tables() const;
|
||
bool create_indexes() const;
|
||
bool rko_outta_nowhere(const char* table_name) const;
|
||
bool empty_tables(const char* table_name) const;
|
||
// Funzioni di esportazione
|
||
bool dir_gen() const;
|
||
bool trc_gen() const;
|
||
bool export_manager(const TString generalErrors) const;
|
||
bool show_log();
|
||
void log(int severity, const char* msg);
|
||
|
||
public:
|
||
bool my_range();
|
||
virtual void main_loop();
|
||
void set_table(TToken_string s) { _tables = s; }
|
||
bool set_parameters(TString dsn, TString utente, TString password);
|
||
bool connect(const TString& _DSN, const TString& _usr, const TString& _psw);
|
||
//bool checkParameters() { TODBC_recordset connTest(""); return connTest.connect(_DSN, _usr, _psw) ? set_parameters(_DSN, _usr, _psw) : false; }
|
||
bool test_field_seq(int val, int arr[]) const;
|
||
bool create_gen_ms() const;
|
||
TMSSQLExport_app() : _visual(false) { }
|
||
~TMSSQLExport_app() { delete _db; }
|
||
};
|
||
|
||
// Funzioni Utility ****************************************************************************************************************************
|
||
const TString TMSSQLExport_app::toEscape(TString val) const
|
||
{
|
||
TString app;
|
||
for(int k = 0; k < val.len(); k++)
|
||
{
|
||
switch (val[k])
|
||
{
|
||
case '\'':
|
||
app << "''";
|
||
break;
|
||
default:
|
||
app << val[k];
|
||
break;
|
||
}
|
||
}
|
||
return app;
|
||
}
|
||
|
||
const TString TMSSQLExport_app::queryToNull(TString val) const
|
||
{
|
||
int lastpos = val.find("(\'\'", 0); // Devo trovarne uno tra virgole
|
||
while(lastpos != -1)
|
||
{
|
||
lastpos++;
|
||
val[lastpos] = ' ';
|
||
val[lastpos+1] = ' ';
|
||
val.insert("NULL", lastpos);
|
||
lastpos = val.find(",\'\'", lastpos);
|
||
}
|
||
lastpos = val.find(",\'\'", 0); // Devo trovarne uno tra virgole
|
||
while(lastpos != -1)
|
||
{
|
||
lastpos++;
|
||
val[lastpos] = ' ';
|
||
val[lastpos+1] = ' ';
|
||
val.insert("NULL", lastpos);
|
||
lastpos = val.find(",\'\'", lastpos);
|
||
}
|
||
|
||
return val;
|
||
}
|
||
|
||
const TString TMSSQLExport_app::toDate(TString val) const
|
||
{
|
||
// Trasforma una data 11-03-2016 in 2013-03-11 accettabile da MSSQL
|
||
TString app;
|
||
app << val[6] << val[7] << val[8] << val[9] << "-" << val[3] << val[4] << "-" << val[0] << val[1]; // I codici quelli belli
|
||
return app;
|
||
}
|
||
|
||
|
||
bool TMSSQLExport_app::set_parameters(TString dsn, TString utente, TString password)
|
||
{
|
||
// Salvo i parametri
|
||
ini_set_string(CONFIG_DITTA, "Campo_MSSQL_Export", "_DSN", dsn);
|
||
ini_set_string(CONFIG_DITTA, "Campo_MSSQL_Export", "User", utente);
|
||
ini_set_string(CONFIG_DITTA, "Campo_MSSQL_Export", "Password", password);
|
||
_DSN = dsn;
|
||
_usr = utente;
|
||
_psw = password;
|
||
return true;
|
||
}
|
||
|
||
bool TMSSQLExport_app::empty_tables() const
|
||
{
|
||
TODBC_recordset sqlset("");
|
||
TString table;
|
||
|
||
if (!sqlset.connect(_DSN, _usr, _psw))
|
||
return false;
|
||
|
||
for (int i = 0; i < _tables.size(); i++)
|
||
{
|
||
TString theQuery; // The query: una tabella (donna) per cui uccidere
|
||
|
||
_tables.get(i, table);
|
||
theQuery << "DELETE FROM "<< table << ";";
|
||
sqlset.exec(theQuery);
|
||
}
|
||
// Committo i cambiamenti
|
||
sqlset.exec("COMMIT;");
|
||
return true;
|
||
}
|
||
|
||
bool TMSSQLExport_app::rko_gen() const
|
||
{
|
||
TString query;
|
||
query <<
|
||
"DROP TABLE [dir_gen];";
|
||
if (!_db->sq_set_exec(query))
|
||
return false;
|
||
|
||
query.cut(0) <<
|
||
"DROP TABLE [trc_gen];";
|
||
if (!_db->sq_set_exec(query))
|
||
return false;
|
||
|
||
query.cut(0) <<
|
||
"DROP TABLE [trc_keydes];";
|
||
if (!_db->sq_set_exec(query))
|
||
return false;
|
||
|
||
query.cut(0) <<
|
||
"DROP TABLE [trc_recfdes];";
|
||
if (!_db->sq_set_exec(query))
|
||
return false;
|
||
|
||
return _db->sq_commit();
|
||
}
|
||
|
||
// Controllo che il valore passato sia > e diverso da quelli presenti nell'array
|
||
bool TMSSQLExport_app::test_field_seq(int val, int arr[]) const
|
||
{
|
||
for (int i = 0; i < MKFields; i++)
|
||
if(val == arr[i] || val < arr[i]) return false;
|
||
return true;
|
||
}
|
||
|
||
// Main Program *****************************************************************************************************************************************************************
|
||
bool TMSSQLExport_app::create_gen_ms() const
|
||
{
|
||
|
||
rko_gen();
|
||
TString query;
|
||
query <<
|
||
"IF OBJECT_ID('dbo.dir_gen', 'U') IS NOT NULL DROP TABLE dbo.dir_gen;\n" <<
|
||
"CREATE TABLE[dbo].[dir_gen](\n" <<
|
||
"[_ID_][int] IDENTITY(1, 1) NOT NULL,\n" <<
|
||
"[NUMERO][int] NOT NULL,\n" <<
|
||
"[SYSNAME] VARCHAR(MAX) NOT NULL,\n" <<
|
||
"[EOD][int] NULL,\n" <<
|
||
"[EOX][int] NULL,\n" <<
|
||
"[FLAGS][int] NULL,\n" <<
|
||
"[LENR][int] NULL,\n" <<
|
||
"[DES] VARCHAR(MAX) NULL,\n" <<
|
||
"[CALC] VARCHAR(MAX) NULL,\n" <<
|
||
"[GENPROMPT] VARCHAR(MAX) NULL,\n" <<
|
||
"PRIMARY KEY CLUSTERED\n" <<
|
||
"([_ID_] ASC) WITH\n" <<
|
||
"(PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON[PRIMARY]\n" <<
|
||
") ON[PRIMARY] TEXTIMAGE_ON[PRIMARY];";
|
||
|
||
if (!_db->sq_set_exec(query))
|
||
return false;
|
||
|
||
query.cut(0) <<
|
||
"IF OBJECT_ID('dbo.trc_gen', 'U') IS NOT NULL DROP TABLE dbo.trc_gen;\n" <<
|
||
"CREATE TABLE[dbo].[trc_gen](\n" <<
|
||
"[_ID_][int] IDENTITY(1, 1) NOT NULL,\n" <<
|
||
"[NFields][int] NOT NULL,\n" <<
|
||
"[SortFd] VARCHAR(MAX) NULL,\n" <<
|
||
"[NKeys][int] NOT NULL,\n" <<
|
||
"[logicname][int] NOT NULL\n" <<
|
||
") ON[PRIMARY] TEXTIMAGE_ON[PRIMARY];";
|
||
|
||
if (!_db->sq_set_exec(query))
|
||
return false;
|
||
|
||
query.cut(0) <<
|
||
"IF OBJECT_ID('dbo.trc_keydes', 'U') IS NOT NULL DROP TABLE dbo.trc_keydes;\n" <<
|
||
"CREATE TABLE[dbo].[trc_keydes](\n" <<
|
||
"[_ID_][int] IDENTITY(1, 1) NOT NULL,\n" <<
|
||
"[DupKeys][int] NOT NULL,\n" <<
|
||
"[NkFields][int] NOT NULL,\n" <<
|
||
"[FieldSeq] VARCHAR(MAX) NULL,\n" <<
|
||
"[FromCh] VARCHAR(MAX) NULL,\n" <<
|
||
"[ToCh] VARCHAR(MAX) NULL,\n" <<
|
||
"[logicname][int] NOT NULL\n" <<
|
||
") ON[PRIMARY] TEXTIMAGE_ON[PRIMARY];";
|
||
|
||
if (!_db->sq_set_exec(query))
|
||
return false;
|
||
|
||
query.cut(0) <<
|
||
"IF OBJECT_ID('dbo.trc_recfdes', 'U') IS NOT NULL DROP TABLE dbo.trc_recfdes;\n" <<
|
||
"CREATE TABLE[dbo].[trc_recfdes](\n" <<
|
||
"[_ID_][int] IDENTITY(1, 1) NOT NULL,\n" <<
|
||
"[Name] VARCHAR(MAX) NOT NULL,\n" <<
|
||
"[TypeF][int] NOT NULL,\n" <<
|
||
"[Len][int] NULL,\n" <<
|
||
"[Dec][int] NULL,\n" <<
|
||
"[RecOff][int] NULL,\n" <<
|
||
"[logicname][int] NOT NULL\n" <<
|
||
") ON[PRIMARY] TEXTIMAGE_ON[PRIMARY];";
|
||
|
||
if (!_db->sq_set_exec(query))
|
||
return false;
|
||
|
||
return _db->sq_commit();
|
||
|
||
}
|
||
bool TMSSQLExport_app::create_gen() const
|
||
{
|
||
ifstream queryFile; // stream dei files con le query
|
||
|
||
// Prima le tabelle gen
|
||
TFilename gen("sql\\gensql.sql");
|
||
queryFile.open(gen);
|
||
if(queryFile.is_open())
|
||
{
|
||
TString gensql; // Qua metter<65> le query
|
||
while(!queryFile.eof())
|
||
{
|
||
char aganaye[10000];
|
||
queryFile.getline(aganaye, 10000); // Sei stronzo se fai una riga con pi<70> di 10.000 caratteri
|
||
gensql << aganaye;
|
||
}
|
||
queryFile.close();
|
||
if(!_db->sq_exec(gensql)) // EXEC
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
TString msg("Errore apertura file "); msg << gen;
|
||
message_box(msg);
|
||
return false;
|
||
}
|
||
|
||
// Committo la creazione iniziale delle tabelle custom fondamentali per il passaggio a DB di Campo
|
||
return _db->sq_commit();
|
||
}
|
||
|
||
TString TMSSQLExport_app::tab_name(int logicnum, TString& ditta_name)
|
||
{
|
||
const TString& table = logic2table(logicnum);
|
||
const bool studio_tab = TDir(logicnum).is_com();
|
||
return TString("[") << (!studio_tab ? ditta_name : "") << table << "]";
|
||
}
|
||
|
||
void TMSSQLExport_app::set_range_tab(int& logicnum, int& endtab) const
|
||
{
|
||
logicnum = 2;
|
||
endtab = prefix().items();
|
||
if (_msk->get_bool(CHK_ONLYTAB))
|
||
{
|
||
check_range_tab(*_msk);
|
||
logicnum = _msk->get_int(F_FROMTAB);
|
||
endtab = _msk->get_int(F_TOTAB);
|
||
endtab++;
|
||
}
|
||
}
|
||
|
||
bool TMSSQLExport_app::connect(const TString& _DSN, const TString& _usr, const TString& _psw)
|
||
{
|
||
if (_db == nullptr)
|
||
_db = new SSimple_query();
|
||
bool connected = _db->sq_is_connect();
|
||
if (!connected)
|
||
{
|
||
_db->sq_set_con_option("UseAPI", "OLEDB");
|
||
connected = _db->sq_connect(_DSN, _usr, _psw, TSDB_MSSQL) == NOERR;
|
||
}
|
||
return connected;
|
||
}
|
||
|
||
bool TMSSQLExport_app::create_tables() const
|
||
{
|
||
bool ok = true;
|
||
TString ditta_name; ditta_name << prefix().name() << "_";
|
||
TString last_col_name = " ";
|
||
|
||
int logicnum;
|
||
int endtab;
|
||
set_range_tab(logicnum, endtab);
|
||
|
||
for(; logicnum < endtab && ok; logicnum++)
|
||
{
|
||
last_col_name = " ";
|
||
const RecDes& rd = prefix().get_recdes(logicnum);
|
||
TString table_name = tab_name(logicnum, ditta_name);
|
||
TString column_name;
|
||
bool last_err = false;
|
||
// Droppo la tabella prima di crearla
|
||
rko_outta_nowhere(table_name);
|
||
// Create new table
|
||
if (rd.NFields == 0)
|
||
continue;
|
||
TString sql; sql.cut(0) << "CREATE TABLE " << table_name << "(\n";
|
||
sql << "[_ID_][int] IDENTITY(1, 1) NOT NULL,\n";
|
||
for (int i = 0; i < rd.NFields; i++)
|
||
{
|
||
|
||
if (i > 0 && !last_err) sql << ",\n";
|
||
column_name.cut(0) << "[" << rd.Fd[i].Name << "] ";
|
||
if (column_name == last_col_name)
|
||
{
|
||
last_err = true;
|
||
continue;
|
||
}
|
||
last_err = false;
|
||
last_col_name = column_name;
|
||
sql << column_name;
|
||
switch (rd.Fd[i].TypeF)
|
||
{
|
||
case _charfld:
|
||
case _alfafld:
|
||
sql << "VARCHAR(" << rd.Fd[i].Len << ")";
|
||
break;
|
||
case _memofld:
|
||
sql << "VARCHAR(MAX)"; break;
|
||
case _datefld:
|
||
sql << "DATE"; break;
|
||
case _boolfld:
|
||
sql << "BIT DEFAULT 0"; break;
|
||
case _realfld:
|
||
case _wordfld:
|
||
case _intfld:
|
||
case _longfld:
|
||
case _intzerofld:
|
||
case _longzerofld:
|
||
default: sql << "NUMERIC(" << rd.Fd[i].Len << "," << rd.Fd[i].Dec << ")"; break;
|
||
}
|
||
}
|
||
sql << "\n);";
|
||
|
||
ok = _db->sq_set_exec(sql) && _db->sq_commit();
|
||
TString err = _db->sq_get_string_error();
|
||
TString err2 = _db->sq_get_text_error();
|
||
}
|
||
return ok;
|
||
}
|
||
|
||
/*
|
||
* Creatore di indici NON CLUSTER per campo
|
||
* Sintassi: CREATE NONCLUSTERED INDEX nome_indice ON nome_tabella (colonna1 [ASC | DESC], colonna2 [ASC | DESC][,...n])
|
||
*
|
||
*/
|
||
bool TMSSQLExport_app::create_indexes() const
|
||
{
|
||
TODBC_recordset sqlset("");
|
||
if (!sqlset.connect(_DSN, _usr, _psw))
|
||
return "Connessione fallita!";
|
||
int items = TABELLE_CAMPO; // Numero totale di tabelle
|
||
COpenDir((int)_manulock, NORDIR); // Apro dir.gen
|
||
|
||
// Creo il cursore delle ditte per i nomi delle tabelle
|
||
TRelation relTDitte(LF_NDITTE);
|
||
TCursor curDitte(&relTDitte);
|
||
int itemsDitte = curDitte.items();
|
||
|
||
TProgress_monitor p(items, "Creazione indici");
|
||
for (int i = 2; i < items; i++)
|
||
{
|
||
if (!p.add_status())
|
||
break;
|
||
if (i > 30 && i != 171) continue;
|
||
FileDes d;
|
||
CGetFile(i, &d, _nolock, NORDIR);
|
||
|
||
RecDes r;
|
||
CGetRec(i, &r, NORDIR);
|
||
for (int k = 0; k < r.NKeys; k++)
|
||
{
|
||
KeyDes key = r.Ky[k];
|
||
// Precarico le chiavi
|
||
TString columns;
|
||
for(int j = 0; j < key.NkFields; j++)
|
||
{
|
||
// Trovo il numero del campo
|
||
int field = (int)key.FieldSeq[j];
|
||
// Controllo se <20> upper
|
||
bool upper = false;
|
||
if (field > 100)
|
||
{
|
||
field -= 100;
|
||
upper = true;
|
||
}
|
||
|
||
// Lo vado a trovare in RecFieldDes
|
||
RecFieldDes fDes = r.Fd[field];
|
||
|
||
columns << (false ? "UPPER (" : "") << fDes.Name << (false ? ")," : ","); // Disabilitato upper
|
||
}
|
||
columns << "_ID_";
|
||
|
||
TString sqlQuery(""); // Inizio la creazione dell'indice
|
||
TString indexName;
|
||
if(d.SysName[0] == '%')
|
||
{
|
||
indexName << "CI_" << TString(d.SysName + 1).upper() << "_K" << k + 1;
|
||
TString tableName; tableName << "[" << d.SysName + 1 << "]";
|
||
//Creo la query
|
||
sqlQuery << "CREATE NONCLUSTERED INDEX " << indexName << " ON [" << d.SysName + 1 << "] (" << columns << ");";
|
||
}
|
||
else
|
||
{
|
||
// Ciclo per ogni azienda
|
||
for(curDitte = 0; curDitte.pos() < curDitte.items(); ++curDitte)
|
||
{
|
||
TRectype dittaCurr = curDitte.curr();
|
||
TString nomeDitta(dittaCurr.get("CODDITTA"));
|
||
for (int i = 0, applen = nomeDitta.len(); i < 5 - applen; i++)
|
||
nomeDitta.insert("0");
|
||
|
||
indexName = TString("CI_") << nomeDitta << "A_" << TString(d.SysName + 1).upper() << "_K" << k + 1;
|
||
TString tableName; tableName << "[" << nomeDitta << "A_" << d.SysName + 1 << "]";
|
||
// Aggiungo alla query
|
||
sqlQuery << "CREATE NONCLUSTERED INDEX " <<indexName << " ON "<< tableName << " (" << columns << ");";
|
||
}
|
||
}
|
||
if(sqlset.exec(queryToNull(sqlQuery)) != 1)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
if(sqlset.commit() == -1)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool TMSSQLExport_app::rko_outta_nowhere(const char* table_name) const
|
||
{
|
||
_db->sq_set_exec(TString().cut(0) << "DROP TABLE " << table_name << ';');
|
||
return _db->sq_commit();
|
||
}
|
||
|
||
bool TMSSQLExport_app::empty_tables(const char* table_name) const
|
||
{
|
||
const bool ok = _db->sq_set_exec(TString().cut(0) << "DELETE FROM " << table_name << ';');
|
||
return ok && _db->sq_commit();
|
||
}
|
||
|
||
bool TMSSQLExport_app::expor_gen() const
|
||
{
|
||
return rko_gen() && create_gen_ms() && dir_gen() && trc_gen();
|
||
}
|
||
|
||
bool TMSSQLExport_app::file_valid(int logicnum) const
|
||
{
|
||
TFilename filename;
|
||
const TIsam_handle isam_handle = prefix().open_isamfile(logicnum, filename, false, true);
|
||
const TCodeb_handle fhnd = isam_handle > 0 ? prefix().get_handle(isam_handle, 1) : isam_handle;
|
||
const int trcreclen = prefix().get_reclen(logicnum);
|
||
const int dbfreclen = DB_reclen(fhnd);
|
||
return dbfreclen == trcreclen;
|
||
}
|
||
|
||
const TString to_escape(const TString& val)
|
||
{
|
||
TString& app = get_tmp_string();
|
||
for (int k = 0; k < val.len(); k++)
|
||
{
|
||
switch (val[k])
|
||
{
|
||
case '\'':
|
||
app << "''";
|
||
break;
|
||
default:
|
||
app << val[k];
|
||
break;
|
||
}
|
||
}
|
||
return app;
|
||
}
|
||
|
||
const TString query_to_null(TString& val)
|
||
{
|
||
int lastpos = val.find("(\'\'", 0); // Devo trovarne uno tra virgole
|
||
while (lastpos != -1)
|
||
{
|
||
lastpos++;
|
||
val[lastpos] = ' ';
|
||
val[lastpos + 1] = ' ';
|
||
val.insert("NULL", lastpos);
|
||
lastpos = val.find(",\'\'", lastpos);
|
||
}
|
||
lastpos = val.find(",\'\'", 0); // Devo trovarne uno tra virgole
|
||
while (lastpos != -1)
|
||
{
|
||
lastpos++;
|
||
val[lastpos] = ' ';
|
||
val[lastpos + 1] = ' ';
|
||
val.insert("NULL", lastpos);
|
||
lastpos = val.find(",\'\'", lastpos);
|
||
}
|
||
|
||
return val;
|
||
}
|
||
|
||
int TMSSQLExport_app::export_tables()
|
||
{
|
||
// Innanzitutto svuoto le tabelle
|
||
|
||
bool check = true;
|
||
TString ditta_name; ditta_name << prefix().name() << "_";
|
||
|
||
int logicnum;
|
||
int endtab;
|
||
set_range_tab(logicnum, endtab);
|
||
int last_tab_err = -1;
|
||
|
||
for (; logicnum < endtab && check; logicnum++)
|
||
{
|
||
empty_tables(logic2table(logicnum));
|
||
TString nome_tab = tab_name(logicnum, ditta_name);
|
||
const RecDes& rd = prefix().get_recdes(logicnum);
|
||
if (prefix().get_recdes(logicnum).NKeys <= 0)
|
||
{
|
||
log(2, TString("Il file ") << logicnum << " non esiste");
|
||
continue;
|
||
}
|
||
TLocalisamfile table(logicnum);
|
||
if(!file_valid(logicnum))
|
||
{
|
||
log(2, TString("Impossibile esportare il file ") << logicnum << ". Lunghezza record incoerente.");
|
||
continue;
|
||
}
|
||
|
||
TString queryF, queryV;
|
||
TProgress_monitor p(table.items(), TString("Esportazione tabella ") << logic2table(logicnum));
|
||
bool export_status = true;
|
||
bool ok = table.first() == NOERR;
|
||
for (; ok && export_status; ok = table.next() == NOERR)
|
||
{
|
||
if (_visual && !p.add_status())
|
||
return logicnum;
|
||
queryF.cut(0) << "INSERT INTO " << nome_tab << " (";
|
||
queryV.cut(0) << "(";
|
||
for (int k = 0; k < rd.NFields; k++)
|
||
{
|
||
queryF << "[" << rd.Fd[k].Name << "]";
|
||
if (table.get(rd.Fd[k].Name).empty()) // Vuoto, causa errori se non controllato
|
||
queryV << "''";
|
||
else
|
||
{
|
||
switch (rd.Fd[k].TypeF)
|
||
{
|
||
case _intfld:
|
||
case _wordfld:
|
||
case _intzerofld:
|
||
queryV << "'" << table.get_int(rd.Fd[k].Name) << "'";
|
||
break;
|
||
|
||
case _longfld:
|
||
case _longzerofld:
|
||
queryV << "'" << table.get_long(rd.Fd[k].Name) << "'";
|
||
break;
|
||
|
||
// Real
|
||
case _realfld:
|
||
queryV << "'" << table.get_real(rd.Fd[k].Name).string() << "'";
|
||
break;
|
||
|
||
case _datefld:
|
||
queryV << "'" << table.get_date(rd.Fd[k].Name).date2ansi() << "'";
|
||
break;
|
||
|
||
case _boolfld:
|
||
if (table.get_bool(rd.Fd[k].Name))
|
||
queryV << "'1'";
|
||
else
|
||
queryV << "'0'";
|
||
break;
|
||
|
||
case _charfld:
|
||
case _alfafld:
|
||
default:
|
||
queryV << "'" << to_escape(table.get(rd.Fd[k].Name)) << "'";
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (k + 1 < rd.NFields) // Modo pi<70> comodo
|
||
{
|
||
queryF << ",";
|
||
queryV << ",";
|
||
}
|
||
}
|
||
|
||
|
||
queryV << ")";
|
||
queryF << ") VALUES " << queryV;
|
||
//export_status &= _db->sq_set_exec(query_to_null(queryF));
|
||
if(!_db->sq_set_exec(query_to_null(queryF), false))
|
||
{
|
||
if (last_tab_err != logicnum)
|
||
{
|
||
log(2, TString("Errore esportazione tabella ") << logicnum << "\n\tQuery:" << queryF);
|
||
last_tab_err = logicnum;
|
||
}
|
||
else
|
||
log(2, TString("\tQuery: ") << queryF);
|
||
log(2, _db->sq_get_string_error());
|
||
log(2, _db->sq_get_text_error());
|
||
}
|
||
}
|
||
check = export_status && _db->sq_commit();
|
||
}
|
||
return check ? 0 : -1;
|
||
}
|
||
|
||
bool TMSSQLExport_app::dir_gen() const
|
||
{
|
||
const int items = prefix().items()-1; // Numero totale di tabelle
|
||
const TString msg("Esportazione elenco directory");
|
||
COpenDir((int)_manulock, NORDIR); // Apro dir.gen
|
||
TProgress_monitor p(items, msg);
|
||
for (int i = 1; i <= items && !p.is_cancelled(); i++)
|
||
{
|
||
if (!p.add_status())
|
||
break;
|
||
FileDes d;
|
||
CGetFile(i, &d, _nolock, NORDIR);
|
||
TString sqlQuery;
|
||
sqlQuery
|
||
<< "INSERT INTO DIR_GEN (NUMERO,SYSNAME,EOD,EOX,LENR,FLAGS,DES,CALC,GENPROMPT) VALUES ('"
|
||
<< i << "','"
|
||
<< d.SysName << "','"
|
||
<< d.EOD << "','"
|
||
<< d.EOX << "','"
|
||
<< d.LenR << "','"
|
||
<< d.Flags << "','"
|
||
<< toEscape(d.Des) << "','"
|
||
<< toEscape(d.FCalc) << "','"
|
||
<< toEscape(d.GenPrompt) << "')";
|
||
if(!_db->sq_set_exec(queryToNull(sqlQuery), false))
|
||
return false;
|
||
}
|
||
return _db->sq_commit();
|
||
}
|
||
|
||
bool TMSSQLExport_app::trc_gen() const
|
||
{
|
||
const int items = prefix().items()-1; // Numero totale di tabelle
|
||
const TString msg("Esportazione tracciati record");
|
||
COpenDir((int)_manulock, NORDIR); // Apro dir.gen
|
||
TProgress_monitor p(items-1, msg);
|
||
for (int i = 2; i <= items && !p.is_cancelled(); i++)
|
||
{
|
||
if (!p.add_status()) // Fallisce se il numero di elenti / il numero di secondi fa 0 wtf!?
|
||
break;
|
||
RecDes d;
|
||
CGetRec(i, &d, NORDIR);
|
||
|
||
// Prima la tabella trc_gen
|
||
TToken_string SortFd("");
|
||
int appFd = 0;
|
||
do
|
||
{
|
||
SortFd.add((int)d.SortFd[appFd]);
|
||
appFd++;
|
||
} while (appFd < MaxFields);
|
||
|
||
TString sqlQueryTrc;
|
||
sqlQueryTrc
|
||
<< "INSERT INTO TRC_GEN (NFields,SortFd,NKeys,logicname) VALUES ('"
|
||
<< d.NFields << "','"
|
||
<< SortFd << "','"
|
||
<< d.NKeys << "','"
|
||
<< i << "')";
|
||
if(!_db->sq_set_exec(queryToNull(sqlQueryTrc), false))
|
||
return false;
|
||
|
||
// Poi trc_recfdes
|
||
for (int j = 0; j < d.NFields; j++)
|
||
{
|
||
RecFieldDes r = d.Fd[j];
|
||
TString sqlQueryRFD;
|
||
sqlQueryRFD
|
||
<< "INSERT INTO TRC_RECFDES (Name,TypeF,Len,Dec,RecOff,logicname) VALUES ('"
|
||
<< r.Name << "','"
|
||
<< (int)r.TypeF << "','"
|
||
<< r.Len << "','"
|
||
<< r.Dec << "','"
|
||
<< r.RecOff << "','"
|
||
<< i << "')";
|
||
if(!_db->sq_set_exec(queryToNull(sqlQueryRFD), false))
|
||
return false;
|
||
}
|
||
|
||
//Infine trc_keydes
|
||
for (int j = 0; j < MaxKeys; j++)
|
||
{
|
||
KeyDes k = d.Ky[j];
|
||
if (k.NkFields == 0) break; // Esco se non esistono pi<70> chiavi
|
||
// test
|
||
// Carico la token string che metter<65> nel DB con i valori presenti in FieldSeq,
|
||
// siccome i valori possono essere sporchi (mannaggina) controllo che dopo la prima chiave (must have) le altre celle non abbiano un valore fuori range o != 0
|
||
TToken_string FieldSeq("");
|
||
int appFS = 0, vappFS[MKFields] = { 0 };
|
||
// Metto tanti valori quanti ne sono presenti in NkFields
|
||
for(int i = 0; i < k.NkFields; i++)
|
||
FieldSeq.add((int)k.FieldSeq[i]);
|
||
// FromCh, ToCh
|
||
TToken_string FromCh(""), ToCh("");
|
||
int app = 0;
|
||
do
|
||
{
|
||
FromCh.add((int)k.FromCh[app]);
|
||
ToCh.add((int)k.ToCh[app]);
|
||
app++;
|
||
} while (app < MKFields);
|
||
|
||
TString sqlQueryKD;
|
||
sqlQueryKD
|
||
<< "INSERT INTO TRC_KEYDES (DupKeys,NkFields,FieldSeq,FromCh,ToCh,logicname) VALUES ('"
|
||
<< k.DupKeys << "','"
|
||
<< k.NkFields << "','"
|
||
<< FieldSeq << "','"
|
||
<< FromCh << "','"
|
||
<< ToCh << "','"
|
||
<< i << "')";
|
||
if(!_db->sq_set_exec(queryToNull(sqlQueryKD), false))
|
||
return false;
|
||
}
|
||
}
|
||
return _db->sq_commit();
|
||
}
|
||
|
||
bool TMSSQLExport_app::export_manager(TString generalErrors) const
|
||
{
|
||
TODBC_recordset sqlset("", true);
|
||
// Controllo la connessione
|
||
if (!sqlset.connect(_DSN, _usr, _psw))
|
||
return false;
|
||
|
||
COpenDir((int)_manulock, NORDIR); // Apro dir.gen
|
||
int items = TABELLE_CAMPO; // Numero totale di tabelle
|
||
TString msg("Esportazione Tabelle");
|
||
TProgress_monitor p(items-1, msg);
|
||
|
||
for (int i = 2; i <= items && !p.is_cancelled(); i++)
|
||
{
|
||
if (!p.add_status())
|
||
break;
|
||
if (i > 30 && i != 171) continue;
|
||
FileDes fd;
|
||
CGetFile(i, &fd, _nolock, NORDIR); // Informazioni per il nome tabella
|
||
|
||
RecDes rd;
|
||
CGetRec(i, &rd, NORDIR); // Informazioni per i campi
|
||
// Creo relazione e cursore
|
||
TRelation relTable(i);
|
||
TCursor curTable(&relTable);
|
||
int itemsTable = curTable.items();
|
||
TString msgTable; msgTable << "Esportazione tabella " << fd.SysName;
|
||
TProgress_monitor pTable(itemsTable, msgTable);
|
||
for(int j = curTable.pos(); curTable.pos() < itemsTable; j++, ++curTable)
|
||
{
|
||
if (!pTable.add_status())
|
||
break;
|
||
TRectype rowTable = curTable.curr();
|
||
// Creo la query con due stringhe
|
||
TString queryF, queryV;
|
||
TString prefix(fd.SysName[0] == '$' ? "00001A_" : "");
|
||
queryF << "INSERT INTO [dbo].[" << prefix << fd.SysName + 1 << "] ("; // Tolgo il simbolo iniziale
|
||
queryV << "(";
|
||
|
||
for(int k = 0; k < rd.NFields; k++)
|
||
{
|
||
// So easy, so peasy
|
||
queryF << "[" << rd.Fd[k].Name << "]";
|
||
if(rowTable.get(rd.Fd[k].Name) == '\'\'') // Vuoto, causa errori se non controllato
|
||
queryV << "''";
|
||
else
|
||
{
|
||
switch (rd.Fd[k].TypeF)
|
||
{
|
||
// Int
|
||
case 2:
|
||
case 6:
|
||
queryV << "'" << atoi(rowTable.get(rd.Fd[k].Name)) << "'";
|
||
break;
|
||
|
||
// Long
|
||
case 3:
|
||
queryV << "'" << atol(rowTable.get(rd.Fd[k].Name)) << "'";
|
||
break;
|
||
|
||
// Real
|
||
case 4:
|
||
queryV << "'" << real(rowTable.get(rd.Fd[k].Name)) << "'";
|
||
break;
|
||
|
||
case 5:
|
||
queryV << "'" << toDate(rowTable.get(rd.Fd[k].Name)) << "'";
|
||
break;
|
||
|
||
case 8:
|
||
if(rowTable.get(rd.Fd[k].Name) == "X")
|
||
queryV << "'True'";
|
||
else
|
||
queryV << "'False'";
|
||
break;
|
||
|
||
// Int zerof
|
||
case 9:
|
||
queryV << "'" << atoi(rowTable.get(rd.Fd[k].Name)) << "'";
|
||
break;
|
||
|
||
// Long zerof
|
||
case 10:
|
||
queryV << "'" << atol(rowTable.get(rd.Fd[k].Name)) << "'";
|
||
break;
|
||
|
||
default:
|
||
queryV << "'" << toEscape(rowTable.get(rd.Fd[k].Name)) << "'";
|
||
break;
|
||
}
|
||
}
|
||
if( k+1 < rd.NFields ) // Modo pi<70> comodo
|
||
{
|
||
queryF << ",";
|
||
queryV << ",";
|
||
}
|
||
}
|
||
queryV << ")";
|
||
queryF << ") VALUES " << queryV;
|
||
TString app(queryToNull(queryF));
|
||
if(sqlset.exec(queryToNull(queryF)) != 1)
|
||
{
|
||
generalErrors << "ERRORE " << fd.SysName + 1;
|
||
return false;
|
||
}
|
||
}
|
||
if(sqlset.commit() == -1)
|
||
{
|
||
generalErrors << "ERRORE GENERALE ESPORTAZIONE TABELLA" << fd.SysName << "\n";
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool TMSSQLExport_app::show_log()
|
||
{
|
||
if (_log)
|
||
{
|
||
_log->preview();
|
||
delete _log;
|
||
_log = NULL;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void TMSSQLExport_app::log(int severity, const char* msg)
|
||
{
|
||
if (_log == nullptr)
|
||
{
|
||
_log = new TLog_report;
|
||
// Tento l'eliminazione del file
|
||
std::remove("ba_export.log");
|
||
}
|
||
if (severity < 0)
|
||
{
|
||
_logstr = msg;
|
||
}
|
||
else
|
||
{
|
||
static TString txt;
|
||
txt.cut(0);
|
||
if (_logstr.full())
|
||
{
|
||
txt << _logstr << ": " << msg;
|
||
}
|
||
else
|
||
txt << msg;
|
||
_log->log(severity, txt);
|
||
// Scrivo anche su file
|
||
std::filebuf fb;
|
||
fb.open("ba_export.log", std::ios::out | std::ios::app);
|
||
std::ostream os(&fb);
|
||
os << txt << std::endl;
|
||
fb.close();
|
||
}
|
||
}
|
||
|
||
bool TMSSQLExport_app::my_range()
|
||
{
|
||
TString myrange(_msk->get(F_MYRANGE));
|
||
if (myrange.empty())
|
||
return false;
|
||
TToken_string range_tok(myrange, ',');
|
||
if(range_tok.items() > 0)
|
||
{
|
||
TToken_string one_range(range_tok.get(0), '-');
|
||
_msk->set(F_FROMTAB, one_range.get(0));
|
||
one_range.items() == 0 ? _msk->set(F_TOTAB, one_range.get(0)) : _msk->set(F_TOTAB, one_range.get(1));
|
||
range_tok.destroy(0);
|
||
TString rewrite;
|
||
for(int i=0; i < range_tok.items(); i++)
|
||
{
|
||
if (i > 0)
|
||
rewrite << ",";
|
||
rewrite << range_tok.get();
|
||
}
|
||
_msk->set(F_MYRANGE, rewrite);
|
||
}
|
||
return !TString(_msk->get(F_MYRANGE)).empty(); // se vuoto anche solo la prima volta interrompo il loop
|
||
}
|
||
|
||
void TMSSQLExport_app::main_loop()
|
||
{
|
||
TMSSQLExport_msk msk;
|
||
_msk = &msk;
|
||
|
||
while (msk.run() == K_ENTER)
|
||
{
|
||
const TString& _DSN = msk.get(F_DSN);
|
||
const TString& _usr = msk.get(F_USR);
|
||
const TString& _psw = msk.get(F_PWD);
|
||
_visual = true;
|
||
// Chiamo la funzione globale esporta
|
||
if(connect(_DSN, _usr, _psw))
|
||
{
|
||
bool loop;
|
||
do
|
||
{
|
||
loop = my_range();
|
||
// Per comodit<69> utilizzo gli AND short circuits, solo se i bool danno true eseguo la funzione dopo!
|
||
if (msk.get_bool(CHK_CREATEGEN))
|
||
if (!create_gen_ms())
|
||
message_box("ERROR: Creazione tabelle gen fallita");
|
||
if (msk.get_bool(CHK_CREATETABLES))
|
||
if (!create_tables())
|
||
message_box("ERROR: Creazione tabelle campo fallita");
|
||
if (msk.get_bool(CHK_EXPORTGEN))
|
||
if (!expor_gen())
|
||
message_box("CERROR: Esportazione tabelle gen fallita");
|
||
if (msk.get_bool(CHK_EXPORTTABLES))
|
||
{
|
||
int err;
|
||
if ((err = export_tables()))
|
||
message_box(TString("ERROR: Esportazione tabelle campo fallita") << (err >= 2? TString(":\n Errorre tabella ") << err : ""));
|
||
}
|
||
message_box("Migrazione effettuata correttamente!");
|
||
} while (loop);
|
||
show_log();
|
||
}
|
||
else
|
||
message_box("Fallita connessione");
|
||
}
|
||
}
|
||
|
||
|
||
int ba2900(int argc, char* argv[])
|
||
{
|
||
TMSSQLExport_app app;
|
||
// Imposto le tabelle da utilizzare
|
||
app.set_table("TRC_GEN|TRC_KEYDES|TRC_RECFDES");
|
||
app.run(argc, argv, TR("Migrazione DB a MSSQL"));
|
||
return 0;
|
||
}
|