mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-08-28 06:12:53 -06:00
ODBC connector (1st working version)
git-svn-id: svn://ultimatepp.org/upp/trunk@908 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
f57fad159d
commit
486c0e793b
5 changed files with 300 additions and 111 deletions
|
|
@ -2,13 +2,63 @@
|
|||
|
||||
NAMESPACE_UPP
|
||||
|
||||
class 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:
|
||||
friend class ODBCSession;
|
||||
|
||||
ODBCSession *session;
|
||||
struct Param {
|
||||
int ctype;
|
||||
int sqltype;
|
||||
String data;
|
||||
SQLLEN li;
|
||||
};
|
||||
Array<Param> param, bparam;
|
||||
String last_insert_table;
|
||||
|
||||
int rowsprocessed;
|
||||
Vector< Vector<double> > number;
|
||||
Vector< Vector<String> > text;
|
||||
Vector< Vector<Time> > time;
|
||||
int rowcount;
|
||||
int rowi;
|
||||
Vector<Value> fetchrow;
|
||||
|
||||
bool IsOk(SQLRETURN ret) const;
|
||||
void Flush();
|
||||
bool Fetch0();
|
||||
bool IsCurrent() const { return session->current == this; }
|
||||
};
|
||||
|
||||
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;
|
||||
if(IsOk(SQLDriverConnect(hdbc, NULL, (SQLCHAR *)cs, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT))) {
|
||||
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
|
||||
return true;
|
||||
}
|
||||
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
|
||||
hdbc = SQL_NULL_HANDLE;
|
||||
SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS);
|
||||
SQLSetConnectAttr(hdbc, SQL_ATTR_TXN_ISOLATION, (SQLPOINTER)SQL_TRANSACTION_SERIALIZABLE, SQL_NTS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -21,17 +71,55 @@ bool ODBCSession::IsOpen() const
|
|||
void ODBCSession::Close()
|
||||
{
|
||||
if(hdbc != SQL_NULL_HANDLE) {
|
||||
current = NULL;
|
||||
FlushConnections();
|
||||
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
|
||||
hdbc = SQL_NULL_HANDLE;
|
||||
hstmt = SQL_NULL_HANDLE;
|
||||
current = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ODBCSession::FlushConnections()
|
||||
{
|
||||
DLOG("FlushConnections");
|
||||
if(current) {
|
||||
current->Flush();
|
||||
current = NULL;
|
||||
}
|
||||
SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||
}
|
||||
|
||||
bool ODBCSession::IsOk(SQLRETURN ret)
|
||||
{
|
||||
if(SQL_SUCCEEDED(ret))
|
||||
return true;
|
||||
SQLCHAR SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH];
|
||||
SQLINTEGER NativeError;
|
||||
SQLSMALLINT MsgLen;
|
||||
String error;
|
||||
int i = 1;
|
||||
while(SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, i++, SqlState, &NativeError,
|
||||
Msg, sizeof(Msg), &MsgLen) != SQL_NO_DATA) {
|
||||
if(error.GetCount())
|
||||
error << "\r\n";
|
||||
error << (char *)Msg;
|
||||
}
|
||||
SetError(error, statement);
|
||||
return false;
|
||||
}
|
||||
|
||||
ODBCSession::ODBCSession()
|
||||
{
|
||||
hdbc = SQL_NULL_HANDLE;
|
||||
hstmt = SQL_NULL_HANDLE;
|
||||
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
|
||||
if(henv)
|
||||
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
|
||||
tlevel = 0;
|
||||
Dialect(MSSQL);
|
||||
current = NULL;
|
||||
}
|
||||
|
||||
ODBCSession::~ODBCSession()
|
||||
|
|
@ -42,23 +130,40 @@ ODBCSession::~ODBCSession()
|
|||
|
||||
void ODBCSession::Begin()
|
||||
{
|
||||
if(tlevel == 0)
|
||||
SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_NTS);
|
||||
tlevel++;
|
||||
}
|
||||
|
||||
void ODBCSession::Commit()
|
||||
{
|
||||
tlevel--;
|
||||
ASSERT(tlevel >= 0);
|
||||
if(tlevel == 0) {
|
||||
SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);
|
||||
SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS);
|
||||
}
|
||||
}
|
||||
|
||||
void ODBCSession::Rollback()
|
||||
{
|
||||
tlevel--;
|
||||
ASSERT(tlevel >= 0);
|
||||
if(tlevel == 0) {
|
||||
SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK);
|
||||
SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS);
|
||||
}
|
||||
}
|
||||
|
||||
String ODBCSession::Savepoint()
|
||||
{
|
||||
NEVER();
|
||||
return "";
|
||||
}
|
||||
|
||||
void ODBCSession::RollbackTo(const String& savepoint)
|
||||
{
|
||||
NEVER();
|
||||
}
|
||||
|
||||
Vector<String> ODBCSession::EnumUsers()
|
||||
|
|
@ -98,42 +203,33 @@ String ODBCSession::EnumRowID(String database, String table)
|
|||
|
||||
bool ODBCPerformScript(const String& text, StatementExecutor& executor, Gate2<int, int> progress_canceled)
|
||||
{
|
||||
return false;
|
||||
const char *p = text;
|
||||
while(*p) {
|
||||
String cmd;
|
||||
while(*p && *p != ';')
|
||||
if(*p == '\'') {
|
||||
const char *s = p;
|
||||
while(*++p && (*p != '\'' || *++p == '\''))
|
||||
;
|
||||
cmd.Cat(s, int(p - s));
|
||||
}
|
||||
else {
|
||||
if(*p > ' ')
|
||||
cmd.Cat(*p);
|
||||
else if(!cmd.IsEmpty() && *cmd.Last() != ' ')
|
||||
cmd.Cat(' ');
|
||||
p++;
|
||||
}
|
||||
if(progress_canceled(int(p - text.Begin()), text.GetLength()))
|
||||
return false;
|
||||
if(!IsNull(cmd) && !executor.Execute(cmd))
|
||||
return false;
|
||||
if(*p == ';')
|
||||
p++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -142,25 +238,33 @@ SqlConnection *ODBCSession::CreateConnection()
|
|||
ODBCConnection::ODBCConnection(ODBCSession *session_)
|
||||
: session(session_)
|
||||
{
|
||||
if(session)
|
||||
LinkAfter(&session->clink);
|
||||
hstmt = SQL_NULL_HANDLE;
|
||||
SQLAllocHandle(SQL_HANDLE_STMT, session->hdbc, &hstmt);
|
||||
DLOG("ODBCConnection " << (void *)this << " " << (void *)session);
|
||||
rowcount = rowi = 0;
|
||||
}
|
||||
|
||||
ODBCConnection::~ODBCConnection()
|
||||
{
|
||||
if(hstmt != SQL_NULL_HANDLE)
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
|
||||
if(session)
|
||||
Unlink();
|
||||
if(IsCurrent())
|
||||
session->current = NULL;
|
||||
DLOG("~ODBCConnection " << (void *)this << " " << (void *)session);
|
||||
}
|
||||
|
||||
bool ODBCConnection::IsOk(SQLRETURN ret)
|
||||
bool ODBCConnection::IsOk(SQLRETURN ret) const
|
||||
{
|
||||
if(session->IsOk(ret))
|
||||
if(SQL_SUCCEEDED(ret))
|
||||
return true;
|
||||
param.Clear();
|
||||
SQLCHAR SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH];
|
||||
SQLINTEGER NativeError;
|
||||
SQLSMALLINT MsgLen;
|
||||
String error;
|
||||
int i = 1;
|
||||
while(SQLGetDiagRec(SQL_HANDLE_STMT, session->hstmt, i++, SqlState, &NativeError,
|
||||
Msg, sizeof(Msg), &MsgLen) != SQL_NO_DATA) {
|
||||
if(error.GetCount())
|
||||
error << "\r\n";
|
||||
error << (char *)Msg;
|
||||
}
|
||||
session->SetError(error, statement);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -201,25 +305,38 @@ void ODBCConnection::SetParam(int i, const Value& r)
|
|||
|
||||
bool ODBCConnection::Execute()
|
||||
{
|
||||
if(hstmt == SQL_NULL_HANDLE)
|
||||
DLOG("Execute " << (void *)this << " " << (void *)session);
|
||||
if(session->hstmt == SQL_NULL_HANDLE)
|
||||
return false;
|
||||
if(parse) {
|
||||
if(!IsOk(SQLPrepare(hstmt, (SQLCHAR *)~statement, statement.GetCount())))
|
||||
return false;
|
||||
parse = false;
|
||||
}
|
||||
if(IsCurrent())
|
||||
session->current = NULL;
|
||||
session->FlushConnections();
|
||||
last_insert_table.Clear();
|
||||
number.Clear();
|
||||
text.Clear();
|
||||
time.Clear();
|
||||
CParser p(statement);
|
||||
if((p.Id("insert") || p.Id("INSERT")) && (p.Id("into") || p.Id("INTO")) && p.IsId())
|
||||
last_insert_table = p.ReadId();
|
||||
if(!IsOk(SQLPrepare(session->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,
|
||||
if(!IsOk(SQLBindParameter(session->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))))
|
||||
if(!IsOk(SQLExecute(session->hstmt)) || !IsOk(SQLNumResultCols(session->hstmt, &ncol))) {
|
||||
SQLFreeStmt(session->hstmt, SQL_CLOSE);
|
||||
return false;
|
||||
}
|
||||
session->current = this;
|
||||
info.Clear();
|
||||
for(int i = 1; i <= ncol; i++) {
|
||||
SQLCHAR ColumnName[256];
|
||||
SQLSMALLINT NameLength;
|
||||
|
|
@ -227,13 +344,13 @@ bool ODBCConnection::Execute()
|
|||
SQLULEN ColumnSize;
|
||||
SQLSMALLINT DecimalDigits;
|
||||
SQLSMALLINT Nullable;
|
||||
if(!IsOk(SQLDescribeCol(hstmt, i, ColumnName, 255, &NameLength, &DataType, &ColumnSize,
|
||||
&DecimalDigits, &Nullable)))
|
||||
if(!IsOk(SQLDescribeCol(session->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.scale = 0;
|
||||
f.width = ColumnSize;
|
||||
f.name = (char *)ColumnName;
|
||||
switch(DataType) {
|
||||
|
|
@ -258,80 +375,148 @@ bool ODBCConnection::Execute()
|
|||
break;
|
||||
}
|
||||
}
|
||||
SQLLEN rc;
|
||||
SQLRowCount(session->hstmt, &rc);
|
||||
rowsprocessed = rc;
|
||||
return true;
|
||||
}
|
||||
|
||||
int ODBCConnection::GetRowsProcessed() const
|
||||
{
|
||||
SQLLEN rc;
|
||||
SQLRowCount(hstmt, &rc);
|
||||
return (int)rc;
|
||||
return rowsprocessed;
|
||||
}
|
||||
|
||||
bool ODBCConnection::Fetch0()
|
||||
{
|
||||
DLOG("Fetch0 " << (void *)this << " " << (void *)session);
|
||||
int ret = SQLFetch(session->hstmt);
|
||||
DDUMP(ret == SQL_NO_DATA);
|
||||
if(ret == SQL_NO_DATA || !IsOk(ret))
|
||||
return false;
|
||||
fetchrow.Clear();
|
||||
double dbl;
|
||||
SQL_TIMESTAMP_STRUCT tm;
|
||||
SQLLEN li;
|
||||
for(int i = 0; i < info.GetCount(); i++) {
|
||||
Value v = Null;
|
||||
switch(info[i].type) {
|
||||
case DOUBLE_V:
|
||||
if(!IsOk(SQLGetData(session->hstmt, i + 1, SQL_C_DOUBLE, &dbl, sizeof(dbl), &li)))
|
||||
break;
|
||||
if(li != SQL_NULL_DATA)
|
||||
v = dbl;
|
||||
break;
|
||||
case TIME_V:
|
||||
if(!IsOk(SQLGetData(session->hstmt, i + 1, SQL_C_TYPE_TIMESTAMP, &tm, sizeof(tm), &li)))
|
||||
break;
|
||||
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:
|
||||
if(!IsOk(SQLGetData(session->hstmt, i + 1, SQL_C_CHAR, &tm, 0, &li)))
|
||||
break;
|
||||
if(li != SQL_NULL_DATA) {
|
||||
StringBuffer sb;
|
||||
sb.SetLength(li);
|
||||
if(!IsOk(SQLGetData(session->hstmt, i + 1, SQL_C_CHAR, ~sb, li + 1, &li)))
|
||||
break;
|
||||
v = String(sb);
|
||||
}
|
||||
break;
|
||||
}
|
||||
fetchrow.Add(v);
|
||||
}
|
||||
return ret != SQL_NO_DATA && IsOk(ret);
|
||||
}
|
||||
|
||||
bool ODBCConnection::Fetch()
|
||||
{
|
||||
if(!hstmt)
|
||||
if(IsCurrent())
|
||||
return Fetch0();
|
||||
if(rowi >= rowcount)
|
||||
return false;
|
||||
int ret = SQLFetch(hstmt);
|
||||
return ret != SQL_NO_DATA && IsOk(ret);
|
||||
fetchrow.Clear();
|
||||
for(int i = 0; i < info.GetCount(); i++) {
|
||||
Value v;
|
||||
switch(info[i].type) {
|
||||
case DOUBLE_V:
|
||||
v = number[i][rowi];
|
||||
break;
|
||||
case TIME_V:
|
||||
v = time[i][rowi];
|
||||
break;
|
||||
default:
|
||||
v = text[i][rowi];
|
||||
break;
|
||||
}
|
||||
fetchrow.Add(v);
|
||||
}
|
||||
++rowi;
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
DLOG("GetColumn " << (void *)this << " " << (void *)session);
|
||||
r.SetValue(fetchrow[i]);
|
||||
}
|
||||
|
||||
void ODBCConnection::Flush()
|
||||
{
|
||||
DLOG("Flush " << (void *)this);
|
||||
rowcount = 0;
|
||||
rowi = 0;
|
||||
while(Fetch0()) {
|
||||
rowcount++;
|
||||
for(int i = 0; i < info.GetCount(); i++)
|
||||
switch(info[i].type) {
|
||||
case DOUBLE_V:
|
||||
number[i].Add(fetchrow[i]);
|
||||
break;
|
||||
case STRING_V:
|
||||
text[i].Add(fetchrow[i]);
|
||||
break;
|
||||
case TIME_V:
|
||||
time[i].Add(fetchrow[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
r.SetValue(v);
|
||||
}
|
||||
|
||||
void ODBCConnection::Cancel()
|
||||
{
|
||||
param.Clear();
|
||||
bparam.Clear();
|
||||
number.Clear();
|
||||
text.Clear();
|
||||
time.Clear();
|
||||
}
|
||||
|
||||
String ODBCConnection::ToString() const
|
||||
{
|
||||
return "";
|
||||
return statement;
|
||||
}
|
||||
|
||||
Value ODBCConnection::GetInsertedId() const
|
||||
{
|
||||
return Null;
|
||||
Sql sql(GetSession());
|
||||
return last_insert_table.GetCount() ? sql.Select("IDENT_CURRENT('" + last_insert_table + "')")
|
||||
: sql.Select("@@IDENTITY");
|
||||
}
|
||||
|
||||
String MSSQLTextType(int width)
|
||||
{
|
||||
if(width <= 4000)
|
||||
return NFormat("varchar(%d)", width);
|
||||
return "text";
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
NAMESPACE_UPP
|
||||
|
||||
bool ODBCPerformScript(const String& text, StatementExecutor& executor, Gate2<int, int> progress_canceled = false);
|
||||
String MSSQLTextType(int width);
|
||||
|
||||
class ODBCSession : public SqlSession {
|
||||
public:
|
||||
|
|
@ -37,10 +38,13 @@ private:
|
|||
friend class ODBCConnection;
|
||||
HENV henv;
|
||||
HDBC hdbc;
|
||||
Link<ODBCConnection> clink;
|
||||
HSTMT hstmt;
|
||||
String user;
|
||||
int tlevel;
|
||||
ODBCConnection *current;
|
||||
|
||||
bool IsOk(SQLRETURN ret) { return SQL_SUCCEEDED(ret); }
|
||||
void FlushConnections();
|
||||
bool IsOk(SQLRETURN ret);
|
||||
|
||||
public:
|
||||
bool Connect(const char *cs);
|
||||
|
|
|
|||
|
|
@ -1464,7 +1464,7 @@ bool OleDBPerformScript(const String& text, StatementExecutor& executor, Gate2<i
|
|||
return true;
|
||||
}
|
||||
|
||||
String OleDBTextType(int width)
|
||||
String MSSQLTextType(int width)
|
||||
{
|
||||
if(width <= 4000)
|
||||
return NFormat("varchar(%d)", width);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
NAMESPACE_UPP
|
||||
|
||||
bool OleDBPerformScript(const String& text, StatementExecutor& executor, Gate2<int, int> progress_canceled = false);
|
||||
String OleDBTextType(int width);
|
||||
String MSSQLTextType(int width);
|
||||
|
||||
class OleDBSession : public SqlSession
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@
|
|||
#define TIME_(x) COLUMN_("datetime", Time, x, 0, 0)
|
||||
#define TIME_ARRAY_(x, items) COLUMN_ARRAY_("datetime", Time, x, 0, 0, items)
|
||||
|
||||
#define STRING(x, n) COLUMN(OleDBTextType(n), String, x, n, 0)
|
||||
#define STRING_ARRAY(x, n, items) COLUMN_ARRAY(OleDBTextType(n), String, x, n, 0, items)
|
||||
#define STRING_(x, n) COLUMN_(OleDBTextType(n), String, x, n, 0)
|
||||
#define STRING_ARRAY_(x, n, items) COLUMN_ARRAY_(OleDBTextType(n), String, x, n, 0, items)
|
||||
#define STRING(x, n) COLUMN(MSSQLTextType(n), String, x, n, 0)
|
||||
#define STRING_ARRAY(x, n, items) COLUMN_ARRAY(MSSQLTextType(n), String, x, n, 0, items)
|
||||
#define STRING_(x, n) COLUMN_(MSSQLTextType(n), String, x, n, 0)
|
||||
#define STRING_ARRAY_(x, n, items) COLUMN_ARRAY_(MSSQLTextType(n), String, x, n, 0, items)
|
||||
|
||||
#define LONGRAW(x) COLUMN("varbinary(max)", String, x, 0, 0)
|
||||
#define LONGRAW_(x) COLUMN_("varbinary(max)", String, x, 0, 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue