.Core: fixed recent omission in ArrayMap - added using clause to include AMap's Insert variants previously hidden by Insert(int index, const K& key, T *newt)

+Oracle: implemented one of the ugliest interfaces I've ever seen - OracleClob to read/write Oracle CLOB's both in single-character and UTF8 mode

git-svn-id: svn://ultimatepp.org/upp/trunk@3499 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
rylek 2011-06-08 19:30:46 +00:00
parent 76c9546784
commit 529afaf310
3 changed files with 225 additions and 9 deletions

View file

@ -159,6 +159,7 @@ public:
T& Add(const K& k) { return B::Add(k); }
T& Add(const K& k, T *newt) { B::key.Add(k); return B::value.Add(newt); }
T& Insert(int i, const K& k, T *newt) { B::key.Insert(i, k); return B::value.Insert(i, newt); }
using B::Insert;
template <class TT> TT& Create(const K& k) { TT *q = new TT; B::key.Add(k); return B::value.Add(q); }
T& Set(int i, T *ptr) { return B::value.Set(i, ptr); }

View file

@ -791,10 +791,14 @@ void OCI8Connection::GetColumn(int i, String& s) const {
int handle;
GetColumn(i, handle);
if(!IsNull(handle)) {
OracleBlob blob(*session, handle);
s = LoadStream(blob);
if(session->utf8_session && c.type == SQLT_CLOB)
s = ToCharset(CHARSET_DEFAULT, s, CHARSET_UTF8);
if(c.type == SQLT_CLOB && session->utf8_session) {
OracleClob clob(*session, handle);
s = FromUnicode(clob.Read());
}
else {
OracleBlob blob(*session, handle);
s = LoadStream(blob);
}
}
else
s = Null;
@ -820,12 +824,15 @@ void OCI8Connection::GetColumn(int i, WString& ws) const {
int handle;
GetColumn(i, handle);
if(!IsNull(handle)) {
OracleBlob blob(*session, handle);
String s = LoadStream(blob);
if(session->utf8_session && c.type == SQLT_CLOB)
ws = FromUtf8(s);
else
if(session->utf8_session && c.type == SQLT_CLOB) {
OracleClob clob(*session, handle);
ws = clob.Read();
}
else {
OracleBlob blob(*session, handle);
String s = LoadStream(blob);
ws = s.ToWString();
}
}
else
ws = Null;
@ -1435,4 +1442,179 @@ OracleBlob::~OracleBlob() {
Close();
}
void OracleClob::SetLength(int sz)
{
SetStreamSize(sz << 1);
}
void OracleClob::SetStreamSize(int64 pos) {
ASSERT(pos <= GetStreamSize());
if(pos < (int)GetStreamSize())
session->oci8.OCILobTrim(session->svchp, session->errhp, locp, (int)(pos >> 1));
}
dword OracleClob::Read(int64 at, void *ptr, dword size) {
ASSERT(IsOpen() && (style & STRM_READ) && session);
ASSERT(at == (dword)at);
int full_bytes = 0;
bool utf8 = session->IsUtf8Session();
ub4 readpos = (ub4)(at >> 1);
ub4 readsize = (ub4)(((at + size + 1) & ~1) - (readpos << 1));
ub4 read16 = (readsize + 1) >> 1;
ub4 bufsize = min(utf8 ? 4 * (int)read16 : (int)read16, 16384);
Buffer<char> charbuf(bufsize);
while(read16 > 0) {
ub4 nchars = read16;
sword res = session->oci8.OCILobRead(session->svchp, session->errhp, locp,
&nchars, readpos + 1, charbuf, bufsize,
NULL, NULL, 0, SQLCS_IMPLICIT);
if(res != OCI_SUCCESS && res != OCI_NEED_DATA)
return full_bytes;
WString unibuf;
if(utf8)
unibuf = FromUtf8(charbuf, nchars);
else {
WStringBuffer tmp;
tmp.SetLength(nchars);
ToUnicode(tmp, charbuf, nchars, CHARSET_DEFAULT);
unibuf = tmp;
}
int ulen = unibuf.GetLength();
int uoff = (int)(at & 1);
int upart = min((int)size, 2 * ulen - uoff);
memcpy(ptr, (const byte *)~unibuf + uoff, upart);
ptr = (byte *)ptr + upart;
at += upart;
size -= upart;
read16 -= ulen;
full_bytes += upart;
if(res != OCI_NEED_DATA)
break;
}
return full_bytes;
}
void OracleClob::Write(int64 at, const void *ptr, dword size) {
ASSERT(IsOpen() && (style & STRM_WRITE) && session);
ASSERT(at == (dword)at);
bool utf8 = session->IsUtf8Session();
if(at & 1) {
char auxbuf[2];
Read(at - 1, auxbuf, 1);
auxbuf[1] = *(byte *)ptr;
word wch = Peek16le(auxbuf);
String chrbuf = (utf8 ? ToUtf8(wch) : String(FromUnicode(wch, CHARSET_DEFAULT), 1));
ub4 n = chrbuf.GetLength();
sword res = session->oci8.OCILobWrite(session->svchp, session->errhp, locp,
&n, (dword)(at >> 1) + 1, (dvoid *)chrbuf.Begin(), chrbuf.GetLength(),
OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
if(res != OCI_SUCCESS || n != 1) {
SetError();
return;
}
ptr = (byte *)ptr + 1;
size--;
at++;
}
if(size >> 1) {
ub4 nchars = size >> 1;
String chrbuf;
if(utf8)
chrbuf = ToUtf8((const wchar *)ptr, nchars);
else {
StringBuffer tmp;
tmp.SetLength(nchars);
FromUnicode(tmp, (const wchar *)ptr, nchars, CHARSET_DEFAULT);
chrbuf = tmp;
}
ub4 n = chrbuf.GetLength();
sword res = session->oci8.OCILobWrite(session->svchp, session->errhp, locp,
&n, (dword)(at >> 1) + 1, (dvoid *)chrbuf.Begin(), chrbuf.GetLength(),
OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
if(res != OCI_SUCCESS || n != nchars) {
SetError();
return;
}
ptr = (byte *)ptr + (nchars << 1);
at += (nchars << 1);
size -= (nchars << 1);
}
if(size & 1) {
char auxbuf[2];
ub4 pos16 = (ub4)(at >> 1);
Read(at, auxbuf + 1, 1);
auxbuf[0] = *((byte *)ptr + size - 1);
word wch = Peek16le(auxbuf);
String chrbuf = (utf8 ? ToUtf8(wch) : String(FromUnicode(wch, CHARSET_DEFAULT), 1));
ub4 n = chrbuf.GetLength();
sword res = session->oci8.OCILobWrite(session->svchp, session->errhp, locp,
&n, pos16 + 1, (dvoid *)chrbuf.Begin(), chrbuf.GetLength(),
OCI_ONE_PIECE, NULL, NULL, 0, SQLCS_IMPLICIT);
if(res != OCI_SUCCESS || n != 1) {
SetError();
return;
}
}
}
WString OracleClob::Read()
{
WStringBuffer out;
int nchars = (int)(GetLeft() >> 1);
out.SetCount(nchars);
Seek(0);
Stream::Get(out, 2 * nchars);
return out;
}
void OracleClob::Write(const WString& w)
{
Put(w, 2 * w.GetLength());
}
void OracleClob::Assign(Oracle8& s, int blob) {
session = &s;
locp = (OCILobLocator *)blob;
ub4 n;
OpenInit(READWRITE,
session->oci8.OCILobGetLength(session->svchp, session->errhp, locp, &n) == OCI_SUCCESS
? 2 * n : 0);
}
void OracleClob::Assign(const Sql& sql, int blob) {
Oracle8 *session = dynamic_cast<Oracle8 *>(&sql.GetSession());
ASSERT(session);
Assign(*session, blob);
}
bool OracleClob::IsOpen() const {
return locp;
}
void OracleClob::Close() {
if(locp) Flush();
locp = NULL;
}
OracleClob::OracleClob(const Sql& sql, int blob) {
Assign(sql, blob);
}
OracleClob::OracleClob(Oracle8& session, int blob) {
Assign(session, blob);
}
OracleClob::OracleClob() {
locp = NULL;
session = NULL;
}
OracleClob::~OracleClob() {
Close();
}
END_UPP_NAMESPACE

View file

@ -71,6 +71,7 @@ private:
private:
friend class OCI8Connection;
friend class OracleBlob;
friend class OracleClob;
OCIEnv *envhp;
OCIError *errhp;
@ -137,6 +138,38 @@ public:
~OracleBlob();
};
class OracleClob : public BlockStream {
protected:
virtual void SetStreamSize(int64 size);
virtual dword Read(int64 at, void *ptr, dword size);
virtual void Write(int64 at, const void *data, dword size);
public:
virtual bool IsOpen() const;
virtual void Close();
protected:
OCILobLocator *locp;
Oracle8 *session;
void Init(dword size);
public:
operator bool() const { return IsOpen(); }
void Assign(const Sql& sql, int blob);
void Assign(Oracle8& session, int blob);
WString Read();
void Write(const WString& w);
void SetLength(int sz);
OracleClob();
OracleClob(const Sql& sql, int blob);
OracleClob(Oracle8& session, int blob);
~OracleClob();
};
#ifdef text
#undef text
#endif