Developing ODBC connector

git-svn-id: svn://ultimatepp.org/upp/trunk@907 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-02-26 11:03:36 +00:00
parent ab65cba3d8
commit f57fad159d
7 changed files with 430 additions and 2 deletions

337
uppsrc/ODBC/ODBC.cpp Normal file
View file

@ -0,0 +1,337 @@
#include "ODBC.h"
NAMESPACE_UPP
bool ODBCSession::Connect(const char *cs)
{
if(henv && IsOk(SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc))) {
if(IsOk(SQLDriverConnect(hdbc, NULL, (SQLCHAR *)cs, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT)))
return true;
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
hdbc = SQL_NULL_HANDLE;
}
return false;
}
bool ODBCSession::IsOpen() const
{
return hdbc != SQL_NULL_HANDLE;
}
void ODBCSession::Close()
{
if(hdbc != SQL_NULL_HANDLE) {
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
hdbc = SQL_NULL_HANDLE;
}
}
ODBCSession::ODBCSession()
{
hdbc = SQL_NULL_HANDLE;
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
if(henv)
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
}
ODBCSession::~ODBCSession()
{
if(henv)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
void ODBCSession::Begin()
{
}
void ODBCSession::Commit()
{
}
void ODBCSession::Rollback()
{
}
String ODBCSession::Savepoint()
{
return "";
}
void ODBCSession::RollbackTo(const String& savepoint)
{
}
Vector<String> ODBCSession::EnumUsers()
{
return Vector<String>();
}
Vector<String> ODBCSession::EnumDatabases()
{
return Vector<String>();
}
Vector<String> ODBCSession::EnumTables(String database)
{
return Vector<String>();
}
Vector<String> ODBCSession::EnumViews(String database)
{
return Vector<String>();
}
Vector<String> ODBCSession::EnumSequences(String database)
{
return Vector<String>();
}
Vector<String> ODBCSession::EnumPrimaryKeys(String database, String table)
{
return Vector<String>();
}
String ODBCSession::EnumRowID(String database, String table)
{
return "";
}
bool ODBCPerformScript(const String& text, StatementExecutor& executor, Gate2<int, int> progress_canceled)
{
return false;
}
class ODBCConnection : public Link<ODBCConnection>, public SqlConnection
{
public:
ODBCConnection(ODBCSession *session);
virtual ~ODBCConnection();
void Clear();
virtual void SetParam(int i, const Value& r);
virtual bool Execute();
virtual int GetRowsProcessed() const;
virtual bool Fetch();
virtual void GetColumn(int i, Ref r) const;
virtual void Cancel();
virtual SqlSession& GetSession() const { ASSERT(session); return *session; }
virtual String GetUser() const { ASSERT(session); return session->user; }
virtual String ToString() const;
virtual Value GetInsertedId() const;
private:
ODBCSession *session;
HSTMT hstmt;
struct Param {
int ctype;
int sqltype;
String data;
SQLLEN li;
};
Array<Param> param, bparam;
bool IsOk(SQLRETURN ret);
};
SqlConnection *ODBCSession::CreateConnection()
{
return new ODBCConnection(this);
}
ODBCConnection::ODBCConnection(ODBCSession *session_)
: session(session_)
{
if(session)
LinkAfter(&session->clink);
hstmt = SQL_NULL_HANDLE;
SQLAllocHandle(SQL_HANDLE_STMT, session->hdbc, &hstmt);
}
ODBCConnection::~ODBCConnection()
{
if(hstmt != SQL_NULL_HANDLE)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
if(session)
Unlink();
}
bool ODBCConnection::IsOk(SQLRETURN ret)
{
if(session->IsOk(ret))
return true;
param.Clear();
return false;
}
void ODBCConnection::SetParam(int i, const Value& r)
{
Param& p = param.At(i);
if(IsNumber(r)) {
double x = r;
p.ctype = SQL_C_DOUBLE;
p.sqltype = SQL_DOUBLE;
p.data = String((char *)&x, sizeof(x));
p.li = sizeof(x);
}
if(IsString(r)) {
p.ctype = SQL_C_CHAR;
p.sqltype = SQL_LONGVARCHAR;
p.data = r;
p.li = p.data.GetLength();
}
if(IsDateTime(r)) {
p.ctype = SQL_C_TYPE_TIMESTAMP;
p.sqltype = SQL_TYPE_TIMESTAMP;
Time t = r;
SQL_TIMESTAMP_STRUCT tm;
tm.year = t.year;
tm.month = t.month;
tm.day = t.day;
tm.hour = t.hour;
tm.minute = t.minute;
tm.second = t.second;
tm.fraction = 0;
p.data = String((char *)&tm, sizeof(tm));
p.li = sizeof(tm);
}
if(IsNull(r))
p.li = SQL_NULL_DATA;
}
bool ODBCConnection::Execute()
{
if(hstmt == SQL_NULL_HANDLE)
return false;
if(parse) {
if(!IsOk(SQLPrepare(hstmt, (SQLCHAR *)~statement, statement.GetCount())))
return false;
parse = false;
}
bparam = param;
param.Clear();
for(int i = 0; i < bparam.GetCount(); i++) {
Param& p = bparam[i];
if(!IsOk(SQLBindParameter(hstmt, i + 1, SQL_PARAM_INPUT, p.ctype, p.sqltype,
p.data.GetCount(), 0, (SQLPOINTER)~p.data, p.data.GetLength(),
&p.li)))
return false;
}
SQLSMALLINT ncol;
if(!IsOk(SQLExecute(hstmt) || !IsOk(SQLNumResultCols(hstmt, &ncol))))
return false;
for(int i = 1; i <= ncol; i++) {
SQLCHAR ColumnName[256];
SQLSMALLINT NameLength;
SQLSMALLINT DataType;
SQLULEN ColumnSize;
SQLSMALLINT DecimalDigits;
SQLSMALLINT Nullable;
if(!IsOk(SQLDescribeCol(hstmt, i, ColumnName, 255, &NameLength, &DataType, &ColumnSize,
&DecimalDigits, &Nullable)))
return false;
SqlColumnInfo& f = info.Add();
f.nullable = Nullable != SQL_NO_NULLS;
f.precision = DecimalDigits;
f.scale = 0; // ?!
f.width = ColumnSize;
f.name = (char *)ColumnName;
switch(DataType) {
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_SMALLINT:
case SQL_INTEGER:
case SQL_REAL:
case SQL_FLOAT:
case SQL_DOUBLE:
case SQL_BIT:
case SQL_TINYINT:
case SQL_BIGINT:
f.type = DOUBLE_V;
break;
case SQL_TYPE_DATE:
case SQL_TYPE_TIMESTAMP:
f.type = TIME_V;
break;
default:
f.type = STRING_V;
break;
}
}
return true;
}
int ODBCConnection::GetRowsProcessed() const
{
SQLLEN rc;
SQLRowCount(hstmt, &rc);
return (int)rc;
}
bool ODBCConnection::Fetch()
{
if(!hstmt)
return false;
int ret = SQLFetch(hstmt);
return ret != SQL_NO_DATA && IsOk(ret);
}
void ODBCConnection::GetColumn(int i, Ref r) const
{
SQLLEN li;
double dbl;
SQL_TIMESTAMP_STRUCT tm;
Value v = Null;
switch(info[i].type) {
case DOUBLE_V:
SQLGetData(hstmt, i + 1, SQL_C_DOUBLE, &dbl, sizeof(dbl), &li);
if(li != SQL_NULL_DATA)
v = dbl;
break;
case TIME_V:
SQLGetData(hstmt, i + 1, SQL_C_TYPE_TIMESTAMP, &tm, sizeof(tm), &li);
if(li != SQL_NULL_DATA) {
Time m;
m.year = tm.year;
m.month = (byte)tm.month;
m.day = (byte)tm.day;
m.hour = (byte)tm.hour;
m.minute = (byte)tm.minute;
m.second = (byte)tm.second;
v = m;
}
break;
default:
StringBuffer sb;
sb.SetLength(256);
SQLGetData(hstmt, i + 1, SQL_C_CHAR, ~sb, 255, &li);
if(li > 255) {
sb.SetLength(li);
SQLGetData(hstmt, i + 1, SQL_C_CHAR, ~sb, li, &li);
}
if(li != SQL_NULL_DATA) {
sb.SetLength(li);
v = String(sb);
}
break;
}
r.SetValue(v);
}
void ODBCConnection::Cancel()
{
param.Clear();
bparam.Clear();
}
String ODBCConnection::ToString() const
{
return "";
}
Value ODBCConnection::GetInsertedId() const
{
return Null;
}
END_UPP_NAMESPACE

55
uppsrc/ODBC/ODBC.h Normal file
View file

@ -0,0 +1,55 @@
#ifndef _ODBC_ODBC_h
#define _ODBC_ODBC_h
#include <Sql/Sql.h>
#include <sql.h>
#include <sqlext.h>
NAMESPACE_UPP
bool ODBCPerformScript(const String& text, StatementExecutor& executor, Gate2<int, int> progress_canceled = false);
class ODBCSession : public SqlSession {
public:
virtual void Begin();
virtual void Commit();
virtual void Rollback();
virtual String Savepoint();
virtual void RollbackTo(const String& savepoint);
virtual bool IsOpen() const;
virtual Vector<String> EnumUsers();
virtual Vector<String> EnumDatabases();
virtual Vector<String> EnumTables(String database);
virtual Vector<String> EnumViews(String database);
virtual Vector<String> EnumSequences(String database);
virtual Vector<String> EnumPrimaryKeys(String database, String table);
virtual String EnumRowID(String database, String table);
virtual RunScript GetRunScript() const { return &ODBCPerformScript; }
protected:
virtual SqlConnection *CreateConnection();
private:
friend class ODBCConnection;
HENV henv;
HDBC hdbc;
Link<ODBCConnection> clink;
String user;
bool IsOk(SQLRETURN ret) { return SQL_SUCCEEDED(ret); }
public:
bool Connect(const char *cs);
void Close();
ODBCSession();
~ODBCSession();
};
END_UPP_NAMESPACE
#endif

9
uppsrc/ODBC/ODBC.upp Normal file
View file

@ -0,0 +1,9 @@
uses
Sql;
library(WIN32) odbc32;
file
ODBC.h,
ODBC.cpp;

4
uppsrc/ODBC/init Normal file
View file

@ -0,0 +1,4 @@
#ifndef _ODBC_icpp_init_stub
#define _ODBC_icpp_init_stub
#include "Sql/init"
#endif

21
uppsrc/Painter/Copying Normal file
View file

@ -0,0 +1,21 @@
Copyright 1998-2009 The U++ Project. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE U++ PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -35,7 +35,9 @@ file
Mask.cpp optimize_speed,
Gradient.cpp optimize_speed,
RadialGradient.cpp optimize_speed,
srcimp.tpp;
srcimp.tpp,
Info readonly separator,
Copying;
mainconfig
"" = "GUI";

View file

@ -2,7 +2,7 @@
#define _Painter_icpp_init_stub
#include "Core/init"
#include "CtrlLib/init"
#define BLITZ_INDEX__ F1F279540D3FE6AF9024371A0E93C1FBB
#define BLITZ_INDEX__ F18922416C44F220B741A74F8D9F1A79C
#include "PaintPainting.icpp"
#undef BLITZ_INDEX__
#endif