diff --git a/src/include/odbcrset.cpp b/src/include/odbcrset.cpp index 12cffac81..7e8727f3e 100755 --- a/src/include/odbcrset.cpp +++ b/src/include/odbcrset.cpp @@ -73,7 +73,7 @@ bool TODBC_recordset::connect(const char* dsn, const char* usr, const char* pwd, if (name.starts_with("ACEODB")) _driver = ODBC_access; else - if (name.starts_with("SQLSRV")) + if (name.starts_with("SQLSRV") || name.starts_with("sqlncl")) _driver = ODBC_mssql; else if (name.starts_with("MYSQL??")) diff --git a/src/include/postman.cpp b/src/include/postman.cpp index 4e91d7a45..5b8e7a491 100755 --- a/src/include/postman.cpp +++ b/src/include/postman.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -295,15 +296,131 @@ static int write_xml(TConfig& cfg, void* jolly) typedef enum { db_add, db_update, db_remove } db_op; -HIDDEN const TString & build_statement(const db_op op, int logicnum, const TString_array & keys, const TString_array & values) +const TString & table_name(int logicnum) +{ + TString & name = get_tmp_string(); + const int firm = prefix().get_codditta(); + TDir d(logicnum); + + if (d.is_firm()) + name << format("%05lda", firm) << '.'; + else + name << "COM."; + name << logic2table(logicnum); + return name; +} + +HIDDEN bool create_table(TODBC_recordset & recset, int logicnum, const char * table_name, TTrec & recdef) +{ + TString sql = "CREATE TABLE ["; + int nfields = recdef.fields(); + + sql << table_name << "](\n"; + for (int i = 0; i < nfields; i++) + { + TToken_string def = recdef.fielddef(i); + TString field(def.get(0)); + TFieldtypes t = (TFieldtypes)def.get_int(1); + + if (i > 0) + sql << ", "; + sql << "[" << field << "] "; + switch (t) + { + case _charfld: + case _alfafld: + sql << "VARCHAR(" << def.get_int(2) << ")"; + 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(" << def.get_int(2) << "," << def.get_int(3) << ")"; break; + } + + } + sql << ");\n"; + int err = recset.exec(sql); + + if (err < 0) + return false; + for (int k = 0; k < recdef.keys(); k++) + { + TToken_string key(recdef.keydef(k), '+'); + bool dupkeys = false; + int pos = key.find("|"); + int el = 0; + + if (pos > 0) + { + dupkeys = key.mid(pos + 1).full(); + key = key.left(pos); + } + sql = "CREATE "; + sql << (dupkeys ? "INDEX KEY" : "UNIQUE INDEX KEY") << k + 1 << " ON [" << table_name << "] ("; + + FOR_EACH_STR_TOKEN(key, field) + { + if (el++ > 0) + sql << ','; + if (field.starts_with("UPPER")) + { + field = field.mid(6, field.len() - 7); + sql << field << "_UPPER"; + TString alter = "ALTER TABLE ["; + + alter << table_name << "] ADD " << field << "_UPPER AS UPPER(" << field << ");"; + err = recset.exec(alter); + } + else + { + int pos = field.find("["); + + if (pos > 0) + { + TString fld = field.left(pos); + + sql << fld << "_MID"; + + const int start = atoi(field.mid(pos + 1)); + + pos = field.find(",", pos + 1); + const int end = pos > 0 ? atoi(field.mid(pos + 1)) : 0; + + TString alter = "ALTER TABLE ["; + + alter << table_name << "] ADD " << fld << "_MID AS " << (recset.driver() == ODBC_mssql ? "SUBSTRING(" : "MID(") << fld << ',' << start; + + if (end > 0) + alter << ',' << end - start + 1; + alter << ");"; + err = recset.exec(alter); + } + else + sql << field; + } + } + sql << ");\n"; + int err = recset.exec(sql); + + if (err < 0) + return false; + } + return err >= 0; +} + +HIDDEN const TString & build_statement(const db_op op, int logicnum, const char * table_name, const TString_array & keys, const TString_array & values) { TString & statement = get_tmp_string(); - TString table_name; - const int firm = prefix().get_codditta(); - if (firm > 0) - table_name << format("%05lda", firm) << '_'; - table_name << logic2table(logicnum); if (op == db_add) { statement << "INSERT INTO [" << table_name << "] ("; @@ -355,6 +472,111 @@ HIDDEN const TString & build_statement(const db_op op, int logicnum, const TStri return statement; } +HIDDEN const char * make_val(const char * fld, TFieldtypes t, TString &src) +{ + TString & val = get_tmp_string(); + int pos = src.find("'"); + + val << fld << '='; + while (pos > 0) + { + src.insert("'", pos); + pos = src.find("'", pos + 2); + } + switch (t) + { + case _alfafld: + case _charfld: + case _datefld: + case _memofld: + val << '\'' << src << '\''; + break; + case _intfld: + case _longfld: + case _realfld: + case _wordfld: + case _intzerofld: + case _longzerofld: + val << (src.blank() ? "0" : src); + break; + case _boolfld: + val << (src.blank() ? "'FALSE'" : "'TRUE'"); + break; + default: + val << src; + break; + } + return val; +} +HIDDEN bool popolate_table(TODBC_recordset & recset, int logicnum, const char * table_name, TTrec & recdef) +{ + bool ok = false; + int nfields = recdef.fields(); + TCursor c(new TRelation(logicnum)); + const long items = c.items(); + TProgress_monitor pi(items, format(TR("caricamento tabella %s"), table_name)); + + for (c.pos() = 0; pi.addstatus() && c.pos() < items; ++c) + { + TString_array values; + TString_array keys; + + for (int i = 0; i < nfields; i++) + { + TToken_string def = recdef.fielddef(i); + TString field(def.get(0)); + TFieldtypes t = (TFieldtypes)def.get_int(1); + TString str = c.curr().get(field); + TToken_string row(make_val(field, t, str), '='); + + values.add(row); + } + + TToken_string key(recdef.keydef(), '+'); + int pos = key.find("|"); + + if (pos > 0) + key = key.left(pos); + FOR_EACH_STR_TOKEN(key, field) + { + TString fld = field; + int pos = fld.find("["); + + if (pos > 0) + fld = fld.left(pos); + + TToken_string def = recdef.fielddef(recdef.field(fld)); + TFieldtypes t = (TFieldtypes)def.get_int(1); + TString str = c.curr().get(fld); + + if (pos > 0) + { + int start = atoi(field.mid(pos)); + + pos = field.find(',', pos); + str = str.smid(start, pos > 0 ? pos : 0); + } + + TToken_string row(make_val(field, t, str), '='); + + keys.add(row); + } + + const TString & statement = build_statement(db_add, logicnum, table_name, keys, values); + int err = recset.exec(statement); + + if (err <= 0) + { + const TString & statement = build_statement( db_update, logicnum, table_name, keys, values); + + err = recset.exec(statement); + } + if (err <= 0) + error_box(FR("Errore n. %d invio file %d"), logicnum, err); + } + return ok; +} + HIDDEN void odbc_send(const TString & dsn, int num, TAuto_token_string & elab_files, const TFilename & name) { TODBC_recordset recset; @@ -406,111 +628,96 @@ HIDDEN void odbc_send(const TString & dsn, int num, TAuto_token_string & elab_fi ini.set_paragraph(*row); TTrec wrk(curr_file_num); int nfields = wrk.fields(); + const TString name = table_name(curr_file_num); - for (int i = 0; i < nfields; i++) + TString check_statement = "SELECT TOP 1 * FROM ["; + + check_statement << name << "];"; + if (recset.exec(check_statement) < 0) { - TToken_string def = wrk.fielddef(i); - TString field(def.get(0)); - TFieldtypes t = (TFieldtypes)def.get_int(1); - TToken_string row(field, '='); - - TString str = ini.get(field); - TString val; - - str.strip("\""); - switch (t) - { - case _alfafld: - case _charfld: - case _datefld: - case _memofld: - val << '\'' << str << '\''; - break; - case _intfld: - case _longfld: - case _realfld: - case _wordfld: - case _intzerofld: - case _longzerofld: - val = str.blank() ? "0" : str; - break; - case _boolfld: - val = str.blank() ? "'FALSE'" : "'TRUE'"; - break; - default: - val = str; - break; - } - row.add(val); - values.add(row); + create_table(recset, num, name, wrk); + popolate_table(recset, num, name, wrk); + recset.exec("COMMIT;"); } - - TToken_string key(wrk.keydef(), '+'); - int pos = key.find("|"); - - if (pos > 0) - key = key.left(pos); - FOR_EACH_STR_TOKEN(key, field) + else { - TToken_string row(field, '='); - int pos = field.find("["); + for (int i = 0; i < nfields; i++) + { + TToken_string def = wrk.fielddef(i); + TString field(def.get(0)); + TFieldtypes t = (TFieldtypes)def.get_int(1); + TString str = ini.get(field); + str = str.strip("\""); + TToken_string row(make_val(field, t, str), '='); + + values.add(row); + } + + TToken_string key(wrk.keydef(), '+'); + int pos = key.find("|"); if (pos > 0) - field = field.left(pos); - - TString str = ini.get(field); - - if (str.blank()) + key = key.left(pos); + pos = 0; + FOR_EACH_STR_TOKEN(key, field) { - ini.set_paragraph(main_file); - str = ini.get(field); + TString fld = field; + + if (fld.starts_with("UPPER")) + { + fld = fld.smid(7); + fld.rtrim(1); + fld << "_UPPER"; + } + else + { + pos = fld.find("["); + + if (pos > 0) + fld = fld.left(pos); + } + + TString str = ini.get(field); + if (str.blank()) - str << rowkey.get(); - ini.set_paragraph(*row); + { + ini.set_paragraph(main_file); + str = ini.get(fld); + if (str.blank()) + str << rowkey.get(); + ini.set_paragraph(*row); + } + str = str.strip("\""); + + TToken_string def = wrk.fielddef(wrk.field(fld)); + TFieldtypes t = (TFieldtypes)def.get_int(1); + + if (pos > 0) + { + int start = atoi(field.mid(pos + 1)); + + pos = field.find(',', pos + 1); + str = str.smid(start, pos > 0 ? atoi(field.mid(pos + 1)) : 0); + fld << "_MID"; + } + + TToken_string row(make_val(fld, t, str), '='); + keys.add(row); } + const TString & statement = build_statement(op, curr_file_num, name, keys, values); + int err = recset.exec(statement); - TToken_string def = wrk.fielddef(wrk.field(field)); - TFieldtypes t = (TFieldtypes)def.get_int(1); - TString val; - - str.strip("\""); - switch (t) + if (op < db_remove && err <= 0) { - case _alfafld: - case _charfld: - case _datefld: - case _memofld: - val << '\'' << str << '\''; - break; - case _intfld: - case _longfld: - case _realfld: - case _wordfld: - case _intzerofld: - case _longzerofld: - val = str.blank() ? "0" : str; - break; - case _boolfld: - val = str.blank() ? "'FALSE'" : "'TRUE'"; - break; - default: - val = str; - break; + const TString & statement = build_statement(op == db_add ? db_update : db_add, curr_file_num, name, keys, values); + + err = recset.exec(statement); } - row.add(val); - keys.add(row); + if (err <= 0) + error_box(FR("Errore n. %d invio file %d"), curr_file_num, err); + else + recset.exec("COMMIT;"); } - const TString & statement = build_statement(op, curr_file_num, keys, values); - int err = recset.exec(statement); - - if (op < db_remove && err <= 0) - { - const TString & statement = build_statement(op == db_add ? db_update : db_add, curr_file_num, keys, values); - - err = recset.exec(statement); - } - if (err <= 0) - error_box(FR("Errore file %d invio n. %d"), curr_file_num, err); } } } @@ -680,8 +887,10 @@ bool TPostman::dispatch_transaction(const TRectype& rec, FOR_EACH_TOKEN(odbc_dest, r) { const TString & dsn = r; + TAuto_token_string files = odbc_files.get(); + ::odbc_send(dsn, rec.num(), files, name); } remove_file(name);