diff --git a/uppsrc/ODBC/ODBC.cpp b/uppsrc/ODBC/ODBC.cpp new file mode 100644 index 000000000..e253cad40 --- /dev/null +++ b/uppsrc/ODBC/ODBC.cpp @@ -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 ODBCSession::EnumUsers() +{ + return Vector(); +} + +Vector ODBCSession::EnumDatabases() +{ + return Vector(); +} + +Vector ODBCSession::EnumTables(String database) +{ + return Vector(); +} + +Vector ODBCSession::EnumViews(String database) +{ + return Vector(); +} + +Vector ODBCSession::EnumSequences(String database) +{ + return Vector(); +} + +Vector ODBCSession::EnumPrimaryKeys(String database, String table) +{ + return Vector(); +} + +String ODBCSession::EnumRowID(String database, String table) +{ + return ""; +} + +bool ODBCPerformScript(const String& text, StatementExecutor& executor, Gate2 progress_canceled) +{ + return false; +} + +class ODBCConnection : public Link, 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, 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 diff --git a/uppsrc/ODBC/ODBC.h b/uppsrc/ODBC/ODBC.h new file mode 100644 index 000000000..2a5dd66f7 --- /dev/null +++ b/uppsrc/ODBC/ODBC.h @@ -0,0 +1,55 @@ +#ifndef _ODBC_ODBC_h +#define _ODBC_ODBC_h + +#include +#include +#include + +NAMESPACE_UPP + +bool ODBCPerformScript(const String& text, StatementExecutor& executor, Gate2 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 EnumUsers(); + virtual Vector EnumDatabases(); + virtual Vector EnumTables(String database); + virtual Vector EnumViews(String database); + virtual Vector EnumSequences(String database); + virtual Vector 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 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 diff --git a/uppsrc/ODBC/ODBC.upp b/uppsrc/ODBC/ODBC.upp new file mode 100644 index 000000000..b4a8eea35 --- /dev/null +++ b/uppsrc/ODBC/ODBC.upp @@ -0,0 +1,9 @@ +uses + Sql; + +library(WIN32) odbc32; + +file + ODBC.h, + ODBC.cpp; + diff --git a/uppsrc/ODBC/init b/uppsrc/ODBC/init new file mode 100644 index 000000000..3efad477c --- /dev/null +++ b/uppsrc/ODBC/init @@ -0,0 +1,4 @@ +#ifndef _ODBC_icpp_init_stub +#define _ODBC_icpp_init_stub +#include "Sql/init" +#endif diff --git a/uppsrc/Painter/Copying b/uppsrc/Painter/Copying new file mode 100644 index 000000000..f3ef3b75c --- /dev/null +++ b/uppsrc/Painter/Copying @@ -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. diff --git a/uppsrc/Painter/Painter.upp b/uppsrc/Painter/Painter.upp index 45918d46a..39f7051b1 100644 --- a/uppsrc/Painter/Painter.upp +++ b/uppsrc/Painter/Painter.upp @@ -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"; diff --git a/uppsrc/Painter/init b/uppsrc/Painter/init index 78c03394f..356309386 100644 --- a/uppsrc/Painter/init +++ b/uppsrc/Painter/init @@ -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