#include #include void TODBC_recordset::close() { if (_odbc != NULL) { xvt_odbc_free_connection(_odbc); _odbc = NULL; } } bool TODBC_recordset::connect(const char* dsn, const char* usr, const char* pwd, const char* dir) { close(); _odbc = xvt_odbc_get_connection(dsn, usr, pwd, dir); return _odbc != NULL; } XVT_ODBC TODBC_recordset::connection() const { if (_odbc == NULL) ((TODBC_recordset*)this)->connect(""); return _odbc; } const TString& TODBC_recordset::query_text() const { return _sql; } void TODBC_recordset::reset() { _first_row = 0; _items = 0; _current_row = -1; _pagesize = 512; _page.destroy(); _column.destroy(); _columns_loaded = false; } int TODBC_recordset::on_get_columns(int argc, char** values, char** columns) { static unsigned long _counter = 0; if (_column.empty()) { _counter = 0; for (int i = 0; i < argc; i++) { const char* fldtype = NULL; TRecordset_column_info* info = new TRecordset_column_info; info->_width = 1; info->_type = _alfafld; if (columns != NULL) { info->_name = columns[i]; fldtype = columns[argc+i]; } else info->_name.format("FIELD%d", i+1); if (fldtype != NULL) { if (xvt_str_compare_ignoring_case(fldtype, "DATE") == 0) { info->_type = _datefld; info->_width = 10; } else if (xvt_str_compare_ignoring_case(fldtype, "NUMERIC") == 0) { info->_type = _realfld; } else if (xvt_str_compare_ignoring_case(fldtype, "BLOB") == 0) { info->_type = _memofld; info->_width = 50; } } _column.add(info); } } const bool processed = _counter++ < 128; if (processed) { for (int i = 0; i < argc; i++) if (values[i] && *values[i]) { TRecordset_column_info& info = (TRecordset_column_info&)_column[i]; if (info._type == _alfafld || info._type == _realfld) { const int len = strlen(values[i]); if (len > info._width) info._width = len; } } } return processed ? 0 : -1; } static int query_get_columns(void* jolly, int argc, char** values, char** columns) { TODBC_recordset* q = (TODBC_recordset*)jolly; return q->on_get_columns(argc, values, columns); } void TODBC_recordset::requery() { _items = 0; _current_row = -1; _page.destroy(); } int TODBC_recordset::on_get_items(int argc, char** values, char** columns) { if (!_columns_loaded) on_get_rows(argc, values, columns); return 0; } static int query_get_items(void* jolly, int argc, char** values, char** columns) { TODBC_recordset* q = (TODBC_recordset*)jolly; return q->on_get_items(argc, values, columns); } TRecnotype TODBC_recordset::items() const { if (_items == 0) { TString sql; parsed_text(sql); TPerformance_profiler prof("ODBC count"); TRecnotype& i = (TRecnotype&)_items; if (!_columns_loaded) { ((TArray&)_page).destroy(); i = xvt_odbc_execute(connection(), sql, query_get_items, (void*)this); (bool&)_columns_loaded = true; } else i = xvt_odbc_execute(connection(), sql, NULL, NULL); } return _items; } unsigned int TODBC_recordset::columns() const { if (!_columns_loaded && _column.items() == 0) { TString sql; parsed_text(sql); TPerformance_profiler prof("ODBC info"); xvt_odbc_execute(connection(), sql, query_get_columns, (void*)this); (bool&)_columns_loaded = true; } return _column.items(); } const TRecordset_column_info& TODBC_recordset::column_info(unsigned int c) const { if (c >= columns()) // Generare column infos if needed c = 0; return (const TRecordset_column_info&)_column[c]; } // Funzione chiamata per riempire la pagina corrente delle righe della query int TODBC_recordset::on_get_rows(int argc, char** values, char** columns) { if (!_columns_loaded) on_get_columns(argc, values, columns); if (_page.items() >= _pagesize) return -1; TArray* a = new TArray; for (int c = 0; c < argc; c++) { TVariant* var = new TVariant; switch (column_info(c)._type) { case _alfafld: var->set(values[c]); break; case _memofld: if (values[c]) { TFixed_string memo(values[c]); memo.replace(char(0xB6), '\n'); var->set(memo); } break; case _datefld: var->set(TDate(values[c])); break; default: var->set(real(values[c])); break; } a->add(var, c); } _page.add(a); return 0; } static int query_get_rows(void* jolly, int argc, char** values, char** columns) { TODBC_recordset* rs = (TODBC_recordset*)jolly; return rs->on_get_rows(argc, values, columns); } bool TODBC_recordset::move_to(TRecnotype n) { const TRecnotype tot = items(); _current_row = n; if (n < 0 || n >= tot) { _page.destroy(); // Forza rilettura la prossima volta _first_row = 0; return false; } if (n < _first_row || n >= _first_row+_page.items()) { TString sql; parsed_text(sql); if (tot > _pagesize && sql.find("LIMIT ") < 0) { const int semicolon = sql.rfind(';'); if (semicolon >= 0) sql.cut(semicolon); sql.trim(); _page.destroy(); if (n >= _pagesize) _first_row = n-_pagesize/8; // Prendo qualche riga dalla pagina precedente, per velocizzare il pagina su else _first_row = n; sql << "\nLIMIT "; if (_first_row > 0) sql << _first_row << ','; sql << _pagesize << ';'; } TPerformance_profiler prof("ODBC query"); xvt_odbc_execute(connection(), sql, query_get_rows, this); if (!_columns_loaded) _columns_loaded = true; // Brutto posto ma necessario } return true; } long TODBC_recordset::exec(const char* sql) { TPerformance_profiler prof("ODBC command"); set(sql); TString cmd; parsed_text(cmd); return xvt_odbc_execute(connection(), cmd, NULL, NULL); } TRecnotype TODBC_recordset::current_row() const { return _current_row; } const TArray* TODBC_recordset::row(TRecnotype n) { const TArray* a = NULL; if (move_to(n)) a = (const TArray*)_page.objptr(n-_first_row); return a; } const TVariant& TODBC_recordset::get(unsigned int c) const { const TArray* a = (const TArray*)_page.objptr(_current_row-_first_row); if (a != NULL) { const TVariant* s = (const TVariant*)a->objptr(c); if (s != NULL) return *s; } return NULL_VARIANT; } const TVariant& TODBC_recordset::get(const char* name) const { return TRecordset::get(name); } void TODBC_recordset::set(const char* sql) { reset(); _sql = sql; if (_sql.starts_with("ODBC", true)) { _sql.ltrim(4); _sql.trim(); if (_sql[0] == '(') { const int par = _sql.find(')'); if (par > 0) { TToken_string conn(_sql.sub(1, par), ','); _sql.ltrim(par+1); _sql.trim(); TString dsn = conn.get(); dsn.strip("\""); TString usr = conn.get(); usr.strip("\""); TString pwd = conn.get(); pwd.strip("\""); TString dir = conn.get(); dir.strip("\""); if (!connect(dsn, usr, pwd, dir)) error_box("Couldn't connect to %s", (const char*)dsn); } } } if (_sql.find("SELECT") >= 0 || _sql.find("select") >= 0) find_and_reset_vars(); } TODBC_recordset::TODBC_recordset(const char* sql) : _odbc(NULL) { set(sql); } TODBC_recordset::~TODBC_recordset() { close(); } /////////////////////////////////////////////////////////// // Creazione "intelligente" del recordset appropriato in base alla query /////////////////////////////////////////////////////////// TRecordset* create_recordset(const TString& sql) { TRecordset* rex = NULL; if (!sql.blank()) { if (sql.starts_with("US", true)) rex = new TISAM_recordset(sql); else { if (sql.starts_with("ODBC", true)) rex = new TODBC_recordset(sql); else rex = new TSQL_recordset(sql); } } return rex; }