#include #include #include #include #include #include #include #include #include "ba2900.h" #include //#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ò le query while(!queryFile.eof()) { char aganaye[10000]; queryFile.getline(aganaye, 10000); // Sei stronzo se fai una riga con più 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 è 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 " <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ù 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ù chiavi // test // Carico la token string che metterò 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ù 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à 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; }