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
This commit is contained in:
parent
3e0338e500
commit
323eb75e3e
300
include/odbcrset.cpp
Executable file
300
include/odbcrset.cpp
Executable file
@ -0,0 +1,300 @@
|
||||
#include <odbcrset.h>
|
||||
#include <utility.h>
|
||||
|
||||
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;
|
||||
}
|
47
include/odbcrset.h
Executable file
47
include/odbcrset.h
Executable file
@ -0,0 +1,47 @@
|
||||
#ifndef __ODBCRSET_H
|
||||
#define __ODBCRSET_H
|
||||
|
||||
#ifndef __RECSET_H
|
||||
#include <recset.h>
|
||||
#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
|
Loading…
x
Reference in New Issue
Block a user