diff --git a/uppsrc/Geom/Draw/plotter.cpp b/uppsrc/Geom/Draw/plotter.cpp index a0fd5d5dc..2424d2929 100644 --- a/uppsrc/Geom/Draw/plotter.cpp +++ b/uppsrc/Geom/Draw/plotter.cpp @@ -10,10 +10,6 @@ NAMESPACE_UPP #define STAT_LINES 0 // 0 = off, 1 = on, 2 = log individual vertices -#if defined(CPU_IA32) && defined(COMPILER_MSC) - #define MSC_ASSEMBLY -#endif - static void DrawFatPolyPolygonOutline(Draw& draw, const Point *vertices, int vertex_counts, const int *polygon_counts, int polygon_count_counts, @@ -713,52 +709,12 @@ Rectf Plotter::PtoL(const Rectf& rc) const Point Plotter::LtoPointFull(Pointf pt) const { -#ifdef MSC_ASSEMBLY - Point result; - const Matrixf& mx = physical; - __asm mov ebx, [mx] - __asm fld qword ptr [ebx]Matrixf.a.y - __asm fld qword ptr [ebx]Matrixf.a.x - __asm fld qword ptr [pt]Pointf.x - __asm fld st(0) - __asm fmul qword ptr [ebx]Matrixf.x.x - __asm faddp st(2), st - __asm fmul qword ptr [ebx]Matrixf.x.y - __asm faddp st(2), st - __asm fld qword ptr [pt]Pointf.y - __asm fld st(0) - __asm fmul qword ptr [ebx]Matrixf.y.x - __asm faddp st(2), st - __asm fmul qword ptr [ebx]Matrixf.y.y - __asm faddp st(2), st - __asm fistp dword ptr [result + 0] - __asm fistp dword ptr [result + 4] - return result; -#else return PointfToPoint(pt * physical); -#endif } Point Plotter::LtoPointOrtho(Pointf pt) const { -#ifdef MSC_ASSEMBLY - Point result; - const Matrixf& mx = physical; - __asm mov ebx, [mx] - __asm fld qword ptr [ebx]Matrixf.a.y - __asm fld qword ptr [ebx]Matrixf.a.x - __asm fld qword ptr [pt]Pointf.y - __asm fmul qword ptr [ebx]Matrixf.y.y - __asm fld qword ptr [pt]Pointf.x - __asm fmul qword ptr [ebx]Matrixf.x.x - __asm faddp st(2), st - __asm faddp st(2), st - __asm fistp dword ptr [result + 0] - __asm fistp dword ptr [result + 4] - return result; -#else return Point((int)(pt.x * physical.x.x + physical.a.x), (int)(pt.y * physical.y.y + physical.a.y)); -#endif } static void PaintRectPart(Draw& draw, int x, int y, int w, int h) diff --git a/uppsrc/Geom/geometry.cpp b/uppsrc/Geom/geometry.cpp index f7532d67c..7dbaf4992 100644 --- a/uppsrc/Geom/geometry.cpp +++ b/uppsrc/Geom/geometry.cpp @@ -218,29 +218,9 @@ Matrixf& Matrixf::operator *= (const Matrixf& m) Pointf operator * (Pointf point, const Matrixf& matrix) { -#if defined(CPU_IA32) && defined(COMPILER_MSC) - Pointf result; - __asm mov ebx, [matrix] - __asm fld qword ptr [ebx]Matrixf.a.y - __asm fld qword ptr [ebx]Matrixf.a.x - __asm fld qword ptr [point.x] - __asm fld st(0) - __asm fmul qword ptr [ebx]Matrixf.x.x - __asm faddp st(2), st - __asm fmul qword ptr [ebx]Matrixf.x.y - __asm faddp st(2), st - __asm fld qword ptr [point.y] - __asm fld st(0) - __asm fmul qword ptr [ebx]Matrixf.y.x - __asm faddp st(2), st - __asm fmul qword ptr [ebx]Matrixf.y.y - __asm faddp st(2), st - __asm fstp [result]Pointf.x - __asm fstp [result]Pointf.y - return result; -#else - return point.x * matrix.x + point.y * matrix.y + matrix.a; -#endif + return Pointf( + point.x * matrix.x.x + point.y * matrix.y.x + matrix.a.x, + point.x * matrix.x.y + point.y * matrix.y.y + matrix.a.y); } Pointf operator / (Pointf point, const Matrixf& matrix) diff --git a/uppsrc/MySql/MySql.cpp b/uppsrc/MySql/MySql.cpp index eab0468e3..a7677dd4d 100644 --- a/uppsrc/MySql/MySql.cpp +++ b/uppsrc/MySql/MySql.cpp @@ -309,6 +309,7 @@ bool MySqlConnection::Execute() { if(lastid) { SqlColumnInfo& f = info.Add(); f.width = f.scale = f.precision = 0; + f.binary = false; f.type = DOUBLE_V; f.name = "LAST_INSERT_ID"; rows = 1; diff --git a/uppsrc/ODBC/ODBC.cpp b/uppsrc/ODBC/ODBC.cpp index 6df2fe93e..117472f61 100644 --- a/uppsrc/ODBC/ODBC.cpp +++ b/uppsrc/ODBC/ODBC.cpp @@ -370,6 +370,7 @@ bool ODBCConnection::Execute() binary.Add(false); SqlColumnInfo& f = info.Add(); f.nullable = Nullable != SQL_NO_NULLS; + f.binary = false; f.precision = DecimalDigits; f.scale = 0; f.width = ColumnSize; @@ -397,6 +398,7 @@ bool ODBCConnection::Execute() case SQL_VARBINARY: case SQL_LONGVARBINARY: f.type = STRING_V; + f.binary = true; binary.Top() = true; break; default: diff --git a/uppsrc/OleDB/OleDB.cpp b/uppsrc/OleDB/OleDB.cpp index d405c0501..d9dc9a546 100644 --- a/uppsrc/OleDB/OleDB.cpp +++ b/uppsrc/OleDB/OleDB.cpp @@ -66,7 +66,7 @@ void OleDBVerify(HRESULT hr) { if(SUCCEEDED(hr)) return; - throw Exc(OleDBErrorInfo(hr).ToString()); + throw OleExc(hr, OleDBErrorInfo(hr).ToString()); } const char *OleDBParseString(const char *s) @@ -158,7 +158,11 @@ static void DBInDouble(const DBBINDING& binding, byte *data, const Value& v) static void DBInString(const DBBINDING& binding, byte *data, const Value& v) { - String s(v); + String s; + if(IsString(v)) + s = v; + else if(IsTypeRaw(v)) + s = ValueTo(v); int l = s.GetLength(); ASSERT(binding.cbMaxLen >= l + 1u); memcpy(data + binding.obValue, s, l + 1); @@ -228,22 +232,23 @@ static Value DBOutTime(const DBBINDING& binding, const byte *data) static Value DBOutBytes(const DBBINDING& binding, const byte *data) { - String r; + StringBuffer r; HRESULT hr; - BYTE pbBuff[3000]; - ULONG cbRead; - ISequentialStream* pISequentialStream; - IUnknown* pIUnknown = *((IUnknown**)(data + binding.obValue)); - pIUnknown->QueryInterface(IID_ISequentialStream, (void**)&pISequentialStream); - ULONG cbNeeded = 3000; - do { - hr = pISequentialStream->Read(pbBuff, cbNeeded, &cbRead); - r.Cat(pbBuff, 3000); + static const int CHUNK = 65536; + Buffer pbBuff(CHUNK); + ISequentialStream *pISequentialStream = *((ISequentialStream **)(data + binding.obValue)); + for(;;) { + ULONG cbNeeded = CHUNK; + ULONG cbRead = 0; + hr = pISequentialStream->Read(pbBuff, cbNeeded, &cbRead); + if(FAILED(hr)) + return ErrorValue(OleExc(hr)); + if(hr == S_FALSE || cbRead == 0) + break; + r.Cat((const char*)~pbBuff, (int)cbRead); } - while (SUCCEEDED(hr) && hr != S_FALSE && cbRead == cbNeeded); pISequentialStream->Release(); - pIUnknown->Release(); - return r; + return (String)r; } /* @@ -262,6 +267,7 @@ struct BindingPart { Vector colindex; Vector bindings; + Vector colnames; int rowbytes; Vector bindproc; Array objects; @@ -274,7 +280,7 @@ void BindingPart::GetRowData(Vector& out) const for(int i = 0; i < bindings.GetCount(); i++) { const DBBINDING& dbbind = bindings[i]; Value& op = out[colindex[i]]; - int status = *(const dword *)(~rowbuffer + dbbind.obStatus); + int status = *(const DBSTATUS *)(~rowbuffer + dbbind.obStatus); switch(status) { case DBSTATUS_S_ISNULL: { op = Value(); @@ -312,6 +318,7 @@ static Array GetRowDataBindings(const DBCOLUMNINFO *columns, int co } BindingPart& part = out_parts[part_index]; part.colindex.Add(i); + part.colnames.Add(WString(col.pwszName).ToString()); DBBINDING& db = part.bindings.Add(); OutBindProc& ob = part.bindproc.Add(); memset(&db, 0, sizeof(db)); @@ -794,6 +801,7 @@ void OleDBConnection::Execute(IRef rowset) colinfo.precision = (dbci.bPrecision == (byte)~0 ? int(Null) : dbci.bPrecision); colinfo.scale = (dbci.bScale == (byte)~0 ? int(Null) : dbci.bScale); colinfo.width = (int)dbci.ulColumnSize; + colinfo.binary = false; switch(dbci.wType) { case DBTYPE_I1: case DBTYPE_I2: case DBTYPE_I4: case DBTYPE_UI1: case DBTYPE_UI2: case DBTYPE_UI4: @@ -817,6 +825,10 @@ void OleDBConnection::Execute(IRef rowset) break; case DBTYPE_BYTES: + colinfo.binary = true; + colinfo.type = STRING_V; + break; + case DBTYPE_STR: case DBTYPE_BSTR: case DBTYPE_WSTR: @@ -899,16 +911,29 @@ void OleDBConnection::TryPrefetch() if(countrows <= 0) return; for(unsigned i = 0; i < countrows; i++) { + Vector& val = prefetch.Add(); + val.SetCount(info.GetCount()); for(int p = 0; p < fetch_bindings.GetCount(); p++) { BindingPart& part = fetch_bindings[p]; LTIMING("OleDBConnection::TryPrefetch->GetData"); - OleDBVerify(fetch_rowset->GetData(fetch_hrows[i], part.haccessor, part.rowbuffer)); + try { + OleDBVerify(fetch_rowset->GetData(fetch_hrows[i], part.haccessor, part.rowbuffer)); + fetch_bindings[p].GetRowData(val); + } + catch(OleExc e) { + String col_errs; + for(int b = 0; b < part.bindings.GetCount(); b++) { + const DBBINDING& dbbind = part.bindings[b]; + int status = *(const DBSTATUS *)(~part.rowbuffer + dbbind.obStatus); + if(status != S_OK && status != DBSTATUS_S_ISNULL) { + if(!IsNull(col_errs)) + col_errs.Cat("; "); + col_errs << part.colnames[b] << ": " << OleExc(status); + } + } + throw OleExc(e.hresult, col_errs); + } } - LTIMING("OleDBConnection::TryPrefetch->GetRowData"); - Vector& val = prefetch.Add(); - val.SetCount(info.GetCount()); - for(int p = 0; p < fetch_bindings.GetCount(); p++) - fetch_bindings[p].GetRowData(val); } LTIMING("OleDBConnection::TryPrefetch->ReleaseRows"); OleDBVerify(fetch_rowset->ReleaseRows(countrows, prows, NULL, NULL, NULL)); diff --git a/uppsrc/Oracle/Oci7.cpp b/uppsrc/Oracle/Oci7.cpp index df3f1125f..309da8f3a 100644 --- a/uppsrc/Oracle/Oci7.cpp +++ b/uppsrc/Oracle/Oci7.cpp @@ -430,6 +430,7 @@ bool OCI7Connection::GetColumnInfo() h[hlen] = '\0'; ii.name = h; ii.name = ToUpper(TrimRight(ii.name)); + ii.binary = (type == SQLT_LBI || type == SQLT_BLOB); tp.Add(type); if(type == SQLT_LBI || type == SQLT_BLOB || type == SQLT_CLOB) frows = 1; diff --git a/uppsrc/Oracle/Oci8.cpp b/uppsrc/Oracle/Oci8.cpp index fb0e57b13..ad0123103 100644 --- a/uppsrc/Oracle/Oci8.cpp +++ b/uppsrc/Oracle/Oci8.cpp @@ -678,6 +678,7 @@ bool OCI8Connection::GetColumnInfo() { ci.width = p.dyna_width; ci.precision = Null; ci.scale = Null; + ci.binary = (p.type == SQLT_LBI || p.type == SQLT_BLOB); } parse = false; return true; @@ -703,6 +704,7 @@ bool OCI8Connection::GetColumnInfo() { ii.precision = prec; ii.scale = scale; ii.name = ToUpper(TrimRight(String(name, name_len))); + ii.binary = false; bool blob = false; switch(type) { case SQLT_NUM: @@ -717,6 +719,7 @@ bool OCI8Connection::GetColumnInfo() { ii.type = ORA_BLOB_V; AddColumn(SQLT_BLOB, sizeof(OCILobLocator *)); blob = true; + ii.binary = true; break; case SQLT_CLOB: ii.type = ORA_CLOB_V; diff --git a/uppsrc/PostgreSQL/PostgreSQL.cpp b/uppsrc/PostgreSQL/PostgreSQL.cpp index 5f3c30e01..98f6cb2aa 100644 --- a/uppsrc/PostgreSQL/PostgreSQL.cpp +++ b/uppsrc/PostgreSQL/PostgreSQL.cpp @@ -264,6 +264,7 @@ Vector PostgreSQLSession::EnumColumns(String database, String tab ci.precision = (type_mod >> 16) & 0xffff; ci.scale = type_mod & 0xffff; ci.nullable = AsString(sql[4]) == "0"; + ci.binary = false; } return vec; } diff --git a/uppsrc/Sql/Sqls.h b/uppsrc/Sql/Sqls.h index fee2e6ae8..005180285 100644 --- a/uppsrc/Sql/Sqls.h +++ b/uppsrc/Sql/Sqls.h @@ -37,6 +37,7 @@ struct SqlColumnInfo : Moveable { int precision; //number of total digits in numeric types int scale; //number of digits after comma in numeric types bool nullable; //true - column can hold null values + bool binary; //column holds binary data }; class SqlConnection { diff --git a/uppsrc/SqlCtrl/SqlConsole.cpp b/uppsrc/SqlCtrl/SqlConsole.cpp index 1b3ec1624..20bd54331 100644 --- a/uppsrc/SqlCtrl/SqlConsole.cpp +++ b/uppsrc/SqlCtrl/SqlConsole.cpp @@ -7,6 +7,139 @@ NAMESPACE_UPP #define IMAGECLASS SqlConsoleImg #include +static bool scmpw(const byte *s, const char *w) { + for(;;) { + if(*w == '\0') + return *s == ' ' || *s == '\t'; + if(ToUpper(*s++) != ToUpper(*w++)) + return false; + } +} + +static const int MAX_NESTING_LEVEL = 10; +static const int PROGRESS_RANGE = 1000000000; + +bool SqlRunScript(int dialect, Stream& script_stream, + Gate1 executor, Gate2 progress, + Index& script_file_names, int progress_min, int progress_max) +{ + int line_number = 1; + for(int c; (c = script_stream.Term()) >= 0;) { + if(c <= ' ') { + if(c == '\n') + line_number++; + script_stream.Get(); + } + else if(c == '@') { + script_stream.Get(); + int64 start = script_stream.GetPos() - 1; + bool rel = false; + if(script_stream.Term() == '@') { + script_stream.Get(); + rel = true; + } + StringBuffer subscript_fn; + while((c = script_stream.Get()) >= 0 && c != '\n') + subscript_fn.Cat((char)c); + int e = subscript_fn.GetLength(); + while(e > 0 && subscript_fn[e - 1] <= ' ') + e--; + String fn(~subscript_fn, e); + fn = NormalizePath(fn, GetFileDirectory(script_file_names[rel ? script_file_names.GetCount() - 1 : 0])); + String norm = fn; +#if !PLATFORM_PATH_HAS_CASE + norm = ToLower(norm); +#endif + if(script_file_names.Find(norm) >= 0) + throw Exc(NFormat(t_("circular script inclusion of %s at %s:%d"), + fn, script_file_names.Top(), line_number)); + if(script_file_names.GetCount() >= MAX_NESTING_LEVEL) + throw Exc(NFormat(t_("script nesting too deep (%d levels)"), script_file_names.GetCount())); + int64 end = script_stream.GetPos(); + + int new_min = progress_min + (int)((progress_max - progress_min) * start / script_stream.GetSize()); + int new_max = progress_min + (int)((progress_max - progress_min) * end / script_stream.GetSize()); + + FileIn fi; + if(!fi.Open(fn)) + throw Exc(NFormat(t_("error opening script file '%s'"), fn)); + + script_file_names.Add(norm); + if(!SqlRunScript(dialect, fi, executor, progress, script_file_names, new_min, new_max)) + return false; + script_file_names.Drop(); + } + else { + StringBuffer statement; + bool exec = false; + bool body = false; + bool chr = false; + + while(!script_stream.IsEof() && !exec) { + String line = script_stream.GetLine(); + line_number++; + + int l = line.GetLength(); + if(l && line[0] == '/' && !body && !chr) + exec = true; + else + if(l && line[0] == '.' && body && !chr) + body = false; + else { + if(statement.GetLength() && !chr) + statement.Cat(' '); + bool spc = true; + bool create = false; + for(const byte *s = (const byte *)(const char *)line; *s; s++) { + if(s[0] == '-' && s[1] == '-' && !chr) break; + if(*s == '\'') chr = !chr; + if(!chr && spc && scmpw(s, "create")) + create = true; + if(!chr && spc && (scmpw(s, "begin") || scmpw(s, "declare") || + create && (scmpw(s, "procedure") || scmpw(s, "function") || scmpw(s, "trigger")) + )) + body = true; + if(*s == ';' && !chr && !body) { + exec = true; + break; + } + if(*s > ' ' || chr) { + statement.Cat(*s); + spc = false; + } + else + if(*s == '\t' || *s == ' ') { + if(!spc) statement.Cat(' '); + spc = true; + } + else + spc = false; + } + if(chr) statement.Cat("\r\n"); + } + } + if(progress((int)(progress_min + script_stream.GetPos() + * (progress_max - progress_min) / script_stream.GetSize()), PROGRESS_RANGE)) + throw AbortExc(); + if(!executor(statement)) + return false; + } + } + return true; +} + +bool SqlRunScript(int dialect, Stream& script_stream, const String& file_name, + Gate1 executor, Gate2 progress) +{ + Index script_file_names; + String fn = NormalizePath(file_name); +#if !PLATFORM_PASH_HAS_CASE + fn = ToLower(fn); +#endif + script_file_names.Add(fn); + return SqlRunScript(dialect, script_stream, executor, progress, script_file_names, 0, PROGRESS_RANGE); +} + void RunDlgSqlExport(Sql& cursor, String command, String tablename); class MacroSet { @@ -245,12 +378,16 @@ protected: friend class Exec; class Exec : public StatementExecutor { public: + typedef Exec CLASSNAME; Exec(bool quiet) : quiet(quiet) {} SqlConsole *me; bool quiet; virtual bool Execute(const String& stmt) { me->command <<= stmt; me->Sync(); me->Execute(quiet ? QUIET : SCRIPT); return true; } + bool GateExec(String stmt) { return Execute(stmt); } + operator Gate1 () { return THISBACK(GateExec); } + }; public: @@ -495,11 +632,11 @@ void SqlConsole::SaveTrace() { } void SqlConsole::RunScript(bool quiet) { - UPP::RunScript runscript = cursor.GetSession().GetRunScript(); - if(!runscript) { - Exclamation(t_("Database connection doesn't support running scripts.")); - return; - } +// UPP::RunScript runscript = cursor.GetSession().GetRunScript(); +// if(!runscript) { +// Exclamation(t_("Database connection doesn't support running scripts.")); +// return; +// } FileSelector fsel; fsel.ActiveDir(LastDir); fsel.DefaultExt("sql"); @@ -510,7 +647,17 @@ void SqlConsole::RunScript(bool quiet) { exec.me = this; LastDir = GetFileDirectory(~fsel); Progress progress(t_("Executing script")); - (*runscript)(LoadFile(~fsel), exec, progress); + FileIn fi; + if(!fi.Open(~fsel)) { + Exclamation(NFormat(t_("Cannot open file [* \1%s\1]."), ~fsel)); + return; + } + try { + SqlRunScript(cursor.GetDialect(), fi, ~fsel, exec, progress); + } + catch(Exc e) { + ShowExc(e); + } } void SqlConsole::TraceMenu(Bar& menu) { diff --git a/uppsrc/SqlCtrl/SqlCtrl.upp b/uppsrc/SqlCtrl/SqlCtrl.upp index 787ad307f..cd6441e50 100644 --- a/uppsrc/SqlCtrl/SqlCtrl.upp +++ b/uppsrc/SqlCtrl/SqlCtrl.upp @@ -14,8 +14,8 @@ file SqlDetail.cpp, SqlDlg.h, SqlDlg.cpp, - SqlConsole.cpp, SqlObjectTree.cpp, + SqlConsole.cpp, SqlCtrl.lay, SqlCtrl.iml, SqlCtrl.usc, diff --git a/uppsrc/SqlCtrl/SqlObjectTree.cpp b/uppsrc/SqlCtrl/SqlObjectTree.cpp index 37c5d3e95..f54f8dca8 100644 --- a/uppsrc/SqlCtrl/SqlObjectTree.cpp +++ b/uppsrc/SqlCtrl/SqlObjectTree.cpp @@ -177,7 +177,7 @@ void DlgSqlExport::Run(Sql& cursor, String command, String tablename) } case FMT_SQL: { if(i) script.Cat(", "); -// script << SqlCompile(SQLD_ORACLE, SqlFormat(v)); + script << SqlCompile(cursor.GetDialect(), SqlFormat(v)); break; } } diff --git a/uppsrc/SqlCtrl/init b/uppsrc/SqlCtrl/init index 23ddb2cb1..dd205e6b8 100644 --- a/uppsrc/SqlCtrl/init +++ b/uppsrc/SqlCtrl/init @@ -3,7 +3,7 @@ #include "Sql/init" #include "CtrlLib/init" #include "Report/init" -#define BLITZ_INDEX__ F893B01C4DCFC6A13274E6B20E2CC8D8F +#define BLITZ_INDEX__ F13D66F2A492C0EEDA4C2329579AD9C4A #include "SqlCtrl_init.icpp" #undef BLITZ_INDEX__ #endif diff --git a/uppsrc/plugin/sqlite3/Sqlite3upp.cpp b/uppsrc/plugin/sqlite3/Sqlite3upp.cpp index 33e1df131..07198fa0e 100644 --- a/uppsrc/plugin/sqlite3/Sqlite3upp.cpp +++ b/uppsrc/plugin/sqlite3/Sqlite3upp.cpp @@ -186,6 +186,7 @@ bool Sqlite3Connection::Execute() { for (int i = 0; i < numfields; ++i) { SqlColumnInfo& field = info[i]; field.name = sqlite3_column_name(current_stmt,i); + field.binary = false; String coltype = sqlite3_column_decltype(current_stmt,i); switch (sqlite3_column_type(current_stmt,i)) { case SQLITE_INTEGER: @@ -223,6 +224,7 @@ bool Sqlite3Connection::Execute() { break; case SQLITE_BLOB: field.type = STRING_V; + field.binary = true; break; default: NEVER();