Browse Source

--- Merging r29680 into '.':
U packages/mysql/src/mysql.inc
--- Recording mergeinfo for merge of r29680 into '.':
U .
--- Merging r29681 into '.':
U packages/dblib/src/dblib.pp
--- Recording mergeinfo for merge of r29681 into '.':
G .
--- Merging r29719 into '.':
U packages/fcl-db/src/sqldb/odbc/odbcconn.pas
--- Recording mergeinfo for merge of r29719 into '.':
G .
--- Merging r29751 into '.':
G packages/fcl-db/src/sqldb/odbc/odbcconn.pas
U packages/fcl-db/tests/testsqldb.pas
--- Recording mergeinfo for merge of r29751 into '.':
G .
--- Merging r29758 into '.':
U packages/fcl-db/src/base/db.pas
U packages/fcl-db/src/base/fields.inc
--- Recording mergeinfo for merge of r29758 into '.':
G .
--- Merging r29759 into '.':
U packages/fcl-db/src/sqldb/oracle/oracleconnection.pp
--- Recording mergeinfo for merge of r29759 into '.':
G .
--- Merging r29764 into '.':
G packages/fcl-db/src/sqldb/odbc/odbcconn.pas
--- Recording mergeinfo for merge of r29764 into '.':
G .
--- Merging r29765 into '.':
U packages/fcl-db/src/sqldb/sqlite/sqlite3conn.pp
--- Recording mergeinfo for merge of r29765 into '.':
G .
--- Merging r29766 into '.':
U packages/sqlite/src/sqlite3.inc
--- Recording mergeinfo for merge of r29766 into '.':
G .
--- Merging r30005 into '.':
U packages/fcl-db/src/dbase/dbf_str_pl.pas
--- Recording mergeinfo for merge of r30005 into '.':
G .
--- Merging r30012 into '.':
U packages/fcl-db/src/dbase/dbf_str_fr.pas
U packages/fcl-db/src/dbase/dbf_str_nl.pas
U packages/fcl-db/src/dbase/dbf_str_ita.pas
U packages/fcl-db/src/dbase/dbf_str.pas
U packages/fcl-db/src/dbase/dbf_str_pt.pas
U packages/fcl-db/src/dbase/dbf_str_ru.pas
U packages/fcl-db/src/dbase/dbf_str_es.pas
--- Recording mergeinfo for merge of r30012 into '.':
G .
--- Merging r30082 into '.':
U packages/fcl-db/src/sqldb/mssql/mssqlconn.pp
--- Recording mergeinfo for merge of r30082 into '.':
G .
--- Merging r30120 into '.':
U packages/fcl-db/src/sqldb/mysql/mysqlconn.inc
--- Recording mergeinfo for merge of r30120 into '.':
G .
--- Merging r30121 into '.':
U packages/fcl-db/src/sqldb/postgres/pqconnection.pp
--- Recording mergeinfo for merge of r30121 into '.':
G .

# revisions: 29680,29681,29719,29751,29758,29759,29764,29765,29766,30005,30012,30082,30120,30121

git-svn-id: branches/fixes_3_0@31067 -

marco 10 years ago
parent
commit
6f7a3ea841

+ 32 - 31
packages/dblib/src/dblib.pp

@@ -173,6 +173,7 @@ const
 
 
   // Error codes:
   // Error codes:
   SYBEFCON = 20002;      // SQL Server connection failed
   SYBEFCON = 20002;      // SQL Server connection failed
+  SYBESMSG = 20018;      // General SQL Server error: Check messages from the SQL Server.
 
 
 type
 type
   PLOGINREC=Pointer;
   PLOGINREC=Pointer;
@@ -275,8 +276,8 @@ type
     str: array[0..DBMAXCHAR-1] of AnsiChar;
     str: array[0..DBMAXCHAR-1] of AnsiChar;
   end;
   end;
 
 
-  DBERRHANDLE_PROC=function(dbproc: PDBPROCESS; severity, dberr, oserr:INT; dberrstr, oserrstr:PChar):INT; cdecl;
-  DBMSGHANDLE_PROC=function(dbproc: PDBPROCESS; msgno: DBINT; msgstate, severity:INT; msgtext, srvname, procname:PChar; line:DBUSMALLINT):INT; cdecl;
+  DBERRHANDLE_PROC=function(dbproc: PDBPROCESS; severity, dberr, oserr:INT; dberrstr, oserrstr:PAnsiChar):INT; cdecl;
+  DBMSGHANDLE_PROC=function(dbproc: PDBPROCESS; msgno: DBINT; msgstate, severity:INT; msgtext, srvname, procname:PAnsiChar; line:DBUSMALLINT):INT; cdecl;
 
 
   {$IFDEF ntwdblib}
   {$IFDEF ntwdblib}
     {$PACKRECORDS 2}
     {$PACKRECORDS 2}
@@ -305,27 +306,27 @@ var
   DBLibInit: boolean=false; //was dbinit() already called ?
   DBLibInit: boolean=false; //was dbinit() already called ?
 
 
 {$IFNDEF LOAD_DYNAMICALLY}
 {$IFNDEF LOAD_DYNAMICALLY}
-  function dbinit():{$IFDEF freetds}RETCODE{$ELSE}PChar{$ENDIF}; cdecl; external DBLIBDLL;
+  function dbinit():{$IFDEF freetds}RETCODE{$ELSE}PAnsiChar{$ENDIF}; cdecl; external DBLIBDLL;
   function dblogin():PLOGINREC; cdecl; external DBLIBDLL;
   function dblogin():PLOGINREC; cdecl; external DBLIBDLL;
-  function dbsetlname(login:PLOGINREC; value:PChar; which:INT):RETCODE; cdecl; external DBLIBDLL;
+  function dbsetlname(login:PLOGINREC; value:PAnsiChar; which:INT):RETCODE; cdecl; external DBLIBDLL;
   function dbsetlogintime(seconds:INT):RETCODE; cdecl; external DBLIBDLL;
   function dbsetlogintime(seconds:INT):RETCODE; cdecl; external DBLIBDLL;
   function dbsettime(seconds:INT):RETCODE; cdecl; external DBLIBDLL;
   function dbsettime(seconds:INT):RETCODE; cdecl; external DBLIBDLL;
   function dberrhandle(handler:DBERRHANDLE_PROC):DBERRHANDLE_PROC; cdecl; external DBLIBDLL;
   function dberrhandle(handler:DBERRHANDLE_PROC):DBERRHANDLE_PROC; cdecl; external DBLIBDLL;
   function dbmsghandle(handler:DBMSGHANDLE_PROC):DBMSGHANDLE_PROC; cdecl; external DBLIBDLL;
   function dbmsghandle(handler:DBMSGHANDLE_PROC):DBMSGHANDLE_PROC; cdecl; external DBLIBDLL;
-  function dbsetopt(dbproc:PDBPROCESS; option: INT; param:PChar {$IFDEF freetds};int_param:INT{$ENDIF}):RETCODE; cdecl; external DBLIBDLL;
-  function dbuse(dbproc:PDBPROCESS; dbname:PChar):RETCODE; cdecl; external DBLIBDLL;
-  function dbcmd(dbproc:PDBPROCESS; cmdstring:PChar):RETCODE; cdecl; external DBLIBDLL;
+  function dbsetopt(dbproc:PDBPROCESS; option: INT; param:PAnsiChar {$IFDEF freetds};int_param:INT{$ENDIF}):RETCODE; cdecl; external DBLIBDLL;
+  function dbuse(dbproc:PDBPROCESS; dbname:PAnsiChar):RETCODE; cdecl; external DBLIBDLL;
+  function dbcmd(dbproc:PDBPROCESS; cmdstring:PAnsiChar):RETCODE; cdecl; external DBLIBDLL;
   function dbcmdrow(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
   function dbcmdrow(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
   function dbsqlexec(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
   function dbsqlexec(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
   function dbresults(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
   function dbresults(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
   function dbmorecmds(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
   function dbmorecmds(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
   function dbnextrow(dbproc:PDBPROCESS):STATUS; cdecl; external DBLIBDLL;
   function dbnextrow(dbproc:PDBPROCESS):STATUS; cdecl; external DBLIBDLL;
   function dbnumcols(dbproc:PDBPROCESS):INT; cdecl; external DBLIBDLL;
   function dbnumcols(dbproc:PDBPROCESS):INT; cdecl; external DBLIBDLL;
-  function dbcolname(dbproc:PDBPROCESS; column:INT):PChar; cdecl; external DBLIBDLL;
+  function dbcolname(dbproc:PDBPROCESS; column:INT):PAnsiChar; cdecl; external DBLIBDLL;
   function dbcoltype(dbproc:PDBPROCESS; column:INT):INT; cdecl; external DBLIBDLL;
   function dbcoltype(dbproc:PDBPROCESS; column:INT):INT; cdecl; external DBLIBDLL;
   function dbcollen(dbproc:PDBPROCESS; column:INT):DBINT; cdecl; external DBLIBDLL;
   function dbcollen(dbproc:PDBPROCESS; column:INT):DBINT; cdecl; external DBLIBDLL;
   function dbcolinfo(dbproc:PDBPROCESS; typ:INT; column:DBINT; computeid:DBINT; dbcol:PDBCOL):RETCODE; cdecl; external DBLIBDLL;
   function dbcolinfo(dbproc:PDBPROCESS; typ:INT; column:DBINT; computeid:DBINT; dbcol:PDBCOL):RETCODE; cdecl; external DBLIBDLL;
-  function dbprtype(token:INT):PChar; cdecl; external DBLIBDLL;
+  function dbprtype(token:INT):PAnsiChar; cdecl; external DBLIBDLL;
   function dbdatlen(dbproc:PDBPROCESS; column:INT):DBINT; cdecl; external DBLIBDLL;
   function dbdatlen(dbproc:PDBPROCESS; column:INT):DBINT; cdecl; external DBLIBDLL;
   function dbdata(dbproc:PDBPROCESS; column:INT):PByte; cdecl; external DBLIBDLL;
   function dbdata(dbproc:PDBPROCESS; column:INT):PByte; cdecl; external DBLIBDLL;
   function dbwillconvert(srctype, desttype: INT):{$IFDEF freetds}DBBOOL{$ELSE}BOOL{$ENDIF}; cdecl; external DBLIBDLL;
   function dbwillconvert(srctype, desttype: INT):{$IFDEF freetds}DBBOOL{$ELSE}BOOL{$ENDIF}; cdecl; external DBLIBDLL;
@@ -340,41 +341,41 @@ var
   procedure dbfreelogin(login:PLOGINREC); cdecl; external DBLIBDLL {$IFDEF freetds}name 'dbloginfree'{$ENDIF};
   procedure dbfreelogin(login:PLOGINREC); cdecl; external DBLIBDLL {$IFDEF freetds}name 'dbloginfree'{$ENDIF};
   procedure dbexit(); cdecl; external DBLIBDLL;
   procedure dbexit(); cdecl; external DBLIBDLL;
   {$IFDEF ntwdblib}
   {$IFDEF ntwdblib}
-  function dbopen(login:PLOGINREC; servername:PChar):PDBPROCESS; cdecl; external DBLIBDLL;
+  function dbopen(login:PLOGINREC; servername:PAnsiChar):PDBPROCESS; cdecl; external DBLIBDLL;
   function dbclose(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
   function dbclose(dbproc:PDBPROCESS):RETCODE; cdecl; external DBLIBDLL;
   procedure dbwinexit; cdecl; external DBLIBDLL;
   procedure dbwinexit; cdecl; external DBLIBDLL;
   {$ENDIF}
   {$ENDIF}
   {$IFDEF freetds}
   {$IFDEF freetds}
-  function tdsdbopen(login:PLOGINREC; servername:PChar; msdblib:INT):PDBPROCESS; cdecl; external DBLIBDLL;
+  function tdsdbopen(login:PLOGINREC; servername:PAnsiChar; msdblib:INT):PDBPROCESS; cdecl; external DBLIBDLL;
   function dbtablecolinfo(dbproc:PDBPROCESS; column:DBINT; dbcol:PDBCOL):RETCODE; cdecl; external DBLIBDLL;
   function dbtablecolinfo(dbproc:PDBPROCESS; column:DBINT; dbcol:PDBCOL):RETCODE; cdecl; external DBLIBDLL;
   function dbtds(dbproc:PDBPROCESS):INT; cdecl; external DBLIBDLL;
   function dbtds(dbproc:PDBPROCESS):INT; cdecl; external DBLIBDLL;
   function dbsetlversion(login:PLOGINREC; version:BYTE):RETCODE; cdecl; external DBLIBDLL;
   function dbsetlversion(login:PLOGINREC; version:BYTE):RETCODE; cdecl; external DBLIBDLL;
-  function dbservcharset(dbproc:PDBPROCESS):PChar; cdecl; external DBLIBDLL;
+  function dbservcharset(dbproc:PDBPROCESS):PAnsiChar; cdecl; external DBLIBDLL;
   procedure dbclose(dbproc:PDBPROCESS); cdecl; external DBLIBDLL;
   procedure dbclose(dbproc:PDBPROCESS); cdecl; external DBLIBDLL;
   {$ENDIF}
   {$ENDIF}
 {$ELSE}
 {$ELSE}
   var
   var
-  dbinit: function():{$IFDEF freetds}RETCODE{$ELSE}PChar{$ENDIF}; cdecl;
+  dbinit: function():{$IFDEF freetds}RETCODE{$ELSE}PAnsiChar{$ENDIF}; cdecl;
   dblogin: function():PLOGINREC; cdecl;
   dblogin: function():PLOGINREC; cdecl;
-  dbsetlname: function(login:PLOGINREC; value:PChar; which:INT):RETCODE; cdecl;
+  dbsetlname: function(login:PLOGINREC; value:PAnsiChar; which:INT):RETCODE; cdecl;
   dbsetlogintime: function(seconds:INT):RETCODE; cdecl;
   dbsetlogintime: function(seconds:INT):RETCODE; cdecl;
   dbsettime: function(seconds:INT):RETCODE; cdecl;
   dbsettime: function(seconds:INT):RETCODE; cdecl;
   dberrhandle: function(handler:DBERRHANDLE_PROC):DBERRHANDLE_PROC; cdecl;
   dberrhandle: function(handler:DBERRHANDLE_PROC):DBERRHANDLE_PROC; cdecl;
   dbmsghandle: function(handler:DBMSGHANDLE_PROC):DBMSGHANDLE_PROC; cdecl;
   dbmsghandle: function(handler:DBMSGHANDLE_PROC):DBMSGHANDLE_PROC; cdecl;
-  dbsetopt: function(dbproc:PDBPROCESS; option: INT; param:PChar {$IFDEF freetds};int_param:INT{$ENDIF}):RETCODE; cdecl;
-  dbuse: function(dbproc:PDBPROCESS; dbname:PChar):RETCODE; cdecl;
-  dbcmd: function(dbproc:PDBPROCESS; cmdstring:PChar):RETCODE; cdecl;
+  dbsetopt: function(dbproc:PDBPROCESS; option: INT; param:PAnsiChar {$IFDEF freetds};int_param:INT{$ENDIF}):RETCODE; cdecl;
+  dbuse: function(dbproc:PDBPROCESS; dbname:PAnsiChar):RETCODE; cdecl;
+  dbcmd: function(dbproc:PDBPROCESS; cmdstring:PAnsiChar):RETCODE; cdecl;
   dbcmdrow: function(dbproc:PDBPROCESS):RETCODE; cdecl;
   dbcmdrow: function(dbproc:PDBPROCESS):RETCODE; cdecl;
   dbsqlexec: function(dbproc:PDBPROCESS):RETCODE; cdecl;
   dbsqlexec: function(dbproc:PDBPROCESS):RETCODE; cdecl;
   dbresults: function(dbproc:PDBPROCESS):RETCODE; cdecl;
   dbresults: function(dbproc:PDBPROCESS):RETCODE; cdecl;
   dbmorecmds: function(dbproc:PDBPROCESS):RETCODE; cdecl;
   dbmorecmds: function(dbproc:PDBPROCESS):RETCODE; cdecl;
   dbnextrow: function(dbproc:PDBPROCESS):STATUS; cdecl;
   dbnextrow: function(dbproc:PDBPROCESS):STATUS; cdecl;
   dbnumcols: function(dbproc:PDBPROCESS):INT; cdecl;
   dbnumcols: function(dbproc:PDBPROCESS):INT; cdecl;
-  dbcolname: function(dbproc:PDBPROCESS; column:INT):PChar; cdecl;
+  dbcolname: function(dbproc:PDBPROCESS; column:INT):PAnsiChar; cdecl;
   dbcoltype: function(dbproc:PDBPROCESS; column:INT):INT; cdecl;
   dbcoltype: function(dbproc:PDBPROCESS; column:INT):INT; cdecl;
   dbcollen: function(dbproc:PDBPROCESS; column:INT):DBINT; cdecl;
   dbcollen: function(dbproc:PDBPROCESS; column:INT):DBINT; cdecl;
   dbcolinfo: function(dbproc:PDBPROCESS; typ:INT; column:DBINT; computeid:DBINT; dbcol:PDBCOL):RETCODE; cdecl;
   dbcolinfo: function(dbproc:PDBPROCESS; typ:INT; column:DBINT; computeid:DBINT; dbcol:PDBCOL):RETCODE; cdecl;
-  dbprtype: function(token:INT):PChar; cdecl;
+  dbprtype: function(token:INT):PAnsiChar; cdecl;
   dbdatlen: function(dbproc:PDBPROCESS; column:INT):DBINT; cdecl;
   dbdatlen: function(dbproc:PDBPROCESS; column:INT):DBINT; cdecl;
   dbdata: function(dbproc:PDBPROCESS; column:INT):PByte; cdecl;
   dbdata: function(dbproc:PDBPROCESS; column:INT):PByte; cdecl;
   dbwillconvert: function(srctype, desttype: INT):{$IFDEF freetds}DBBOOL{$ELSE}BOOL{$ENDIF}; cdecl;
   dbwillconvert: function(srctype, desttype: INT):{$IFDEF freetds}DBBOOL{$ELSE}BOOL{$ENDIF}; cdecl;
@@ -389,16 +390,16 @@ var
   dbexit: procedure(); cdecl;
   dbexit: procedure(); cdecl;
   dbfreelogin: procedure(login:PLOGINREC); cdecl;
   dbfreelogin: procedure(login:PLOGINREC); cdecl;
   {$IFDEF ntwdblib}
   {$IFDEF ntwdblib}
-  dbopen: function(login:PLOGINREC; servername:PChar):PDBPROCESS; cdecl;
+  dbopen: function(login:PLOGINREC; servername:PAnsiChar):PDBPROCESS; cdecl;
   dbclose: function(dbproc:PDBPROCESS):RETCODE; cdecl;
   dbclose: function(dbproc:PDBPROCESS):RETCODE; cdecl;
   dbwinexit: procedure; cdecl;
   dbwinexit: procedure; cdecl;
   {$ENDIF}
   {$ENDIF}
   {$IFDEF freetds}
   {$IFDEF freetds}
-  tdsdbopen: function(login:PLOGINREC; servername:PChar; msdblib:INT):PDBPROCESS; cdecl;
+  tdsdbopen: function(login:PLOGINREC; servername:PAnsiChar; msdblib:INT):PDBPROCESS; cdecl;
   dbtablecolinfo: function(dbproc:PDBPROCESS; column:DBINT; dbcol:PDBCOL):RETCODE; cdecl;
   dbtablecolinfo: function(dbproc:PDBPROCESS; column:DBINT; dbcol:PDBCOL):RETCODE; cdecl;
   dbtds: function(dbproc:PDBPROCESS):INT; cdecl;
   dbtds: function(dbproc:PDBPROCESS):INT; cdecl;
   dbsetlversion: function(login:PLOGINREC; version:BYTE):RETCODE; cdecl;
   dbsetlversion: function(login:PLOGINREC; version:BYTE):RETCODE; cdecl;
-  dbservcharset: function(dbproc:PDBPROCESS):PChar; cdecl;
+  dbservcharset: function(dbproc:PDBPROCESS):PAnsiChar; cdecl;
   dbclose: procedure(dbproc:PDBPROCESS); cdecl;
   dbclose: procedure(dbproc:PDBPROCESS); cdecl;
   {$ENDIF}
   {$ENDIF}
 
 
@@ -407,17 +408,17 @@ var
 {$ENDIF}
 {$ENDIF}
 
 
 {$IFDEF ntwdblib}
 {$IFDEF ntwdblib}
-function tdsdbopen(login:PLOGINREC; servername:PChar; msdblib:INT):PDBPROCESS;
+function tdsdbopen(login:PLOGINREC; servername:PAnsiChar; msdblib:INT):PDBPROCESS;
 function dbtablecolinfo(dbproc:PDBPROCESS; column:DBINT; dbcol:PDBCOL):RETCODE;
 function dbtablecolinfo(dbproc:PDBPROCESS; column:DBINT; dbcol:PDBCOL):RETCODE;
 function dbsetlversion(login:PLOGINREC; version:BYTE):RETCODE;
 function dbsetlversion(login:PLOGINREC; version:BYTE):RETCODE;
 function dbtds(dbproc:PDBPROCESS):INT;
 function dbtds(dbproc:PDBPROCESS):INT;
-function dbversion():PChar;
+function dbversion():PAnsiChar;
 {$ENDIF}
 {$ENDIF}
 {$IFDEF freetds}
 {$IFDEF freetds}
-function dbopen(login:PLOGINREC; servername:PChar):PDBPROCESS;
+function dbopen(login:PLOGINREC; servername:PAnsiChar):PDBPROCESS;
 procedure dbwinexit;
 procedure dbwinexit;
 {$ENDIF}
 {$ENDIF}
-function dbsetlcharset(login:PLOGINREC; charset:PChar):RETCODE;
+function dbsetlcharset(login:PLOGINREC; charset:PAnsiChar):RETCODE;
 function dbsetlsecure(login:PLOGINREC):RETCODE;
 function dbsetlsecure(login:PLOGINREC):RETCODE;
 function dbdatetimeallcrack(dta: PDBDATETIMEALL): TDateTime;
 function dbdatetimeallcrack(dta: PDBDATETIMEALL): TDateTime;
 function dbmoneytocurr(pdbmoney: PQWord): Currency;
 function dbmoneytocurr(pdbmoney: PQWord): Currency;
@@ -534,12 +535,12 @@ end;
 
 
 //functions, which are not implemented by FreeTDS:
 //functions, which are not implemented by FreeTDS:
 {$IFDEF freetds}
 {$IFDEF freetds}
-function dbopen(login:PLOGINREC; servername:PChar):PDBPROCESS;
+function dbopen(login:PLOGINREC; servername:PAnsiChar):PDBPROCESS;
 begin
 begin
   Result:=tdsdbopen(login, servername, 1{1=MSDBLIB or 0=SYBDBLIB});
   Result:=tdsdbopen(login, servername, 1{1=MSDBLIB or 0=SYBDBLIB});
 end;
 end;
 
 
-function dbsetlcharset(login:PLOGINREC; charset:PChar):RETCODE;
+function dbsetlcharset(login:PLOGINREC; charset:PAnsiChar):RETCODE;
 begin
 begin
   Result:=dbsetlname(login, charset, 10);
   Result:=dbsetlname(login, charset, 10);
 end;
 end;
@@ -558,7 +559,7 @@ end;
 
 
 //functions which are not implemented by ntwdblib:
 //functions which are not implemented by ntwdblib:
 {$IFDEF ntwdblib}
 {$IFDEF ntwdblib}
-function tdsdbopen(login:PLOGINREC; servername:PChar; msdblib:INT):PDBPROCESS;
+function tdsdbopen(login:PLOGINREC; servername:PAnsiChar; msdblib:INT):PDBPROCESS;
 begin
 begin
   Result:=dbopen(login, servername);
   Result:=dbopen(login, servername);
 end;
 end;
@@ -578,7 +579,7 @@ begin
   Result:=dbsetlname(login, nil, version);
   Result:=dbsetlname(login, nil, version);
 end;
 end;
 
 
-function dbsetlcharset(login:PLOGINREC; charset:PChar):RETCODE;
+function dbsetlcharset(login:PLOGINREC; charset:PAnsiChar):RETCODE;
 begin
 begin
   Result:=SUCCEED;
   Result:=SUCCEED;
 end;
 end;
@@ -593,7 +594,7 @@ begin
   Result:=0;
   Result:=0;
 end;
 end;
 
 
-function dbversion():PChar;
+function dbversion():PAnsiChar;
 begin
 begin
   Result:='DB Library version 8.00';
   Result:='DB Library version 8.00';
 end;
 end;

+ 2 - 0
packages/fcl-db/src/base/db.pas

@@ -637,6 +637,7 @@ type
     procedure SetCurrency(const AValue: Boolean);
     procedure SetCurrency(const AValue: Boolean);
     procedure SetPrecision(const AValue: Longint);
     procedure SetPrecision(const AValue: Longint);
   protected
   protected
+    function GetAsBCD: TBCD; override;
     function GetAsFloat: Double; override;
     function GetAsFloat: Double; override;
     function GetAsLargeInt: LargeInt; override;
     function GetAsLargeInt: LargeInt; override;
     function GetAsInteger: Longint; override;
     function GetAsInteger: Longint; override;
@@ -644,6 +645,7 @@ type
     function GetAsString: string; override;
     function GetAsString: string; override;
     function GetDataSize: Integer; override;
     function GetDataSize: Integer; override;
     procedure GetText(var theText: string; ADisplayText: Boolean); override;
     procedure GetText(var theText: string; ADisplayText: Boolean); override;
+    procedure SetAsBCD(const AValue: TBCD); override;
     procedure SetAsFloat(AValue: Double); override;
     procedure SetAsFloat(AValue: Double); override;
     procedure SetAsLargeInt(AValue: LargeInt); override;
     procedure SetAsLargeInt(AValue: LargeInt); override;
     procedure SetAsInteger(AValue: Longint); override;
     procedure SetAsInteger(AValue: Longint); override;

+ 20 - 6
packages/fcl-db/src/base/fields.inc

@@ -1778,6 +1778,15 @@ begin
     FPrecision := 2;
     FPrecision := 2;
 end;
 end;
 
 
+function TFloatField.GetAsBCD: TBCD;
+var f : Double;
+begin
+  if GetData(@f) then
+    Result := DoubleToBCD(f)
+  else
+    Result := NullBCD;
+end;
+
 function TFloatField.GetAsFloat: Double;
 function TFloatField.GetAsFloat: Double;
 
 
 begin
 begin
@@ -1809,11 +1818,11 @@ end;
 
 
 function TFloatField.GetAsString: string;
 function TFloatField.GetAsString: string;
 
 
-var R : Double;
+var f : Double;
 
 
 begin
 begin
-  If GetData(@R) then
-    Result:=FloatToStr(R)
+  If GetData(@f) then
+    Result:=FloatToStr(f)
   else
   else
     Result:='';
     Result:='';
 end;
 end;
@@ -1859,6 +1868,11 @@ begin
     TheText:=FloatToStrF(E,ff,FPrecision,Digits);
     TheText:=FloatToStrF(E,ff,FPrecision,Digits);
 end;
 end;
 
 
+procedure TFloatField.SetAsBCD(const AValue: TBCD);
+begin
+  SetAsFloat(BCDToDouble(AValue));
+end;
+
 procedure TFloatField.SetAsFloat(AValue: Double);
 procedure TFloatField.SetAsFloat(AValue: Double);
 
 
 begin
 begin
@@ -1881,15 +1895,15 @@ end;
 
 
 procedure TFloatField.SetAsString(const AValue: string);
 procedure TFloatField.SetAsString(const AValue: string);
 
 
-var R : Double;
+var f : Double;
 
 
 begin
 begin
   If (AValue='') then
   If (AValue='') then
     Clear
     Clear
   else  
   else  
     try
     try
-      R := StrToFloat(AValue);
-      SetAsFloat(R);
+      f := StrToFloat(AValue);
+      SetAsFloat(f);
     except
     except
       DatabaseErrorFmt(SNotAFloat, [AValue]);
       DatabaseErrorFmt(SNotAFloat, [AValue]);
     end;
     end;

+ 1 - 1
packages/fcl-db/src/dbase/dbf_str.pas

@@ -11,7 +11,7 @@ initialization
 
 
   STRING_FILE_NOT_FOUND               := 'Open: file not found: "%s".';
   STRING_FILE_NOT_FOUND               := 'Open: file not found: "%s".';
   STRING_VERSION                      := 'TDbf V%d.%d';
   STRING_VERSION                      := 'TDbf V%d.%d';
-  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL:= 'This feature is not supported in tablelevel %d';
+  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL := 'This feature is not supported in tablelevel %d';
 
 
   STRING_RECORD_LOCKED                := 'Record locked.';
   STRING_RECORD_LOCKED                := 'Record locked.';
   STRING_WRITE_ERROR                  := 'Error while writing occurred. (Disk full?)';
   STRING_WRITE_ERROR                  := 'Error while writing occurred. (Disk full?)';

+ 1 - 1
packages/fcl-db/src/dbase/dbf_str_es.pas

@@ -12,7 +12,7 @@ initialization
   STRING_FILE_NOT_FOUND               := 'Apertura: archivo no encontrado: "%s".';
   STRING_FILE_NOT_FOUND               := 'Apertura: archivo no encontrado: "%s".';
   STRING_VERSION                      := 'TDbf V%d.%d';
   STRING_VERSION                      := 'TDbf V%d.%d';
   // todo: translate me
   // todo: translate me
-  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL: string; := 'This feature is not supported in tablelevel %d';
+  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL := 'This feature is not supported in tablelevel %d';
 
 
   STRING_RECORD_LOCKED                := 'Registro bloqueado.';
   STRING_RECORD_LOCKED                := 'Registro bloqueado.';
   STRING_WRITE_ERROR                  := 'Error de escritura. (Disco lleno?)';
   STRING_WRITE_ERROR                  := 'Error de escritura. (Disco lleno?)';

+ 1 - 1
packages/fcl-db/src/dbase/dbf_str_fr.pas

@@ -11,7 +11,7 @@ initialization
 
 
   STRING_FILE_NOT_FOUND               := 'Ouverture: fichier non trouvé: "%s"';
   STRING_FILE_NOT_FOUND               := 'Ouverture: fichier non trouvé: "%s"';
   STRING_VERSION                      := 'TDbf V%d.%d';
   STRING_VERSION                      := 'TDbf V%d.%d';
-  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL: string; := 'Cette fonctionnalité n'est pas supporté dans tablelevel %d'; 
+  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL := 'Cette fonctionnalité n''est pas supporté dans tablelevel %d';
   
   
   STRING_RECORD_LOCKED                := 'Enregistrement verrouillé.';
   STRING_RECORD_LOCKED                := 'Enregistrement verrouillé.';
   STRING_KEY_VIOLATION                := 'Violation de clé. (doublon dans un index).'+#13+#10+
   STRING_KEY_VIOLATION                := 'Violation de clé. (doublon dans un index).'+#13+#10+

+ 1 - 1
packages/fcl-db/src/dbase/dbf_str_ita.pas

@@ -13,7 +13,7 @@ initialization
   STRING_FILE_NOT_FOUND               := 'Apertura: file non trovato: "%s"';
   STRING_FILE_NOT_FOUND               := 'Apertura: file non trovato: "%s"';
   STRING_VERSION                      := 'TDbf V%d.%d';
   STRING_VERSION                      := 'TDbf V%d.%d';
   // todo: translate me
   // todo: translate me
-  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL: string; := 'This feature is not supported in tablelevel %d'; 
+  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL := 'This feature is not supported in tablelevel %d'; 
 
 
   STRING_RECORD_LOCKED                := 'Record già in uso.';
   STRING_RECORD_LOCKED                := 'Record già in uso.';
 
 

+ 1 - 1
packages/fcl-db/src/dbase/dbf_str_nl.pas

@@ -11,7 +11,7 @@ initialization
 
 
   STRING_FILE_NOT_FOUND               := 'Openen: bestand niet gevonden: "%s"';
   STRING_FILE_NOT_FOUND               := 'Openen: bestand niet gevonden: "%s"';
   STRING_VERSION                      := 'TDbf V%d.%d';
   STRING_VERSION                      := 'TDbf V%d.%d';
-  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL: string; := 'Deze functionaliteit wordt niet ondersteund in tablelevel %d'; 
+  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL := 'Deze functionaliteit wordt niet ondersteund in tablelevel %d';
 
 
   STRING_RECORD_LOCKED                := 'Record in gebruik.';
   STRING_RECORD_LOCKED                := 'Record in gebruik.';
   STRING_WRITE_ERROR                  := 'Error tijdens schrijven. (Disk vol?)';
   STRING_WRITE_ERROR                  := 'Error tijdens schrijven. (Disk vol?)';

+ 22 - 23
packages/fcl-db/src/dbase/dbf_str_pl.pas

@@ -9,31 +9,30 @@ implementation
 
 
 initialization
 initialization
 
 
-  STRING_FILE_NOT_FOUND               := 'Open: brak pliku: "%s"';
+  STRING_FILE_NOT_FOUND               := 'Otwórz: brak pliku: "%s".';
   STRING_VERSION                      := 'TDbf V%d.%d';
   STRING_VERSION                      := 'TDbf V%d.%d';
-  // todo: translate me
-  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL: string; := 'This feature is not supported in tablelevel %d';
+  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL := 'Ta funkcja nie jest obs³ugiwana w typie bazy (tablelevel) %d';
 
 
   STRING_RECORD_LOCKED                := 'Rekord zablokowany.';
   STRING_RECORD_LOCKED                := 'Rekord zablokowany.';
-  STRING_WRITE_ERROR                  := 'Niezapisano(Brak miejsca na dysku?)';
-  STRING_KEY_VIOLATION                := 'Konflikt klucza. (Klucz obecny w pliku).'+#13+#10+
-                                         'Indeks: %s'+#13+#10+'Rekord=%d Klucz=''%s''';
-
-  STRING_INVALID_DBF_FILE             := 'Uszkodzony plik bazy.';
-  STRING_INVALID_DBF_FILE_FIELDERROR  := 'Uszkodzony plik bazy. Uszkodzony pol.'; //todo: definitely check field part
-  STRING_FIELD_TOO_LONG               := 'Dana za d³uga : %d znaków (dopuszczalne do %d).';
-  STRING_INVALID_FIELD_COUNT          := 'a liczba pól: %d (dozwolone 1 do 4095).';
-  STRING_INVALID_FIELD_TYPE           := 'B³êdny typ pola ''%c'' dla pola ''%s''.';
-  STRING_INVALID_VCL_FIELD_TYPE       := 'Nie mogê tworzyæ pola "%s", typ pola VCL %x nie wspierany przez DBF.';
-
-
-  STRING_INDEX_BASED_ON_UNKNOWN_FIELD := 'Kluczowe pole indeksu "%s" nie istnieje';
-  STRING_INDEX_BASED_ON_INVALID_FIELD := 'Typ pola "%s" niedozwolony dla indeksów';
-  STRING_INDEX_EXPRESSION_TOO_LONG    := 'Zbyt d³ugi wynik "%s", >100 znaków (%d).';
-  STRING_INVALID_INDEX_TYPE           := 'Z³y typ indeksu: tylko string lub float';
-  STRING_CANNOT_OPEN_INDEX            := 'Nie mogê otworzyæ indeksu: "%s"';
-  STRING_TOO_MANY_INDEXES             := 'Nie mogê stworzyæ indeksu: za du¿o w pliku.';
-  STRING_INDEX_NOT_EXIST              := 'Brak indeksu "%s".';
-  STRING_NEED_EXCLUSIVE_ACCESS        := 'Operacja wymaga dostêpu w trybie Exclusive.';
+  STRING_WRITE_ERROR                  := 'Wyst¹pi³ b³¹d podczas zapisu. (Brak miejsca na dysku?)';
+  STRING_KEY_VIOLATION                := 'Konflikt klucza. (Klucz jest obecny w pliku).'+#13+#10+
+                                         'Indeks: %s'+#13+#10+'Rekord=%d Klucz=''%s''.';
+
+  STRING_INVALID_DBF_FILE             := 'Nieprawid³owy plik DBF.';
+  STRING_INVALID_DBF_FILE_FIELDERROR  := 'Nieprawid³owy plik DBF. B³êdna definicja pola.'; 
+  STRING_FIELD_TOO_LONG               := 'Wartoœæ jest za d³uga: %d znaków (maksymalnie %d).';
+  STRING_INVALID_FIELD_COUNT          := 'Nieprawid³owa liczba pól: %d (dozwolone 1 do 4095).';
+  STRING_INVALID_FIELD_TYPE           := 'Nieprawid³owy typ pola ''%s'' dla pola ''%s''.';
+  STRING_INVALID_VCL_FIELD_TYPE       := 'Nie mo¿na utworzyæ pola "%s", typ pola VCL %x nie jest obs³ugiwany przez DBF.';
+
+
+  STRING_INDEX_BASED_ON_UNKNOWN_FIELD := 'Indeks bazuje na nieznanym polu "%s".';
+  STRING_INDEX_BASED_ON_INVALID_FIELD := 'Typ pola "%s" jest nieprawid³owy dla indeksów.';
+  STRING_INDEX_EXPRESSION_TOO_LONG    := 'Wynik indeksu dla "%s" jest za d³ugi, >100 znaków (%d).';
+  STRING_INVALID_INDEX_TYPE           := 'Nieprawid³owy typ indeksu: tylko string lub float.';
+  STRING_CANNOT_OPEN_INDEX            := 'Nie mogê otworzyæ indeksu: "%s".';
+  STRING_TOO_MANY_INDEXES             := 'Nie mogê utworzyæ indeksu: za du¿o indeksów w pliku.';
+  STRING_INDEX_NOT_EXIST              := 'Indeks "%s" nie istnieje.';
+  STRING_NEED_EXCLUSIVE_ACCESS        := 'Wymagany jest wy³¹czny dostêp dla tej operacji.';
 end.
 end.
 
 

+ 1 - 1
packages/fcl-db/src/dbase/dbf_str_pt.pas

@@ -14,7 +14,7 @@ initialization
   STRING_FILE_NOT_FOUND               := 'Abertura: arquivo não encontrado: "%s".';
   STRING_FILE_NOT_FOUND               := 'Abertura: arquivo não encontrado: "%s".';
   STRING_VERSION                      := 'TDbf V%d.%d';
   STRING_VERSION                      := 'TDbf V%d.%d';
   //todo: translate me
   //todo: translate me
-  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL: string; := 'This feature is not supported in tablelevel %d';
+  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL := 'This feature is not supported in tablelevel %d';
 
 
   STRING_RECORD_LOCKED                := 'Registro bloqueado.';
   STRING_RECORD_LOCKED                := 'Registro bloqueado.';
   STRING_WRITE_ERROR                  := 'Erro de escrita. (Disco cheio?)';
   STRING_WRITE_ERROR                  := 'Erro de escrita. (Disco cheio?)';

+ 1 - 1
packages/fcl-db/src/dbase/dbf_str_ru.pas

@@ -17,7 +17,7 @@ initialization
   STRING_FILE_NOT_FOUND               := 'Ôàéë "%s" íå ñóùåñòâóåò. Îòêðûòü íåâîçìîæíî.';
   STRING_FILE_NOT_FOUND               := 'Ôàéë "%s" íå ñóùåñòâóåò. Îòêðûòü íåâîçìîæíî.';
   STRING_VERSION                      := 'TDbf V%d.%d';
   STRING_VERSION                      := 'TDbf V%d.%d';
   //todo: translate me
   //todo: translate me
-  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL: string; := 'This feature is not supported in tablelevel %d';
+  STRING_FEATURE_NOT_SUPPORTED_THIS_TABLELEVEL := 'This feature is not supported in tablelevel %d';
 
 
   STRING_RECORD_LOCKED                := 'Çàïèñü (ñòðîêà òàáëèöû) çàáëîêèðîâàíà.';
   STRING_RECORD_LOCKED                := 'Çàïèñü (ñòðîêà òàáëèöû) çàáëîêèðîâàíà.';
   STRING_WRITE_ERROR                  := 'Îøèáêà çàïèñè íà äèñê (Äèñê çàïîëíåí?)';
   STRING_WRITE_ERROR                  := 'Îøèáêà çàïèñè íà äèñê (Äèñê çàïîëíåí?)';

+ 11 - 6
packages/fcl-db/src/sqldb/mssql/mssqlconn.pp

@@ -725,11 +725,16 @@ begin
       ftString, ftFixedChar:
       ftString, ftFixedChar:
         begin
         begin
         FieldSize := col.MaxLength;
         FieldSize := col.MaxLength;
-        if FieldSize > dsMaxStringSize then FieldSize := dsMaxStringSize;
+        if FieldSize >= $3FFFFFFF then // varchar(max)
+           FieldType := ftMemo;
+
         end;
         end;
-      ftMemo, ftBlob,
       ftBytes, ftVarBytes:
       ftBytes, ftVarBytes:
+        begin
         FieldSize := col.MaxLength;
         FieldSize := col.MaxLength;
+        if FieldSize >= $3FFFFFFF then // varbinary(max)
+           FieldType := ftBlob;
+        end;
       ftBCD:
       ftBCD:
         begin
         begin
         FieldSize := col.Scale;
         FieldSize := col.Scale;
@@ -738,10 +743,10 @@ begin
         end;
         end;
       ftGuid:
       ftGuid:
         FieldSize := 38;
         FieldSize := 38;
-    else
-      FieldSize := 0;
-      if col.Identity and (FieldType = ftInteger) then
-        FieldType := ftAutoInc;
+      else
+        FieldSize := 0;
+        if col.Identity and (FieldType = ftInteger) then
+          FieldType := ftAutoInc;
     end;
     end;
 
 
     with FieldDefs.Add(FieldDefs.MakeNameUnique(FieldName), FieldType, FieldSize, (col.Null=0) and (not col.Identity), i) do
     with FieldDefs.Add(FieldDefs.MakeNameUnique(FieldName), FieldType, FieldSize, (col.Null=0) and (not col.Identity), i) do

+ 20 - 6
packages/fcl-db/src/sqldb/mysql/mysqlconn.inc

@@ -893,7 +893,7 @@ function InternalStrToDateTime(S: string): TDateTime;
 
 
 var
 var
   EY, EM, ED: Word;
   EY, EM, ED: Word;
-  EH, EN, ES: Word;
+  EH, EN, ES, EMS: Word;
 
 
 begin
 begin
   EY := StrToInt(Copy(S, 1, 4));
   EY := StrToInt(Copy(S, 1, 4));
@@ -902,34 +902,44 @@ begin
   EH := StrToInt(Copy(S, 12, 2));
   EH := StrToInt(Copy(S, 12, 2));
   EN := StrToInt(Copy(S, 15, 2));
   EN := StrToInt(Copy(S, 15, 2));
   ES := StrToInt(Copy(S, 18, 2));
   ES := StrToInt(Copy(S, 18, 2));
+  EMS:=0;
+{$IFDEF mysql56}
+  if (Copy(S, 21, 3)<>'') then
+    EMS := StrToIntDef(Copy(S, 21, 3),0);
+{$ENDIF} 
   if (EY = 0) or (EM = 0) or (ED = 0) then
   if (EY = 0) or (EM = 0) or (ED = 0) then
     Result := 0
     Result := 0
   else
   else
     Result := EncodeDate(EY, EM, ED);
     Result := EncodeDate(EY, EM, ED);
-  Result := ComposeDateTime(Result,EncodeTime(EH, EN, ES, 0));
+  Result := ComposeDateTime(Result,EncodeTime(EH, EN, ES, EMS));
 end;
 end;
 
 
 function InternalStrToTime(S: string): TDateTime;
 function InternalStrToTime(S: string): TDateTime;
 
 
 var
 var
-  EH, EM, ES: Word;
+  EH, EM, ES, EMS: Word;
   p: integer;
   p: integer;
 
 
 begin
 begin
   p := 1;
   p := 1;
+  EMS:=0;
   EH := StrToInt(ExtractSubstr(S, p, [':'])); //hours can be 2 or 3 digits
   EH := StrToInt(ExtractSubstr(S, p, [':'])); //hours can be 2 or 3 digits
   EM := StrToInt(ExtractSubstr(S, p, [':']));
   EM := StrToInt(ExtractSubstr(S, p, [':']));
   ES := StrToInt(ExtractSubstr(S, p, ['.']));
   ES := StrToInt(ExtractSubstr(S, p, ['.']));
-  Result := EncodeTimeInterval(EH, EM, ES, 0);
+{$IFDEF mysql56}
+   EMS:= StrToIntDef(ExtractSubstr(S, p, ['.']),0);
+{$ENDIF}   
+  Result := EncodeTimeInterval(EH, EM, ES, EMS);
 end;
 end;
 
 
 function InternalStrToTimeStamp(S: string): TDateTime;
 function InternalStrToTimeStamp(S: string): TDateTime;
 
 
 var
 var
   EY, EM, ED: Word;
   EY, EM, ED: Word;
-  EH, EN, ES: Word;
+  EH, EN, ES, EMS: Word;
 
 
 begin
 begin
+  EMS:=0;
 {$IFNDEF mysql40}
 {$IFNDEF mysql40}
   EY := StrToInt(Copy(S, 1, 4));
   EY := StrToInt(Copy(S, 1, 4));
   EM := StrToInt(Copy(S, 6, 2));
   EM := StrToInt(Copy(S, 6, 2));
@@ -937,6 +947,10 @@ begin
   EH := StrToInt(Copy(S, 12, 2));
   EH := StrToInt(Copy(S, 12, 2));
   EN := StrToInt(Copy(S, 15, 2));
   EN := StrToInt(Copy(S, 15, 2));
   ES := StrToInt(Copy(S, 18, 2));
   ES := StrToInt(Copy(S, 18, 2));
+{$IFDEF mysql56}
+  if (Copy(S, 21, 3)<>'') then
+    EMS := StrToIntDef(Copy(S, 21, 3),0);
+{$ENDIF} 
 {$ELSE}
 {$ELSE}
   EY := StrToInt(Copy(S, 1, 4));
   EY := StrToInt(Copy(S, 1, 4));
   EM := StrToInt(Copy(S, 5, 2));
   EM := StrToInt(Copy(S, 5, 2));
@@ -949,7 +963,7 @@ begin
     Result := 0
     Result := 0
   else
   else
     Result := EncodeDate(EY, EM, ED);
     Result := EncodeDate(EY, EM, ED);
-  Result := Result + EncodeTime(EH, EN, ES, 0);
+  Result := Result + EncodeTime(EH, EN, ES, EMS);
 end;
 end;
 
 
 function TConnectionName.MySQLWriteData(AField: PMYSQL_FIELD; FieldDef: TFieldDef; Source, Dest: PChar; Len: integer; out CreateBlob : boolean): Boolean;
 function TConnectionName.MySQLWriteData(AField: PMYSQL_FIELD; FieldDef: TFieldDef; Source, Dest: PChar; Len: integer; out CreateBlob : boolean): Boolean;

+ 324 - 203
packages/fcl-db/src/sqldb/odbc/odbcconn.pas

@@ -56,10 +56,17 @@ type
 
 
   TODBCConnection = class(TSQLConnection)
   TODBCConnection = class(TSQLConnection)
   private
   private
-    FDriver: string;
-    FEnvironment:TODBCEnvironment;
-    FDBCHandle:SQLHDBC; // ODBC Connection Handle
-    FFileDSN: string;
+    type
+      TDBMSInfo = record
+        GetLastInsertIDSQL: string; // SQL statement for get last insert value for autoincrement column
+      end;
+
+    var
+      FDriver: string;
+      FEnvironment:TODBCEnvironment;
+      FDBCHandle:SQLHDBC; // ODBC Connection Handle
+      FFileDSN: string;
+      FDBMSInfo: TDBMSInfo;
 
 
     procedure SetParameters(ODBCCursor:TODBCCursor; AParams:TParams);
     procedure SetParameters(ODBCCursor:TODBCCursor; AParams:TParams);
     procedure FreeParamBuffers(ODBCCursor:TODBCCursor);
     procedure FreeParamBuffers(ODBCCursor:TODBCCursor);
@@ -87,6 +94,7 @@ type
     // - Statement execution
     // - Statement execution
     procedure Execute(cursor:TSQLCursor; ATransaction:TSQLTransaction; AParams:TParams); override;
     procedure Execute(cursor:TSQLCursor; ATransaction:TSQLTransaction; AParams:TParams); override;
     function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
     function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
+    function RefreshLastInsertID(Query : TCustomSQLQuery; Field : TField): boolean; override;
     // - Result retrieving
     // - Result retrieving
     procedure AddFieldDefs(cursor:TSQLCursor; FieldDefs:TFieldDefs); override;
     procedure AddFieldDefs(cursor:TSQLCursor; FieldDefs:TFieldDefs); override;
     function Fetch(cursor:TSQLCursor):boolean; override;
     function Fetch(cursor:TSQLCursor):boolean; override;
@@ -305,6 +313,74 @@ begin
   end;
   end;
 end;
 end;
 
 
+(*
+function BCDToNumericStruct(const bcd: TBCD): SQL_NUMERIC_STRUCT;
+var i, j, p: integer;
+    nibble: Byte;
+    a, m, carry: DWord;
+    BigInt: array[0..3] of QWord;
+    qw: QWord;
+    pdw: PDWord;
+begin
+  Result.precision := BCDPrecision(bcd);
+  if Result.precision = 0 then Result.precision := 1; // if bcd is NULL
+  Result.scale := BCDScale(bcd);
+  if IsBCDNegative(bcd) then
+    Result.sign := 0
+  else
+    Result.sign := 1;
+  // BigInt := 0
+  FillByte(BigInt, sizeof(BigInt), 0);
+  // process BCD nibbles (high nibble is at 0)
+  p := Result.precision;
+  i := 0;
+  while p > 0 do
+  begin
+    nibble := bcd.Fraction[i];
+    if p = 1 then
+      begin
+      a := nibble shr 4;
+      m := 10;
+      end
+    else
+      begin
+      a := (nibble shr 4)*10 + nibble and $0F;
+      m := 100;
+      end;
+
+    // BigInt := BigInt * m + a
+    // big multiplication
+    j := 0; carry := 0;
+    repeat
+      qw := BigInt[j] * m + carry;
+      BigInt[j] := qw and $FFFFFFFF;
+      carry := qw shr 32;
+      inc(j);
+    until j>high(BigInt);
+
+    // big addition
+    j := 0; carry := 0;
+    repeat
+      qw := BigInt[j] + a + carry;
+      BigInt[j] := qw and $FFFFFFFF;
+      carry := qw shr 32;
+      inc(j);
+    until (carry = 0) or (j>high(BigInt));
+
+    dec(p,2);
+    inc(i);
+  end;
+
+  // SQL_NUMERIC_STRUCT.val size must be 16 bytes (128bit integer)
+  pdw := @Result.val;
+  for j:=0 to high(BigInt) do
+    begin
+    pdw^ := NtoLE(BigInt[j]);
+    inc(pdw);
+    end;
+end;
+*)
+
 procedure TODBCConnection.SetParameters(ODBCCursor: TODBCCursor; AParams: TParams);
 procedure TODBCConnection.SetParameters(ODBCCursor: TODBCCursor; AParams: TParams);
 var
 var
   ParamIndex: integer;
   ParamIndex: integer;
@@ -312,7 +388,7 @@ var
   I, Size: integer;
   I, Size: integer;
   IntVal: clong;
   IntVal: clong;
   LargeVal: clonglong;
   LargeVal: clonglong;
-  StrVal: string;
+  StrVal: ansistring;
   WideStrVal: widestring;
   WideStrVal: widestring;
   FloatVal: cdouble;
   FloatVal: cdouble;
   DateVal: SQL_DATE_STRUCT;
   DateVal: SQL_DATE_STRUCT;
@@ -439,6 +515,18 @@ begin
           ColumnSize:=NumericVal.precision;
           ColumnSize:=NumericVal.precision;
           DecimalDigits:=NumericVal.scale;
           DecimalDigits:=NumericVal.scale;
         end;
         end;
+      ftFmtBCD:
+        begin
+          // bind FmtBCD parameter as string to support higher precision than 10^38 (supported by SQL_NUMERIC_STRUCT)
+          StrVal:=GetAsSQLText(AParams[ParamIndex]);
+          StrLenOrInd:=Length(StrVal);
+          PVal:=@StrVal[1];
+          Size:=Length(StrVal);
+          CType:=SQL_C_CHAR;
+          SqlType:=SQL_CHAR;
+          ColumnSize:=Size;
+          BufferLength:=Size;
+        end;
       ftDate:
       ftDate:
         begin
         begin
           DateVal:=DateTimeToDateStruct(AParams[ParamIndex].AsDate);
           DateVal:=DateTimeToDateStruct(AParams[ParamIndex].AsDate);
@@ -465,6 +553,7 @@ begin
           CType:=SQL_C_TYPE_TIMESTAMP;
           CType:=SQL_C_TYPE_TIMESTAMP;
           SqlType:=SQL_TYPE_TIMESTAMP;
           SqlType:=SQL_TYPE_TIMESTAMP;
           ColumnSize:=23;
           ColumnSize:=23;
+          DecimalDigits:=3; // fractional seconds
         end;
         end;
       ftBoolean:
       ftBoolean:
         begin
         begin
@@ -544,6 +633,7 @@ var
   ConnectionString:string;
   ConnectionString:string;
   OutConnectionString:string;
   OutConnectionString:string;
   ActualLength:SQLSMALLINT;
   ActualLength:SQLSMALLINT;
+  DBMS_NAME: array[0..20] of AnsiChar;
 begin
 begin
   // Do not call the inherited method as it checks for a non-empty DatabaseName, and we don't even use DatabaseName!
   // Do not call the inherited method as it checks for a non-empty DatabaseName, and we don't even use DatabaseName!
   // inherited DoInternalConnect;
   // inherited DoInternalConnect;
@@ -588,9 +678,24 @@ begin
     end;
     end;
   end;
   end;
 
 
-// commented out as the OutConnectionString is not used further at the moment
-//  if ActualLength<BufferLength-1 then
-//    SetLength(OutConnectionString,ActualLength); // fix completed connection string length
+  // set DBMS specific options
+  if SQLGetInfo(FDBCHandle, SQL_DBMS_NAME, @DBMS_NAME, sizeof(DBMS_NAME), @ActualLength) = SQL_SUCCESS then
+    case AnsiString(DBMS_NAME) of
+      'Microsoft SQL Server':
+        begin
+        FDBMSInfo.GetLastInsertIDSQL := 'SELECT @@IDENTITY';
+        Include(FConnOptions, sqLastInsertID);
+        end;
+      'MySQL':
+        begin
+        FDBMSInfo.GetLastInsertIDSQL := 'SELECT last_insert_id()';
+        Include(FConnOptions, sqLastInsertID);
+        end;
+      else
+        begin
+        FDBMSInfo.GetLastInsertIDSQL := '';
+        end;
+    end;
 
 
   // set connection attributes (none yet)
   // set connection attributes (none yet)
 end;
 end;
@@ -778,204 +883,20 @@ begin
     Result:=-1;
     Result:=-1;
 end;
 end;
 
 
-function TODBCConnection.Fetch(cursor: TSQLCursor): boolean;
+function TODBCConnection.RefreshLastInsertID(Query : TCustomSQLQuery; Field : TField): boolean;
 var
 var
-  ODBCCursor:TODBCCursor;
-  Res:SQLRETURN;
+  STMTHandle: SQLHSTMT;
+  StrLenOrInd: SQLLEN;
+  LastInsertID: LargeInt;
 begin
 begin
-  ODBCCursor:=cursor as TODBCCursor;
-
-  // fetch new row
-  Res:=SQLFetch(ODBCCursor.FSTMTHandle);
-  if Res<>SQL_NO_DATA then
-    ODBCCheckResult(Res,SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not fetch new row from result set.');
-
-  // result is true iff a new row was available
-  Result:=Res<>SQL_NO_DATA;
-end;
-
-const
-  DEFAULT_BLOB_BUFFER_SIZE = 1024;
-
-function TODBCConnection.LoadField(cursor: TSQLCursor; FieldDef: TFieldDef; buffer: pointer; out CreateBlob : boolean): boolean;
-var
-  ODBCCursor:TODBCCursor;
-  StrLenOrInd:SQLLEN;
-  ODBCDateStruct:SQL_DATE_STRUCT;
-  ODBCTimeStruct:SQL_TIME_STRUCT;
-  ODBCTimeStampStruct:SQL_TIMESTAMP_STRUCT;
-  DateTime:TDateTime;
-  Res:SQLRETURN;
-begin
-  CreateBlob := False;
-  ODBCCursor:=cursor as TODBCCursor;
-
-  // load the field using SQLGetData
-  // Note: optionally we can implement the use of SQLBindCol later for even more speed
-  // TODO: finish this
-  case FieldDef.DataType of
-    ftWideString,ftFixedWideChar: // mapped to TWideStringField
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_WCHAR, buffer, FieldDef.Size+sizeof(WideChar), @StrLenOrInd); //buffer must contain space for the null-termination character
-    ftGuid, ftFixedChar,ftString: // are mapped to a TStringField (including TGuidField)
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_CHAR, buffer, FieldDef.Size+1, @StrLenOrInd);
-    ftSmallint:           // mapped to TSmallintField
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SSHORT, buffer, SizeOf(Smallint), @StrLenOrInd);
-    ftInteger,ftAutoInc:  // mapped to TLongintField
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SLONG, buffer, SizeOf(Longint), @StrLenOrInd);
-    ftWord:               // mapped to TWordField
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_USHORT, buffer, SizeOf(Word), @StrLenOrInd);
-    ftLargeint:           // mapped to TLargeintField
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SBIGINT, buffer, SizeOf(Largeint), @StrLenOrInd);
-    ftFloat,ftCurrency:   // mapped to TFloatField
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_DOUBLE, buffer, SizeOf(Double), @StrLenOrInd);
-    ftTime:               // mapped to TTimeField
+  if SQLAllocHandle(SQL_HANDLE_STMT, FDBCHandle, STMTHandle) = SQL_SUCCESS then
     begin
     begin
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_TIME, @ODBCTimeStruct, SizeOf(SQL_TIME_STRUCT), @StrLenOrInd);
-      if StrLenOrInd<>SQL_NULL_DATA then
-      begin
-        DateTime:=TimeStructToDateTime(@ODBCTimeStruct);
-        Move(DateTime, buffer^, SizeOf(TDateTime));
-      end;
-    end;
-    ftDate:               // mapped to TDateField
-    begin
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_DATE, @ODBCDateStruct, SizeOf(SQL_DATE_STRUCT), @StrLenOrInd);
-      if StrLenOrInd<>SQL_NULL_DATA then
-      begin
-        DateTime:=DateStructToDateTime(@ODBCDateStruct);
-        Move(DateTime, buffer^, SizeOf(TDateTime));
-      end;
+    if SQLExecDirect(STMTHandle, PChar(FDBMSInfo.GetLastInsertIDSQL), Length(FDBMSInfo.GetLastInsertIDSQL)) = SQL_SUCCESS then
+      if SQLFetch(STMTHandle) = SQL_SUCCESS then
+        if SQLGetData(STMTHandle, 1, SQL_C_SBIGINT, @LastInsertID, SizeOf(LargeInt), @StrLenOrInd) = SQL_SUCCESS then
+          Field.AsLargeInt := LastInsertID;
+    SQLFreeHandle(SQL_HANDLE_STMT, STMTHandle);
     end;
     end;
-    ftDateTime:           // mapped to TDateTimeField
-    begin
-      // Seems like not all ODBC-drivers (mysql on Linux) set the fractional part. Initialize
-      // it's value to avoid 'random' data.
-      ODBCTimeStampStruct.Fraction:=0;
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_TIMESTAMP, @ODBCTimeStampStruct, SizeOf(SQL_TIMESTAMP_STRUCT), @StrLenOrInd);
-      if StrLenOrInd<>SQL_NULL_DATA then
-      begin
-        DateTime:=TimeStampStructToDateTime(@ODBCTimeStampStruct);
-        Move(DateTime, buffer^, SizeOf(TDateTime));
-      end;
-    end;
-    ftBoolean:            // mapped to TBooleanField
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BIT, buffer, SizeOf(Wordbool), @StrLenOrInd);
-    ftBytes:              // mapped to TBytesField
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, buffer, FieldDef.Size, @StrLenOrInd);
-    ftVarBytes:           // mapped to TVarBytesField
-    begin
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, buffer+SizeOf(Word), FieldDef.Size, @StrLenOrInd);
-      if StrLenOrInd < 0 then
-        PWord(buffer)^ := 0
-      else
-        PWord(buffer)^ := StrLenOrInd;
-    end;
-    ftWideMemo,
-    ftBlob, ftMemo:       // BLOBs
-    begin
-      //Writeln('BLOB');
-      // Try to discover BLOB data length
-      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, buffer, 0, @StrLenOrInd);
-      ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not get field data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
-      // Read the data if not NULL
-      if StrLenOrInd<>SQL_NULL_DATA then
-      begin
-        CreateBlob:=true; // defer actual loading of blob data to LoadBlobIntoBuffer method
-        //WriteLn('Deferring loading of blob of length ',StrLenOrInd);
-      end;
-    end;
-    // TODO: Loading of other field types
-  else
-    raise EODBCException.CreateFmt('Tried to load field of unsupported field type %s',[Fieldtypenames[FieldDef.DataType]]);
-  end;
-  ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not get field data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
-  Result:=StrLenOrInd<>SQL_NULL_DATA; // Result indicates whether the value is non-null
-
-  //writeln(Format('Field.Size: %d; StrLenOrInd: %d',[FieldDef.Size, StrLenOrInd]));
-end;
-
-procedure TODBCConnection.LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
-var
-  ODBCCursor: TODBCCursor;
-  Res: SQLRETURN;
-  StrLenOrInd:SQLLEN;
-  BlobBuffer:pointer;
-  BlobBufferSize,BytesRead:SQLINTEGER;
-  BlobMemoryStream:TMemoryStream;
-begin
-  ODBCCursor:=cursor as TODBCCursor;
-  // Try to discover BLOB data length
-  //   NB MS ODBC requires that TargetValuePtr is not nil, so we supply it with a valid pointer, even though BufferLength is 0
-  StrLenOrInd:=0;
-  Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, @BlobBuffer, 0, @StrLenOrInd);
-  if Res<>SQL_NO_DATA then
-    ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not get field data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
-  // Read the data if not NULL
-  if StrLenOrInd<>SQL_NULL_DATA then
-  begin
-    // Determine size of buffer to use
-    if StrLenOrInd<>SQL_NO_TOTAL then begin
-      // Size is known on beforehand
-      // set size & alloc buffer
-      //WriteLn('Loading blob of length ',StrLenOrInd);
-      BlobBufferSize:=StrLenOrInd;
-      ABlobBuf^.BlobBuffer^.Size:=BlobBufferSize;
-      ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer, BlobBufferSize);
-      // get blob data
-      if BlobBufferSize>0 then begin
-        Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, ABlobBuf^.BlobBuffer^.Buffer, BlobBufferSize, @StrLenOrInd);
-        ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not load blob data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
-      end;
-    end else begin
-      // Size is not known on beforehand; read data in chuncks; write to a TMemoryStream (which implements O(n) writing)
-      BlobBufferSize:=DEFAULT_BLOB_BUFFER_SIZE;
-      // init BlobBuffer and BlobMemoryStream to nil pointers
-      BlobBuffer:=nil; // the buffer that will hold the chuncks of data; not to be confused with ABlobBuf^.BlobBuffer
-      BlobMemoryStream:=nil;
-      try
-        // Allocate the buffer and memorystream
-        BlobBuffer:=GetMem(BlobBufferSize);
-        BlobMemoryStream:=TMemoryStream.Create;
-        // Retrieve data in parts
-        repeat
-          Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, BlobBuffer, BlobBufferSize, @StrLenOrInd);
-          ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not load (partial) blob data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
-          // Append data in buffer to memorystream
-          if (StrLenOrInd=SQL_NO_TOTAL) or (StrLenOrInd>BlobBufferSize) then
-            BytesRead:=BlobBufferSize
-          else
-            BytesRead:=StrLenOrInd;
-          BlobMemoryStream.Write(BlobBuffer^, BytesRead);
-        until Res=SQL_SUCCESS;
-        // Copy memory stream data to ABlobBuf^.BlobBuffer
-        BlobBufferSize:=BlobMemoryStream.Size; // actual blob size
-        //   alloc ABlobBuf^.BlobBuffer
-        ABlobBuf^.BlobBuffer^.Size:=BlobBufferSize;
-        ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer, BlobBufferSize);
-        //   read memory stream data into ABlobBuf^.BlobBuffer
-        BlobMemoryStream.Position:=0;
-        BlobMemoryStream.Read(ABlobBuf^.BlobBuffer^.Buffer^, BlobBufferSize);
-      finally
-        // free buffer and memory stream
-        BlobMemoryStream.Free;
-        if BlobBuffer<>nil then
-          Freemem(BlobBuffer,BlobBufferSize);
-      end;
-    end;
-  end;
-end;
-
-procedure TODBCConnection.FreeFldBuffers(cursor: TSQLCursor);
-var
-  ODBCCursor:TODBCCursor;
-begin
-  ODBCCursor:=cursor as TODBCCursor;
-
-  if ODBCCursor.FSTMTHandle <> SQL_NULL_HSTMT then
-    ODBCCheckResult(
-      SQLFreeStmt(ODBCCursor.FSTMTHandle, SQL_CLOSE),
-      SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not close ODBC statement cursor.'
-    );
 end;
 end;
 
 
 procedure TODBCConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TFieldDefs);
 procedure TODBCConnection.AddFieldDefs(cursor: TSQLCursor; FieldDefs: TFieldDefs);
@@ -1201,6 +1122,206 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TODBCConnection.Fetch(cursor: TSQLCursor): boolean;
+var
+  ODBCCursor:TODBCCursor;
+  Res:SQLRETURN;
+begin
+  ODBCCursor:=cursor as TODBCCursor;
+
+  // fetch new row
+  Res:=SQLFetch(ODBCCursor.FSTMTHandle);
+  if Res<>SQL_NO_DATA then
+    ODBCCheckResult(Res,SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not fetch new row from result set.');
+
+  // result is true if a new row was available
+  Result:=Res<>SQL_NO_DATA;
+end;
+
+const
+  DEFAULT_BLOB_BUFFER_SIZE = 1024;
+
+function TODBCConnection.LoadField(cursor: TSQLCursor; FieldDef: TFieldDef; buffer: pointer; out CreateBlob : boolean): boolean;
+var
+  ODBCCursor:TODBCCursor;
+  StrLenOrInd:SQLLEN;
+  ODBCDateStruct:SQL_DATE_STRUCT;
+  ODBCTimeStruct:SQL_TIME_STRUCT;
+  ODBCTimeStampStruct:SQL_TIMESTAMP_STRUCT;
+  DateTime:TDateTime;
+  Res:SQLRETURN;
+begin
+  CreateBlob := False;
+  ODBCCursor:=cursor as TODBCCursor;
+
+  // load the field using SQLGetData
+  // Note: optionally we can implement the use of SQLBindCol later for even more speed
+  // TODO: finish this
+  case FieldDef.DataType of
+    ftWideString,ftFixedWideChar: // mapped to TWideStringField
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_WCHAR, buffer, FieldDef.Size+sizeof(WideChar), @StrLenOrInd); //buffer must contain space for the null-termination character
+    ftGuid, ftFixedChar,ftString: // are mapped to a TStringField (including TGuidField)
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_CHAR, buffer, FieldDef.Size+1, @StrLenOrInd);
+    ftSmallint:           // mapped to TSmallintField
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SSHORT, buffer, SizeOf(Smallint), @StrLenOrInd);
+    ftInteger,ftAutoInc:  // mapped to TLongintField
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SLONG, buffer, SizeOf(Longint), @StrLenOrInd);
+    ftWord:               // mapped to TWordField
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_USHORT, buffer, SizeOf(Word), @StrLenOrInd);
+    ftLargeint:           // mapped to TLargeintField
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_SBIGINT, buffer, SizeOf(Largeint), @StrLenOrInd);
+    ftFloat,ftCurrency:   // mapped to TFloatField
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_DOUBLE, buffer, SizeOf(Double), @StrLenOrInd);
+    ftTime:               // mapped to TTimeField
+    begin
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_TIME, @ODBCTimeStruct, SizeOf(SQL_TIME_STRUCT), @StrLenOrInd);
+      if StrLenOrInd<>SQL_NULL_DATA then
+      begin
+        DateTime:=TimeStructToDateTime(@ODBCTimeStruct);
+        Move(DateTime, buffer^, SizeOf(TDateTime));
+      end;
+    end;
+    ftDate:               // mapped to TDateField
+    begin
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_DATE, @ODBCDateStruct, SizeOf(SQL_DATE_STRUCT), @StrLenOrInd);
+      if StrLenOrInd<>SQL_NULL_DATA then
+      begin
+        DateTime:=DateStructToDateTime(@ODBCDateStruct);
+        Move(DateTime, buffer^, SizeOf(TDateTime));
+      end;
+    end;
+    ftDateTime:           // mapped to TDateTimeField
+    begin
+      // Seems like not all ODBC-drivers (mysql on Linux) set the fractional part. Initialize
+      // it's value to avoid 'random' data.
+      ODBCTimeStampStruct.Fraction:=0;
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_TYPE_TIMESTAMP, @ODBCTimeStampStruct, SizeOf(SQL_TIMESTAMP_STRUCT), @StrLenOrInd);
+      if StrLenOrInd<>SQL_NULL_DATA then
+      begin
+        DateTime:=TimeStampStructToDateTime(@ODBCTimeStampStruct);
+        Move(DateTime, buffer^, SizeOf(TDateTime));
+      end;
+    end;
+    ftBoolean:            // mapped to TBooleanField
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BIT, buffer, SizeOf(Wordbool), @StrLenOrInd);
+    ftBytes:              // mapped to TBytesField
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, buffer, FieldDef.Size, @StrLenOrInd);
+    ftVarBytes:           // mapped to TVarBytesField
+    begin
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, buffer+SizeOf(Word), FieldDef.Size, @StrLenOrInd);
+      if StrLenOrInd < 0 then
+        PWord(buffer)^ := 0
+      else
+        PWord(buffer)^ := StrLenOrInd;
+    end;
+    ftWideMemo,
+    ftBlob, ftMemo:       // BLOBs
+    begin
+      //Writeln('BLOB');
+      // Try to discover BLOB data length
+      Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, buffer, 0, @StrLenOrInd);
+      ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not get field data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
+      // Read the data if not NULL
+      if StrLenOrInd<>SQL_NULL_DATA then
+      begin
+        CreateBlob:=true; // defer actual loading of blob data to LoadBlobIntoBuffer method
+        //WriteLn('Deferring loading of blob of length ',StrLenOrInd);
+      end;
+    end;
+    // TODO: Loading of other field types
+  else
+    raise EODBCException.CreateFmt('Tried to load field of unsupported field type %s',[Fieldtypenames[FieldDef.DataType]]);
+  end;
+  ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not get field data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
+  Result:=StrLenOrInd<>SQL_NULL_DATA; // Result indicates whether the value is non-null
+
+  //writeln(Format('Field.Size: %d; StrLenOrInd: %d',[FieldDef.Size, StrLenOrInd]));
+end;
+
+procedure TODBCConnection.LoadBlobIntoBuffer(FieldDef: TFieldDef; ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction: TSQLTransaction);
+var
+  ODBCCursor: TODBCCursor;
+  Res: SQLRETURN;
+  StrLenOrInd:SQLLEN;
+  BlobBuffer:pointer;
+  BlobBufferSize,BytesRead:SQLINTEGER;
+  BlobMemoryStream:TMemoryStream;
+begin
+  ODBCCursor:=cursor as TODBCCursor;
+  // Try to discover BLOB data length
+  //   NB MS ODBC requires that TargetValuePtr is not nil, so we supply it with a valid pointer, even though BufferLength is 0
+  StrLenOrInd:=0;
+  Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, @BlobBuffer, 0, @StrLenOrInd);
+  if Res<>SQL_NO_DATA then
+    ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not get field data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
+  // Read the data if not NULL
+  if StrLenOrInd<>SQL_NULL_DATA then
+  begin
+    // Determine size of buffer to use
+    if StrLenOrInd<>SQL_NO_TOTAL then begin
+      // Size is known on beforehand
+      // set size & alloc buffer
+      //WriteLn('Loading blob of length ',StrLenOrInd);
+      BlobBufferSize:=StrLenOrInd;
+      ABlobBuf^.BlobBuffer^.Size:=BlobBufferSize;
+      ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer, BlobBufferSize);
+      // get blob data
+      if BlobBufferSize>0 then begin
+        Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, ABlobBuf^.BlobBuffer^.Buffer, BlobBufferSize, @StrLenOrInd);
+        ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not load blob data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
+      end;
+    end else begin
+      // Size is not known on beforehand; read data in chuncks; write to a TMemoryStream (which implements O(n) writing)
+      BlobBufferSize:=DEFAULT_BLOB_BUFFER_SIZE;
+      // init BlobBuffer and BlobMemoryStream to nil pointers
+      BlobBuffer:=nil; // the buffer that will hold the chuncks of data; not to be confused with ABlobBuf^.BlobBuffer
+      BlobMemoryStream:=nil;
+      try
+        // Allocate the buffer and memorystream
+        BlobBuffer:=GetMem(BlobBufferSize);
+        BlobMemoryStream:=TMemoryStream.Create;
+        // Retrieve data in parts
+        repeat
+          Res:=SQLGetData(ODBCCursor.FSTMTHandle, FieldDef.Index+1, SQL_C_BINARY, BlobBuffer, BlobBufferSize, @StrLenOrInd);
+          ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not load (partial) blob data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
+          // Append data in buffer to memorystream
+          if (StrLenOrInd=SQL_NO_TOTAL) or (StrLenOrInd>BlobBufferSize) then
+            BytesRead:=BlobBufferSize
+          else
+            BytesRead:=StrLenOrInd;
+          BlobMemoryStream.Write(BlobBuffer^, BytesRead);
+        until Res=SQL_SUCCESS;
+        // Copy memory stream data to ABlobBuf^.BlobBuffer
+        BlobBufferSize:=BlobMemoryStream.Size; // actual blob size
+        //   alloc ABlobBuf^.BlobBuffer
+        ABlobBuf^.BlobBuffer^.Size:=BlobBufferSize;
+        ReAllocMem(ABlobBuf^.BlobBuffer^.Buffer, BlobBufferSize);
+        //   read memory stream data into ABlobBuf^.BlobBuffer
+        BlobMemoryStream.Position:=0;
+        BlobMemoryStream.Read(ABlobBuf^.BlobBuffer^.Buffer^, BlobBufferSize);
+      finally
+        // free buffer and memory stream
+        BlobMemoryStream.Free;
+        if BlobBuffer<>nil then
+          Freemem(BlobBuffer,BlobBufferSize);
+      end;
+    end;
+  end;
+end;
+
+procedure TODBCConnection.FreeFldBuffers(cursor: TSQLCursor);
+var
+  ODBCCursor:TODBCCursor;
+begin
+  ODBCCursor:=cursor as TODBCCursor;
+
+  if ODBCCursor.FSTMTHandle <> SQL_NULL_HSTMT then
+    ODBCCheckResult(
+      SQLFreeStmt(ODBCCursor.FSTMTHandle, SQL_CLOSE),
+      SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not close ODBC statement cursor.'
+    );
+end;
+
 procedure TODBCConnection.UpdateIndexDefs(IndexDefs: TIndexDefs; TableName: string);
 procedure TODBCConnection.UpdateIndexDefs(IndexDefs: TIndexDefs; TableName: string);
 var
 var
   Len: integer;
   Len: integer;
@@ -1342,7 +1463,7 @@ begin
                 IndexDef.Options:=IndexDef.Options+[ixDescending];
                 IndexDef.Options:=IndexDef.Options+[ixDescending];
               end;
               end;
             end else if (OrdinalPos=1) or not Assigned(IndexDef) then begin
             end else if (OrdinalPos=1) or not Assigned(IndexDef) then begin
-              // create new IndexDef iff OrdinalPos=1 or not Assigned(IndexDef) (the latter should not occur though)
+              // create new IndexDef if OrdinalPos=1 or not Assigned(IndexDef) (the latter should not occur though)
               IndexDef:=IndexDefs.AddIndexDef;
               IndexDef:=IndexDefs.AddIndexDef;
               IndexDef.Name:=PChar(@IndexName[1]); // treat ansistring as zero terminated string
               IndexDef.Name:=PChar(@IndexName[1]); // treat ansistring as zero terminated string
               IndexDef.Fields:=PChar(@ColName[1]);
               IndexDef.Fields:=PChar(@ColName[1]);

+ 3 - 3
packages/fcl-db/src/sqldb/oracle/oracleconnection.pp

@@ -240,7 +240,7 @@ begin
     end;
     end;
 end;
 end;
 
 
-function Nvu2FmtBCE(b:pbyte):tBCD;
+function Nvu2FmtBCD(b:pbyte):tBCD;
 var
 var
   i,j       : integer;
   i,j       : integer;
   bb,size   : byte;
   bb,size   : byte;
@@ -370,7 +370,7 @@ begin
                             AsDateTime := ComposeDateTime(EncodeDate(odt.year,odt.month,odt.day), EncodeTime(odt.hour,odt.min,odt.sec,odt.fsec div 1000000));
                             AsDateTime := ComposeDateTime(EncodeDate(odt.year,odt.month,odt.day), EncodeTime(odt.hour,odt.min,odt.sec,odt.fsec div 1000000));
                             end;
                             end;
         ftFMTBcd          : begin
         ftFMTBcd          : begin
-                            AsFMTBCD:=Nvu2FmtBCE(ParamBuffers[i].buffer);
+                            AsFMTBCD:=Nvu2FmtBCD(ParamBuffers[i].buffer);
                             end;
                             end;
         end;
         end;
 
 
@@ -1089,7 +1089,7 @@ begin
         move(cur,buffer^,SizeOf(Currency));
         move(cur,buffer^,SizeOf(Currency));
         end;
         end;
       ftFmtBCD :
       ftFmtBCD :
-        pBCD(buffer)^:= Nvu2FmtBCE(fieldbuffers[FieldDef.FieldNo-1].buffer);
+        pBCD(buffer)^:= Nvu2FmtBCD(fieldbuffers[FieldDef.FieldNo-1].buffer);
       ftFloat :
       ftFloat :
         move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(double));
         move(fieldbuffers[FieldDef.FieldNo-1].buffer^,buffer^,sizeof(double));
       ftSmallInt :
       ftSmallInt :

+ 2 - 1
packages/fcl-db/src/sqldb/postgres/pqconnection.pp

@@ -176,6 +176,7 @@ const Oid_Bool     = 16;
       Oid_Int8     = 20;
       Oid_Int8     = 20;
       Oid_int2     = 21;
       Oid_int2     = 21;
       Oid_Int4     = 23;
       Oid_Int4     = 23;
+      Oid_JSON     = 114;
       Oid_Float4   = 700;
       Oid_Float4   = 700;
       Oid_Money    = 790;
       Oid_Money    = 790;
       Oid_Float8   = 701;
       Oid_Float8   = 701;
@@ -751,7 +752,7 @@ begin
                              if size > MaxSmallint then size := MaxSmallint;
                              if size > MaxSmallint then size := MaxSmallint;
                              end;
                              end;
 //    Oid_text               : Result := ftstring;
 //    Oid_text               : Result := ftstring;
-    Oid_text               : Result := ftMemo;
+    Oid_text,Oid_JSON      : Result := ftMemo;
     Oid_Bytea              : Result := ftBlob;
     Oid_Bytea              : Result := ftBlob;
     Oid_oid                : Result := ftInteger;
     Oid_oid                : Result := ftInteger;
     Oid_int8               : Result := ftLargeInt;
     Oid_int8               : Result := ftLargeInt;

+ 8 - 14
packages/fcl-db/src/sqldb/sqlite/sqlite3conn.pp

@@ -72,7 +72,7 @@ type
     function GetTransactionHandle(trans : TSQLHandle): pointer; override;
     function GetTransactionHandle(trans : TSQLHandle): pointer; override;
     function Commit(trans : TSQLHandle) : boolean; override;
     function Commit(trans : TSQLHandle) : boolean; override;
     function RollBack(trans : TSQLHandle) : boolean; override;
     function RollBack(trans : TSQLHandle) : boolean; override;
-    function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; override;
+    function StartDBTransaction(trans : TSQLHandle; aParams : string) : boolean; override;
     procedure CommitRetaining(trans : TSQLHandle); override;
     procedure CommitRetaining(trans : TSQLHandle); override;
     procedure RollBackRetaining(trans : TSQLHandle); override;
     procedure RollBackRetaining(trans : TSQLHandle); override;
 
 
@@ -583,18 +583,13 @@ begin
     if TryStrToInt(NextWord(S,':'),Min) then
     if TryStrToInt(NextWord(S,':'),Min) then
     begin
     begin
       if TryStrToInt(NextWord(S,'.'),Sec) then
       if TryStrToInt(NextWord(S,'.'),Sec) then
-      begin // 23:59:59 or 23:59:59.999
-      MSec:=StrToIntDef(S,0);
-      if Interval then
-        Result:=EncodeTimeInterval(Hour,Min,Sec,MSec)
-      else
-        Result:=EncodeTime(Hour,Min,Sec,MSec);
+        // 23:59:59 or 23:59:59.999
+        MSec:=StrToIntDef(S,0)
+      else // 23:59
+      begin
+        Sec:=0;
+        MSec:=0;
       end;
       end;
-    end
-    else //23:59
-    begin
-      Sec:=0;
-      MSec:=0;
       if Interval then
       if Interval then
         Result:=EncodeTimeInterval(Hour,Min,Sec,MSec)
         Result:=EncodeTimeInterval(Hour,Min,Sec,MSec)
       else
       else
@@ -763,8 +758,7 @@ begin
   result:= true;
   result:= true;
 end;
 end;
 
 
-function TSQLite3Connection.StartdbTransaction(trans: TSQLHandle;
-               aParams: string): boolean;
+function TSQLite3Connection.StartDBTransaction(trans: TSQLHandle; aParams: string): boolean;
 begin
 begin
   execsql('BEGIN');
   execsql('BEGIN');
   result:= true;
   result:= true;

+ 0 - 2
packages/fcl-db/tests/testsqldb.pas

@@ -566,8 +566,6 @@ var datatype: string;
 begin
 begin
   with SQLDBConnector do
   with SQLDBConnector do
     begin
     begin
-    if not (sqLastInsertID in Connection.ConnOptions) then
-      Ignore(STestNotApplicable);
     case SQLServerType of
     case SQLServerType of
       ssMySQL:
       ssMySQL:
         datatype := 'integer auto_increment';
         datatype := 'integer auto_increment';

+ 2 - 2
packages/mysql/src/mysql.inc

@@ -779,8 +779,8 @@ uses
     type
     type
 {$if defined(NO_CLIENT_LONG_LONG)}
 {$if defined(NO_CLIENT_LONG_LONG)}
        my_ulonglong = culong;
        my_ulonglong = culong;
-{$elseif defined(mswindows)}
-       my_ulonglong = cint64;
+{$elseif defined(WINDOWS)}
+       my_ulonglong = cuint64;
 {$else}
 {$else}
        my_ulonglong = culonglong;
        my_ulonglong = culonglong;
 {$endif}
 {$endif}

+ 1 - 1
packages/sqlite/src/sqlite3.inc

@@ -427,7 +427,7 @@ const
 
 
 type
 type
   xTrace = procedure(user: pointer; s: pansichar); cdecl;
   xTrace = procedure(user: pointer; s: pansichar); cdecl;
-  xProfile = procedure(user: pointer; s: char; i: sqlite3_uint64); cdecl;
+  xProfile = procedure(user: pointer; s: pansichar; i: sqlite3_uint64); cdecl;
 
 
 {$IFDEF S}function{$ELSE}var{$ENDIF}sqlite3_trace{$IFDEF D}: function{$ENDIF}(db: psqlite3; cb: xTrace; user: pointer): pointer; cdecl;{$IFDEF S}external Sqlite3Lib;{$ENDIF}
 {$IFDEF S}function{$ELSE}var{$ENDIF}sqlite3_trace{$IFDEF D}: function{$ENDIF}(db: psqlite3; cb: xTrace; user: pointer): pointer; cdecl;{$IFDEF S}external Sqlite3Lib;{$ENDIF}
 {$IFDEF S}function{$ELSE}var{$ENDIF}sqlite3_profile{$IFDEF D}: function{$ENDIF}(db: psqlite3; cb: xProfile; user: pointer): pointer; cdecl;{$IFDEF S}external Sqlite3Lib;{$ENDIF}
 {$IFDEF S}function{$ELSE}var{$ENDIF}sqlite3_profile{$IFDEF D}: function{$ENDIF}(db: psqlite3; cb: xProfile; user: pointer): pointer; cdecl;{$IFDEF S}external Sqlite3Lib;{$ENDIF}