Browse Source

--- Merging r24486 into '.':
U packages/fcl-db/src/sqldb/odbc/odbcconn.pas
U packages/odbc/src/odbcsql.inc
--- Merging r24490 into '.':
U packages/fcl-db/src/export/fpdbfexport.pp
--- Merging r24509 into '.':
U packages/fcl-db/tests/testspecifictdbf.pas
U packages/fcl-db/src/dbase/dbf.pas
U packages/fcl-db/src/dbase/history.txt
U packages/fcl-db/src/dbase/dbf_dbffile.pas
--- Merging r24525 into '.':
U packages/fcl-db/tests/dbftoolsunit.pas
U packages/fcl-db/tests/testdbbasics.pas
U packages/fcl-db/src/Dataset.txt
--- Merging r24545 into '.':
U packages/fcl-db/src/dbase/dbf_fields.pas
U packages/fcl-db/tests/bufdatasettoolsunit.pas
G packages/fcl-db/tests/dbftoolsunit.pas
U packages/fcl-db/tests/toolsunit.pas
G packages/fcl-db/tests/testdbbasics.pas
--- Merging r24557 into '.':
U packages/fcl-db/tests/sqldbtoolsunit.pas
G packages/fcl-db/tests/toolsunit.pas
--- Merging r24558 into '.':
U packages/fcl-db/src/base/db.pas
U packages/fcl-db/src/base/fields.inc
--- Merging r24632 into '.':
G packages/fcl-db/src/base/db.pas
G packages/fcl-db/src/base/fields.inc

# revisions: 24486,24490,24509,24525,24545,24557,24558,24632
r24486 | michael | 2013-05-12 15:46:39 +0200 (Sun, 12 May 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/odbc/odbcconn.pas
M /trunk/packages/odbc/src/odbcsql.inc

* Fixed bug #24419
r24490 | reiniero | 2013-05-13 11:51:11 +0200 (Mon, 13 May 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/export/fpdbfexport.pp

* fcl-db/fpdbfexport: fix automatic export field name truncation for DBase files
r24509 | reiniero | 2013-05-15 14:42:11 +0200 (Wed, 15 May 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/dbase/dbf.pas
M /trunk/packages/fcl-db/src/dbase/dbf_dbffile.pas
M /trunk/packages/fcl-db/src/dbase/history.txt
M /trunk/packages/fcl-db/tests/testspecifictdbf.pas

* fcl-db/dbase: add support and test for IndexStream so dbf,memo, and index can work without file backing if streams are used
r24525 | reiniero | 2013-05-18 10:56:16 +0200 (Sat, 18 May 2013) | 3 lines
Changed paths:
M /trunk/packages/fcl-db/src/Dataset.txt
M /trunk/packages/fcl-db/tests/dbftoolsunit.pas
M /trunk/packages/fcl-db/tests/testdbbasics.pas

* fcl-db: clarified Dataset.txt
* fcl-db/dbase tests: fix for failing memo, string test
improvement in naming saved dbf files (if enabled)
r24545 | reiniero | 2013-05-21 15:26:06 +0200 (Tue, 21 May 2013) | 3 lines
Changed paths:
M /trunk/packages/fcl-db/src/dbase/dbf_fields.pas
M /trunk/packages/fcl-db/tests/bufdatasettoolsunit.pas
M /trunk/packages/fcl-db/tests/dbftoolsunit.pas
M /trunk/packages/fcl-db/tests/testdbbasics.pas
M /trunk/packages/fcl-db/tests/toolsunit.pas

* fcl-db: tdbf: better support ftWord field type
* fcl-db tests: test ftWord for bufdataset, tdbf etc
To do: verify why all bufdataset export tests now get an access violation
r24557 | lacak | 2013-05-23 14:06:59 +0200 (Thu, 23 May 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/tests/sqldbtoolsunit.pas
M /trunk/packages/fcl-db/tests/toolsunit.pas

fcl-db: tests: Adjust sqlDB/SQLite3 tests for newly added test TestSupportWordFields (WORD fields are alredy supported by SQLite3Connection)
r24558 | lacak | 2013-05-23 14:11:13 +0200 (Thu, 23 May 2013) | 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: consistent usage of AsInteger and AsLongint. Bug #24456
r24632 | lacak | 2013-05-30 10:26:39 +0200 (Thu, 30 May 2013) | 2 lines
Changed paths:
M /trunk/packages/fcl-db/src/base/db.pas
M /trunk/packages/fcl-db/src/base/fields.inc

fcl-db: base: change formal data type of AsInteger to Longint instead of Integer (in objpas mode it is same as Integer) to be Delphi compatible.
Change call chain GetAsInteger calls GetAsLongint to GetAsLongint calls GetAsInteger, because AsInteger is used often than GetAsLongint so we save one more call.

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

marco 12 years ago
parent
commit
d4210de86d

+ 5 - 5
packages/fcl-db/src/Dataset.txt

@@ -4,7 +4,7 @@ Contents
 + Fields system
 + The buffers
 + Dataset implementation
-+ Scalable Datasets
++ Switchable datasets
 
 ===============
 General remarks
@@ -231,10 +231,10 @@ procedure SetFieldData(Field: TField; Buffer: Pointer); virtual; abstract;
 --------------------------------------------------------------------------
 Move the data in associated with Field from Buffer to the active buffer.
 
-=================
-Scalable datasets
-=================
-In order to have Scalable database access, the concept of TDatabase and
+===================
+Switchable datasets
+===================
+In order to have flexible database access, the concept of TDatabase and
 TDBDataset is introduced. The idea is that, in a visual IDE, the change
 from one database to another is achieved by simply removing one TDatabase
 descendent (Say, TMySqlDatabase) with another (Say, TPostGreSQLDatabase)

+ 20 - 20
packages/fcl-db/src/base/db.pas

@@ -356,7 +356,7 @@ type
     procedure SetAsDateTime(AValue: TDateTime); virtual;
     procedure SetAsFloat(AValue: Double); virtual;
     procedure SetAsLongint(AValue: Longint); virtual;
-    procedure SetAsInteger(AValue: Integer); virtual;
+    procedure SetAsInteger(AValue: Longint); virtual;
     procedure SetAsLargeint(AValue: Largeint); virtual;
     procedure SetAsVariant(const AValue: variant); virtual;
     procedure SetAsString(const AValue: string); virtual;
@@ -392,7 +392,7 @@ type
     property AsFloat: Double read GetAsFloat write SetAsFloat;
     property AsLongint: Longint read GetAsLongint write SetAsLongint;
     property AsLargeInt: LargeInt read GetAsLargeInt write SetAsLargeInt;
-    property AsInteger: Integer read GetAsInteger write SetAsInteger;
+    property AsInteger: Longint read GetAsInteger write SetAsInteger;
     property AsString: string read GetAsString write SetAsString;
     property AsWideString: WideString read GetAsWideString write SetAsWideString;
     property AsVariant: variant read GetAsVariant write SetAsVariant;
@@ -458,7 +458,7 @@ type
     function GetAsBoolean: Boolean; override;
     function GetAsDateTime: TDateTime; override;
     function GetAsFloat: Double; override;
-    function GetAsLongint: Longint; override;
+    function GetAsInteger: Longint; override;
     function GetAsString: string; override;
     function GetAsVariant: variant; override;
     function GetDataSize: Integer; override;
@@ -468,7 +468,7 @@ type
     procedure SetAsBoolean(AValue: Boolean); override;
     procedure SetAsDateTime(AValue: TDateTime); override;
     procedure SetAsFloat(AValue: Double); override;
-    procedure SetAsLongint(AValue: Longint); override;
+    procedure SetAsInteger(AValue: Longint); override;
     procedure SetAsString(const AValue: string); override;
     procedure SetVarValue(const AValue: Variant); override;
   public
@@ -534,27 +534,27 @@ type
     FMinValue,
     FMaxValue,
     FMinRange,
-    FMAxRange  : Longint;
+    FMaxRange  : Longint;
     Procedure SetMinValue (AValue : longint);
     Procedure SetMaxValue (AValue : longint);
   protected
     function GetAsFloat: Double; override;
-    function GetAsLongint: Longint; override;
+    function GetAsInteger: Longint; override;
     function GetAsString: string; override;
     function GetAsVariant: variant; override;
     function GetDataSize: Integer; override;
     procedure GetText(var AText: string; ADisplayText: Boolean); override;
     function GetValue(var AValue: Longint): Boolean;
     procedure SetAsFloat(AValue: Double); override;
-    procedure SetAsLongint(AValue: Longint); override;
+    procedure SetAsInteger(AValue: Longint); override;
     procedure SetAsString(const AValue: string); override;
     procedure SetVarValue(const AValue: Variant); override;
     function GetAsLargeint: Largeint; override;
     procedure SetAsLargeint(AValue: Largeint); override;
   public
     constructor Create(AOwner: TComponent); override;
-    Function CheckRange(AValue : longint) : Boolean;
-    property Value: Longint read GetAsLongint write SetAsLongint;
+    Function CheckRange(AValue : Longint) : Boolean;
+    property Value: Longint read GetAsInteger write SetAsInteger;
   published
     property MaxValue: Longint read FMaxValue write SetMaxValue default 0;
     property MinValue: Longint read FMinValue write SetMinValue default 0;
@@ -573,7 +573,7 @@ type
     Procedure SetMaxValue (AValue : Largeint);
   protected
     function GetAsFloat: Double; override;
-    function GetAsLongint: Longint; override;
+    function GetAsInteger: Longint; override;
     function GetAsLargeint: Largeint; override;
     function GetAsString: string; override;
     function GetAsVariant: variant; override;
@@ -581,7 +581,7 @@ type
     procedure GetText(var AText: string; ADisplayText: Boolean); override;
     function GetValue(var AValue: Largeint): Boolean;
     procedure SetAsFloat(AValue: Double); override;
-    procedure SetAsLongint(AValue: Longint); override;
+    procedure SetAsInteger(AValue: Longint); override;
     procedure SetAsLargeint(AValue: Largeint); override;
     procedure SetAsString(const AValue: string); override;
     procedure SetVarValue(const AValue: Variant); override;
@@ -616,7 +616,7 @@ type
 
   TAutoIncField = class(TLongintField)
   Protected
-    Procedure SetAsLongInt(AValue : Longint); override;
+    procedure SetAsInteger(AValue: Longint); override;
   public
     constructor Create(AOwner: TComponent); override;
   end;
@@ -634,14 +634,14 @@ type
   protected
     function GetAsFloat: Double; override;
     function GetAsLargeInt: LargeInt; override;
-    function GetAsLongint: Longint; override;
+    function GetAsInteger: Longint; override;
     function GetAsVariant: variant; override;
     function GetAsString: string; override;
     function GetDataSize: Integer; override;
     procedure GetText(var theText: string; ADisplayText: Boolean); override;
     procedure SetAsFloat(AValue: Double); override;
     procedure SetAsLargeInt(AValue: LargeInt); override;
-    procedure SetAsLongint(AValue: Longint); override;
+    procedure SetAsInteger(AValue: Longint); override;
     procedure SetAsString(const AValue: string); override;
     procedure SetVarValue(const AValue: Variant); override;
   public
@@ -682,7 +682,7 @@ type
     function GetDefaultWidth: Longint; override;
     procedure SetAsBoolean(AValue: Boolean); override;
     procedure SetAsString(const AValue: string); override;
-    procedure SetAsInteger(AValue: Integer); override;
+    procedure SetAsInteger(AValue: Longint); override;
     procedure SetVarValue(const AValue: Variant); override;
   public
     constructor Create(AOwner: TComponent); override;
@@ -783,7 +783,7 @@ type
     function GetAsBCD: TBCD; override;
     function GetAsCurrency: Currency; override;
     function GetAsFloat: Double; override;
-    function GetAsLongint: Longint; override;
+    function GetAsInteger: Longint; override;
     function GetAsString: string; override;
     function GetValue(var AValue: Currency): Boolean;
     function GetAsVariant: variant; override;
@@ -792,7 +792,7 @@ type
     procedure GetText(var TheText: string; ADisplayText: Boolean); override;
     procedure SetAsBCD(const AValue: TBCD); override;
     procedure SetAsFloat(AValue: Double); override;
-    procedure SetAsLongint(AValue: Longint); override;
+    procedure SetAsInteger(AValue: Longint); override;
     procedure SetAsString(const AValue: string); override;
     procedure SetAsCurrency(AValue: Currency); override;
     procedure SetVarValue(const AValue: Variant); override;
@@ -826,7 +826,7 @@ type
     function GetAsCurrency: Currency; override;
     function GetAsFloat: Double; override;
     function GetAsLargeInt: LargeInt; override;
-    function GetAsLongint: Longint; override;
+    function GetAsInteger: Longint; override;
     function GetAsString: string; override;
     function GetAsVariant: variant; override;
     function GetDataSize: Integer; override;
@@ -835,7 +835,7 @@ type
     procedure SetAsBCD(const AValue: TBCD); override;
     procedure SetAsFloat(AValue: Double); override;
     procedure SetAsLargeInt(AValue: LargeInt); override;
-    procedure SetAsLongint(AValue: Longint); override;
+    procedure SetAsInteger(AValue: Longint); override;
     procedure SetAsString(const AValue: string); override;
     procedure SetAsCurrency(AValue: Currency); override;
     procedure SetVarValue(const AValue: Variant); override;
@@ -943,7 +943,7 @@ type
     procedure SetAsFloat(aValue: Double); override;
 
     function GetAsInteger: Longint; override;
-    procedure SetAsInteger(aValue: Longint); override;
+    procedure SetAsInteger(AValue: Longint); override;
 
     function GetAsString: string; override;
     procedure SetAsString(const aValue: string); override;

+ 32 - 32
packages/fcl-db/src/base/fields.inc

@@ -448,22 +448,22 @@ end;
 function TField.GetAsLongint: Longint;
 
 begin
-  raise AccessError(SInteger);
+  Result:=GetAsInteger;
 end;
 
-function TField.GetAsVariant: Variant;
+function TField.GetAsInteger: Longint;
 
 begin
-  raise AccessError(SVariant);
+  raise AccessError(SInteger);
 end;
 
-
-function TField.GetAsInteger: Integer;
+function TField.GetAsVariant: Variant;
 
 begin
-  Result:=GetAsLongint;
+  raise AccessError(SVariant);
 end;
 
+
 function TField.GetAsString: string;
 
 begin
@@ -797,13 +797,13 @@ end;
 procedure TField.SetAsLongint(AValue: Longint);
 
 begin
-  Raise AccessError(SInteger);
+  SetAsInteger(AValue);
 end;
 
-procedure TField.SetAsInteger(AValue: Integer);
+procedure TField.SetAsInteger(AValue: Longint);
 
 begin
-  SetAsLongint(AValue);
+  raise AccessError(SInteger);
 end;
 
 procedure TField.SetAsLargeint(AValue: Largeint);
@@ -1055,7 +1055,7 @@ begin
   Result:=StrToFloat(GetAsString);
 end;
 
-function TStringField.GetAsLongint: Longint;
+function TStringField.GetAsInteger: Longint;
 
 begin
   Result:=StrToInt(GetAsString);
@@ -1159,7 +1159,7 @@ begin
   SetAsString(FloatToStr(AValue));
 end;
 
-procedure TStringField.SetAsLongint(AValue: Longint);
+procedure TStringField.SetAsInteger(AValue: Longint);
 
 begin
   SetAsString(intToStr(AValue));
@@ -1354,7 +1354,7 @@ end;
 
 procedure TNumericField.SetAsBoolean(AValue: Boolean);
 begin
-  SetAsLongint(ord(AValue));
+  SetAsInteger(ord(AValue));
 end;
 
 { ---------------------------------------------------------------------
@@ -1375,15 +1375,15 @@ end;
 function TLongintField.GetAsFloat: Double;
 
 begin
-  Result:=GetAsLongint;
+  Result:=GetAsInteger;
 end;
 
 function TLongintField.GetAsLargeint: Largeint;
 begin
-  Result:=GetAsLongint;
+  Result:=GetAsInteger;
 end;
 
-function TLongintField.GetAsLongint: Longint;
+function TLongintField.GetAsInteger: Longint;
 
 begin
   If Not GetValue(Result) then
@@ -1455,7 +1455,7 @@ end;
 procedure TLongintField.SetAsLargeint(AValue: Largeint);
 begin
   if (AValue>=FMinRange) and (AValue<=FMaxRange) then
-    SetAsLongint(AValue)
+    SetAsInteger(AValue)
   else
     RangeError(AValue,FMinRange,FMaxRange);
 end;
@@ -1463,10 +1463,10 @@ end;
 procedure TLongintField.SetAsFloat(AValue: Double);
 
 begin
-  SetAsLongint(Round(AValue));
+  SetAsInteger(Round(AValue));
 end;
 
-procedure TLongintField.SetAsLongint(AValue: Longint);
+procedure TLongintField.SetAsInteger(AValue: Longint);
 
 begin
   If CheckRange(AValue) then
@@ -1477,7 +1477,7 @@ end;
 
 procedure TLongintField.SetVarValue(const AValue: Variant);
 begin
-  SetAsLongint(AValue);
+  SetAsInteger(AValue);
 end;
 
 procedure TLongintField.SetAsString(const AValue: string);
@@ -1491,7 +1491,7 @@ begin
     begin
     Val(AValue,L,Code);
     If Code=0 then
-      SetAsLongint(L)
+      SetAsInteger(L)
     else
       DatabaseErrorFMT(SNotAnInteger,[AValue]);
     end;
@@ -1573,7 +1573,7 @@ begin
     Result:=Null;
 end;
 
-function TLargeintField.GetAsLongint: Longint;
+function TLargeintField.GetAsInteger: Longint;
 
 begin
   Result:=GetAsLargeint;
@@ -1641,7 +1641,7 @@ begin
     RangeError(AValue,FMinRange,FMaxRange);
 end;
 
-procedure TLargeintField.SetAsLongint(AValue: Longint);
+procedure TLargeintField.SetAsInteger(AValue: Longint);
 
 begin
   SetAsLargeint(AValue);
@@ -1752,7 +1752,7 @@ begin
   SetDataType(ftAutoInc);
 end;
 
-Procedure TAutoIncField.SetAsLongint(AValue : Longint);
+Procedure TAutoIncField.SetAsInteger(AValue: Longint);
 
 begin
   // Some databases allows insertion of explicit values into identity columns
@@ -1802,7 +1802,7 @@ begin
   Result:=Round(GetAsFloat);
 end;
 
-function TFloatField.GetAsLongint: Longint;
+function TFloatField.GetAsInteger: Longint;
 
 begin
   Result:=Round(GetAsFloat);
@@ -1874,7 +1874,7 @@ begin
   SetAsFloat(AValue);
 end;
 
-procedure TFloatField.SetAsLongint(AValue: Longint);
+procedure TFloatField.SetAsInteger(AValue: Longint);
 
 begin
   SetAsFloat(AValue);
@@ -1978,12 +1978,12 @@ begin
     Result:=Length(FDisplays[false,True]);
 end;
 
-function TBooleanField.GetAsInteger: integer;
+function TBooleanField.GetAsInteger: Longint;
 begin
   Result := ord(GetAsBoolean);
 end;
 
-procedure TBooleanField.SetAsInteger(AValue: Integer);
+procedure TBooleanField.SetAsInteger(AValue: Longint);
 begin
   SetAsBoolean(AValue<>0);
 end;
@@ -2425,7 +2425,7 @@ begin
 end;
 
 
-function TBCDField.GetAsLongint: Longint;
+function TBCDField.GetAsInteger: Longint;
 
 begin
   result := round(GetAsCurrency);
@@ -2523,7 +2523,7 @@ begin
 end;
 
 
-procedure TBCDField.SetAsLongint(AValue: Longint);
+procedure TBCDField.SetAsInteger(AValue: Longint);
 
 begin
   SetAsCurrency(AValue);
@@ -2626,7 +2626,7 @@ begin
     Result := 0;
 end;
 
-function TFMTBCDField.GetAsLongint: Longint;
+function TFMTBCDField.GetAsInteger: Longint;
 begin
   Result := round(GetAsFloat);
 end;
@@ -2721,7 +2721,7 @@ begin
   SetAsBCD(IntegerToBCD(AValue));
 end;
 
-procedure TFMTBCDField.SetAsLongint(AValue: Longint);
+procedure TFMTBCDField.SetAsInteger(AValue: Longint);
 begin
   SetAsBCD(IntegerToBCD(AValue));
 end;
@@ -3138,7 +3138,7 @@ begin
   SetVarValue(aValue);
 end;
 
-procedure TVariantField.SetAsInteger(aValue: Longint);
+procedure TVariantField.SetAsInteger(AValue: Longint);
 begin
   SetVarValue(aValue);
 end;

+ 5 - 0
packages/fcl-db/src/dbase/dbf.pas

@@ -156,6 +156,7 @@ type
     FMasterLink: TDbfMasterLink;
     FParser: TDbfParser;
     FBlobStreams: PDbfBlobList;
+    FUserIndexStream: TStream;
     FUserStream: TStream;  // user stream to open
     FUserMemoStream: TStream; // user-provided/expected stream backing memo file storage
     FTableName: string;    // table path and file name
@@ -400,6 +401,8 @@ type
     property DbfFile: TDbfFile read FDbfFile;
     // Storage for data file if using memory storage
     property UserStream: TStream read FUserStream write FUserStream;
+    // Storage for index file - if any - when using memory storage
+    property UserIndexStream: TStream read FUserIndexStream write FUserIndexStream;
     // Storage for memo file - if any - when using memory storage
     property UserMemoStream: TStream read FUserMemoStream write FUserMemoStream;
     property DisableResyncOnPost: Boolean read FDisableResyncOnPost write FDisableResyncOnPost;
@@ -1150,6 +1153,7 @@ begin
   begin
     FDbfFile.Stream := FUserStream;
     FDbfFile.MemoStream := FUserMemoStream;
+    FDbfFile.IndexStream := FUserIndexStream;
     FDbfFile.Mode := FileModeToMemMode[FileOpenMode];
   end else begin
     FDbfFile.FileName := FAbsolutePath + FTableName;
@@ -1557,6 +1561,7 @@ begin
       if FStorage = stoMemory then
       begin
         FUserStream := FDbfFile.Stream;
+        FUserIndexStream := FDBfFile.IndexStream;
         FUserMemoStream := FDbfFile.MemoStream;
       end;
 

+ 19 - 2
packages/fcl-db/src/dbase/dbf_dbffile.pas

@@ -51,6 +51,7 @@ type
     FFieldDefs: TDbfFieldDefs;
     FIndexNames: TStringList;
     FIndexFiles: TList;
+    FIndexStream: TStream;
     FDbfVersion: TXBaseVersion;
     FPrevBuffer: TRecordBuffer;
     FDefaultBuffer: TRecordBuffer;
@@ -144,6 +145,8 @@ type
     property FieldDefs: TDbfFieldDefs read FFieldDefs;
     property IndexNames: TStringList read FIndexNames;
     property IndexFiles: TList read FIndexFiles;
+    // Backing stream for stream/memory-based index "files"
+    property IndexStream: TStream read FIndexStream write FIndexStream;
     property MdxFile: TIndexFile read FMdxFile;
     property LanguageId: Integer read GetLanguageId;
     property LanguageStr: string read GetLanguageStr;
@@ -535,13 +538,21 @@ begin
         // Deal with case-sensitive filesystems:
         if (FileName<>'') and (UpperCase(FileName)=FileName) then
           lMdxFileName := UpperCase(lMdxFileName);
-        if FileExists(lMdxFileName) then
+        if FileExists(lMdxFileName) or ((Mode in [pfMemoryOpen,pfMemoryCreate])) then
         begin
           // open file
           FMdxFile := TIndexFile.Create(Self);
           FMdxFile.FileName := lMdxFileName;
           FMdxFile.Mode := Mode;
-          FMdxFile.AutoCreate := false;
+          if (Mode in [pfMemoryOpen,pfMemoryCreate]) then
+          begin
+            FMdxFile.Stream := FIndexStream;
+            FMdxFile.AutoCreate := true;
+          end
+          else
+          begin
+            FMdxFile.AutoCreate := false;
+          end;
           FMdxFile.OnLocaleError := FOnLocaleError;
           FMdxFile.CodePage := UseCodePage;
           FMdxFile.Open;
@@ -2439,6 +2450,12 @@ begin
       lIndexFile.FileName := lIndexFileName;
       lIndexFile.Mode := IndexOpenMode[CreateIndex, Mode];
       lIndexFile.AutoCreate := CreateIndex or (Length(IndexField) > 0);
+      if (Mode in [pfMemoryOpen,pfMemoryCreate]) then
+      begin
+        if FIndexStream = nil then
+          FIndexStream := TMemoryStream.Create;
+        lIndexFile.Stream := FIndexStream;
+      end;
       lIndexFile.CodePage := UseCodePage;
       lIndexFile.OnLocaleError := FOnLocaleError;
       lIndexFile.Open;

+ 16 - 8
packages/fcl-db/src/dbase/dbf_fields.pas

@@ -163,14 +163,18 @@ database.
     ... dbf supports:       -999 to  9999
                            4 digits max in practice
         therefore         DIGITS_SMALLINT = 4;
-    ftInteger  32 bits = -2147483648 to 2147483647
-    ... dbf supports:      -99999999 to  999999999                                        12345678901 = 11 digits max
-        therefore        DIGITS_INTEGER = 9;
-    ftLargeInt 64 bits = -9223372036854775808 to 9223372036854775807
-    ... dbf supports:      -99999999999999999 to  999999999999999999
-        therefore        DIGITS_LARGEINT = 18;
+    ftWord 16 bits sign = 0 to     65535
+    ... dbf supports:     0 to 999999999 (in an N field)
+        therefore         DIGITS_WORD = 5;
+    ftInteger  32 bits  = -2147483648 to 2147483647
+    ... dbf supports:       -99999999 to  999999999                                        12345678901 = 11 digits max
+        therefore         DIGITS_INTEGER = 9;
+    ftLargeInt 64 bits  = -9223372036854775808 to 9223372036854775807
+    ... dbf supports:       -99999999999999999 to  999999999999999999
+        therefore         DIGITS_LARGEINT = 18;
  *)
   DIGITS_SMALLINT = 4;
+  DIGITS_WORD = 5;
   DIGITS_INTEGER = 9;
   DIGITS_LARGEINT = 18;
 
@@ -448,7 +452,6 @@ begin
     ftAutoInc  :
       if DbfVersion=xVisualFoxPro then
         FNativeFieldType  := 'I'
-        //todo: set autoincrement fields: offset 18: add flag $0c; 19-22: value of next autoincrement; 23 value of autoincrement step value
       else
         FNativeFieldType  := '+'; //Apparently xbaseV/7+ only; not (Visual) Foxpro
     ftDateTime :
@@ -530,11 +533,16 @@ begin
         // FPC ftBCD/ftCurrency TFieldDef.Size has max 4 which is 4 bytes after decimal
         FPrecision := 4; //Total number of digits
       end;
-    ftSmallInt, ftWord:
+    ftSmallInt:
       begin
         FSize := DIGITS_SMALLINT;
         FPrecision := 0;
       end;
+    ftWord:
+      begin
+        FSize := DIGITS_WORD;
+        FPrecision := 0;
+      end;
     ftInteger, ftAutoInc:
       begin
         if DbfVersion in [xBaseVII,xVisualFoxPro] then

+ 1 - 0
packages/fcl-db/src/dbase/history.txt

@@ -32,6 +32,7 @@ BUGS & WARNINGS
 
 
 FreePascal trunk (future V7.0.0):
+- add support for memo and index stream so no disk files are needed when using streams
 - clarification on field types; remove some workarounds (r24169) todo: reinstate depending on test set
 - initial support for (Visual) FoxPro files (r24139)
 - annotated constants/file structure (r24139)

+ 26 - 24
packages/fcl-db/src/export/fpdbfexport.pp

@@ -42,7 +42,7 @@ Type
     function GetSettings: TDBFExportFormatSettings;
     procedure SetSettings(const AValue: TDBFExportFormatSettings);
   Protected
-    Procedure CheckExportFieldNames(const MaxFieldNameLength: integer); virtual;
+    Procedure CheckExportFieldName(ThisExportField: TExportFieldItem; const MaxFieldNameLength: integer);
     Function BindFields : Boolean; override;
     Function CreateFormatSettings : TCustomExportFormatSettings; override;
 
@@ -97,31 +97,30 @@ begin
   Inherited FormatSettings.Assign(AValue);
 end;
 
-procedure TFPCustomDBFExport.CheckExportFieldNames(const MaxFieldNameLength: integer);
+procedure TFPCustomDBFExport.CheckExportFieldName(ThisExportField: TExportFieldItem; const MaxFieldNameLength: integer);
+// Cut off field name at max length, and rename if it already exists
+Const
+  CounterInvalid=100;
 
 Var
-  i,NameCounter : Integer;
-  EF : TExportFieldItem;
+  NameCounter : Integer;
   NewFieldName : String;
   
 begin
-  For i:=0 to ExportFields.Count-1 do
+  If (Length(ThisExportField.ExportedName)>MaxFieldNameLength) then
     begin
-    EF:=ExportFields[i];
-    { Cut off field name at max length, and
-      rename if it already exists:}
-    If (Length(EF.ExportedName)>MaxFieldNameLength) then
+    NewFieldName:=Copy(ThisExportField.ExportedName,1,MaxFieldNameLength);
+    If ExportFields.IndexOfExportedName(NewFieldName)<>-1 then
       begin
-      NewFieldName:=Copy(EF.ExportedName,1,MaxFieldNameLength);
-      If ExportFields.IndexOfExportedName(NewFieldName)<>-1 then
-        begin
-        NameCounter:=1;
-        Repeat
-          NewFieldName:=Copy(EF.ExportedName,1,8)+Format('%.2d',[NameCounter]);
-        Until (ExportFIelds.IndexOfExportedName(NewFieldName)=-1);
-        end;
-      EF.ExportedName:=NewFieldName;
+      // Try using 2-character number sequence to generate unique name
+      NameCounter:=1;
+      Repeat
+        NewFieldName:=Copy(ThisExportField.ExportedName,1,MaxFieldNameLength-2)+Format('%.2d',[NameCounter]);
+      Until (ExportFields.IndexOfExportedName(NewFieldName)=-1) or (NameCounter=CounterInvalid);
+      if NameCounter=CounterInvalid then
+        ExportError('Could not create a unique export field name for field %s',[ThisExportField.FieldName]);
       end;
+    ThisExportField.ExportedName:=NewFieldName;
     end;
 end;
 
@@ -134,16 +133,17 @@ Const
 Var
   EF : TDBFExportFieldItem;
   i : Integer;
-  
+  MaxFieldName: integer;
+
 begin
+  Result:=Inherited;
   // DBase III,IV, and FoxPro have a 10 character field length limit.
   // Visual Foxpro free tables (without .dbc file) also
-  If FormatSettings.AutoRenameFields and (FormatSettings.TableFormat in [tfDbaseIII,tfDbaseIV,tfFoxPro,tfVisualFoxPro]) then
-    CheckExportFieldNames(10);
   // DBase VII has a 32 character field length limit.
-  If FormatSettings.AutoRenameFields and (FormatSettings.TableFormat=tfDbaseVII) then
-    CheckExportFieldNames(32);
-  Result:=Inherited;
+  if (FormatSettings.TableFormat=tfDbaseVII) then
+    MaxFieldName:=32
+  else
+    MaxFieldName:=10;
   try
     with FDBF.FieldDefs do
       begin
@@ -151,6 +151,8 @@ begin
       For i:=0 to ExportFields.Count-1 do
         begin
         EF:=ExportFields[i] as TDBFExportFieldItem;
+        If FormatSettings.AutoRenameFields then
+          CheckExportFieldName(EF,MaxFieldName);
         If EF.Enabled and Assigned(EF.Field) then
           Add(EF.ExportedName,EF.Field.DataType,EF.Field.Size);
         end;

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

@@ -1160,6 +1160,7 @@ begin
       SQL_VARBINARY:     begin FieldType:=ftVarBytes;   FieldSize:=ColumnSize; end;
       SQL_LONGVARBINARY: begin FieldType:=ftBlob;       FieldSize:=BLOB_BUF_SIZE; end; // is a blob
       SQL_TYPE_DATE:     begin FieldType:=ftDate;       FieldSize:=0; end;
+      SQL_SS_TIME2,
       SQL_TYPE_TIME:     begin FieldType:=ftTime;       FieldSize:=0; end;
       SQL_TYPE_TIMESTAMP:begin FieldType:=ftDateTime;   FieldSize:=0; end;
 {      SQL_TYPE_UTCDATETIME:FieldType:=ftUnknown;}

+ 1 - 0
packages/fcl-db/tests/bufdatasettoolsunit.pas

@@ -152,6 +152,7 @@ begin
       FieldByName('FSTRING').AsString := testStringValues[i];
       FieldByName('FSMALLINT').AsInteger := testSmallIntValues[i];
       FieldByName('FINTEGER').AsInteger := testIntValues[i];
+      FieldByName('FWORD').AsInteger := testWordValues[i];
       FieldByName('FBOOLEAN').AsBoolean := testBooleanValues[i];
       FieldByName('FFLOAT').AsFloat := testFloatValues[i];
       FieldByName('FCURRENCY').AsCurrency := testCurrencyValues[i];

+ 61 - 11
packages/fcl-db/tests/dbftoolsunit.pas

@@ -2,14 +2,13 @@ unit DBFToolsUnit;
 
 { Sets up dbf datasets for testing
 Tests expect Get*Dataset to return a dataset with structure and test data, but closed.
-Because of this, we use file-backed dbfs instead of memory backed dbfs
 }
 
 {$IFDEF FPC}
   {$mode objfpc}{$H+}
 {$ENDIF}
 
-// If defined, do not delete the dbf files when done but print out location to stdout:
+// If defined, save the dbf files when done and print out location to stdout:
 {.$DEFINE KEEPDBFFILES}
 
 interface
@@ -42,6 +41,8 @@ type
   TDBFAutoClean = class(TDBF)
   private
     FBackingStream: TMemoryStream;
+    FIndexBackingStream: TMemoryStream;
+    FMemoBackingStream: TMemoryStream;
     FCreatedBy: string;
   public
     // Keeps track of which function created the dataset, useful for troubleshooting
@@ -68,6 +69,41 @@ implementation
 uses
   FmtBCD;
 
+function GetNewTempDBFName: string;
+// Scans temp directory for dbf names and adds
+var
+  Res: TSearchRec;
+  Path, Name: string;
+  FileAttr: LongInt;
+  Attr,NextFileNo: Integer;
+begin
+  NextFileNo:=0;
+  Attr := faAnyFile;
+  if FindFirst(IncludeTrailingPathDelimiter(GetTempDir)+'*.dbf', Attr, Res) = 0 then
+  begin
+    Path := GetTempDir;
+    repeat
+       Name := ConcatPaths([Path, Res.Name]);
+       FileAttr := FileGetAttr(Name);
+       if FileAttr and faDirectory = 0 then
+       begin
+         // Capture alphabetically latest name
+         try
+           //... only if it is numeric
+           if strtoint(ChangeFileExt(Res.Name,''))>NextFileNo then
+             NextFileNo:=strtoint(ChangeFileExt(Res.Name,''));
+         except
+           // apparently not numeric
+         end;
+       end
+    until FindNext(Res) <> 0;
+  end;
+  FindClose(Res);
+  // now we now the latest file, add 1, and paste the temp directory in front of it
+  NextFileNo:=NextFileNo+1;
+  Result:=IncludeTrailingPathDelimiter(GetTempDir)+IntToStr(NextFileNo)+'.DBF';
+end;
+
 { TDBFAutoClean }
 
 function TDBFAutoClean.UserRequestedTableLevel: integer;
@@ -90,13 +126,18 @@ end;
 
 constructor TDBFAutoClean.Create;
 begin
+  // Create storage for data:
   FBackingStream:=TMemoryStream.Create;
-  // Create a unique name:
-  TableName := FormatDateTime('hhnnssz',Now())+'/'+inttostr(random(32767));
+  FIndexBackingStream:=TMemoryStream.Create;
+  FMemoBackingStream:=TMemoryStream.Create;
+  // Create a unique name (within the 10 character DBIII limit):
+  TableName := FormatDateTime('hhnnssz',Now())+'_'+inttostr(random(99));
   TableLevel := UserRequestedTableLevel;
   Storage:=stoMemory;
   UserStream:=FBackingStream;
-  CreateTable; //write out header to disk
+  UserIndexStream:=FIndexBackingStream;
+  UserMemoStream:=FMemoBackingStream;
+  CreateTable; //this will also write out the dbf header to disk/stream
 end;
 
 constructor TDBFAutoClean.Create(AOwner: TComponent);
@@ -113,12 +154,18 @@ var
 begin
   {$IFDEF KEEPDBFFILES}
   Close;
-  FileName := GetTempFileName;
+  FileName := GetNewTempDBFName;
   FBackingStream.SaveToFile(FileName);
+  FIndexBackingStream.SaveToFile(ChangeFileExt(FileName, '.mdx'));
+  if Self.TableLevel in [TDBF_TABLELEVEL_FOXPRO, TDBF_TABLELEVEL_VISUALFOXPRO] then
+    FMemoBackingStream.SaveToFile(ChangeFileExt(FileName, '.fpt'))
+  else
+    FMemoBackingStream.SaveToFile(ChangeFileExt(FileName, '.dbt'));
   writeln('TDBFAutoClean: file created by ',CreatedBy,' left file: ',FileName);
   {$ENDIF}
   inherited Destroy;
   FBackingStream.Free;
+  FIndexBackingStream.Free;
 end;
 
 
@@ -162,10 +209,10 @@ begin
     FieldDefs.Add('FWORD', ftWord);
     FieldDefs.Add('FBOOLEAN', ftBoolean);
     FieldDefs.Add('FFLOAT', ftFloat);
-    // Field types only available in newer versions
-    if (Result as TDBF).TableLevel >= 25 then
+    // Field types only available in (Visual) FoxPro
+    if (Result as TDBF).TableLevel >= TDBF_TABLELEVEL_FOXPRO then
       FieldDefs.Add('FCURRENCY', ftCurrency);
-    if (Result as TDBF).TableLevel >= 25 then
+    if (Result as TDBF).TableLevel >= TDBF_TABLELEVEL_FOXPRO then
       FieldDefs.Add('FBCD', ftBCD);
     FieldDefs.Add('FDATE', ftDate);
     FieldDefs.Add('FDATETIME', ftDateTime);
@@ -180,15 +227,18 @@ begin
       FieldByName('FSTRING').AsString := testStringValues[i];
       FieldByName('FSMALLINT').AsInteger := testSmallIntValues[i];
       FieldByName('FINTEGER').AsInteger := testIntValues[i];
+      FieldByName('FWORD').AsInteger := testWordValues[i];
       FieldByName('FBOOLEAN').AsBoolean := testBooleanValues[i];
       FieldByName('FFLOAT').AsFloat := testFloatValues[i];
-      if (Result as TDBF).TableLevel >= 25 then
+      if (Result as TDBF).TableLevel >= TDBF_TABLELEVEL_FOXPRO then
         FieldByName('FCURRENCY').AsCurrency := testCurrencyValues[i];
       // work around missing TBCDField.AsBCD:
-      if (Result as TDBF).TableLevel >= 25 then
+      if (Result as TDBF).TableLevel >= TDBF_TABLELEVEL_FOXPRO then
         FieldByName('FBCD').AsBCD := StrToBCD(testFmtBCDValues[i],Self.FormatSettings);
       FieldByName('FDATE').AsDateTime := StrToDate(testDateValues[i], 'yyyy/mm/dd', '-');
+      FieldByName('FDATETIME').AsDateTime := StrToDateTime(testValues[ftDateTime,i], Self.FormatSettings);
       FieldByName('FLARGEINT').AsLargeInt := testLargeIntValues[i];
+      FieldByName('FMEMO').AsString := testStringValues[i];
       Post;
     end;
     Close;

+ 1 - 0
packages/fcl-db/tests/sqldbtoolsunit.pas

@@ -251,6 +251,7 @@ begin
       end;
     ssSQLite:
       begin
+      FieldtypeDefinitions[ftWord] := 'WORD';
       FieldtypeDefinitions[ftCurrency] := 'CURRENCY';
       FieldtypeDefinitions[ftBytes] := 'BINARY(5)';
       FieldtypeDefinitions[ftVarBytes] := 'VARBINARY(10)';

+ 32 - 1
packages/fcl-db/tests/testdbbasics.pas

@@ -32,6 +32,7 @@ type
 
     procedure TestSupportIntegerFields;
     procedure TestSupportSmallIntFields;
+    procedure TestSupportWordFields;
     procedure TestSupportStringFields;
     procedure TestSupportBooleanFields;
     procedure TestSupportFloatFields;
@@ -2297,8 +2298,17 @@ procedure TTestDBBasics.TestSupportIntegerFields;
 var i          : byte;
     ds         : TDataset;
     Fld        : TField;
+    DbfTableLevel: integer;
 
 begin
+  DbfTableLevel:=4;
+  if (uppercase(dbconnectorname)='DBF') then
+  begin
+    DbfTableLevel:=strtointdef(dbconnectorparams,4);
+    if not(DBFTableLevel in [7,30]) then
+      Ignore('TDBF: only Visual Foxpro and DBase7 support full integer range.');
+  end;
+
   TestfieldDefinition(ftInteger,4,ds,Fld);
 
   for i := 0 to testValuesCount-1 do
@@ -2316,6 +2326,8 @@ var i          : byte;
     Fld        : TField;
 
 begin
+  if (uppercase(dbconnectorname)='DBF') then
+    Ignore('TDBF Smallint support only from -999 to 9999');
   TestfieldDefinition(ftSmallint,2,ds,Fld);
 
   for i := 0 to testValuesCount-1 do
@@ -2326,6 +2338,22 @@ begin
   ds.close;
 end;
 
+procedure TTestDBBasics.TestSupportWordFields;
+var i          : byte;
+    ds         : TDataset;
+    Fld        : TField;
+
+begin
+  TestfieldDefinition(ftWord,2,ds,Fld);
+
+  for i := 0 to testValuesCount-1 do
+    begin
+    CheckEquals(testWordValues[i],Fld.AsInteger);
+    ds.Next;
+    end;
+  ds.close;
+end;
+
 
 procedure TTestDBBasics.TestSupportStringFields;
 
@@ -2338,7 +2366,10 @@ begin
 
   for i := 0 to testValuesCount-1 do
     begin
-    CheckEquals(testStringValues[i],Fld.AsString);
+    if (uppercase(dbconnectorname)<>'DBF') then
+      CheckEquals(testStringValues[i],Fld.AsString)
+    else {DBF right-trims spaces in string fields }
+      CheckEquals(TrimRight(testStringValues[i]),Fld.AsString);
     ds.Next;
     end;
   ds.close;

+ 65 - 1
packages/fcl-db/tests/testspecifictdbf.pas

@@ -56,11 +56,13 @@ type
     // Tests like TestMemo, but closes and reopens in memory file
     // in between. Data should still be there.
     procedure TestMemoClose;
+    // Same as TestMemoClose except added index stream
+    procedure TestIndexClose;
     // Tests string field with
     // 254 characters (max for DBase IV)
     // 32767 characters (FoxPro, Visual FoxPro)
     procedure TestLargeString;
-    // Tests codepage in created dbf
+    // Tests codepage in created dbf equals requested codepage
     procedure TestCodePage;
   end;
 
@@ -426,6 +428,68 @@ begin
   MemoStream.Free;
 end;
 
+procedure TTestSpecificTDBF.TestIndexClose;
+const
+  MaxRecs = 10;
+var
+  ds : TDBF;
+  i: integer;
+  DBFStream: TMemoryStream;
+  IndexStream: TMemoryStream;
+  MemoStream: TMemoryStream;
+begin
+  ds := TDBF.Create(nil);
+  DBFStream:=TMemoryStream.Create;
+  IndexStream:=TMemoryStream.Create;
+  MemoStream:=TMemoryStream.Create;
+  DS.Storage:=stoMemory;
+  DS.UserStream:=DBFStream;
+  DS.UserIndexStream:=IndexStream;
+  DS.UserMemoStream:=MemoStream;
+  DS.FieldDefs.Add('ID',ftInteger);
+  DS.FieldDefs.Add('NAME',ftMemo);
+  DS.OpenMode:=omAutoCreate; //let dbf code create memo etc files when needed
+  DS.CreateTable;
+
+  DS.Exclusive:=true;//needed for index
+  DS.Open;
+  DS.AddIndex('idxID','ID', [ixPrimary, ixUnique]);
+  DS.Close;
+  DS.Exclusive:=false;
+
+  DS.Open;
+  for i := 1 to MaxRecs do
+    begin
+    DS.Append;
+    DS.FieldByName('ID').AsInteger := i;
+    DS.FieldByName('NAME').AsString := 'TestName' + inttostr(i);
+    DS.Post;
+    end;
+  DS.Close; //in old implementations, this erased memo memory
+
+  // Check streams have content
+  CheckNotEquals(0,DBFStream.Size,'DBF stream should have content');
+  CheckNotEquals(0,IndexStream.Size,'Index stream should have content');
+  CheckNotEquals(0,MemoStream.Size,'Memo stream should have content');
+
+  DS.Open;
+  DS.First;
+  for i := 1 to MaxRecs do
+    begin
+    CheckEquals(i,DS.fieldbyname('ID').asinteger);
+    CheckEquals('TestName' + inttostr(i),DS.fieldbyname('NAME').AsString);
+    DS.next;
+    end;
+  CheckTrue(DS.EOF,'After reading all records the dataset should show EOF');
+  DS.Close;
+
+  ds.free;
+
+  DBFStream.Free;
+  IndexStream.Free;
+  MemoStream.Free;
+end;
+
 procedure TTestSpecificTDBF.TestLargeString;
 var
   ds : TDBF;

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

@@ -107,6 +107,7 @@ const
   testCurrencyValues : Array[0..testValuesCount-1] of currency = (-100,-65.5,-54.34,-43.34,-2.50,-0.2,45.40,0.3,45.4,127,128,255,256,45,0.3,45.4,127,128,255,256,45,1234.56,43.23,43.43,99.88);
   testFmtBCDValues : Array[0..testValuesCount-1] of string = ('-100','-65.5','-54.3333','-43.3334','-2.5','-0.234567','45.4','0.3','45.414585','127','128','255','256','45','0.3','45.4','127','128','255','256','45','1234.56789','43.23','43.500001','99.88');
   testIntValues : Array[0..testValuesCount-1] of integer = (-maxInt,-maxInt+1,-maxSmallint-1,-maxSmallint,-256,-255,-128,-127,-1,0,1,127,128,255,256,maxSmallint,maxSmallint+1,MaxInt-1,MaxInt,100,130,150,-150,-132,234);
+  testWordValues : Array[0..testValuesCount-1] of Word = (1,2,3,4,5,6,7,8,0,1,127,128,255,256,maxSmallint,maxSmallint+1,maxSmallInt-1,maxSmallInt,65535,100,130,150,151,132,234);
   testSmallIntValues : Array[0..testValuesCount-1] of smallint = (-maxSmallint,-maxSmallint+1,-256,-255,-128,-127,-1,0,1,127,128,255,256,maxSmallint,maxSmallint-1,100,110,120,130,150,-150,-132,234,231,42);
   testLargeIntValues : Array[0..testValuesCount-1] of LargeInt = ( -$7fffffffffffffff,-$7ffffffffffffffe,-maxInt-1,-maxInt+1,-maxSmallint,-maxSmallint+1,-256,-255,-128,-127,-1,0,1,127,128,255,256,maxSmallint,maxSmallint-1,maxSmallint+1,MaxInt-1,MaxInt,$7fffffffffffffff-1,$7fffffffffffffff,235253244);
   testBooleanValues : Array[0..testValuesCount-1] of boolean = (true,false,false,true,true,false,false,true,false,true,true,true,false,false,false,false,true,true,true,true,false,true,true,false,false);
@@ -326,6 +327,7 @@ begin
     testValues[ftFloat,i] := FloatToStr(testFloatValues[i],FormatSettings);
     testValues[ftSmallint,i] := IntToStr(testSmallIntValues[i]);
     testValues[ftInteger,i] := IntToStr(testIntValues[i]);
+    testValues[ftWord,i] := IntToStr(testWordValues[i]);
     testValues[ftLargeint,i] := IntToStr(testLargeIntValues[i]);
     testValues[ftCurrency,i] := CurrToStr(testCurrencyValues[i],FormatSettings);
     testValues[ftBCD,i] := CurrToStr(testCurrencyValues[i],FormatSettings);

+ 3 - 1
packages/odbc/src/odbcsql.inc

@@ -113,7 +113,6 @@ const
   SQL_WVARCHAR      =(-9);
   SQL_WLONGVARCHAR  =(-10);
 
-
   SQL_CHAR          = 1;
   SQL_NUMERIC       = 2;
   SQL_DECIMAL       = 3;
@@ -131,6 +130,9 @@ const
   SQL_TYPE_DATE     = 91;
   SQL_TYPE_TIME     = 92;
   SQL_TYPE_TIMESTAMP= 93;
+  // MS SQL Server types
+  SQL_SS_TIME2            = -154;
+  SQL_SS_TIMESTAMPOFFSET  = -155;
  {$endif}
 
   SQL_DATE       = 9;