From 323eb75e3e0c9ec9bce6e3c91c29a630688a8501 Mon Sep 17 00:00:00 2001 From: guy Date: Tue, 25 Oct 2005 12:18:08 +0000 Subject: [PATCH] Patch level : 2.2 Files correlati : Ricompilazione Demo : [ ] Commento : Aggiunta classe gestione ODBC git-svn-id: svn://10.65.10.50/trunk@13451 c028cbd2-c16b-5b4b-a496-9718f37d4682 --- include/odbcrset.cpp | 300 +++++++++++++++++++++++++++++++++++++++++++ include/odbcrset.h | 47 +++++++ 2 files changed, 347 insertions(+) create mode 100755 include/odbcrset.cpp create mode 100755 include/odbcrset.h diff --git a/include/odbcrset.cpp b/include/odbcrset.cpp new file mode 100755 index 000000000..5d5f1e3a1 --- /dev/null +++ b/include/odbcrset.cpp @@ -0,0 +1,300 @@ +#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(); +} + +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(); +} + +TRecnotype TODBC_recordset::items() const +{ + if (_items == 0) + { + TString sql; parsed_text(sql); + TPerformance_profiler prof("ODBC count"); + ((TODBC_recordset*)this)->_items = xvt_odbc_execute(connection(), _sql, NULL, NULL); + } + return _items; +} + +unsigned int TODBC_recordset::columns() const +{ + if (_column.empty()) + { + TString sql; parsed_text(sql); + TPerformance_profiler prof("ODBC info"); + xvt_odbc_execute(connection(), sql, query_get_columns, (void*)this); + } + 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) +{ + 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); +} + +bool TODBC_recordset::move_to(TRecnotype n) +{ + _current_row = n; + if (n < 0 || n >= items()) + { + _page.destroy(); // Forza rilettura la prossiva volta + _first_row = 0; + return false; + } + + if (n < _first_row || n >= _first_row+_page.items()) + { + TString sql; parsed_text(sql); + if (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 " << _first_row << ',' << _pagesize << ";"; + } + TPerformance_profiler prof("ODBC query"); + xvt_odbc_execute(connection(), sql, query_get_rows, this); + } + + return true; +} + +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; +} + +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; +} diff --git a/include/odbcrset.h b/include/odbcrset.h new file mode 100755 index 000000000..46bbe785c --- /dev/null +++ b/include/odbcrset.h @@ -0,0 +1,47 @@ +#ifndef __ODBCRSET_H +#define __ODBCRSET_H + +#ifndef __RECSET_H +#include +#endif + +class TODBC_recordset : public TRecordset +{ + TString _sql; + XVT_ODBC _odbc; + + TRecnotype _first_row, _pagesize, _items, _current_row; + TArray _column; + TArray _page; + +protected: + XVT_ODBC connection() const; + void close(); + + void reset(); + + const TArray* row(TRecnotype n); + unsigned int columns() const; + const TRecordset_column_info& column_info(unsigned int c) const; + +public: + virtual TRecnotype items() const; + virtual bool move_to(TRecnotype pos); + virtual TRecnotype current_row() const; + virtual void requery(); + virtual const TString& query_text() const; + + const TVariant& get(unsigned int c) const; + + // Callbacks + int on_get_columns(int argc, char** values, char** columns); + int on_get_rows(int argc, char** values); + + void set(const char* sql); + + bool connect(const char* dsn, const char* usr = "", const char* pwd = "", const char* dir = ""); + TODBC_recordset(const char* sql); + virtual ~TODBC_recordset(); +}; + +#endif