Browse Source

--- Merging r22995 into '.':
U packages/fcl-db/src/base/fields.inc
--- Merging r22997 into '.':
U packages/fcl-db/src/base/xmldatapacketreader.pp
--- Merging r23014 into '.':
U packages/ibase/src/ibase60.inc
--- Merging r23016 into '.':
G packages/ibase/src/ibase60.inc
--- Merging r23020 into '.':
G packages/ibase/src/ibase60.inc
--- Merging r23033 into '.':
U packages/fcl-db/src/sqldb/sqlite/sqlite3conn.pp
--- Merging r23035 into '.':
G packages/fcl-db/src/base/xmldatapacketreader.pp
--- Merging r23041 into '.':
U packages/fcl-db/src/sqldb/mysql/mysqlconn.inc
--- Merging r23042 into '.':
G packages/fcl-db/src/sqldb/mysql/mysqlconn.inc
--- Merging r23049 into '.':
U packages/fcl-db/src/sqldb/odbc/odbcconn.pas
--- Merging r23064 into '.':
U packages/fcl-db/src/sqldb/postgres/pqconnection.pp
--- Merging r23066 into '.':
U packages/fcl-db/src/sqldb/interbase/ibconnection.pp
--- Merging r23068 into '.':
U packages/fcl-db/src/base/db.pas
G packages/fcl-db/src/base/fields.inc

# revisions: 22995,22997,23014,23016,23020,23033,23035,23041,23042,23049,23064,23066,23068
r22995 | lacak | 2012-11-16 13:37:53 +0100 (Fri, 16 Nov 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/fields.inc

fcl-db: when moving odd number bytes from blob stream into widestring allocate sufficient space. (f.e. if Len=1 then Len div 2 = 0)
r22997 | lacak | 2012-11-16 13:59:57 +0100 (Fri, 16 Nov 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/xmldatapacketreader.pp

fcl-db: add support for ftFixedWideChar and ftWideMemo into xmldatapacketreader.
r23014 | marco | 2012-11-18 14:34:39 +0100 (Sun, 18 Nov 2012) | 2 lines
Changed paths:
M /trunk/packages/ibase/src/ibase60.inc

* Patch from Reinier to cache libraryname in a global.
r23016 | michael | 2012-11-18 17:23:46 +0100 (Sun, 18 Nov 2012) | 1 line
Changed paths:
M /trunk/packages/ibase/src/ibase60.inc

* Changes to make it more compatible to other connectors
r23020 | michael | 2012-11-18 18:16:59 +0100 (Sun, 18 Nov 2012) | 1 line
Changed paths:
M /trunk/packages/ibase/src/ibase60.inc

* Fixed compilation
r23033 | lacak | 2012-11-19 10:54:25 +0100 (Mon, 19 Nov 2012) | 3 lines
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/sqlite/sqlite3conn.pp

fcl-db: sqlite: Always add null terminator to end of moved strings. (in case of length of data in db > FieldDef.Size null terminator is not moved).
Bug #0023338.
Fixes also already existing failed test.
r23035 | lacak | 2012-11-19 14:50:23 +0100 (Mon, 19 Nov 2012) | 3 lines
Changed paths:
M /trunk/packages/fcl-db/src/base/xmldatapacketreader.pp

fcl-db: change fieldtype for ftWideString and ftFixedWideChar from 'string' to 'string.uni' (Delphi compatibility).
Corrects my prior commit.
Note: Delphi stores characters outside ASCII as numeric character references in form: &#D;
r23041 | michael | 2012-11-22 09:23:53 +0100 (Thu, 22 Nov 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc

* Added GetLastInsertID
r23042 | michael | 2012-11-22 10:45:15 +0100 (Thu, 22 Nov 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc

* Changed GetLastInsertID to GetInsertID so it is the same as in GetLastID
r23049 | lacak | 2012-11-23 14:01:10 +0100 (Fri, 23 Nov 2012) | 2 lines
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/odbc/odbcconn.pas

fcl-db: odbc: fix error when loading blobs.
(revealed by TestSQLClob)
r23064 | lacak | 2012-11-26 14:28:53 +0100 (Mon, 26 Nov 2012) | 2 lines
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/postgres/pqconnection.pp

fcl-db: postgresql: fixes loading of field data of type FLOAT4
(revealed by test TestSQLReal)
r23066 | reiniero | 2012-11-27 09:31:32 +0100 (Tue, 27 Nov 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/interbase/ibconnection.pp

+ fcl-db: Firebird/Interbase: add some metadata support: GetConnectionInfo and ODS major version
r23068 | lacak | 2012-11-27 12:47:57 +0100 (Tue, 27 Nov 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/db.pas
M /trunk/packages/fcl-db/src/base/fields.inc

fcl-db: base: add AsLargeInt for TFMTBCDField

git-svn-id: branches/fixes_2_6@23938 -

marco 12 years ago
parent
commit
3f5ff617cd

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

@@ -820,6 +820,7 @@ type
     function GetAsBCD: TBCD; override;
     function GetAsCurrency: Currency; override;
     function GetAsFloat: Double; override;
+    function GetAsLargeInt: LargeInt; override;
     function GetAsLongint: Longint; override;
     function GetAsString: string; override;
     function GetAsVariant: variant; override;
@@ -828,6 +829,7 @@ type
     procedure GetText(var TheText: string; ADisplayText: Boolean); override;
     procedure SetAsBCD(const AValue: TBCD); override;
     procedure SetAsFloat(AValue: Double); override;
+    procedure SetAsLargeInt(AValue: LargeInt); override;
     procedure SetAsLongint(AValue: Longint); override;
     procedure SetAsString(const AValue: string); override;
     procedure SetAsCurrency(AValue: Currency); override;
@@ -1064,7 +1066,7 @@ type
 
 { TFields }
 
-  Tfields = Class(TObject)
+  TFields = Class(TObject)
     Private
       FDataset : TDataset;
       FFieldList : TFpList;
@@ -1761,7 +1763,7 @@ type
   TMasterParamsDataLink = Class(TMasterDataLink)
   Private
     FParams : TParams;
-    Procedure SetParams(AVAlue : TParams);
+    Procedure SetParams(AValue : TParams);
   Protected
     Procedure DoMasterDisable; override;
     Procedure DoMasterChange; override;

+ 14 - 2
packages/fcl-db/src/base/fields.inc

@@ -2578,6 +2578,15 @@ begin
     Result := 0;
 end;
 
+function TFMTBCDField.GetAsLargeInt: LargeInt;
+var bcd: TBCD;
+begin
+  if GetData(@bcd) then
+    Result := BCDToInteger(bcd)
+  else
+    Result := 0;
+end;
+
 function TFMTBCDField.GetAsLongint: Longint;
 begin
   Result := round(GetAsFloat);
@@ -2669,13 +2678,16 @@ begin
   SetAsBCD(DoubleToBCD(AValue));
 end;
 
+procedure TFMTBCDField.SetAsLargeInt(AValue: LargeInt);
+begin
+  SetAsBCD(IntegerToBCD(AValue));
+end;
 
 procedure TFMTBCDField.SetAsLongint(AValue: Longint);
 begin
   SetAsBCD(IntegerToBCD(AValue));
 end;
 
-
 procedure TFMTBCDField.SetAsString(const AValue: string);
 begin
   if AValue='' then
@@ -2729,7 +2741,7 @@ begin
     With Stream do
       try
         Len := Size;
-        SetLength(Result,Len div 2);
+        SetLength(Result, (Len+1) div 2);
         if Len > 0 then
           ReadBuffer(Result[1] ,Len);
       finally

+ 7 - 7
packages/fcl-db/src/base/xmldatapacketreader.pp

@@ -65,7 +65,7 @@ implementation
 uses xmlwrite, xmlread, base64;
 
 const
-  XMLFieldtypenames : Array [TFieldType] of String[15] =
+  XMLFieldtypenames : Array [TFieldType] of String[16] =
     (
       'Unknown',
       'string',
@@ -90,8 +90,8 @@ const
       'bin.hex:Ole',
       'bin.hex:Graphics',
       '',
-      'string',
-      'string',
+      'string',             // ftFixedChar
+      'string.uni',         // ftWideString
       'i8',
       '',
       '',
@@ -105,8 +105,8 @@ const
       '',
       '',
       'fixedFMT',
-      '',
-      ''
+      'string.uni',         // ftFixedWideChar
+      'bin.hex:WideText'    // ftWideMemo
     );
 
 resourcestring
@@ -351,13 +351,13 @@ begin
        AField := Fields.FieldByNumber(FieldDefs[FieldNr].FieldNo);
        if (FieldDefs[FieldNr].DataType in [ftBlob, ftBytes, ftVarBytes]) and (s <> '') then
          s := DecodeStringBase64(s);
-       if FieldDefs[FieldNr].DataType in [ftBlob, ftMemo] then
+       if FieldDefs[FieldNr].DataType in [ftBlob, ftMemo, ftWideMemo] then
         begin
         ABufBlobField.BlobBuffer:=ADataset.GetNewBlobBuffer;
-        AField.SetData(@ABufBlobField);
         ABufBlobField.BlobBuffer^.Size:=length(s);
         ReAllocMem(ABufBlobField.BlobBuffer^.Buffer,ABufBlobField.BlobBuffer^.Size);
         move(s[1],ABufBlobField.BlobBuffer^.Buffer^,ABufBlobField.BlobBuffer^.Size);
+        AField.SetData(@ABufBlobField);
         end
       else
         AField.AsString := s;  // set it to the filterbuffer

+ 187 - 35
packages/fcl-db/src/sqldb/interbase/ibconnection.pp

@@ -19,6 +19,12 @@ const
   MAXBLOBSEGMENTSIZE = 65535; //Maximum number of bytes that fit in a blob segment.
 
 type
+  TDatabaseInfo = record
+    Dialect             : integer; //Dialect set in database
+    ODSMajorVersion     : integer; //On-Disk Structure version of file
+    ServerVersion       : string;  //Representation of major.minor (.build)
+    ServerVersionString : string;  //Complete version string, including name, platform
+  end;
 
   EIBDatabaseError = class(EDatabaseError)
     public
@@ -48,22 +54,31 @@ type
 
   TIBConnection = class (TSQLConnection)
   private
-    FSQLDatabaseHandle   : pointer;
-    FStatus              : array [0..19] of ISC_STATUS;
-    FDialect             : integer;
-    FDBDialect           : integer;
-    FBLobSegmentSize     : word; //required for backward compatibilty; not used
+    FSQLDatabaseHandle     : pointer;
+    FStatus                : array [0..19] of ISC_STATUS;
+    FDatabaseInfo          : TDatabaseInfo;
+    FDialect               : integer;
+    FBlobSegmentSize       : word; //required for backward compatibilty; not used
 
     procedure ConnectFB;
-    function GetDialect: integer;
+
     procedure AllocSQLDA(var aSQLDA : PXSQLDA;Count : integer);
+
+    // Metadata:
+    procedure GetDatabaseInfo; //Queries for various information from server once connected
+    procedure ResetDatabaseInfo; //Useful when disconnecting
+    function GetDialect: integer;
+    function GetODSMajorVersion: integer;
+    function ParseServerVersion(const CompleteVersion: string): string; //Extract version info from complete version identification string
+
+    // conversion methods
     procedure TranslateFldType(SQLType, SQLSubType, SQLLen, SQLScale : integer;
       var TrType : TFieldType; var TrLen : word);
-    // conversion methods
     procedure GetDateTime(CurrBuff, Buffer : pointer; AType : integer);
     procedure SetDateTime(CurrBuff: pointer; PTime : TDateTime; AType : integer);
     procedure GetFloat(CurrBuff, Buffer : pointer; Size : Byte);
     procedure SetFloat(CurrBuff: pointer; Dbl: Double; Size: integer);
+
     procedure CheckError(ProcName : string; Status : PISC_STATUS);
     procedure SetParameters(cursor : TSQLCursor; aTransation : TSQLTransaction; AParams : TParams);
     procedure FreeSQLDABuffer(var aSQLDA : PXSQLDA);
@@ -99,10 +114,11 @@ type
   public
     constructor Create(AOwner : TComponent); override;
     procedure CreateDB; override;
+    function GetConnectionInfo(InfoType:TConnInfoType): string; override;
     procedure DropDB; override;
     //Segment size is not used in the code; property kept for backward compatibility
     property BlobSegmentSize : word read FBlobSegmentSize write FBlobSegmentSize; deprecated;
-    function GetDBDialect: integer;
+    property ODSMajorVersion : integer read GetODSMajorVersion; //ODS major version number; influences database compatibility/feature level.
   published
     property DatabaseName;
     property Dialect : integer read GetDialect write FDialect stored IsDialectStored default DEFDIALECT;
@@ -121,6 +137,7 @@ type
     Class Function DefaultLibraryName : String; override;
     Class Function LoadFunction : TLibraryLoadFunction; override;
     Class Function UnLoadFunction : TLibraryUnLoadFunction; override;
+    Class Function LoadedLibraryName: string; override;
   end;
                   
 implementation
@@ -131,6 +148,7 @@ uses
 const
   SQL_BOOLEAN_INTERBASE = 590;
   SQL_BOOLEAN_FIREBIRD = 32764;
+  INVALID_DATA = -1;
 
 type
   TTm = packed record
@@ -173,9 +191,9 @@ constructor TIBConnection.Create(AOwner : TComponent);
 begin
   inherited;
   FConnOptions := FConnOptions + [sqSupportParams] + [sqEscapeRepeat];
-  FBLobSegmentSize := 65535; //Shows we're using the maximum segment size
-  FDialect := -1;
-  FDBDialect := -1;
+  FBlobSegmentSize := 65535; //Shows we're using the maximum segment size
+  FDialect := INVALID_DATA;
+  ResetDatabaseInfo;
 end;
 
 
@@ -267,6 +285,8 @@ begin
     if isc_rollback_retaining(@Status[0], @TransactionHandle) <> 0 then
       CheckError('RollBackRetaining', Status);
 end;
+
+
 procedure TIBConnection.DropDB;
 
 begin
@@ -286,6 +306,7 @@ begin
 {$EndIf}
 end;
 
+
 procedure TIBConnection.CreateDB;
 
 var ASQLDatabaseHandle,
@@ -324,7 +345,6 @@ begin
 end;
 
 procedure TIBConnection.DoInternalConnect;
-
 begin
 {$IfDef LinkDynamically}
   InitialiseIBase60;
@@ -336,10 +356,10 @@ end;
 
 procedure TIBConnection.DoInternalDisconnect;
 begin
-  FDialect := -1;
-  FDBDialect := -1;
+  FDialect := INVALID_DATA;
   if not Connected then
   begin
+    ResetDatabaseInfo;
     FSQLDatabaseHandle := nil;
     Exit;
   end;
@@ -351,40 +371,164 @@ begin
 {$EndIf}
 end;
 
+function TIBConnection.GetConnectionInfo(InfoType: TConnInfoType): string;
+begin
+  result:='';
+  {$IFDEF LinkDynamically}
+  InitialiseIBase60;
+  {$ENDIF}
+  try
+    case InfoType of
+      citServerType:
+        // Firebird returns own name in ServerVersion; Interbase 7.5 doesn't.
+        if pos('FIREBIRD',UpperCase(FDatabaseInfo.ServerVersionString))=0 then
+          result := 'Interbase'
+        else
+          result := 'Firebird';
+      citServerVersion:
+        // Firebird returns major.minor, Interbase major.minor.build
+        result := FDatabaseInfo.ServerVersion;
+      citServerVersionString:
+        result := FDatabaseInfo.ServerVersionString;
+      citClientName:
+        result:=TIBConnectionDef.LoadedLibraryName;
+    else
+      //including citClientVersion, for which no single IB+FB and Win+*nux solution exists
+      result:=inherited GetConnectionInfo(InfoType);
+    end;
+  finally
+    {$IFDEF LinkDynamically}
+    ReleaseIBase60;
+    {$ENDIF}
+  end;
+end;
 
-function TIBConnection.GetDBDialect: integer;
+procedure TIBConnection.GetDatabaseInfo;
+// Asks server for multiple values
+const
+  ResBufHigh = 512; //hopefully enough to include version string as well.
 var
   x : integer;
   Len : integer;
-  Buffer : array [0..1] of byte;
-  ResBuf : array [0..39] of byte;
+  ReqBuf : array [0..3] of byte;
+  ResBuf : array [0..ResBufHigh] of byte; // should be big enough for version string etc
 begin
-  result := -1;
+  ResetDatabaseInfo;
   if Connected then
-    begin
-    Buffer[0] := isc_info_db_sql_dialect;
-    Buffer[1] := isc_info_end;
-    if isc_database_info(@FStatus[0], @FSQLDatabaseHandle, Length(Buffer),
-      pchar(@Buffer[0]), SizeOf(ResBuf), pchar(@ResBuf[0])) <> 0 then
-        CheckError('SetDBDialect', FStatus);
+  begin
+    ReqBuf[0] := isc_info_ods_version;
+    ReqBuf[1] := isc_info_version;
+    ReqBuf[2] := isc_info_db_sql_dialect;
+    ReqBuf[3] := isc_info_end;
+    if isc_database_info(@FStatus[0], @FSQLDatabaseHandle, Length(ReqBuf),
+      pchar(@ReqBuf[0]), SizeOf(ResBuf), pchar(@ResBuf[0])) <> 0 then
+        CheckError('CacheServerInfo', FStatus);
     x := 0;
-    while x < 40 do
+    while x < ResBufHigh+1 do
       case ResBuf[x] of
         isc_info_db_sql_dialect :
           begin
           Inc(x);
           Len := isc_vax_integer(pchar(@ResBuf[x]), 2);
           Inc(x, 2);
-          Result := isc_vax_integer(pchar(@ResBuf[x]), Len);
+          FDatabaseInfo.Dialect := isc_vax_integer(pchar(@ResBuf[x]), Len);
           Inc(x, Len);
           end;
-        isc_info_end : Break;
+        isc_info_ods_version :
+          begin
+          Inc(x);
+          Len := isc_vax_integer(pchar(@ResBuf[x]), 2);
+          Inc(x, 2);
+          FDatabaseInfo.ODSMajorVersion := isc_vax_integer(pchar(@ResBuf[x]), Len);
+          Inc(x, Len);
+          end;
+        isc_info_version :
+          begin
+          Inc(x);
+          Len := isc_vax_integer(pchar(@ResBuf[x]), 2);
+          Inc(x, 2);
+          SetString(FDatabaseInfo.ServerVersionString, PAnsiChar(@ResBuf[x + 2]), Len-2);
+          FDatabaseInfo.ServerVersion := ParseServerVersion(FDatabaseInfo.ServerVersionString);
+          Inc(x, Len);
+          end;
+        isc_info_end, isc_info_error : Break;
+        isc_info_truncated : Break; //result buffer too small; fix your code!
       else
         inc(x);
       end;
+  end;
+end;
+
+procedure TIBConnection.ResetDatabaseInfo;
+begin
+  FDatabaseInfo.Dialect:=0;
+  FDatabaseInfo.ODSMajorVersion:=0;
+  FDatabaseInfo.ServerVersion:='';
+  FDatabaseInfo.ServerVersionString:=''; // don't confuse applications with 'Firebird' or 'Interbase'
+end;
+
+
+function TIBConnection.GetODSMajorVersion: integer;
+begin
+  result:=FDatabaseInfo.ODSMajorVersion;
+end;
+
+function TIBConnection.ParseServerVersion(const CompleteVersion: string): string;
+// String representation of integer version number derived from
+// major.minor.build => should give e.g. 020501
+const
+  Delimiter = '.';
+  DigitsPerNumber = 2;
+  MaxNumbers = 3;
+var
+  BeginPos,EndPos,StartLook,i: integer;
+  NumericPart: string;
+  Version: integer;
+begin
+  result := '';
+  // Ignore 6.x version number in front of "Firebird"
+  StartLook := Pos('Firebird', CompleteVersion);
+  if StartLook = 0 then
+    StartLook := 1;
+  BeginPos := 0;
+  // Catch all numerics + decimal point:
+  for i := StartLook to Length(CompleteVersion) do
+  begin
+    if (BeginPos > 0) and
+      ((CompleteVersion[i] < '0') or (CompleteVersion[i] > '9')) and (CompleteVersion[i] <> '.') then
+    begin
+      EndPos := i - 1;
+      break;
     end;
+    if (BeginPos = 0) and
+      (CompleteVersion[i] >= '0') and (CompleteVersion[i] <= '9') then
+    begin
+      BeginPos := i;
+    end;
+  end;
+  if BeginPos > 0 then
+  begin
+    NumericPart := copy(CompleteVersion, BeginPos, 1+EndPos-BeginPos);
+    BeginPos := 1;
+    for i := 1 to MaxNumbers do
+    begin
+      EndPos := PosEx(Delimiter,NumericPart,BeginPos);
+      if EndPos > 0 then
+      begin
+        result := result + rightstr(StringOfChar('0',DigitsPerNumber)+copy(NumericPart,BeginPos,EndPos-BeginPos),DigitsPerNumber);
+        BeginPos := EndPos+1;
+      end
+      else
+      begin
+        result := result + rightstr(StringOfChar('0',DigitsPerNumber)+copy(NumericPart,BeginPos,Length(NumericPart)),DigitsPerNumber);
+        break;
+      end;
+    end;
+    result := leftstr(result + StringOfChar('0',DigitsPerNumber * MaxNumbers), DigitsPerNumber * MaxNumbers);
+  end;
 end;
 
+
 procedure TIBConnection.ConnectFB;
 var
   ADatabaseName: String;
@@ -413,12 +557,12 @@ end;
 
 function TIBConnection.GetDialect: integer;
 begin
-  if FDialect = -1 then
+  if FDialect = INVALID_DATA then
   begin
-    if FDBDialect = -1 then
+    if FDatabaseInfo.Dialect=0 then
       Result := DEFDIALECT
     else
-      Result := FDBDialect;
+      Result := FDatabaseInfo.Dialect;
   end else
     Result := FDialect;
 end;
@@ -652,21 +796,20 @@ begin
         Dispose(aSQLDA^.SQLVar[x].sqlind);
         aSQLDA^.SQLVar[x].sqlind := nil;
         end
-        
       end;
 {$R+}
 end;
 
 function TIBConnection.IsDialectStored: boolean;
 begin
-  result := (FDialect<>-1);
+  result := (FDialect<>INVALID_DATA);
 end;
 
 procedure TIBConnection.DoConnect;
 const NoQuotes: TQuoteChars = (' ',' ');
 begin
   inherited DoConnect;
-  FDBDialect := GetDBDialect;
+  GetDatabaseInfo; //Get db dialect, db metadata
   if Dialect < 3 then
     FieldNameQuoteChars := NoQuotes
   else
@@ -748,8 +891,8 @@ begin
   with cursor as TIBCursor do
   begin
     if FStatementType = stExecProcedure then
-      //it is not recommended fetch from non-select statement, i.e. statement which have no cursor
-      //starting from Firebird 2.5 it leads to error 'Invalid cursor reference'
+      //do not fetch from a non-select statement, i.e. statement which has no cursor
+      //on Firebird 2.5+ it leads to error 'Invalid cursor reference'
       if SQLDA^.SQLD = 0 then
         retcode := 100 //no more rows to retrieve
       else
@@ -1466,6 +1609,15 @@ begin
   Result:=@ReleaseIBase60
 end;
 
+class function TIBConnectionDef.LoadedLibraryName: string;
+begin
+  {$IfDef LinkDynamically}
+  Result:=IBaseLoadedLibrary;
+  {$else}
+  Result:='';
+  {$endif}
+end;
+
 initialization
   RegisterConnection(TIBConnectionDef);
 

+ 7 - 0
packages/fcl-db/src/sqldb/mysql/mysqlconn.inc

@@ -122,6 +122,7 @@ Type
     procedure GetFieldNames(const TableName : string; List :  TStrings); override;
     procedure GetTableNames(List : TStrings; SystemTables : Boolean = false); override;
     function GetConnectionInfo(InfoType:TConnInfoType): string; override;
+    Function GetInsertID: int64;
     procedure CreateDB; override;
     procedure DropDB; override;
     Property ServerInfo : String Read FServerInfo;
@@ -296,6 +297,12 @@ begin
   Result := mysql_stat(FMYSQL);
 end;
 
+function TConnectionName.GetInsertID: Int64;
+begin
+  CheckConnected;
+  Result:=mysql_insert_id(GetHandle);
+end;
+
 procedure TConnectionName.ConnectMySQL(var HMySQL : PMySQL;H,U,P : pchar);
 
 Var

+ 3 - 1
packages/fcl-db/src/sqldb/odbc/odbcconn.pas

@@ -960,8 +960,10 @@ 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);
-  ODBCCheckResult(Res, SQL_HANDLE_STMT, ODBCCursor.FSTMTHandle, 'Could not get field data for field "%s" (index %d).',[FieldDef.Name, FieldDef.Index+1]);
+  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

+ 16 - 12
packages/fcl-db/src/sqldb/postgres/pqconnection.pp

@@ -780,7 +780,7 @@ type TNumericRecord = record
      end;
 
 var
-  x,i,j         : integer;
+  x,i           : integer;
   s             : string;
   li            : Longint;
   CurrBuff      : pchar;
@@ -814,18 +814,22 @@ begin
       result := true;
 
       case FieldDef.DataType of
-        ftInteger, ftSmallint, ftLargeInt, ftFloat :
-          begin
-          i := PQfsize(res, x);
-          case i of               // postgres returns big-endian numbers
-            sizeof(int64) : pint64(buffer)^ := BEtoN(pint64(CurrBuff)^);
-            sizeof(integer) : pinteger(buffer)^ := BEtoN(pinteger(CurrBuff)^);
-            sizeof(smallint) : psmallint(buffer)^ := BEtoN(psmallint(CurrBuff)^);
-          else
-            for j := 1 to i do
-              pchar(Buffer)[j-1] := CurrBuff[i-j];
+        ftInteger, ftSmallint, ftLargeInt :
+          case PQfsize(res, x) of  // postgres returns big-endian numbers
+            sizeof(int64) : pint64(buffer)^ := BEtoN(pint64(CurrBuff)^); // INT8
+            sizeof(integer) : pinteger(buffer)^ := BEtoN(pinteger(CurrBuff)^); // INT4
+            sizeof(smallint) : psmallint(buffer)^ := BEtoN(psmallint(CurrBuff)^); // INT2
+          end; {case}
+        ftFloat :
+          case PQfsize(res, x) of  // postgres returns big-endian numbers
+            sizeof(int64) :  // FLOAT8
+              pint64(buffer)^ := BEtoN(pint64(CurrBuff)^);
+            sizeof(integer) :  // FLOAT4
+              begin
+              li := BEtoN(pinteger(CurrBuff)^);
+              pdouble(buffer)^ := psingle(@li)^
+              end;
           end; {case}
-          end;
         ftString, ftFixedChar :
           begin
           case PQftype(res, x) of

+ 5 - 3
packages/fcl-db/src/sqldb/sqlite/sqlite3conn.pp

@@ -628,6 +628,7 @@ begin
                 int1:=FieldDef.Size;
               if int1 > 0 then 
                  move(sqlite3_column_text(st,fnum)^,buffer^,int1);
+              PAnsiChar(buffer + int1)^ := #0;
               end;
     ftFmtBCD: begin
               int1:= sqlite3_column_bytes(st,fnum);
@@ -648,11 +649,12 @@ begin
     ftFixedWideChar,
     ftWideString:
       begin
-      int1 := sqlite3_column_bytes16(st,fnum)+2; //The value returned does not include the zero terminator at the end of the string
-      if int1>(FieldDef.Size+1)*2 then
-        int1:=(FieldDef.Size+1)*2;
+      int1 := sqlite3_column_bytes16(st,fnum); //The value returned does not include the zero terminator at the end of the string
+      if int1>FieldDef.Size*2 then
+        int1:=FieldDef.Size*2;
       if int1 > 0 then
         move(sqlite3_column_text16(st,fnum)^, buffer^, int1); //Strings returned by sqlite3_column_text() and sqlite3_column_text16(), even empty strings, are always zero terminated.
+      PWideChar(buffer + int1)^ := #0;
       end;
     ftVarBytes,
     ftBytes:

+ 22 - 9
packages/ibase/src/ibase60.inc

@@ -2463,8 +2463,8 @@ function InitialiseIBase60(Const LibraryName : AnsiString) : integer;
 function InitialiseIBase60 : integer;
 procedure ReleaseIBase60;
 
-var IBaseLibraryHandle : TLibHandle;
-
+Function IBaseLibraryHandle : TLibHandle;
+Function IBaseLoadedLibrary : AnsiString;
 {$ENDIF}
 
 implementation
@@ -2479,7 +2479,20 @@ ResourceString
   
 var 
   RefCount : integer;
-  LoadedLibrary : String;
+  LoadedLibrary : AnsiString;
+  LibHandle : TLibHandle;
+  
+Function IBaseLibraryHandle : TLibHandle;
+
+begin
+  result:=LibHandle;
+end;
+
+Function IBaseLoadedLibrary : AnsiString;
+  
+begin
+  Result:=LoadedLibrary;
+end;  
 
 Function TryInitialiseIBase60(Const LibraryName : AnsiString) : integer;
 
@@ -2487,8 +2500,8 @@ begin
   Result := 0;
   if (RefCount=0) then
     begin
-    IBaseLibraryHandle:=LoadLibrary(LibraryName);
-    if (IBaseLibraryHandle=nilhandle) then
+    LibHandle:=LoadLibrary(LibraryName);
+    if (LibHandle=nilhandle) then
       Exit;
     inc(RefCount);
     LoadedLibrary:=LibraryName;
@@ -2695,11 +2708,11 @@ begin
   Result := TryInitialiseIBase60(LibraryName);
   If Result = 0 then
     Raise EInOutError.CreateFmt(SErrLoadFailed,[LibraryName])
-  else If (LibraryName<>LoadedLibrary) then
+  else If (LibraryName<>IBaseLoadedLibrary) then
     begin
     Dec(RefCount);
     Result := RefCount;
-    Raise EInOUtError.CreateFmt(SErrAlreadyLoaded,[LoadedLibrary]);
+    Raise EInOUtError.CreateFmt(SErrAlreadyLoaded,[IBaseLoadedLibrary]);
     end;
 end;
 
@@ -2709,10 +2722,10 @@ Procedure ReleaseIBase60;
 begin
   if RefCount>1 then
     Dec(RefCount)
-  else if UnloadLibrary(IBaseLibraryHandle) then 
+  else if UnloadLibrary(LibHandle) then 
     begin
     Dec(RefCount);
-    IBaseLibraryHandle := NilHandle;
+    LibHandle := NilHandle;
     LoadedLibrary:='';
     end;
 end;