home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2003 January
/
Chip_2003-01_cd1.bin
/
zkuste
/
delphi
/
kompon
/
d56
/
VKDBF.ZIP
/
VKDBFDataSet.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
2002-10-18
|
247KB
|
7,478 lines
{Copyright: Vlad Karpov mailto:KarpovVV@protek.ru
Author: Vlad Karpov
Remarks: freeware, but this Copyright must be included
Description: TDataSet component for work with DBF tables,
DBT LOB storage and NTX indexes from CLIPPER.
That is much more then only DBFNTX driver for Delphi.
It supports many extended types (~60) such as Byte,
Word, Indeger, Int64, Real4, Real6, Real8, Binary LOB
any size and so on...
There is a Crypt DBF feature.
Version: 1.0.0 beta 28.01.2002
1.0.1 beta 28.01.2002
1) Fix bug in Exclusive index support;
2) Fix bug in Add Fields in Design time;
3) Fix bug with Long Number fields (like ["F1", "N", 10, 0]);
4) WideString support was added;
5) Truncate (ZAP) method was added;
6) More...;
1.0.2 beta 18.02.2002
1) Pack method was added;
2) LookupOptions property was added;
3) Explicitly type convention in SeekFields, Lookup, Locate
was added;
4) Recall and Delete record methodths was added;
5) Explicit full scan added in LocateRecord method;
6) ReindexAll method was added;
7) Fix bug with dbftBlob and dbftGraphic types;
8) Fix bug 'List index out of bounds' for index expression
with Numeric literal contain decimal separator. Ambiguously
determined decimal separator and literal separator ','.
1.0.3 beta 25.03.2002
1) In Mamory manager add raise error 'TVKDBFOneAlloc: Can not
allocate 0 bytes memory!'
2) Add methods CompareBookmarks, BookmarkValid
3) CretateNow -> CreateNow
4) Deleted constant LOCATE_BUFFER_SIZE
5) Check empty KeyValues in LocateRecord->LocatePass
6) Fixed bug in indexing Int64 fields
7) TVKNTXIndex.CreateCompactIndex method was added
8) Add Partial Key for index Locate and SeekFirst methods
in TVKNTXIndex class
9) Add 1A byte at end of DBF table in InternalClose method
10) Add DBEval method and OnDBEval event
1.0.4 beta 23.05.2002
1) Add Method TranslateBuff and rewrite methods
CreateBlobStream and SaveToDBT with TranslateBuff
to prevent 'Access violation' in read and write CLOB.
2) When set RecNo check Filter, SetDeleted and Range validation.
3) Fix bud in TVKNTXRange.InRange(S: String) method
4) Add event OnCreateIndex
5) Add public var FullLengthCharFieldCopy to TVKSmartDBF for
manage SetFieldData for 'C' type fields
6) Fix buf with allocate memory for FLocateBuffer (AV when
Locate, Lookup, ReindexAll, DBEval or Pack if BufferSize <> 4096)
7) Complex actions to make index compatibility with CLIPPER:
- Full rewrite TVKNTXIndex.DeleteKey procedure, now it
normalize index like a CLIPPER.
- Make TVKNTXIndex.DeleteKeyStyle property to switch
Delete Key style between CLIPPER normalize index and
all athers (Apollo, Halcyon...).
- Add TVKNTXCompactIndex.NormalizeRest method to make
normalize index in TVKNTXIndex.CreateCompactIndex and
TVKNTXIndex.SubNtx procedures.
ATTENTION: Rebuild all indexes after apply this version !
8) Add methods:
TVKNTXIndex.FindKey
TVKNTXIndex.FindKeyFields with overloaded some parameters
It is the same SeekFirst..., but subject to SetDeleted, Filter
and Range.
Partual key sapport Ok!
9) Rewrite Lokate and Lookup on TVKNTXIndex.FindKeyFields.
10) Add methods:
TVKSmartDBF.SetKey;
TVKSmartDBF.EditKey;
TVKSmartDBF.GotoKey;
TVKSmartDBF.GotoNearest;
TVKSmartDBF.DropEditKey;
TVKSmartDBF.FindKey;
TVKSmartDBF.FindNearest;
All this methods work throw TVKNTXIndex.FindKeyFields.
11) Add TVKSmartDBF.IndexName property.
12) Make type 'C' is not be NULL, if field empty Field.AsString
return string of spases lethgt of field length.
1.0.5 beta 18.10.2002
1) New property StorageType
2) property DBFFieldDefs now fill fields definition on open DataSet
3) New data tapes:
dbftDBFDataSet, // DataSet
dbftDBFDataSet_NB, // DataSet with absolute pointer
// (dbftU4_NB) to a lob
// file and not align 512 byte
// pages into the Lob
4) New component TVKNestedDBF related with dbftDBFDataSet and
dbftDBFDataSet_NB.
5) Fix bug when Field.IsNull for 'C' data type always return True.
(Thanks Alexander Manuzin)
6) Fix bug in TVKSmartDBF.NextBuffer. When read 1A end byte, it
replace first byte in FBuffer (Delete byte in first record in
FBuffer).
7) Fix bug: When Edit record and it filtered by Filter or
SetDeleted the record is not hidden in DB-Aware controls.
8) Add SoftSeek parameter in TVKNTXIndex.FindKey procedure.
9) TVKNTXIndex.Seek, TVKNTXIndex.SeekFirst,
TVKNTXIndex.SeekFirstRecord, TVKNTXIndex.SeekFields made
throw TVKNTXIndex.FindKey procedure subject to SetDeleted,
Filter and Range.
10) Fix bug: IsNull in culculated and lookup field not work.
11) Add Validation handler to the Field and ReadOnly check.
12) On SetDeleted and Filtered call Refresh method
(it was First method).
13) Add properties TVKDBFNTX.Orders[Num]: TVKNTXIndex and
TVKDBFNTX.OrdersByName[Name]: TVKNTXIndex
14) Make Source for D5 and D6. (Use $IFDEF VER130, VER140)
15) Delete property TAccessMode.ShareDenyRead and
TAccessMode.ShareCompat
16) Fix bug: Incorrect work with OEM Unique index.
17) Fix bug: If LookUp result Integer or Float - error.
18) Fix bug: Lookup field by calculated field - error.
19) Now Filtering record accepted into the DataSet use
Filter string AND OnFilterRecord event together.
20) Fix bug: When set range by index for LowKey and HiKey
are out of keys in index the DataSet show last record by
index.
21) Fix bug: Modify DataSet incorrect when unique index or
FOR index used.
22) Make over Range.
23) Add parameter Rec in TVKNTXIndex.FindKey method.
24) Fix bug: 'Variant array index out of bounds' with
partual key search in TVKSmartDBF.FindKey for multiple
key.
25) Property IndexDefs...
26) Property IndexBags... with set of orders and StorageType.
27) Add functions in Expression Parser:
- IF()
- IIF()
- RIGHT()
- LEFT()
- SPACE()
- STRZERO()
- ALLTRIM()
28) Add TVKDBFFieldDef.Tag property. Use it instead of
TField.Tag because TField.Tag occupied with TVKDBFFieldDef
object reference.
ATTANTION:
Use TVKDBFFieldDef(TField.Tag).Tag
instead of
TField.Tag
29) Add error 'TVKSmartDBF.InternalOpen: BufferSize too small!'
30) Message 'Table %s create successfully!' not appear in
Loading state.
WISH:
- Limit loaded NTX pages in mamory.
- Range by index don't work with descended index
- Realize Cashed updates.
- New locate type by ordered DBF.
- DBASE 7 support.
- Realize FPT lob storage.
- Realize IDX and CDX indexes.
- Realize NDX and MDX indexes.
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
unit VKDBFDataSet;
interface
uses
Windows, Messages, SysUtils, Classes, Forms, Db, DbConsts,
{$IFDEF VER140} Variants, FmtBcd, {$ENDIF}
VKDBFPrx, VKDBFParser, VKDBFIndex, VKDBFNTX, VKDBFCDX,
VKDBFUtil, VKDBFMemMgr, VKDBFCrypt;
type
{$A-}
DBF_HEAD = packed record
dbf_id: Byte; //0
last_update: array[0..2] of Byte; //1
last_rec: Longint; //4
data_offset: Word; //8
rec_size: Word; //10
Dummy1: Word; // 12-13
IncTrans: byte; // 14
Encrypt: byte; // 15
Dummy2: Integer; // 16-19
Dummy3: array[20..27] of byte; // 20-27
prod_ind: Shortint; //28
lang: Shortint; //29
Dummy4: Word; //30 - 31
end;
num_size = packed record
len: Byte;
dec: Byte;
end;
len_info = packed record
case Shortint of
0: (char_len: Word);
1: (num_len: num_size);
end;
TVKDBFType = (
dbftS1, //Shortint (1 byte)
dbftS1_N, //Shortint with NULL (1 byte ShortInt + 1 byte null/not null)
dbftU1, //Byte
dbftU1_N, //Byte with NULL
dbftS2, //Smallint
dbftS2_N, //Smallint with NULL
dbftU2, //Word
dbftU2_N, //Word with NULL
dbftS4, //Longint
dbftS4_N, //Longint with NULL
dbftU4, //Longword
dbftU4_N, //Longword with NULL
dbftS8, //Int64
dbftS8_N, //Int64 with NULL
dbftR4, //Single
dbftR4_N, //Single with NULL
dbftR6, //Real48
dbftR6_N, //Real48 with NULL
dbftR8, //Double
dbftR8_N, //Double with NULL
dbftR10, //Extended !!!!!!!Not yet realized
dbftR10_N, //Extended with NULL !!!!!!!Not yet realized
dbftD1, //TDateTime
dbftD1_N, //TDateTime with NULL
dbftD2, //DataSet DateTime
dbftD2_N, //DataSet DateTime with NULL
//
dbftString, //String
dbftString_N, //String witn NULL
dbftFixedChar, //FixedChar
dbftWideString, //WideString
dbftCurrency, //Currency
dbftCurrency_N, //Currency with NULL
//
dbftClob, //Clob
dbftBlob, //Blob
dbftGraphic, //Graphic
dbftFmtMemo, //FmtMemo
//
dbftBCD, //BCD (34 bytes VCL BCD structure TBCD)
//
dbftDate, //Date (Integer, 4 bytes)
dbftDate_N, //Date with NULL (Integer, 4 bytes + 1 null/not null byte)
dbftTime, //Time (Integer, 4 bytes)
dbftTime_N, //Time with NULL (Integer, 4 bytes + 1 null/not null byte)
dbftD3, //TDateTime as dbftR6 (6 bytes)
dbftD3_N, //TDateTime as dbftR6 (6 bytes) with NULL ( + 1 byte null/not null)
////////////////////////////////////////////////////////////////////////////////
/// This integer and real types with 1 null/not null bit instead of sign bit
////////////////////////////////////////////////////////////////////////////////
dbftU1_NB, //Byte ( 0 - 127 )
dbftU2_NB, //Word ( 0 - 32767 )
dbftU4_NB, //Longword ( 0 - 2147483647 )
dbftR4_NB, //Single ( Positive Single )
dbftR6_NB, //Real48 ( Positive Real48 )
dbftR8_NB, //Double ( Positive Double )
dbftD1_NB, //TDateTime ( Positive TDateTime ) (8 bytes)
dbftD2_NB, //DataSet DateTime ( Positive DataSet DateTime) (8 bytes)
//
dbftCurrency_NB, //Currency
//
dbftDate_NB, //Date
dbftTime_NB, //Time
dbftD3_NB, //TDateTime as dbftR6 (6 bytes) ( Positive Real48 )
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/////////// This is Lob types with absolute pointer (dbftU4_NB) to a lob
/////////// file and not align 512 byte pages into the Lob
////////////////////////////////////////////////////////////////////////////////
dbftClob_NB, //Clob
dbftBlob_NB, //Blob
dbftGraphic_NB, //Graphic
dbftFmtMemo_NB, //FmtMemo
////////////////////////////////////////////////////////////////////////////////
dbftUndefined, //Special type
////////////////////////////////////////////////////////////////////////////////
dbftDBFDataSet, //DataSet
dbftDBFDataSet_NB, //DataSet with absolute pointer (dbftU4_NB) to a lob
//file and not align 512 byte pages into the Lob
////////////////////////////////////////////////////////////////////////////////
/////////// Not yet realized
////////////////////////////////////////////////////////////////////////////////
dbftBytes, //Bytes
dbftVarBytes, //VarBytes
dbftTypedBinary, //TypedBinary
dbftADT, //ADT
dbftArray, //Array
dbftReference, //Reference
dbftVariant, //Variant
dbftInterface, //Interface
dbftIDispatch, //IDispatch
dbftGuid //Guid
////////////////////////////////////////////////////////////////////////////////
);
FIELD_REC = packed record
field_name: array[0..10] of char;
field_type: char; //C N D L M E - Extendes types
extend_type: TVKDBFType; //use if field_type = 'E'
dummy: array[0..2] of char;
lendth: len_info;
NextAutoInc: DWord;
filler: array [0..9] of char;
end;
TRecInfo = packed record
RecordRowID: Longint;
UpdateStatus: TUpdateStatus;
BookmarkFlag: TBookmarkFlag;
end;
{$A+}
TBufDirection = (bdFromTop, bdFromBottom);
pTRecInfo = ^TRecInfo;
ppTRecInfo = ^pTRecInfo;
pDouble = ^Double;
pInteger = ^Integer;
pReal48 = ^Real48;
TVKSmartDBF = class;
TVKNestedDBF = class;
TCryptMethod = (cmNone, cmXOR, cmGost);
TOnCrypt = procedure(Sender: TObject; Context: LongWord; Buff: Pointer; Size: Integer) of object;
TOnDBEval = procedure(Sender: TObject; nRecNo: LongWord) of object;
{TVKDBFCrypt}
TVKDBFCrypt = class(TPersistent)
private
FActive: boolean;
FCryptMethod: TCryptMethod;
FPassword: String;
FOnEncrypt: TOnCrypt;
FOnDecrypt: TOnCrypt;
FOnActivate: TNotifyEvent;
FOnDeactivate: TNotifyEvent;
FObjectID: LongWord;
procedure SetActive(const Value: boolean);
public
SmartDBF: TVKSmartDBF;
constructor Create;
destructor Destroy; override;
procedure Encrypt(Context: LongWord; Buff: Pointer; Size: Integer);
procedure Decrypt(Context: LongWord; Buff: Pointer; Size: Integer);
property ObjectID: LongWord read FObjectID write FObjectID;
published
property Active: boolean read FActive write SetActive;
property CryptMethod: TCryptMethod read FCryptMethod write FCryptMethod;
property Password: String read FPassword write FPassword;
property OnActivateCrypt: TNotifyEvent read FOnActivate write FOnActivate;
property OnDeactivateCrypt: TNotifyEvent read FOnDeactivate write FOnDeactivate;
property OnEncrypt: TOnCrypt read FOnEncrypt write FOnEncrypt;
property OnDecrypt: TOnCrypt read FOnDecrypt write FOnDecrypt;
end;
TVKDBFFieldDef = class;
{TVKDataLink}
TVKDataLink = class(TDataLink)
private
FDBFDataSet: TVKSmartDBF;
protected
procedure DataEvent(Event: TDataEvent; Info: Longint); override;
procedure DataSetScrolled(Distance: Integer); override;
public
property DBFDataSet: TVKSmartDBF read FDBFDataSet write FDBFDataSet;
end;
{TVKDBFFieldDefs}
TVKDBFFieldDefs = class(TOwnedCollection)
private
{$IFDEF VER130}
function GetCollectionOwner: TPersistent;
{$ENDIF}
function GetItem(Index: Integer): TVKDBFFieldDef;
procedure SetItem(Index: Integer; const Value: TVKDBFFieldDef);
public
constructor Create(AOwner: TPersistent);
procedure AssignValues(Value: TVKDBFFieldDefs);
function FindIndex(const Value: string): TVKDBFFieldDef;
function IsEqual(Value: TVKDBFFieldDefs): Boolean;
{$IFDEF VER130}
property Owner: TPersistent read GetCollectionOwner;
{$ENDIF}
property Items[Index: Integer]: TVKDBFFieldDef read GetItem write SetItem; default;
end;
{TVKDBFFieldDef}
TVKDBFFieldDef = class(TCollectionItem)
private
FTag: Integer;
FOff: Integer;
FOffHD: Integer;
FieldRec: FIELD_REC;
Fdec: Word;
Flen: Word;
FDBFFieldDefs: TVKDBFFieldDefs;
function GetField: FIELD_REC;
function GetDataSize: Word;
procedure SetDBFFieldDefs(const Value: TVKDBFFieldDefs);
procedure ReadDBFFieldDefData(Reader: TReader);
procedure WriteDBFFieldDefData(Writer: TWriter);
protected
FFieldDefRef: TFieldDef;
function GetDisplayName: string; override;
procedure SetDisplayName(const Value: string); override;
procedure AssignTo(Dest: TPersistent); override;
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
procedure DefineProperties(Filer: TFiler); override;
function IsEqual(Value: TVKDBFFieldDef): Boolean; virtual;
property Field: FIELD_REC read GetField;
property DataSize: Word read GetDataSize;
property FieldDefRef: TFieldDef read FFieldDefRef;
published
property DBFFieldDefs: TVKDBFFieldDefs read FDBFFieldDefs write SetDBFFieldDefs stored false;
property Name: string read GetDisplayName write SetDisplayName;
property field_type: char read FieldRec.field_type write FieldRec.field_type;
property extend_type: TVKDBFType read FieldRec.extend_type write FieldRec.extend_type;
property len: Word read Flen write Flen;
property dec: Word read Fdec write Fdec;
property Offset: Integer read FOff;
property OffsetHD: Integer read FOffHD;
property Tag: Integer read FTag write FTag;
end;
{TVKDBTStream}
TVKDBTStream = class(TMemoryStream)
protected
FModified: boolean;
FSmartDBF: TVKSmartDBF;
FField: TField;
public
constructor Create;
constructor CreateDBTStream(dbf: TVKSmartDBF; field: TField);
destructor Destroy; override;
procedure Clear;
procedure SetSize(NewSize: Longint); override;
procedure SaveToDBT;
function Write(const Buffer; Count: Longint): Longint; override;
property SmartDBF: TVKSmartDBF read FSmartDBF write FSmartDBF;
property Field: TField read FField write FField;
end;
{TVKSmartDBF}
TVKSmartDBF = class(TDataSet)
private
FOpenWithoutIndexes: boolean;
FSaveOnTheSamePlace: boolean;
FIndexName: ShortString;
FSaveState: TDataSetState;
FDataLink: TVKDataLink;
FDBFFieldDefs: TVKDBFFieldDefs;
FDBFIndexDefs: TVKDBFIndexDefs;
FIndRecBuf: pChar;
FIndState: boolean;
FLocateBuffer: pChar;
FMasterFields: String;
FRange: boolean;
ListMasterFields: TList;
FAddBuffered: boolean;
FAddBuffer: pChar;
FAddBufferCrypt: pChar;
FAddBufferCount: Integer;
FAddBufferCurrent: Integer;
FLookupOptions: TLocateOptions;
FStorageType: TProxyStreamType;
FOuterStream: TStream;
FCreateNow: boolean;
FOuterLobStream: TStream;
FOnOuterStreamLock: TLockEvent;
FOnOuterStreamUnlock: TUnlockEvent;
procedure SetRngInt;
function GetRecBuf: pChar;
function GetRecNoBuf: Longint;
procedure SetDataSource(const Value: TDataSource);
function GetCreateNow: Boolean;
procedure SetCreateNow(const Value: Boolean);
procedure SetMasterFields(const Value: String);
function GetMasterFields: Variant;
procedure SetDBFFieldDefs(const Value: TVKDBFFieldDefs);
procedure SetDBFIndexDefs(const Value: TVKDBFIndexDefs);
procedure SetOnEncrypt(const Value: TOnCrypt);
function GetOnEncrypt: TOnCrypt;
procedure SetOnDecrypt(const Value: TOnCrypt);
function GetOnDecrypt: TOnCrypt;
function GetOnCryptActivate: TNotifyEvent;
function GetOnCryptDeActivate: TNotifyEvent;
procedure SetOnCryptActivate(const Value: TNotifyEvent);
procedure SetOnCryptDeActivate(const Value: TNotifyEvent);
function GetInnerStream: TStream;
function GetInnerLobStream: TStream;
procedure HiddenInitFieldDefs(FDs: TFieldDefs; DBFFDs: TVKDBFFieldDefs; BeginOffset, BeginOffsetHD: Integer; NamePrefix: String = ''; CreateFieldDef: boolean = true);
private
{ Private declarations }
FStreamedActive: boolean;
FStreamedCreateNow: boolean;
FTempRecord: pChar;
FFilterRecord: pChar;
FSetKeyBuffer: pChar;
FFilterParser: TVKDBFExprParser;
FDBFFileName: String;
DBFHandler: TProxyStream;
LobHandler: TProxyStream;
DBFHeader: DBF_HEAD;
FRecordSize: Integer;
FAccessMode: TAccessMode;
FVKDBFCrypt: TVKDBFCrypt;
FCryptBuff: Pointer;
FOEM: Boolean;
FSetDeleted: Boolean;
FIndexes: TIndexes;
FTmpActive: boolean;
FKeyCalk: boolean;
FWaitBusyRes: Integer;
FBufferSize: Integer;
FRecordsPerBuf: Integer;
FBuffer: pChar;
FBufInd: pLongint;
FBufCnt: Longint;
FBufDir: TBufDirection;
FCurInd: Integer;
FBOF: boolean;
FEOF: boolean;
FFileLock: boolean;
FLockRecords: TList;
FLastFastPostRecord: boolean;
FFastPostRecord: boolean;
FPackProcess: boolean;
FPackLobHandler: TProxyStream;
FOnDBEval: TOnDBEval;
function GetRecordBufferSize: Integer;
property RecordBufferSize: Integer read GetRecordBufferSize;
property RecBuf: pChar read GetRecBuf;
property RecNoBuf: Longint read GetRecNoBuf;
function GetActiveRecBuf(var pRecBuf: PChar): Boolean;
function GetDeleted: Boolean;
procedure SetDeletedFlag(const Value: Boolean);
function GetRecordByBuffer(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
function AcceptRecord: Boolean;
procedure SetSetDeleted(const Value: Boolean);
procedure ReadIndexData(Reader: TReader);
procedure WriteIndexData(Writer: TWriter);
procedure SetIndexList(const Value: TIndexes);
function AcceptRecordInternal: boolean;
procedure SetRecNoInternal(Value: Integer);
procedure BindDBFFieldDef;
procedure InternalSetCurrentIndex(i: Integer);
protected
{ Protected declarations }
procedure Loaded; override;
procedure DoAfterOpen; override;
procedure DoBeforeClose; override;
procedure DataConvert(Field: TField; Source, Dest: Pointer; ToNative: Boolean); override;
function AllocRecordBuffer: PChar; override;
procedure FreeRecordBuffer(var Buffer: PChar); override;
procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;
function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;
function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
function GetRecordSize: Word; override;
procedure InternalAddRecord(Buffer: Pointer; Append: Boolean); override;
procedure InternalClose; override;
procedure DeleteRecallRecord(Del: boolean = true); virtual;
procedure InternalDelete; override;
procedure InternalFirst; override;
procedure InternalGotoBookmark(Bookmark: Pointer); override;
procedure InternalHandleException; override;
procedure InternalInitFieldDefs; override;
procedure InternalInitRecord(Buffer: PChar); override;
procedure InternalLast; override;
procedure InternalOpen; override;
procedure InternalEdit; override;
procedure InternalPost; override;
procedure InternalSetToRecord(Buffer: PChar); override;
procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;
procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override;
procedure SetFieldData(Field: TField; Buffer: Pointer); override;
procedure SetActive(Value: Boolean); override;
procedure InternalRefresh; override;
function FindRecord(Restart, GoForward: Boolean): Boolean; override;
procedure SetRange(FieldList: String; FieldValues: array of const); overload; virtual;
procedure SetRange(FieldList: String; FieldValues: variant); overload; virtual;
procedure ClearRange; virtual;
procedure NextIndexBuf;
procedure PriorIndexBuf;
function NextBuffer: Longint;
function PriorBuffer: Longint;
procedure GetBufferByRec(Rec: Longint);
procedure RefreshBufferByRec(Rec: Longint);
function GetRecordCount: Integer; override;
function GetRecNo: Integer; override;
procedure SetRecNo(Value: Integer); override;
function GetStateFieldValue(State: TDataSetState; Field: TField): Variant; override;
function CompareLocateField(const Fields: TList; const KeyValues: Variant; Options: TLocateOptions): Integer;
procedure SetFiltered(Value: Boolean); override;
function GetDataSource: TDataSource; override;
function GetCurIndByRec(nRec: Longint): Integer;
function LockHeader: boolean;
function UnlockHeader: boolean;
procedure LobHandlerCreate; virtual;
procedure CreateLobStream(dbf_id: Byte); virtual;
procedure OpenLobStream(dbf_id: Byte); virtual;
procedure CloseLobStream; virtual;
procedure LobHandlerDestroy; virtual;
procedure PackLobHandlerCreate; virtual;
procedure PackLobHandlerOpen(TempLobName: String); virtual;
procedure PackLobHandlerClose(LobName, TempLobName: String); virtual;
procedure PackLobHandlerDestroy; virtual;
function GetPackLobHandler: TProxyStream; virtual;
property PackLobHandler: TProxyStream read GetPackLobHandler;
public
{ Public declarations }
FullLengthCharFieldCopy: boolean;
Changed: boolean;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function IsCursorOpen: Boolean; override;
function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override;
function Translate(Src, Dest: PChar; ToOem: Boolean): Integer; override;
function TranslateBuff(Src, Dest: PChar; ToOem: Boolean; Len: Integer): Integer;
function CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Integer; override;
function BookmarkValid(Bookmark: TBookmark): Boolean; override;
function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
procedure CreateNestedStream(NestedDataSet: TVKSmartDBF; Field: TField; NestedStream: TStream); virtual;
procedure SaveToDBT(Source: TMemoryStream; Field: TField); virtual;
procedure SaveOnTheSamePlaceToDBT(Source: TMemoryStream; Field: TField); virtual;
procedure CreateTable;
procedure Reindex;
procedure ReindexWithOutActivated;
procedure ReindexAll;
procedure DefineProperties(Filer: TFiler); override;
property LockRecords: TList read FLockRecords;
property Deleted: Boolean read GetDeleted write SetDeletedFlag;
property Header: DBF_HEAD read DBFHeader;
property Handle: TProxyStream read DBFHandler;
property IndRecBuf: pChar read FIndRecBuf write FIndRecBuf;
property IndState: boolean read FIndState write FIndState;
function FirstByIndex(IndInd: Integer): TGetResult;
function PriorByIndex(IndInd: Integer): TGetResult;
function NextByIndex(IndInd: Integer): TGetResult;
function LastByIndex(IndInd: Integer): TGetResult;
procedure AddRecord(const Values: array of const); overload;
procedure AddRecord(ne: TNotifyEvent); overload;
procedure AddRecord(const Values: variant); overload;
procedure BeginAddRecord;
procedure EndAddRecord;
procedure SetTmpRecord(nRec: DWORD);
procedure CloseTmpRecord;
procedure BeginAddBuffered(RecInBuffer: Integer);
procedure FlushAddBuffer;
procedure EndAddBuffered;
function LocateRecord( const KeyFields: string;
const KeyValues: Variant;
Options: TLocateOptions;
nRec: DWORD = 1;
FullScanOnly: boolean = false): Integer;
function Locate(const KeyFields: string; const KeyValues: Variant;
Options: TLocateOptions): Boolean; override;
function Lookup(const KeyFields: string; const KeyValues: Variant;
const ResultFields: string): Variant; override;
function GetPrec(aField: TField): Integer;
function GetLen(aField: TField): Integer;
function RLock: Boolean; overload;
function RLock(nRec: Integer): Boolean; overload;
function RUnLock: Boolean; overload;
function RUnLock(nRec: Integer): Boolean; overload;
function FLock: Boolean;
function UnLock: Boolean;
procedure SetOrder(nOrd: Integer); overload;
procedure SetOrder(sOrd: ShortString); overload;
procedure SetOrderName(sOrd: ShortString); overload;
function GetOrder: ShortString;
property Last_Rec: Longint read DBFHeader.last_rec;
function SetAutoInc(const FieldName: String; Value: DWORD): boolean; overload;
function SetAutoInc(const FieldNum: Integer; Value: DWORD): boolean; overload;
function GetCurrentAutoInc(const FieldName: String): DWORD; overload;
function GetCurrentAutoInc(const FieldNum: Integer): DWORD; overload;
function GetNextAutoInc(const FieldName: String): DWORD; overload;
function GetNextAutoInc(const FieldNum: Integer): DWORD; overload;
procedure Truncate;
procedure Zap;
procedure DeleteRecord;
procedure RecallRecord;
procedure Pack;
procedure DBEval;
function AcceptTmpRecord(nRec: DWORD): boolean;
procedure SetKey;
procedure EditKey;
function GotoKey: boolean;
procedure GotoNearest;
procedure DropEditKey;
function FindKey(const KeyValues: array of const): Boolean;
procedure FindNearest(const KeyValues: array of const);
property OuterStream: TStream read FOuterStream write FOuterStream;
property InnerStream: TStream read GetInnerStream;
property OuterLobStream: TStream read FOuterLobStream write FOuterLobStream;
property InnerLobStream: TStream read GetInnerLobStream;
property Indexes: TIndexes read FIndexes write SetIndexList stored false;
property IndexName: ShortString read GetOrder write SetOrderName;
property StorageType: TProxyStreamType read FStorageType write FStorageType;
property DBFFieldDefs: TVKDBFFieldDefs read FDBFFieldDefs write SetDBFFieldDefs stored false;
property DBFIndexDefs: TVKDBFIndexDefs read FDBFIndexDefs write SetDBFIndexDefs stored false;
property DBFFileName: String read FDBFFileName write FDBFFileName;
property AccessMode: TAccessMode read FAccessMode write FAccessMode;
property Crypt: TVKDBFCrypt read FVKDBFCrypt write FVKDBFCrypt;
property BufferSize: Integer read FBufferSize write FBufferSize;
property WaitBusyRes: Integer read FWaitBusyRes write FWaitBusyRes;
property DataSource: TDataSource read GetDataSource write SetDataSource;
property CreateNow: Boolean read GetCreateNow write SetCreateNow;
property MasterFields: String read FMasterFields write SetMasterFields;
published
{ Published declarations }
property Active;
property OEM: Boolean read FOEM write FOEM default false;
property SetDeleted: Boolean read FSetDeleted write SetSetDeleted;
property FastPostRecord: Boolean read FFastPostRecord write FFastPostRecord;
property LookupOptions: TLocateOptions read FLookupOptions write FLookupOptions;
property Filter;
property Filtered;
property FilterOptions;
property BeforeOpen;
property AfterOpen;
property BeforeClose;
property AfterClose;
property BeforeInsert;
property AfterInsert;
property BeforeEdit;
property AfterEdit;
property BeforePost;
property AfterPost;
property BeforeCancel;
property AfterCancel;
property BeforeDelete;
property AfterDelete;
property BeforeScroll;
property AfterScroll;
property OnCalcFields;
property OnDeleteError;
property OnEditError;
property OnFilterRecord;
property OnNewRecord;
property OnPostError;
property OnEncrypt: TOnCrypt read GetOnEncrypt write SetOnEncrypt;
property OnDecrypt: TOnCrypt read GetOnDecrypt write SetOnDecrypt;
property OnCryptActivate: TNotifyEvent read GetOnCryptActivate
write SetOnCryptActivate;
property OnCryptDeActivate: TNotifyEvent read GetOnCryptDeActivate
write SetOnCryptDeActivate;
property OnDBEval: TOnDBEval read FOnDBEval write FOnDBEval;
property OnOuterStreamLock: TLockEvent read FOnOuterStreamLock write FOnOuterStreamLock;
property OnOuterStreamUnlock: TUnlockEvent read FOnOuterStreamUnlock write FOnOuterStreamUnlock;
end;
{TVKNestedDBF}
TVKNestedDBF = class(TVKSmartDBF)
private
function GetParentDataSet: TVKSmartDBF;
protected
procedure LobHandlerCreate; override;
procedure CreateLobStream(dbf_id: Byte); override;
procedure OpenLobStream(dbf_id: Byte); override;
procedure CloseLobStream; override;
procedure LobHandlerDestroy; override;
procedure PackLobHandlerCreate; override;
procedure PackLobHandlerOpen(TempLobName: String); override;
procedure PackLobHandlerClose(LobName, TempLobName: String); override;
procedure PackLobHandlerDestroy; override;
function GetPackLobHandler: TProxyStream; override;
procedure SetDataSetField(const Value: TDataSetField); override;
procedure InternalOpen; override;
procedure InternalPost; override;
procedure DeleteRecallRecord(Del: boolean = true); override;
procedure DataEvent(Event: TDataEvent; Info: Longint); override;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
property ParentDataSet: TVKSmartDBF read GetParentDataSet;
published
property DataSetField;
property DBFFieldDefs;
property BufferSize;
end;
{TDBFNTX}
TVKDBFNTX = class(TVKSmartDBF)
private
procedure ReadDBFFieldDefData(Reader: TReader);
procedure WriteDBFFieldDefData(Writer: TWriter);
procedure ReadDBFIndexDefData(Reader: TReader);
procedure WriteDBFIndexDefData(Writer: TWriter);
function GetOrdersByNum(Index: Integer): TVKNTXIndex;
function GetOrdersByName(const Index: String): TVKNTXIndex;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DefineProperties(Filer: TFiler); override;
procedure SetRange(FieldList: String; FieldValues: array of const); overload; override;
procedure SetRange(FieldList: String; FieldValues: variant); overload; override;
procedure ClearRange; override;
property Orders[Index: Integer]: TVKNTXIndex read GetOrdersByNum;
property OrdersByName[const Index: String]: TVKNTXIndex read GetOrdersByName;
published
property StorageType;
property DBFFieldDefs;
property DBFIndexDefs;
property Indexes;
property IndexName;
property DBFFileName;
property AccessMode;
property Crypt;
property BufferSize;
property WaitBusyRes;
property DataSource;
property CreateNow;
property MasterFields;
end;
{TDBFCDX}
TVKDBFCDX = class(TVKSmartDBF)
private
procedure ReadDBFFieldDefData(Reader: TReader);
procedure WriteDBFFieldDefData(Writer: TWriter);
procedure ReadDBFIndexDefData(Reader: TReader);
procedure WriteDBFIndexDefData(Writer: TWriter);
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DefineProperties(Filer: TFiler); override;
published
property StorageType;
property DBFFieldDefs;
property DBFIndexDefs;
property Indexes;
property IndexName;
property DBFFileName;
property AccessMode;
property Crypt;
property BufferSize;
property WaitBusyRes;
property DataSource;
property CreateNow;
property MasterFields;
end;
procedure Wait(t: double; l: boolean = true);
function Space(iSize: Integer): String;
function Zerro(iSize: Integer): String;
function DoEncodeDate(Year, Month, Day: Word; var Date: TDateTime): Boolean;
function IsBlank(Buff: pChar; BufLen: Integer): boolean;
function ExtType2Str(t: TVKDBFType): String;
function Str2ExtType(s: String): TVKDBFType;
procedure Register;
implementation
uses Dialogs, DBcommon, ActiveX;
{$R DBF.RES}
//******************************************************************************
procedure Register;
begin
RegisterComponents('VK DBF', [TVKDBFNTX, {TVKDBFCDX,} TVKNestedDBF]);
end;
//******************************************************************************
procedure Wait(t: double; l: boolean = true);
var
t1: TDateTime;
begin
t1 := Now;
while (Now - t1) < (0.0000115741 * t) do
if l then Application.ProcessMessages;
end;
//******************************************************************************
function Space(iSize: Integer): String;
var
i: Integer;
begin
Result := '';
for i := 1 to iSize do
Result := Result + ' ';
end;
//******************************************************************************
function Zerro(iSize: Integer): String;
var
i: Integer;
begin
Result := '';
for i := 1 to iSize do
Result := Result + #0;
end;
//******************************************************************************
function DoEncodeDate(Year, Month, Day: Word; var Date: TDateTime): Boolean;
var
I: Integer;
DayTable: PDayTable;
begin
Result := False;
DayTable := @MonthDays[IsLeapYear(Year)];
if (Year >= 1) and (Year <= 9999) and (Month >= 1) and (Month <= 12) and
(Day >= 1) and (Day <= DayTable^[Month]) then
begin
for I := 1 to Month - 1 do Inc(Day, DayTable^[I]);
I := Year - 1;
Date := I * 365 + I div 4 - I div 100 + I div 400 + Day - DateDelta;
Result := True;
end;
end;
//******************************************************************************
function IsBlank(Buff: pChar; BufLen: Integer): boolean;
var
i, j: Integer;
begin
Result := true;
j := BufLen - 1;
for i := 0 to j do
begin
if Buff[i] <> #32 then
begin
Result := false;
break;
end;
end;
end;
function ExtType2Str(t: TVKDBFType): String;
begin
case t of
DBFTS1 : Result := 'DBFTS1 ';
DBFTU1 : Result := 'DBFTU1 ';
DBFTS2 : Result := 'DBFTS2 ';
DBFTU2 : Result := 'DBFTU2 ';
DBFTS4 : Result := 'DBFTS4 ';
DBFTU4 : Result := 'DBFTU4 ';
DBFTS8 : Result := 'DBFTS8 ';
DBFTR4 : Result := 'DBFTR4 ';
DBFTR6 : Result := 'DBFTR6 ';
DBFTR8 : Result := 'DBFTR8 ';
DBFTR10 : Result := 'DBFTR10 ';
DBFTD1 : Result := 'DBFTD1 ';
DBFTD2 : Result := 'DBFTD2 ';
DBFTS1_N : Result := 'DBFTS1_N ';
DBFTU1_N : Result := 'DBFTU1_N ';
DBFTS2_N : Result := 'DBFTS2_N ';
DBFTU2_N : Result := 'DBFTU2_N ';
DBFTS4_N : Result := 'DBFTS4_N ';
DBFTU4_N : Result := 'DBFTU4_N ';
DBFTS8_N : Result := 'DBFTS8_N ';
DBFTR4_N : Result := 'DBFTR4_N ';
DBFTR6_N : Result := 'DBFTR6_N ';
DBFTR8_N : Result := 'DBFTR8_N ';
DBFTR10_N : Result := 'DBFTR10_N ';
DBFTD1_N : Result := 'DBFTD1_N ';
DBFTD2_N : Result := 'DBFTD2_N ';
DBFTCLOB : Result := 'DBFTCLOB ';
DBFTBLOB : Result := 'DBFTBLOB ';
DBFTGRAPHIC : Result := 'DBFTGRAPHIC ';
DBFTFMTMEMO : Result := 'DBFTFMTMEMO ';
DBFTSTRING : Result := 'DBFTSTRING ';
DBFTSTRING_N : Result := 'DBFTSTRING_N ';
DBFTFIXEDCHAR : Result := 'DBFTFIXEDCHAR ';
DBFTWIDESTRING : Result := 'DBFTWIDESTRING ';
DBFTCURRENCY : Result := 'DBFTCURRENCY ';
DBFTCURRENCY_N : Result := 'DBFTCURRENCY_N ';
DBFTCURRENCY_NB : Result := 'DBFTCURRENCY_NB ';
DBFTBCD : Result := 'DBFTBCD ';
DBFTDATE : Result := 'DBFTDATE ';
DBFTDATE_N : Result := 'DBFTDATE_N ';
DBFTTIME : Result := 'DBFTTIME ';
DBFTTIME_N : Result := 'DBFTTIME_N ';
DBFTD3 : Result := 'DBFTD3 ';
DBFTD3_N : Result := 'DBFTD3_N ';
DBFTU1_NB : Result := 'DBFTU1_NB ';
DBFTU2_NB : Result := 'DBFTU2_NB ';
DBFTU4_NB : Result := 'DBFTU4_NB ';
DBFTR4_NB : Result := 'DBFTR4_NB ';
DBFTR6_NB : Result := 'DBFTR6_NB ';
DBFTR8_NB : Result := 'DBFTR8_NB ';
DBFTD1_NB : Result := 'DBFTD1_NB ';
DBFTD2_NB : Result := 'DBFTD2_NB ';
DBFTD3_NB : Result := 'DBFTD3_NB ';
DBFTDATE_NB : Result := 'DBFTDATE_NB ';
DBFTTIME_NB : Result := 'DBFTTIME_NB ';
DBFTCLOB_NB : Result := 'DBFTCLOB_NB ';
DBFTBLOB_NB : Result := 'DBFTBLOB_NB ';
DBFTGRAPHIC_NB : Result := 'DBFTGRAPHIC_NB ';
DBFTFMTMEMO_NB : Result := 'DBFTFMTMEMO_NB ';
DBFTDBFDATASET : Result := 'DBFTDBFDATASET ';
DBFTDBFDATASET_NB : Result := 'DBFTDBFDATASET_NB';
else
Result := '';
end;
Result := trim(Result);
end;
function Str2ExtType(s: String): TVKDBFType;
var
q: String;
begin
Result := dbftUndefined;
q := Uppercase(Trim(s));
if q = 'DBFTS1' then Result := DBFTS1;
if q = 'DBFTU1' then Result := DBFTU1;
if q = 'DBFTS2' then Result := DBFTS2;
if q = 'DBFTU2' then Result := DBFTU2;
if q = 'DBFTS4' then Result := DBFTS4;
if q = 'DBFTU4' then Result := DBFTU4;
if q = 'DBFTS8' then Result := DBFTS8;
if q = 'DBFTR4' then Result := DBFTR4;
if q = 'DBFTR6' then Result := DBFTR6;
if q = 'DBFTR8' then Result := DBFTR8;
if q = 'DBFTR10' then Result := DBFTR10;
if q = 'DBFTD1' then Result := DBFTD1;
if q = 'DBFTD2' then Result := DBFTD2;
if q = 'DBFTS1_N' then Result := DBFTS1_N;
if q = 'DBFTU1_N' then Result := DBFTU1_N;
if q = 'DBFTS2_N' then Result := DBFTS2_N;
if q = 'DBFTU2_N' then Result := DBFTU2_N;
if q = 'DBFTS4_N' then Result := DBFTS4_N;
if q = 'DBFTU4_N' then Result := DBFTU4_N;
if q = 'DBFTS8_N' then Result := DBFTS8_N;
if q = 'DBFTR4_N' then Result := DBFTR4_N;
if q = 'DBFTR6_N' then Result := DBFTR6_N;
if q = 'DBFTR8_N' then Result := DBFTR8_N;
if q = 'DBFTR10_N' then Result := DBFTR10_N;
if q = 'DBFTD1_N' then Result := DBFTD1_N;
if q = 'DBFTD2_N' then Result := DBFTD2_N;
if q = 'DBFTCLOB' then Result := DBFTCLOB;
if q = 'DBFTBLOB' then Result := DBFTBLOB;
if q = 'DBFTGRAPHIC' then Result := DBFTGRAPHIC;
if q = 'DBFTFMTMEMO' then Result := DBFTFMTMEMO;
if q = 'DBFTSTRING' then Result := DBFTSTRING;
if q = 'DBFTSTRING_N' then Result := DBFTSTRING_N;
if q = 'DBFTFIXEDCHAR' then Result := DBFTFIXEDCHAR;
if q = 'DBFTWIDESTRING' then Result := DBFTWIDESTRING;
if q = 'DBFTCURRENCY' then Result := DBFTCURRENCY;
if q = 'DBFTCURRENCY_N' then Result := DBFTCURRENCY_N;
if q = 'DBFTCURRENCY_NB' then Result := DBFTCURRENCY_NB;
if q = 'DBFTBCD' then Result := DBFTBCD;
if q = 'DBFTDATE' then Result := DBFTDATE;
if q = 'DBFTDATE_N' then Result := DBFTDATE_N;
if q = 'DBFTTIME' then Result := DBFTTIME;
if q = 'DBFTTIME_N' then Result := DBFTTIME_N;
if q = 'DBFTD3' then Result := DBFTD3;
if q = 'DBFTD3_N' then Result := DBFTD3_N;
if q = 'DBFTU1_NB' then Result := DBFTU1_NB;
if q = 'DBFTU2_NB' then Result := DBFTU2_NB;
if q = 'DBFTU4_NB' then Result := DBFTU4_NB;
if q = 'DBFTR4_NB' then Result := DBFTR4_NB;
if q = 'DBFTR6_NB' then Result := DBFTR6_NB;
if q = 'DBFTR8_NB' then Result := DBFTR8_NB;
if q = 'DBFTD1_NB' then Result := DBFTD1_NB;
if q = 'DBFTD2_NB' then Result := DBFTD2_NB;
if q = 'DBFTD3_NB' then Result := DBFTD3_NB;
if q = 'DBFTDATE_NB' then Result := DBFTDATE_NB;
if q = 'DBFTTIME_NB' then Result := DBFTTIME_NB;
if q = 'DBFTCLOB_NB' then Result := DBFTCLOB_NB;
if q = 'DBFTBLOB_NB' then Result := DBFTBLOB_NB;
if q = 'DBFTGRAPHIC_NB' then Result := DBFTGRAPHIC_NB;
if q = 'DBFTFMTMEMO_NB' then Result := DBFTFMTMEMO_NB;
if q = 'DBFTDBFDATASET' then Result := DBFTDBFDATASET;
if q = 'DBFTDBFDATASET_NB' then Result := DBFTDBFDATASET_NB;
end;
{ TVKSmartDBF }
function TVKSmartDBF.AcceptRecord: Boolean;
begin
Result := true;
if Assigned(OnFilterRecord) then
OnFilterRecord(self, Result);
if Filter <> '' then
Result := Result and FFilterParser.Execute;
if FSetDeleted then
Result := Result and ( not Deleted );
end;
function TVKSmartDBF.AllocRecordBuffer: PChar;
begin
Result := VKDBFMemMgr.oMem.GetMem(self, RecordBufferSize);
end;
function TVKSmartDBF.CompareLocateField(const Fields: TList;
const KeyValues: Variant; Options: TLocateOptions): Integer;
var
FieldCount: Integer;
Field: TField;
KeyVal: Variant;
v1, v2: String;
i1, i2: Integer;
l1, l2, l3: Int64;
w1, w2: Word;
b1, b2: boolean;
f1, f2: double;
i: Integer;
Code: Integer;
kk: Int64;
{$IFDEF VER130}
Vr: Variant;
{$ENDIF}
begin
Result := 1;
FieldCount := Fields.Count;
if FieldCount = 1 then
begin
try
Field := TField(Fields.First);
except
Field := nil;
end;
try
if VarIsArray(KeyValues) then
KeyVal := KeyValues[0]
else
KeyVal := KeyValues;
except
KeyVal := NULL;
end;
case Field.DataType of
ftFixedChar, ftWideString, ftString, ftMemo:
begin
KeyVal := VarAsType(KeyVal, varString);
v1 := Field.AsString;
if not VarIsNull(KeyVal) then v2 := KeyVal else v2 := '';
if loPartialKey in Options then begin
if ( loCaseInsensitive in Options ) then begin
v1 := AnsiUpperCase(v1);
v2 := AnsiUpperCase(v2);
end;
Result := Pos(v2, v1);
if Result <> 1 then
Result := AnsiCompareStr(v1, v2)
else
Result := 0;
end else
if loCaseInsensitive in Options then
Result := AnsiCompareText(v1, v2)
else
Result := AnsiCompareStr(v1, v2);
end;
ftSmallint, ftInteger:
begin
KeyVal := VarAsType(KeyVal, varInteger);
i1 := Field.AsInteger;
if not VarIsNull(KeyVal) then i2 := KeyVal else i2 := 0;
Result := i1 - i2;
end;
ftLargeint:
begin
//
{$IFDEF VER130}
if TVarData(KeyVal).VType <> VT_DECIMAL then begin
{$ENDIF}
{$IFDEF VER140}
if (VarType(KeyVal) <> varInt64) then begin
{$ENDIF}
Val(KeyVal, kk, code);
if code <> 0 then
KeyVal := Null
else begin
{$IFDEF VER130}
TVarData(Vr).VType := VT_DECIMAL;
Decimal(Vr).lo64 := kk;
KeyVal := Vr;
{$ENDIF}
{$IFDEF VER140}
KeyVal := kk;
{$ENDIF}
end;
end;
//
l1 := TLargeintField(Field).AsLargeInt;
if not VarIsNull(KeyVal) then
{$IFDEF VER130}
l2 := Decimal(KeyVal).lo64
{$ENDIF}
{$IFDEF VER140}
l2 := KeyVal
{$ENDIF}
else
l2 := 0;
l3 := l1 - l2;
if l3 < 0 then
Result := -1
else if l3 = 0 then
Result := 0
else if l3 > 0 then
Result := 1;
end;
ftWord:
begin
KeyVal := VarAsType(KeyVal, varInteger);
w1 := Field.AsInteger;
if not VarIsNull(KeyVal) then w2 := KeyVal else w2 := 0;
Result := w1 - w2;
end;
ftBoolean:
begin
KeyVal := VarAsType(KeyVal, varBoolean);
b1 := Field.AsBoolean;
if not VarIsNull(KeyVal) then b2 := KeyVal else b2 := false;
if (not b1) and b2 then
Result := -1;
if b1 = b2 then
Result := 0;
if b1 and (not b2) then
Result := 1;
end;
ftFloat, ftCurrency, ftBCD:
begin
Result := VarAsType(Result, varDouble);
f1 := Field.AsFloat;
if not VarIsNull(KeyVal) then f2 := KeyVal else f2 := 0;
if f1 < f2 then
Result := -1;
if f1 = f2 then
Result := 0;
if f1 > f2 then
Result := 1;
end;
ftDate, ftTime, ftDateTime:
begin
Result := VarAsType(Result, varDate);
f1 := Field.AsDateTime;
if not VarIsNull(KeyVal) then f2 := KeyVal else f2 := 0;
if f1 < f2 then
Result := -1;
if f1 = f2 then
Result := 0;
if f1 > f2 then
Result := 1;
end;
end;
end else begin
for i := 0 to FieldCount - 1 do
begin
//
try
Field := TField(Fields.Items[i]);
except
Field := nil;
end;
try
if VarIsArray(KeyValues) then
KeyVal := KeyValues[i]
else
KeyVal := NULL;
except
KeyVal := NULL;
end;
case Field.DataType of
ftFixedChar, ftWideString, ftString:
begin
KeyVal := VarAsType(KeyVal, varString);
v1 := Field.AsString;
if not VarIsNull(KeyVal) then v2 := KeyVal else v2 := '';
if loPartialKey in Options then begin
if ( loCaseInsensitive in Options ) then begin
v1 := AnsiUpperCase(v1);
v2 := AnsiUpperCase(v2);
end;
Result := Pos(v2, v1);
if Result <> 1 then
Result := AnsiCompareStr(v1, v2)
else
Result := 0;
end else
if loCaseInsensitive in Options then
Result := AnsiCompareText(v1, v2)
else
Result := AnsiCompareStr(v1, v2);
end;
ftSmallint, ftInteger:
begin
KeyVal := VarAsType(KeyVal, varInteger);
i1 := Field.AsInteger;
if not VarIsNull(KeyVal) then i2 := KeyVal else i2 := 0;
Result := i1 - i2;
end;
ftLargeint:
begin
//
{$IFDEF VER130}
if TVarData(KeyVal).VType <> VT_DECIMAL then begin
{$ENDIF}
{$IFDEF VER140}
if (VarType(KeyVal) <> varInt64) then begin
{$ENDIF}
Val(KeyVal, kk, code);
if code <> 0 then
KeyVal := Null
else begin
{$IFDEF VER130}
TVarData(Vr).VType := VT_DECIMAL;
Decimal(Vr).lo64 := kk;
KeyVal := Vr;
{$ENDIF}
{$IFDEF VER140}
KeyVal := kk;
{$ENDIF}
end;
end;
//
l1 := TLargeintField(Field).AsLargeInt;
if not VarIsNull(KeyVal) then
{$IFDEF VER130}
l2 := Decimal(KeyVal).lo64
{$ENDIF}
{$IFDEF VER140}
l2 := KeyVal
{$ENDIF}
else
l2 := 0;
l3 := l1 - l2;
if l3 < 0 then
Result := -1
else if l3 = 0 then
Result := 0
else if l3 > 0 then
Result := 1;
end;
ftWord:
begin
KeyVal := VarAsType(KeyVal, varInteger);
w1 := Field.AsInteger;
if not VarIsNull(KeyVal) then w2 := KeyVal else w2 := 0;
Result := w1 - w2;
end;
ftBoolean:
begin
KeyVal := VarAsType(KeyVal, varBoolean);
b1 := Field.AsBoolean;
if not VarIsNull(KeyVal) then b2 := KeyVal else b2 := false;
if (not b1) and b2 then
Result := -1;
if b1 = b2 then
Result := 0;
if b1 and (not b2) then
Result := 1;
end;
ftFloat, ftCurrency, ftBCD:
begin
KeyVal := VarAsType(KeyVal, varDouble);
f1 := Field.AsFloat;
if not VarIsNull(KeyVal) then f2 := KeyVal else f2 := 0;
if f1 < f2 then
Result := -1;
if f1 = f2 then
Result := 0;
if f1 > f2 then
Result := 1;
end;
ftDate, ftTime, ftDateTime:
begin
KeyVal := VarAsType(KeyVal, varDate);
f1 := Field.AsDateTime;
if not VarIsNull(KeyVal) then f2 := KeyVal else f2 := 0;
if f1 < f2 then
Result := -1;
if f1 = f2 then
Result := 0;
if f1 > f2 then
Result := 1;
end;
end;
//
if Result <> 0 then
Exit;
end;
end;
end;
constructor TVKSmartDBF.Create(AOwner: TComponent);
var
FieldMap: TFieldMap;
begin
inherited Create(AOwner);
DBFHandler := TProxyStream.Create;
LobHandlerCreate;
FStorageType := pstFile;
FFilterParser := TVKDBFExprParser.Create(self, '', [], [poExtSyntax], '', nil, FieldMap);
FAccessMode := TAccessMode.Create;
FVKDBFCrypt := TVKDBFCrypt.Create;
FVKDBFCrypt.SmartDBF := self;
FLockRecords := TList.Create;
FDBFFieldDefs := TVKDBFFieldDefs.Create(self);
FOEM := false;
FDBFFileName := '';
FTmpActive := false;
FKeyCalk := false;
FBufferSize := 4096;
FRecordsPerBuf := 0;
FBuffer := nil;
FBufInd := nil;
FBufCnt := 0;
FCurInd := -1;
FBufDir := bdFromTop;;
FBOF := false;
FEOF := false;
FWaitBusyRes := 3000; //3 sec. waiting for a locking resource
FDataLink := TVKDataLink.Create;
FDataLink.DBFDataSet := self;
FFileLock := false;
FIndRecBuf := nil;
FIndState := false;
FMasterFields := '';
FRange := false;
ListMasterFields := TList.Create;
FFastPostRecord := false;
FAddBuffered := false;
FAddBuffer := nil;
FAddBufferCrypt := nil;
FAddBufferCount := -1;
FAddBufferCurrent := -1;
FLookupOptions := [];
FPackProcess := false;
FPackLobHandler := nil;
FullLengthCharFieldCopy := false;
FOnOuterStreamLock := nil;
FOnOuterStreamUnlock := nil;
ObjectView := true;
Changed := False;
NestedDataSetClass := TVKNestedDBF;
FSaveOnTheSamePlace := False;
FOpenWithoutIndexes := False;
end;
procedure TVKSmartDBF.CreateTable;
var
cHeader: DBF_HEAD;
i, j: Integer;
Year, Month, Day: Word;
qq: byte;
oBag: TVKDBFIndexBag;
oOrd: TVKDBFOrder;
OldActiveIndexObject: TIndex;
procedure WriteFieldDef(DBFFDs: TVKDBFFieldDefs; LastWrite: boolean = false);
var
i: Integer;
cField: FIELD_REC;
begin
if DBFFDs.Count = 0 then
raise Exception.Create('TVKSmartDBF.CreateTable: You should define one field at least to create table!');
for i := 0 to DBFFDs.Count - 1 do
begin
cHeader.rec_size := cHeader.rec_size + DBFFDs[i].DataSize;
cField := DBFFDs[i].Field;
cField.NextAutoInc := 0;
if ( cField.field_type = 'M' ) or
( ( cField.field_type = 'E' ) and ( cField.extend_type in
[dbftClob, dbftBlob, dbftGraphic, dbftFmtMemo,
dbftClob_NB, dbftBlob_NB, dbftGraphic_NB, dbftFmtMemo_NB,
dbftDBFDataSet, dbftDBFDataSet_NB] ) ) then
cHeader.dbf_id := $83;
DBFHandler.Write(cField, SizeOf(FIELD_REC));
Inc(cHeader.data_offset, SizeOf(FIELD_REC));
if ( cField.field_type = 'E' ) and
( cField.extend_type in [dbftDBFDataSet, dbftDBFDataSet_NB]) then begin
// Recursive call
WriteFieldDef(DBFFDs[i].DBFFieldDefs);
end;
end;
cField.field_name[0] := #$D;
if LastWrite then
DBFHandler.Write(cField, 1)
else begin
DBFHandler.Write(cField, SizeOf(FIELD_REC));
Inc(cHeader.data_offset, SizeOf(FIELD_REC));
end;
end;
begin
if not Active then
begin
DBFHandler.FileName := DBFFileName;
DBFHandler.AccessMode.AccessMode := AccessMode.AccessMode;
DBFHandler.ProxyStreamType := FStorageType;
DBFHandler.OuterStream := FOuterStream;
DBFHandler.CreateProxyStream;
if DBFHandler.IsOpen then
begin
DecodeDate(Now, Year, Month, Day);
with cHeader do
begin
dbf_id := $03;
last_update[0] := Byte(Year);
last_update[1] := Byte(Month);
last_update[2] := Byte(Day);
last_rec := 0;
data_offset := 1;
rec_size := 1;
Dummy1 := 0;
IncTrans := 0;
Encrypt := 0;
Dummy2 := 0;
for i := 20 to 27 do
Dummy3[i] := 0;
prod_ind := 0;
lang := 0;
Dummy4 := 0;
end;
DBFHandler.Seek(0, 0);
DBFHandler.Write(cHeader, SizeOf(DBF_HEAD));
cHeader.data_offset := cHeader.data_offset + SizeOf(DBF_HEAD);
WriteFieldDef(FDBFFieldDefs, true);
cHeader.data_offset := cHeader.data_offset + 1;
qq := $1A;
DBFHandler.Write(qq, 1);
DBFHandler.SetEndOfFile;
DBFHandler.Seek(0, 0);
DBFHandler.Write(cHeader, SizeOf(DBF_HEAD));
DBFHandler.Close;
CreateLobStream(cHeader.dbf_id);
end else raise Exception.Create('TVKSmartDBF.CreateTable: Create error');
if Indexes <> nil then begin
OldActiveIndexObject := Indexes.ActiveObject;
Indexes.ActiveObject := nil;
FOpenWithoutIndexes := True;
try
Active := True;
for i := 0 to DBFIndexDefs.Count - 1 do begin
oBag := TVKDBFIndexBag(DBFIndexDefs[i]);
oBag.CreateBag;
for j := 0 to oBag.Orders.Count - 1 do begin
oOrd := TVKDBFOrder(oBag.Orders[j]);
oOrd.CreateOrder;
end;
oBag.Close;
end;
Active := False;
finally
FOpenWithoutIndexes := False;
if Indexes <> nil then
Indexes.ActiveObject := OldActiveIndexObject;
end;
end;
end else raise Exception.Create('TVKSmartDBF.CreateTable: Can not create table while dataset is open');
end;
destructor TVKSmartDBF.Destroy;
begin
try
FLockRecords.Destroy;
FAccessMode.Destroy;
FVKDBFCrypt.Destroy;
FFilterParser.Destroy;
FDataLink.Destroy;
FDBFFieldDefs.Destroy;
ListMasterFields.Free;
LobHandlerDestroy;
DBFHandler.Destroy;
inherited Destroy;
except
if DBFHandler.IsOpen then DBFHandler.Close;
if LobHandler.IsOpen then LobHandler.Close;
end;
end;
function TVKSmartDBF.FindRecord(Restart, GoForward: Boolean): Boolean;
var
SaveState: TDataSetState;
Accept: Boolean;
Ret: TGetResult;
begin
if (not Filtered) and (Filter <> '') then
FFilterParser.SetExprParams(Filter, FilterOptions, [poExtSyntax], '');
CheckBrowseMode;
DoBeforeScroll;
SetFound(False);
UpdateCursorPos;
CursorPosChanged;
if GoForward then
begin
if Restart then InternalFirst;
repeat
Ret := GetRecordByBuffer(FFilterRecord, gmNext, false);
SaveState := SetTempState(dsFilter);
Accept := AcceptRecordInternal;
RestoreState(SaveState);
until Accept or (Ret <> grOK);
end else
begin
if Restart then InternalLast;
repeat
Ret := GetRecordByBuffer(FFilterRecord, gmPrior, false);
SaveState := SetTempState(dsFilter);
Accept := AcceptRecordInternal;
RestoreState(SaveState);
until Accept or (Ret <> grOK);
end;
if Ret = grOK then
begin
Resync([rmExact, rmCenter]);
SetFound(True);
end else
InternalSetToRecord(ActiveBuffer);
Result := Found;
if Result then DoAfterScroll;
end;
procedure TVKSmartDBF.FreeRecordBuffer(var Buffer: PChar);
begin
VKDBFMemMgr.oMem.FreeMem(Buffer)
end;
function TVKSmartDBF.GetActiveRecBuf(var pRecBuf: PChar): Boolean;
begin
if FIndState then begin
pRecBuf := FIndRecBuf;
end else begin
if FKeyCalk then begin
pRecBuf := RecBuf
end else begin
if FTmpActive then
pRecBuf := FTempRecord
else begin
case State of
dsBrowse: if IsEmpty then pRecBuf := nil else pRecBuf := ActiveBuffer;
dsEdit, dsInsert: pRecBuf := ActiveBuffer;
dsFilter: pRecBuf := FFilterRecord;
dsNewValue, dsOldValue, dsCurValue: pRecBuf := ActiveBuffer;
dsCalcFields: pRecBuf := CalcBuffer;
dsSetKey: pRecBuf := FSetKeyBuffer;
else
pRecBuf := nil;
end;
end;
end;
end;
Result := pRecBuf <> nil;
end;
procedure TVKSmartDBF.GetBookmarkData(Buffer: PChar; Data: Pointer);
begin
Longword(Data^) := pTRecInfo(Buffer + FRecordSize).RecordRowID;
end;
function TVKSmartDBF.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
begin
Result := pTRecInfo(Buffer + FRecordSize).BookmarkFlag;
end;
function TVKSmartDBF.GetDeleted: Boolean;
var
ActBuff: pChar;
begin
Result := false;
GetActiveRecBuf(ActBuff);
if ActBuff <> nil then
//begin
// if ActBuff[0] = #42 then //'*'
// Result := true;
// if not ( ActBuff[0] in [#32, #42] ) then //' '
// Result := false;
Result := (ActBuff[0] = #42); //'*'
//end;
end;
procedure TVKSmartDBF.SetDeletedFlag(const Value: Boolean);
var
ActBuff: pChar;
c: Boolean;
begin
GetActiveRecBuf(ActBuff);
if ActBuff <> nil then
begin
c := ( ActBuff[0] = #42 );
if Value <> c then begin
if not (State in [dsEdit, dsInsert]) then Edit;
if Value then
ActBuff[0] := #42 //'*'
else
ActBuff[0] := #32; //' '
SetModified(True);
end;
end;
end;
function TVKSmartDBF.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
var
iCode, dInt: Integer;
dInt64: Int64;
dFloat: Double;
ww: Extended;
dBool: WordBool;
dDate: TDateTime;
sTS: TTimeStamp;
dd: double;
Year, Month, Day: Word;
ss: pChar;
ss1: array [0..255] of char;
ActiveBuf: pChar;
qq: TVKDBFFieldDef;
oDS: TDataSet;
LookupResult: Variant;
LastSetp: Char;
SLen: WORD;
WLen: Integer;
begin
Result := false;
case Field.FieldKind of
fkData:
begin
qq := TVKDBFFieldDef(Pointer(Field.Tag));
GetActiveRecBuf(ActiveBuf);
if ActiveBuf <> nil then
begin
ss := ActiveBuf + qq.FOff;
if Buffer <> nil then
begin
case Field.DataType of
ftTime:
begin
case qq.extend_type of
dbftTime:
begin
Integer(Buffer^) := pInteger(ss)^;
Result := true;
end;
dbftTime_N:
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
Integer(Buffer^) := pInteger(ss + 1)^;
end;
dbftTime_NB:
begin
Result := ( ( pLongword(ss)^ and $80000000 ) = $80000000 );
if Result then
Longword(Buffer^) := ( pLongword(ss)^ and $7FFFFFFF );
end;
end;
end;
ftDate:
begin
if qq.field_type <> 'E' then begin
Result := not IsBlank(ss, qq.FLen);
if Result then begin
Year := (Byte(ss[0]) - $30) * 1000 + (Byte(ss[1]) - $30) * 100 + (Byte(ss[2]) - $30) * 10 + (Byte(ss[3]) - $30);
Month := (Byte(ss[4]) - $30) * 10 + (Byte(ss[5]) - $30);
Day := (Byte(ss[6]) - $30) * 10 + (Byte(ss[7]) - $30);
if DoEncodeDate(Year, Month, Day, dDate) then
begin
sTS := DateTimeToTimeStamp(dDate);
//dd := 3600.0*24*1000*sTS.Date + sTS.Time;
//double(Buffer^) := dd;
Integer(Buffer^) := sTS.Date;
end else
Result := false;
end;
end else begin
case qq.extend_type of
dbftDate:
begin
Integer(Buffer^) := pInteger(ss)^;
Result := true;
end;
dbftDate_NB:
begin
Result := ( ( pLongword(ss)^ and $80000000 ) = $80000000 );
if Result then
Longword(Buffer^) := ( pLongword(ss)^ and $7FFFFFFF );
end;
dbftDate_N:
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
Integer(Buffer^) := pInteger(ss + 1)^;
end;
end;
end;
end;
ftBCD:
begin
Result := (( Byte(ss[1]) and $40 ) <> $00);
if Result then begin
Tbcd(Buffer^) := Pbcd(ss)^;
Tbcd(Buffer^).SignSpecialPlaces := (Tbcd(Buffer^).SignSpecialPlaces or $40);
end;
end;
ftCurrency:
begin
case qq.extend_type of
dbftCurrency:
begin
Currency(Buffer^) := pCurrency(ss)^;
Result := true;
end;
dbftCurrency_N:
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
Currency(Buffer^) := pCurrency(ss + 1)^;
end;
dbftCurrency_NB:
begin
Result := ( ( pByte(ss + 7)^ and $80 ) = $80 );
if Result then begin
pByte(ss + 7)^ := ( pByte(ss + 7)^ and $7F );
Currency(Buffer^) := Currency( Pointer(ss)^ );
pByte(ss + 7)^ := ( pByte(ss + 7)^ or $80 );
end;
end;
end;
end;
ftWideString:
begin
Result := not IsBlank(ss, qq.FLen);
if Result then begin
WLen := pInteger(ss)^;
Move(ss^, Buffer^, WLen + 6);
end;
end;
ftString:
begin
if qq.field_type <> 'E' then begin
//Result := not IsBlank(ss, qq.FLen);
//if Result then begin
Move(ss^, Buffer^, qq.FLen);
pChar(Buffer)[qq.FLen] := #0;
//end;
Result := true;
end else
case qq.extend_type of
dbftString: //
begin
SLen := pWORD(ss)^;
if SLen < 8224 then begin
ss := ss + SizeOf(WORD);
Move(ss^, Buffer^, SLen);
pChar(Buffer)[SLen] := #0;
Result := true;
end else
Result := false;
end;
dbftString_N: //
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then begin
ss := ss + 1;
SLen := pWORD(ss)^;
ss := ss + SizeOf(WORD);
Move(ss^, Buffer^, SLen);
pChar(Buffer)[SLen] := #0;
end;
end;
dbftFixedChar:
begin
Result := not IsBlank(ss, qq.FLen + 1);
if Result then
Move(ss^, Buffer^, qq.FLen + 1);
end;
else
Result := false;
end;
end;
ftSmallint:
begin
case qq.extend_type of
dbftS1: //Shortint
begin
Smallint(Buffer^) := pShortint(ss)^;
Result := true;
end;
dbftS2: //Smallint
begin
Smallint(Buffer^) := pSmallint(ss)^;
Result := true;
end;
dbftS1_N: //Shortint with NULL
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
Smallint(Buffer^) := pShortint(ss + 1)^;
end;
dbftS2_N: //Smallint with NULL
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
Smallint(Buffer^) := pSmallint(ss + 1)^;
end;
else
Result := false;
end;
end;
ftWord:
begin
case qq.extend_type of
dbftU1: //Byte
begin
Word(Buffer^) := pByte(ss)^;
Result := true;
end;
dbftU2: //Word
begin
Word(Buffer^) := pWord(ss)^;
Result := true;
end;
dbftU1_N: //Byte with NULL
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
Word(Buffer^) := pByte(ss + 1)^;
end;
dbftU2_N: //Word with NULL
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
Word(Buffer^) := pWord(ss + 1)^;
end;
dbftU1_NB: //Positive byte with NULL bit instead of sign bit
begin
Result := ( ( Byte(ss[0]) and $80 ) = $80 );
if Result then
Word(Buffer^) := ( Byte(ss[0]) and $7F );
end;
dbftU2_NB: //Positive word with NULL bit instead of sign bit
begin
Result := ( ( pWord(ss)^ and $8000 ) = $8000 );
if Result then
Word(Buffer^) := ( pWord(ss)^ and $7FFF );
end;
else
Result := false;
end;
end;
ftInteger:
begin
if qq.field_type <> 'E' then begin
Move(ss^, ss1, qq.FLen);
ss1[qq.FLen] := #0;
Val(ss1, dInt, iCode);
if iCode = 0 then
begin
Integer(Buffer^) := dInt;
Result := true;
end else
Result := false;
end else begin
case qq.extend_type of
dbftS4, dbftU4: //Longint, Longword
begin
Integer(Buffer^) := pInteger(ss)^;
Result := true;
end;
dbftS4_N, dbftU4_N: //Longint with NULL, Longword with NULL
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
Integer(Buffer^) := pInteger(ss + 1)^;
end;
dbftU4_NB:
begin
Result := ( ( pLongword(ss)^ and $80000000 ) = $80000000 );
if Result then
Longword(Buffer^) := ( pLongword(ss)^ and $7FFFFFFF );
end;
else
Result := false;
end;
end;
end;
ftLargeint:
begin
if qq.field_type <> 'E' then begin
Move(ss^, ss1, qq.FLen);
ss1[qq.FLen] := #0;
Val(ss1, dInt64, iCode);
if iCode = 0 then
begin
Int64(Buffer^) := dInt64;
Result := true;
end else
Result := false;
end else begin
case qq.extend_type of
dbftS8: //Int64
begin
Int64(Buffer^) := pInt64(ss)^;
Result := true;
end;
dbftS8_N: //Int64 with NULL
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
Int64(Buffer^) := pInt64(ss + 1)^;
end;
else
Result := false;
end;
end;
end;
ftFloat:
begin
if qq.field_type <> 'E' then begin
Result := not IsBlank(ss, qq.FLen);
if Result then begin
Move(ss^, ss1, qq.FLen);
ss1[qq.FLen] := #0;
LastSetp := DecimalSeparator;
DecimalSeparator := '.';
if TextToFloat(ss1, ww, fvExtended) then
begin
dFloat := ww;
double(Buffer^) := dFloat;
end else
Result := false;
DecimalSeparator := LastSetp;
end;
end else begin
case qq.extend_type of
dbftR4:
begin
double(Buffer^) := pSingle(ss)^;
Result := true;
end;
dbftR6:
begin
double(Buffer^) := pReal48(ss)^;
Result := true;
end;
dbftR8:
begin
double(Buffer^) := pDouble(ss)^;
Result := true;
end;
dbftR10:
begin
Extended(Buffer^) := pExtended(ss)^;
Result := true;
end;
dbftR4_N:
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
double(Buffer^) := pSingle(ss + 1)^;
end;
dbftR4_NB:
begin
Result := ( ( pByte(ss + 3)^ and $80 ) = $80 );
if Result then begin
pByte(ss + 3)^ := ( pByte(ss + 3)^ and $7F );
double(Buffer^) := Single( Pointer(ss)^ );
pByte(ss + 3)^ := ( pByte(ss + 3)^ or $80 );
end;
end;
dbftR6_NB:
begin
Result := ( ( pByte(ss + 5)^ and $80 ) = $80 );
if Result then begin
pByte(ss + 5)^ := ( pByte(ss + 5)^ and $7F );
double(Buffer^) := Real48( Pointer(ss)^ );
pByte(ss + 5)^ := ( pByte(ss + 5)^ or $80 );
end;
end;
dbftR8_NB:
begin
Result := ( ( pByte(ss + 7)^ and $80 ) = $80 );
if Result then begin
pByte(ss + 7)^ := ( pByte(ss + 7)^ and $7F );
double(Buffer^) := double( Pointer(ss)^ );
pByte(ss + 7)^ := ( pByte(ss + 7)^ or $80 );
end;
end;
dbftR6_N:
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
double(Buffer^) := pReal48(ss + 1)^;
end;
dbftR8_N:
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
double(Buffer^) := pDouble(ss + 1)^;
end;
dbftR10_N:
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
Extended(Buffer^) := pExtended(ss + 1)^;
end;
else
Result := false;
end;
end;
end;
ftMemo, ftBlob, ftFmtMemo, ftGraphic:
begin
if ( qq.field_type = 'M' ) or
( ( qq.field_type = 'E' ) and
( qq.extend_type in [ dbftClob, dbftFmtMemo,
dbftBlob, dbftGraphic] )) then begin
Result := not IsBlank(ss, 10);
if Result then
Move(ss^, Buffer^, 10);
end else begin
Result := ( ( pLongword(ss)^ and $80000000 ) = $80000000 );
if Result then
Integer(Buffer^) := Integer(Pointer(ss)^);
end;
end;
ftDateTime:
begin
case qq.extend_type of
dbftD1:
begin
sTS := DateTimeToTimeStamp(pDouble(ss)^);
dd := 3600.0*24*1000*sTS.Date + sTS.Time;
double(Buffer^) := dd;
Result := true;
end;
dbftD1_NB:
begin
Result := ( ( pByte(ss + 7)^ and $80 ) = $80 );
if Result then begin
pByte(ss + 7)^ := ( pByte(ss + 7)^ and $7F );
sTS := DateTimeToTimeStamp(pDouble(ss)^);
pByte(ss + 7)^ := ( pByte(ss + 7)^ or $80 );
dd := 3600.0*24*1000*sTS.Date + sTS.Time;
double(Buffer^) := dd;
end;
end;
dbftD2:
begin
double(Buffer^) := pDouble(ss)^;
Result := true;
end;
dbftD2_NB:
begin
Result := ( ( pByte(ss + 7)^ and $80 ) = $80 );
if Result then begin
pByte(ss + 7)^ := ( pByte(ss + 7)^ and $7F );
double(Buffer^) := pDouble(ss)^;
pByte(ss + 7)^ := ( pByte(ss + 7)^ or $80 );
end;
end;
dbftD3:
begin
sTS := DateTimeToTimeStamp(pReal48(ss)^);
dd := 3600.0*24*1000*sTS.Date + sTS.Time;
double(Buffer^) := dd;
Result := true;
end;
dbftD3_NB:
begin
Result := ( ( pByte(ss + 5)^ and $80 ) = $80 );
if Result then begin
pByte(ss + 5)^ := ( pByte(ss + 5)^ and $7F );
double(Buffer^) := pReal48(ss)^;
pByte(ss + 5)^ := ( pByte(ss + 5)^ or $80 );
end;
end;
dbftD1_N:
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then begin
sTS := DateTimeToTimeStamp(pDouble(ss + 1)^);
dd := 3600.0*24*1000*sTS.Date + sTS.Time;
double(Buffer^) := dd;
end;
end;
dbftD2_N:
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then
double(Buffer^) := pDouble(ss + 1)^;
end;
dbftD3_N:
begin
Result := (ss[0] <> ' '); //if ' ' then NULL
if Result then begin
sTS := DateTimeToTimeStamp(pReal48(ss + 1)^);
dd := 3600.0*24*1000*sTS.Date + sTS.Time;
double(Buffer^) := dd;
end;
end;
end;
end;
ftBoolean:
begin
case ss[0] of
'T':
begin
dBool := true;
Result := true;
end;
'F':
begin
dBool := false;
Result := true;
end;
' ':
begin
dBool := false;
Result := false;
end;
else
dBool := false;
Result := false;
end;
WordBool(Buffer^) := dBool;
end;
ftDataSet:
begin
case qq.extend_type of
dbftDBFDataSet:
begin
Result := not IsBlank(ss, qq.FLen);
if Result then
Move(ss^, Buffer^, qq.FLen);
end;
dbftDBFDataSet_NB:
begin
Result := ( ( pLongword(ss)^ and $80000000 ) = $80000000 );
if Result then
Integer(Buffer^) := Integer(Pointer(ss)^);
end;
end;
end;
end;
end else begin
if qq.field_type <> 'E' then begin
if qq.field_type <> 'C' then
Result := not IsBlank(ss, qq.FLen)
else
Result := true;
end else begin
case qq.extend_type of
dbftS1_N, //Shortint with NULL
dbftU1_N, //Byte with NULL
dbftS2_N, //Smallint with NULL
dbftU2_N, //Word with NULL
dbftS4_N, //Longint with NULL
dbftU4_N, //Longword with NULL
dbftS8_N, //Int64 with NULL
dbftR4_N, //Single with NULL
dbftR6_N, //Real48 with NULL
dbftR8_N, //Double with NULL
dbftR10_N, //Extended with NULL
dbftD1_N,
dbftD2_N,
dbftD3_N,
dbftString_N, //String with NULL
dbftCurrency_N, //Currency with NULL
dbftDate_N,
dbftTime_N: Result := not (ss[0] = ' '); //if ' ' then NULL
dbftU1_NB: Result := not ( ( Byte(ss[0]) and $80 ) = $80 );
dbftU2_NB: Result := ( ( pWord(ss)^ and $8000 ) = $8000 );
dbftU4_NB: Result := ( ( pLongword(ss)^ and $80000000 ) = $80000000 );
dbftR4_NB: Result := ( ( pByte(ss + 3)^ and $80 ) = $80 );
dbftR6_NB: Result := ( ( pByte(ss + 5)^ and $80 ) = $80 );
dbftR8_NB: Result := ( ( pByte(ss + 7)^ and $80 ) = $80 );
dbftCurrency_NB: Result := ( ( pByte(ss + 7)^ and $80 ) = $80 );
dbftD1_NB: Result := ( ( pByte(ss + 7)^ and $80 ) = $80 );
dbftD2_NB: Result := ( ( pByte(ss + 7)^ and $80 ) = $80 );
dbftD3_NB: Result := ( ( pByte(ss + 5)^ and $80 ) = $80 );
dbftDate_NB: Result := ( ( pLongword(ss)^ and $80000000 ) = $80000000 );
dbftTime_NB: Result := ( ( pLongword(ss)^ and $80000000 ) = $80000000 );
dbftClob, dbftFmtMemo, dbftBlob, dbftGraphic, dbftDBFDataSet:
Result := not IsBlank(ss, qq.FLen);
dbftClob_NB, dbftFmtMemo_NB, dbftBlob_NB, dbftGraphic_NB, dbftDBFDataSet_NB:
Result := ( ( pLongword(ss)^ and $80000000 ) = $80000000 );
dbftString: Result := not ( pWORD(ss)^ = 8224 );
dbftFixedChar: Result := not IsBlank(ss, qq.FLen + 1);
dbftS1,
dbftU1,
dbftS2,
dbftU2,
dbftS4,
dbftU4,
dbftS8,
dbftR4,
dbftR6,
dbftR8,
dbftR10,
dbftD1,
dbftD2,
dbftD3,
dbftCurrency,
dbftDate,
dbftTime: Result := true;
dbftBCD: Result := not ( ( Byte(ss[1]) and $40 ) = $00 );
else
Result := false;
end;
end;
end;
end else
Result := false;
end;
fkCalculated:
begin
GetActiveRecBuf(ActiveBuf);
if (ActiveBuf <> nil) then begin
ss := ActiveBuf + FRecordSize + sizeof(TRecInfo) + Field.Offset;
if Buffer <> nil then
begin
if not (csDesigning in ComponentState) then
begin
Move(ss^, Buffer^, Field.DataSize);
if Field.DataType in [ftString, ftBytes, ftVarBytes] then pChar(Buffer)[Field.DataSize] := Char(0);
Result := true;
end else begin
FillChar(Buffer^, Field.DataSize, ' ');
Result := false;
end;
end else
Result := not IsBlank(ss, Field.DataSize);
end;
end;
fkLookup:
begin
Result := false;
if GetActiveRecBuf(ActiveBuf) then
begin
oDS := Field.LookupDataSet;
if Buffer <> nil then
begin
if (oDS <> nil) and oDS.Active then
begin
LookupResult := oDS.Lookup(Field.LookupKeyFields, FieldValues[Field.KeyFields], Field.LookupResultField);
if (not VarIsEmpty(LookupResult)) and (not VarIsNull(LookupResult)) then
begin
case Field.DataType of
ftString:
begin
ss := TVarData(LookupResult).VPointer;
Move(ss^, Buffer^, Length(ss) + 1);
end;
ftSmallint: Smallint(Buffer^) := TVarData(LookupResult).VSmallint;
ftInteger: Integer(Buffer^) := TVarData(LookupResult).VInteger;
ftWord: Word(Buffer^) := TVarData(LookupResult).VSmallint;
ftBoolean: WordBool(Buffer^) := TVarData(LookupResult).VBoolean;
ftFloat: double(Buffer^) := TVarData(LookupResult).VDouble;
ftCurrency: Currency(Buffer^) := TVarData(LookupResult).VCurrency;
ftDateTime: double(Buffer^) := TVarData(LookupResult).VDate;
ftTime:
begin
sTS := DateTimeToTimeStamp(TVarData(LookupResult).VDate);
Integer(Buffer^) := sTS.Time;
end;
ftDate:
begin
sTS := DateTimeToTimeStamp(TVarData(LookupResult).VDate);
Integer(Buffer^) := sTS.Date;
end;
else
ss := pChar(@(TVarData(LookupResult).VAny));
Move(ss^, Buffer^, Field.DataSize);
end;
Result := true;
end;
end;
end else begin
if (oDS <> nil) and oDS.Active then
begin
LookupResult := oDS.Lookup(Field.LookupKeyFields, FieldValues[Field.KeyFields], Field.LookupResultField);
if (not VarIsEmpty(LookupResult)) and (not VarIsNull(LookupResult)) then Result := True;
end;
end;
end else begin
FillChar(Buffer^, Field.DataSize, ' ');
Result := false;
end;
end;
end;
end;
function TVKSmartDBF.GetRecNo: Integer;
var
ActiveBuf: pChar;
begin
Result := -1;
GetActiveRecBuf(ActiveBuf);
if ActiveBuf <> nil then
Result := pTRecInfo(ActiveBuf + RecordSize).RecordRowID;
end;
function TVKSmartDBF.GetRecord(Buffer: PChar; GetMode: TGetMode;
DoCheck: Boolean): TGetResult;
var
SaveState: TDataSetState;
Accept: Boolean;
begin
if not Filtered then
begin
if not FSetDeleted then
Result := GetRecordByBuffer(Buffer, GetMode, DoCheck)
else begin
Accept := False;
if GetMode <> gmCurrent then
begin
repeat
Result := GetRecordByBuffer(FFilterRecord, GetMode, DoCheck);
if Result <> grOK then Break;
SaveState := SetTempState(dsFilter);
Accept := not Deleted;
RestoreState(SaveState);
until Accept;
end else begin
Result := GetRecordByBuffer(FFilterRecord, GetMode, DoCheck);
if Result = grOK then begin
SaveState := SetTempState(dsFilter);
Accept := not Deleted;
RestoreState(SaveState);
if not Accept then Result := grError;
end;
end;
if Accept then
Move(FFilterRecord^, Buffer^, RecordBufferSize)
else
Move(FTempRecord^, Buffer^, RecordBufferSize);
end;
end else begin
Accept := False;
if GetMode <> gmCurrent then
begin
repeat
Result := GetRecordByBuffer(FFilterRecord, GetMode, DoCheck);
if Result <> grOK then Break;
SaveState := SetTempState(dsFilter);
Accept := AcceptRecordInternal;
RestoreState(SaveState);
until Accept;
end else begin
Result := GetRecordByBuffer(FFilterRecord, GetMode, DoCheck);
if Result = grOK then begin
SaveState := SetTempState(dsFilter);
Accept := AcceptRecordInternal;
RestoreState(SaveState);
if not Accept then Result := grError;
end;
end;
if Accept then
Move(FFilterRecord^, Buffer^, RecordBufferSize)
else
Move(FTempRecord^, Buffer^, RecordBufferSize);
end;
end;
function TVKSmartDBF.GetRecordBufferSize: Integer;
begin
Result := FRecordSize + sizeof(TRecInfo) + CalcFieldsSize;
end;
function TVKSmartDBF.GetRecordByBuffer(Buffer: PChar; GetMode: TGetMode;
DoCheck: Boolean): TGetResult;
var
cc: PChar;
begin
Result := grOK;
cc := pChar(Buffer);
case GetMode of
gmCurrent:
if ( not FBOF ) and ( not FEOF ) then
begin
InternalInitRecord(cc);
pTRecInfo(cc + FRecordSize).BookmarkFlag := bfCurrent;
pTRecInfo(cc + FRecordSize).RecordRowID := RecNoBuf;
pTRecInfo(cc + FRecordSize).UpdateStatus := usUnmodified;
Move(RecBuf^, cc^, FRecordSize);
end else begin
InternalInitRecord(FTempRecord);
Move(FTempRecord^, Buffer^, RecordBufferSize);
pTRecInfo(FTempRecord + FRecordSize).BookmarkFlag := bfEOF;
pTRecInfo(FTempRecord + FRecordSize).RecordRowID := 0;
pTRecInfo(FTempRecord + FRecordSize).UpdateStatus := usUnmodified;
Result := grError;
end;
gmNext:
begin
NextIndexBuf;
if not FEOF then
begin
InternalInitRecord(cc);
pTRecInfo(cc + FRecordSize).BookmarkFlag := bfCurrent;
pTRecInfo(cc + FRecordSize).RecordRowID := RecNoBuf;
pTRecInfo(cc + FRecordSize).UpdateStatus := usUnmodified;
Move(RecBuf^, cc^, FRecordSize);
end else begin
InternalInitRecord(FTempRecord);
Move(FTempRecord^, Buffer^, RecordBufferSize);
pTRecInfo(FTempRecord + FRecordSize).BookmarkFlag := bfEOF;
pTRecInfo(FTempRecord + FRecordSize).RecordRowID := 0;
pTRecInfo(FTempRecord + FRecordSize).UpdateStatus := usUnmodified;
Result := grEOF;
end;
end;
gmPrior:
begin
PriorIndexBuf;
if not FBOF then
begin
InternalInitRecord(cc);
pTRecInfo(cc + FRecordSize).BookmarkFlag := bfCurrent;
pTRecInfo(cc + FRecordSize).RecordRowID := RecNoBuf;
pTRecInfo(cc + FRecordSize).UpdateStatus := usUnmodified;
Move(RecBuf^, cc^, FRecordSize);
end else begin
InternalInitRecord(FTempRecord);
Move(FTempRecord^, Buffer^, RecordBufferSize);
pTRecInfo(FTempRecord + FRecordSize).BookmarkFlag := bfBOF;
pTRecInfo(FTempRecord + FRecordSize).RecordRowID := 0;
pTRecInfo(FTempRecord + FRecordSize).UpdateStatus := usUnmodified;
Result := grBOF;
end;
end;
end;
if Result = grOK then
GetCalcFields(Buffer);
end;
function TVKSmartDBF.GetRecordCount: Integer;
begin
if LockHeader then
try
DBFHeader.last_rec := ( (DBFHandler.Seek(0, 2) - DBFHeader.data_offset) div DBFHeader.rec_size );
finally
UnLockHeader;
end;
Result := DBFHeader.last_rec;
end;
function TVKSmartDBF.GetRecordSize: Word;
begin
Result := FRecordSize;
end;
function TVKSmartDBF.GetStateFieldValue(State: TDataSetState;
Field: TField): Variant;
begin
Result := NULL;
if State in [dsNewValue, dsCurValue, dsOldValue] then
Result := inherited GetStateFieldValue(State, Field);
end;
procedure TVKSmartDBF.CloseTmpRecord;
begin
FTmpActive := false;
FFastPostRecord := FLastFastPostRecord;
end;
procedure TVKSmartDBF.SetTmpRecord(nRec: DWORD);
begin
DBFHandler.Seek(DBFHeader.data_offset + (nRec - 1) * DWORD(FRecordSize), soFromBeginning);
DBFHandler.Read(FTempRecord^, FRecordSize);
if Crypt.Active then
Crypt.Decrypt(nRec, Pointer(FTempRecord), FRecordSize);
SetBookmarkData(FTempRecord, @nRec);
SetBookmarkFlag(FTempRecord, bfCurrent);
FTmpActive := true;
FLastFastPostRecord := FFastPostRecord;
FFastPostRecord := true;
end;
procedure TVKSmartDBF.AddRecord(const Values: variant);
var
i, j: Integer;
begin
InternalInitRecord(FTempRecord);
FTmpActive := true;
FLastFastPostRecord := FFastPostRecord;
FFastPostRecord := true;
try
j := VarArrayHighBound(Values, 1);
for i := 0 to j - 1 do
Fields[i].AsVariant := Values[i];
InternalAddRecord(FTempRecord, true);
finally
FTmpActive := false;
FFastPostRecord := FLastFastPostRecord;
end;
end;
procedure TVKSmartDBF.AddRecord(ne: TNotifyEvent);
begin
InternalInitRecord(FTempRecord);
FTmpActive := true;
FLastFastPostRecord := FFastPostRecord;
FFastPostRecord := true;
try
if Assigned(ne) then ne(self);
InternalAddRecord(FTempRecord, true);
finally
FTmpActive := false;
FFastPostRecord := FLastFastPostRecord;
end;
end;
procedure TVKSmartDBF.BeginAddRecord;
begin
InternalInitRecord(FTempRecord);
FTmpActive := true;
FLastFastPostRecord := FFastPostRecord;
FFastPostRecord := true;
end;
procedure TVKSmartDBF.EndAddRecord;
begin
InternalAddRecord(FTempRecord, true);
FTmpActive := false;
FFastPostRecord := FLastFastPostRecord;
end;
procedure TVKSmartDBF.AddRecord(const Values: array of const);
begin
InternalInitRecord(FTempRecord);
FTmpActive := true;
FLastFastPostRecord := FFastPostRecord;
FFastPostRecord := true;
try
SetFields(Values);
InternalAddRecord(FTempRecord, true);
finally
FTmpActive := false;
FFastPostRecord := FLastFastPostRecord;
end;
end;
procedure TVKSmartDBF.InternalAddRecord(Buffer: Pointer; Append: Boolean);
var
i, RealRead, l, r: Integer;
lpMsgBuf: array [0..500] of Char;
le: DWORD;
NewR: Longint;
NewKey: String;
b: boolean;
cc: pChar;
begin
CheckActive;
if FAddBuffered then begin
if FAddBufferCurrent = FAddBufferCount - 1 then FlushAddBuffer;
Inc(FAddBufferCurrent);
cc := FAddBuffer + FAddBufferCurrent * DBFHeader.rec_size;
Move(Buffer^, cc^, DBFHeader.rec_size);
Changed := True;
end else begin
b := false;
if LockHeader then begin
try
DBFHeader.last_rec := ( (DBFHandler.Seek(0, 2) - DBFHeader.data_offset) div DBFHeader.rec_size );
NewR := DBFHeader.last_rec + 1;
if RLock(NewR) then begin
try
pTRecInfo(pChar(Buffer) + FRecordSize).RecordRowID := NewR;
DBFHandler.Seek(DBFHeader.data_offset + LongWord(DBFHeader.last_rec * FRecordSize), 0);
//Crypt
if Crypt.FActive then begin
Move(Buffer^, FCryptBuff^, DBFHeader.rec_size);
Crypt.Encrypt(NewR, FCryptBuff, DBFHeader.rec_size);
RealRead := DBFHandler.Write(FCryptBuff^, DBFHeader.rec_size);
end else
RealRead := DBFHandler.Write(Buffer^, DBFHeader.rec_size);
if RealRead = -1 then
begin
le := GetLastError();
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
nil,
le,
0, // Default language
lpMsgBuf,
500,
nil
);
raise Exception.Create('TVKSmartDBF: ' + lpMsgBuf);
end else begin
Inc(DBFHeader.last_rec);
DBFHandler.Seek(0, 0); //go to the begin
RealRead := DBFHandler.Write(DBFHeader, SizeOf(DBFHeader));
if RealRead = -1 then
begin
le := GetLastError();
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
nil,
le,
0, // Default language
lpMsgBuf,
500,
nil
);
raise Exception.Create('TVKSmartDBF: ' + lpMsgBuf);
end else begin
l := DBFHeader.last_rec;
if Indexes <> nil then
for i := 0 to Indexes.Count - 1 do begin
NewKey := Indexes[i].EvaluteKeyExpr;
//if (Indexes.ActiveObject <> nil) and
// (Indexes.ActiveObject = Indexes[i]) and
// (Indexes[i].IsRanged) and
// (not Indexes[i].InRange(NewKey)) then b := true;
if not (
( (FAccessMode.FLast and fmShareExclusive) = fmShareExclusive ) or
( (FAccessMode.FLast and fmShareDenyWrite) = fmShareDenyWrite ) or
FFileLock
) then begin
if Indexes[i].FLock then
try
Indexes[i].StartUpdate(false);
Indexes[i].AddKey(NewKey, DBFHeader.last_rec);
finally
Indexes[i].Flush;
Indexes[i].FUnLock;
end
else
raise Exception.Create('TVKSmartDBF.InternalAddRecord: Can not add key to index file (FLock is false).');
end else begin
if Indexes[i].FLock then
try
Indexes[i].AddKey(NewKey, DBFHeader.last_rec);
finally
Indexes[i].FUnLock;
end
else
raise Exception.Create('TVKSmartDBF.InternalAddRecord: Can not add key to index file (FLock is false).');
end;
if ( Indexes.ActiveObject <> nil ) and
( Indexes.ActiveObject = Indexes[i] ) and
( Indexes.ActiveObject.IsUniqueIndex or Indexes.ActiveObject.IsForIndex ) and
( not FFastPostRecord ) then begin
r := Indexes.ActiveObject.FindKey(NewKey, true);
if r <> 0 then begin
if r <> l then l := r;
end else begin
InternalFirst;
b := true;
end;
end;
end;
if not FFastPostRecord then
if not b then begin
GetBufferByRec(l);
RefreshBufferByRec(l);
end;
end;
Changed := True;
end;
finally
RUnLock(NewR);
end
end else
raise Exception.Create('TVKSmartDBF.InternalAddRecord: Can not lock DBF record.');
finally
UnLockHeader;
end
end else
raise Exception.Create('TVKSmartDBF.InternalAddRecord: Can not lock DBF header.');
end;
end;
procedure TVKSmartDBF.DoBeforeClose;
begin
EndAddBuffered;
inherited DoBeforeClose;
end;
procedure TVKSmartDBF.InternalClose;
var
i: Integer;
end1a: Byte;
begin
try
if Indexes <> nil then
for i := 0 to Indexes.Count - 1 do Indexes[i].Flush;
FreeRecordBuffer(FBuffer);
FRecordsPerBuf := 0;
FBuffer := nil;
VKDBFMemMgr.oMem.FreeMem(FBufInd);
VKDBFMemMgr.oMem.FreeMem(FLocateBuffer);
FBufInd := nil;
FBufCnt := 0;
FBufDir := bdFromTop;
FreeRecordBuffer(FTempRecord);
FreeRecordBuffer(FFilterRecord);
FreeRecordBuffer(FSetKeyBuffer);
FreeRecordBuffer(pChar(FCryptBuff));
BindFields(false);
if DefaultFields then DestroyFields;
if FIndexes <> nil then FIndexes.CloseAll;
finally
CloseLobStream;
if DBFHandler.IsOpen then begin
//Add 1A at end dbf file
if AccessMode.OpenReadWrite then begin
DBFHandler.Seek(0, 2);
DBFHandler.Seek(-1, 1);
end1a := 0;
DBFHandler.Read(end1a, 1);
if end1a <> $1A then begin
end1a := $1A;
DBFHandler.Seek(0, 2);
DBFHandler.Write(end1a, 1);
end;
end;
DBFHandler.Close;
end;
end;
end;
procedure TVKSmartDBF.DeleteRecallRecord(Del: boolean = true);
var
l, fOffset: Integer;
ActiveBuf: pChar;
RealRead: Integer;
lpMsgBuf: array [0..500] of Char;
le: DWORD;
begin
CheckActive;
GetActiveRecBuf(ActiveBuf);
if Del then
ActiveBuf[0] := #42 //'*'
else
ActiveBuf[0] := #32; //' '
l := pTRecInfo(ActiveBuf + RecordSize).RecordRowID;
fOffset := DBFHandler.Seek(0, 1);
if RLock(l) then
try
DBFHandler.Seek(DBFHeader.data_offset + LongWord((l - 1) * FRecordSize), 0);
//Crypt
if Crypt.FActive then begin
Move(ActiveBuf^, FCryptBuff^, DBFHeader.rec_size);
Crypt.Encrypt(l, FCryptBuff, DBFHeader.rec_size);
RealRead := DBFHandler.Write(FCryptBuff^, DBFHeader.rec_size);
end else
RealRead := DBFHandler.Write(ActiveBuf^, DBFHeader.rec_size);
Move(ActiveBuf^, (FBuffer + GetCurIndByRec(l) * FRecordSize)^, FRecordSize);
if RealRead = -1 then
begin
le := GetLastError();
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
nil,
le,
0, // Default language
lpMsgBuf,
500,
nil
);
raise Exception.Create('TVKSmartDBF: ' + lpMsgBuf);
end else begin
if not FFastPostRecord then begin
//GetBufferByRec(l);
RefreshBufferByRec(l);
SetModified(true);
DataEvent(deRecordChange, 0);
end;
end;
finally
RUnLock(l);
DBFHandler.Seek(fOffset, 0);
end
else
raise Exception.Create('TVKSmartDBF.InternalPost: Can not lock DBF record.');
end;
procedure TVKSmartDBF.InternalDelete;
begin
DeleteRecallRecord;
end;
procedure TVKSmartDBF.DeleteRecord;
begin
DeleteRecallRecord;
end;
procedure TVKSmartDBF.RecallRecord;
begin
DeleteRecallRecord(false);
end;
procedure TVKSmartDBF.Pack;
var
RecPareBuf, i, j, k: Integer;
ReadSize, RealRead, RealWrite, BufCnt, BufCntPack: Integer;
Rec, RecPack: Integer;
Offset, OffsetPack: Integer;
IndPackBuf: pChar;
LobName: String;
TempLobName: String;
lb: TStream;
LobFieldsNum: TList;
DataSetFieldsNum: TList;
NstDSet: TVKNestedDBF;
BlobFld: TBlobField;
DataSetFld: TDataSetField;
begin
CheckActive;
if State = dsEdit then Post;
if LockHeader then begin
PackLobHandlerCreate;
LobFieldsNum := TList.Create;
DataSetFieldsNum := TList.Create;
try
FPackProcess := true;
if LobHandler.IsOpen then begin
//Create new LOB
LobName := ChangeFileExt(DBFFileName, '.dbt');
TempLobName := GetTmpFileName;
PackLobHandlerOpen(TempLobName);
for k := 0 to FieldCount - 1 do begin
if Fields[k].IsBlob then
LobFieldsNum.Add(Pointer(k));
if Fields[k].DataType = ftDataSet then
DataSetFieldsNum.Add(Pointer(k));
end;
end;
if Indexes <> nil then
for j := 0 to Indexes.Count - 1 do Indexes.Items[j].BeginCreateIndexProcess;
IndState := true;
try
RecPareBuf := FBufferSize div Header.rec_size;
if RecPareBuf >= 1 then begin
ReadSize := RecPareBuf * Header.rec_size;
Offset := Header.data_offset;
OffsetPack := Header.data_offset;
Rec := 0;
RecPack := 0;
repeat
Handle.Seek(Offset, 0);
RealRead := Handle.Read(FLocateBuffer^, ReadSize);
Inc(Offset, RealRead);
BufCntPack := 0;
BufCnt := RealRead div Header.rec_size;
for i := 0 to BufCnt - 1 do begin
IndRecBuf := FLocateBuffer + Header.rec_size * i;
if Crypt.FActive then
Crypt.Decrypt(Rec + 1, Pointer(IndRecBuf), FRecordSize);
Inc(Rec);
if IndRecBuf[0] = #32 then begin (* If not Deleted *)
//Lob copy from old to new location
if LobHandler.IsOpen then begin
for k := 0 to LobFieldsNum.Count - 1 do
if Fields[Integer(LobFieldsNum.Items[k])].IsBlob then begin
BlobFld := TBlobField(Fields[Integer(LobFieldsNum.Items[k])]);
lb := CreateBlobStream(BlobFld, bmRead);
try
BlobFld.LoadFromStream(lb);
finally
lb.free;
end;
end;
for k := 0 to DataSetFieldsNum.Count - 1 do
if Fields[Integer(DataSetFieldsNum.Items[k])].DataType = ftDataSet then begin
DataSetFld := TDataSetField(Fields[Integer(DataSetFieldsNum.Items[k])]);
if not DataSetFld.IsNull then begin
NstDSet := TVKNestedDBF(DataSetFld.NestedDataSet);
NstDSet.Close;
NstDSet.Open;
NstDSet.Pack;
end;
end;
end;
//
IndPackBuf := FLocateBuffer + Header.rec_size * BufCntPack;
if IndRecBuf <> IndPackBuf then
Move(IndRecBuf^, IndPackBuf^, Header.rec_size);
if Crypt.FActive then
Crypt.Encrypt(RecPack + 1, Pointer(IndPackBuf), FRecordSize);
Inc(BufCntPack);
Inc(RecPack);
if Indexes <> nil then
for j := 0 to Indexes.Count - 1 do Indexes.Items[j].EvaluteAndAddKey(RecPack);
end;
end;
if BufCntPack > 0 then begin
Handle.Seek(OffsetPack, 0);
RealWrite := Handle.Write(FLocateBuffer^, Header.rec_size * BufCntPack);
Inc(OffsetPack, RealWrite);
end;
until ( BufCnt <= 0 );
DBFHeader.last_rec := RecPack;
Handle.Seek(0, 0);
Handle.Write(DBFHeader, SizeOf(DBFHeader));
Handle.Seek(OffsetPack, 0);
Handle.SetEndOfFile;
if LobHandler.IsOpen then
PackLobHandlerClose(LobName, TempLobName);
end else raise Exception.Create('TVKSmartDBF.Pack: Record size too large');
finally
if Indexes <> nil then
for j := 0 to Indexes.Count - 1 do Indexes.Items[j].EndCreateIndexProcess;
IndState := false;
IndRecBuf := nil;
FPackProcess := false;
end;
finally
PackLobHandlerDestroy;
DataSetFieldsNum.Free;
LobFieldsNum.Free;
UnLockHeader;
Refresh;
end;
end else
raise Exception.Create('TVKSmartDBF.Pack: Can not lock DBF header.');
end;
procedure TVKSmartDBF.InternalFirst;
var
i, RealRead: Integer;
begin
FBOF := true;
FEOF := false;
FBufDir := bdFromTop;
FCurInd := -1;
if (FIndexes = nil) or (FIndexes.ActiveObject = nil) then begin
DBFHandler.Seek(DBFHeader.data_offset, soFromBeginning);
RealRead := DBFHandler.Read(FBuffer^, FRecordsPerBuf * FRecordSize);
FBufCnt := RealRead div FRecordSize;
for i := 0 to FBufCnt - 1 do begin
pLongint(pChar(FBufInd) + i * SizeOf(LongInt))^ := i + 1;
if Crypt.FActive then
Crypt.Decrypt(i + 1, Pointer(FBuffer + i * FRecordSize), FRecordSize);
end;
if FBufCnt = 0 then begin
FBOF := true;
FEOF := true;
end;
end else begin
if FIndexes.ActiveObject.FLock then
try
FBufCnt := FIndexes.ActiveObject.FillFirstBufRecords(DBFHandler, FBuffer, FRecordsPerBuf, FRecordSize, FBufInd, DBFHeader.data_offset);
finally
FIndexes.ActiveObject.FUnLock;
end
else
raise Exception.Create('TDBFDataSet: Can not read from index file (FLock is false).');
end;
end;
procedure TVKSmartDBF.InternalGotoBookmark(Bookmark: Pointer);
var
i : Longint;
begin
i := pTRecInfo(Bookmark).RecordRowID;
GetBufferByRec(i);
end;
procedure TVKSmartDBF.InternalHandleException;
begin
Application.HandleException(self);
end;
procedure TVKSmartDBF.HiddenInitFieldDefs(FDs: TFieldDefs; DBFFDs: TVKDBFFieldDefs; BeginOffset, BeginOffsetHD: Integer; NamePrefix: String = ''; CreateFieldDef: boolean = true);
var
DBFField: FIELD_REC;
dbOffset, dbOffsetHD: Integer;
dbSize: Integer;
FD, CFD: TFieldDef;
DBFFD: TVKDBFFieldDef;
s: String;
begin
CFD := TFieldDef.Create(nil);
try
dbOffset := BeginOffset;
dbOffsetHD := BeginOffsetHD;
while true do
begin
DBFHandler.Read(DBFField, SizeOf(FIELD_REC));
if DBFField.field_name[0] = #13 then break;
dbSize := 0;
if CreateFieldDef then
FD := FDs.AddFieldDef
else
FD := CFD;
s := UpperCase(Trim(DBFField.field_name));
with FD do begin
Name := NamePrefix + s;
Required := false;
end;
DBFFD := TVKDBFFieldDef(DBFFDs.Add);
with DBFFD do begin
Name := s;
field_type := DBFField.field_type;
extend_type := DBFField.extend_type;
if field_type <> 'E' then
extend_type := dbftUndefined;
FOff := dbOffset;
FOffHD := dbOffsetHD;
if CreateFieldDef then
FFieldDefRef := FD
else
FFieldDefRef := nil;
end;
//
case DBFField.field_type of
'C':
begin
FD.DataType := ftString;
FD.Size := DBFField.lendth.char_len;
dbSize := DBFField.lendth.char_len;
FD.Precision := 0;
DBFFD.FLen := dbSize;
DBFFD.Fdec := 0;
end;
'N':
begin
if DBFField.lendth.num_len.dec = 0 then
begin
if DBFField.lendth.num_len.len < 10 then begin
FD.DataType := ftInteger;
FD.Size := 0;
dbSize := DBFField.lendth.num_len.len;
FD.Precision := 0;
end else begin
FD.DataType := ftLargeint;
FD.Size := 0;
dbSize := DBFField.lendth.num_len.len;
FD.Precision := 0;
end;
end else begin
FD.DataType := ftFloat;
FD.Size := 0;
dbSize := DBFField.lendth.num_len.len;
FD.Precision := DBFField.lendth.num_len.dec;
end;
DBFFD.FLen := dbSize;
DBFFD.Fdec := FD.Precision;
end;
'D':
begin
FD.DataType := ftDate;
FD.Size := 0;
dbSize := 8;
FD.Precision := 0;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
'L':
begin
FD.DataType := ftBoolean;
FD.Size := 0;
dbSize := 1;
FD.Precision := 0;
DBFFD.FLen := 1;
DBFFD.Fdec := 0;
end;
'M':
begin
FD.DataType := ftMemo;
FD.Size := 0;
dbSize := 10;
FD.Precision := 0;
DBFFD.FLen := 10;
DBFFD.Fdec := 0;
end;
'E': //Extended types
begin
case DBFField.extend_type of
dbftS1: //Shortint
begin
FD.DataType := ftSmallint;
dbSize := 1;
DBFFD.FLen := 4;
DBFFD.Fdec := 0;
end;
dbftU1: //Byte
begin
FD.DataType := ftWord;
dbSize := 1;
DBFFD.FLen := 4;
DBFFD.Fdec := 0;
end;
dbftU1_NB: //Byte with null bit instead of sign bit
begin
FD.DataType := ftWord;
dbSize := 1;
DBFFD.FLen := 3;
DBFFD.Fdec := 0;
end;
dbftU2_NB: //Byte with null bit instead of sign bit
begin
FD.DataType := ftWord;
dbSize := 2;
DBFFD.FLen := 5;
DBFFD.Fdec := 0;
end;
dbftS2: //Smallint
begin
FD.DataType := ftSmallint;
dbSize := 2;
DBFFD.FLen := 6;
DBFFD.Fdec := 0;
end;
dbftU2: //Word
begin
FD.DataType := ftWord;
dbSize := 2;
DBFFD.FLen := 6;
DBFFD.Fdec := 0;
end;
dbftS4: //Longint
begin
FD.DataType := ftInteger;
dbSize := 4;
DBFFD.FLen := 11;
DBFFD.Fdec := 0;
end;
dbftU4: //Longword
begin
FD.DataType := ftInteger;
dbSize := 4;
DBFFD.FLen := 11;
DBFFD.Fdec := 0;
end;
dbftU4_NB: //
begin
FD.DataType := ftInteger;
dbSize := 4;
DBFFD.FLen := 10;
DBFFD.Fdec := 0;
end;
dbftS8: //Int64
begin
FD.DataType := ftLargeint;
dbSize := 8;
DBFFD.FLen := 21;
DBFFD.Fdec := 0;
end;
dbftR4: //Single
begin
FD.DataType := ftFloat;
dbSize := 4;
DBFFD.FLen := 18;
DBFFD.Fdec := 8;
end;
dbftR4_NB:
begin
FD.DataType := ftFloat;
dbSize := 4;
DBFFD.FLen := 18;
DBFFD.Fdec := 8;
end;
dbftR6_NB:
begin
FD.DataType := ftFloat;
dbSize := 6;
DBFFD.FLen := 26;
DBFFD.Fdec := 12;
end;
dbftR8_NB:
begin
FD.DataType := ftFloat;
dbSize := 8;
DBFFD.FLen := 34;
DBFFD.Fdec := 16;
end;
dbftR6: //Real48
begin
FD.DataType := ftFloat;
dbSize := 6;
DBFFD.FLen := 26;
DBFFD.Fdec := 12;
end;
dbftR8: //Double
begin
FD.DataType := ftFloat;
dbSize := 8;
DBFFD.FLen := 34;
DBFFD.Fdec := 16;
end;
dbftR10: //Extended
begin
FD.DataType := ftFloat;
dbSize := 10;
DBFFD.FLen := 42;
DBFFD.Fdec := 20;
end;
dbftD1:
begin
FD.DataType := ftDateTime;
dbSize := 8;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftD1_NB:
begin
FD.DataType := ftDateTime;
dbSize := 8;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftD2:
begin
FD.DataType := ftDateTime;
dbSize := 8;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftD2_NB:
begin
FD.DataType := ftDateTime;
dbSize := 8;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftD3:
begin
FD.DataType := ftDateTime;
dbSize := 6;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftD3_NB:
begin
FD.DataType := ftDateTime;
dbSize := 6;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftS1_N: //Shortint with NULL
begin
FD.DataType := ftSmallint;
dbSize := 2;
DBFFD.FLen := 4;
DBFFD.Fdec := 0;
end;
dbftU1_N: //Byte with NULL
begin
FD.DataType := ftWord;
dbSize := 2;
DBFFD.FLen := 4;
DBFFD.Fdec := 0;
end;
dbftS2_N: //Smallint with NULL
begin
FD.DataType := ftSmallint;
dbSize := 3;
DBFFD.FLen := 6;
DBFFD.Fdec := 0;
end;
dbftU2_N: //Word with NULL
begin
FD.DataType := ftWord;
dbSize := 3;
DBFFD.FLen := 6;
DBFFD.Fdec := 0;
end;
dbftS4_N: //Longint with NULL
begin
FD.DataType := ftInteger;
dbSize := 5;
DBFFD.FLen := 11;
DBFFD.Fdec := 0;
end;
dbftU4_N: //Longword with NULL
begin
FD.DataType := ftInteger;
dbSize := 5;
DBFFD.FLen := 11;
DBFFD.Fdec := 0;
end;
dbftS8_N: //Int64 with NULL
begin
FD.DataType := ftLargeint;
dbSize := 9;
DBFFD.FLen := 21;
DBFFD.Fdec := 0;
end;
dbftR4_N: //Single with NULL
begin
FD.DataType := ftFloat;
dbSize := 5;
DBFFD.FLen := 18;
DBFFD.Fdec := 8;
end;
dbftR6_N: //Real48 with NULL
begin
FD.DataType := ftFloat;
dbSize := 7;
DBFFD.FLen := 26;
DBFFD.Fdec := 12;
end;
dbftR8_N: //Double with NULL
begin
FD.DataType := ftFloat;
dbSize := 9;
DBFFD.FLen := 34;
DBFFD.Fdec := 16;
end;
dbftR10_N: //Extended with NULL
begin
FD.DataType := ftFloat;
FD.Size := 11;
dbSize := 11;
DBFFD.FLen := 42;
DBFFD.Fdec := 20;
end;
dbftD1_N:
begin
FD.DataType := ftDateTime;
dbSize := 9;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftD2_N:
begin
FD.DataType := ftDateTime;
dbSize := 9;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftD3_N:
begin
FD.DataType := ftDateTime;
dbSize := 7;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftDate:
begin
FD.DataType := ftDate;
dbSize := 4;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftDate_N:
begin
FD.DataType := ftDate;
dbSize := 5;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftDate_NB:
begin
FD.DataType := ftDate;
dbSize := 4;
DBFFD.FLen := 8;
DBFFD.Fdec := 0;
end;
dbftTime:
begin
FD.DataType := ftTime;
dbSize := 4;
DBFFD.FLen := 6;
DBFFD.Fdec := 0;
end;
dbftTime_NB:
begin
FD.DataType := ftTime;
dbSize := 4;
DBFFD.FLen := 6;
DBFFD.Fdec := 0;
end;
dbftTime_N:
begin
FD.DataType := ftTime;
dbSize := 5;
DBFFD.FLen := 6;
DBFFD.Fdec := 0;
end;
dbftClob, dbftFmtMemo:
begin
FD.DataType := ftMemo;
FD.Size := 0;
dbSize := 10;
FD.Precision := 0;
DBFFD.FLen := 10;
DBFFD.Fdec := 0;
end;
dbftBlob, dbftGraphic:
begin
FD.DataType := ftBlob;
FD.Size := 0;
dbSize := 10;
FD.Precision := 0;
DBFFD.FLen := 10;
DBFFD.Fdec := 0;
end;
dbftClob_NB, dbftFmtMemo_NB:
begin
FD.DataType := ftMemo;
FD.Size := 0;
dbSize := 4;
FD.Precision := 0;
DBFFD.FLen := 4;
DBFFD.Fdec := 0;
end;
dbftBlob_NB, dbftGraphic_NB:
begin
FD.DataType := ftBlob;
FD.Size := 0;
dbSize := 4;
FD.Precision := 0;
DBFFD.FLen := 4;
DBFFD.Fdec := 0;
end;
dbftString:
begin
FD.DataType := ftString;
FD.Size := DBFField.lendth.char_len;
dbSize := DBFField.lendth.char_len + 2;
FD.Precision := 0;
DBFFD.FLen := DBFField.lendth.char_len;
DBFFD.Fdec := 0;
end;
dbftString_N:
begin
FD.DataType := ftString;
FD.Size := DBFField.lendth.char_len;
dbSize := DBFField.lendth.char_len + 3;
FD.Precision := 0;
DBFFD.FLen := DBFField.lendth.char_len;
DBFFD.Fdec := 0;
end;
dbftFixedChar:
begin
FD.DataType := ftFixedChar;
FD.Size := DBFField.lendth.char_len;
dbSize := DBFField.lendth.char_len + 1;
FD.Precision := 0;
DBFFD.FLen := DBFField.lendth.char_len;
DBFFD.Fdec := 0;
end;
dbftWideString:
begin
FD.DataType := ftWideString;
FD.Size := DBFField.lendth.char_len;
dbSize := DBFField.lendth.char_len * 2 + 5;
FD.Precision := 0;
DBFFD.FLen := DBFField.lendth.char_len;
DBFFD.Fdec := 0;
end;
dbftCurrency:
begin
FD.DataType := ftCurrency;
dbSize := 8;
DBFFD.FLen := 25;
DBFFD.Fdec := 4;
end;
dbftCurrency_N:
begin
FD.DataType := ftCurrency;
dbSize := 9;
DBFFD.FLen := 25;
DBFFD.Fdec := 4;
end;
dbftCurrency_NB:
begin
FD.DataType := ftCurrency;
dbSize := 8;
DBFFD.FLen := 25;
DBFFD.Fdec := 4;
end;
dbftBCD:
begin
FD.DataType := ftBCD;
dbSize := DBFField.lendth.num_len.len shr 1;
if ( DBFField.lendth.num_len.len and $01 ) = $01 then Inc(dbSize);
Inc(dbSize);
DBFFD.FLen := 25;
DBFFD.Fdec := 4;
end;
dbftDBFDataSet:
begin
FD.DataType := ftDataSet;
FD.Size := 0;
dbSize := 10;
FD.Precision := 0;
DBFFD.FLen := 10;
DBFFD.Fdec := 0;
// Recursive call
if CreateFieldDef then
HiddenInitFieldDefs( FD.ChildDefs,
DBFFD.DBFFieldDefs,
dbOffset + dbSize,
dbOffsetHD + SizeOf(FIELD_REC),
NamePrefix,
False)
else
HiddenInitFieldDefs( nil,
DBFFD.DBFFieldDefs,
dbOffset + dbSize,
dbOffsetHD + SizeOf(FIELD_REC),
NamePrefix,
False);
end;
dbftDBFDataSet_NB:
begin
FD.DataType := ftDataSet;
FD.Size := 0;
dbSize := 4;
FD.Precision := 0;
DBFFD.FLen := 4;
DBFFD.Fdec := 0;
// Recursive call
if CreateFieldDef then
HiddenInitFieldDefs( FD.ChildDefs,
DBFFD.DBFFieldDefs,
dbOffset + dbSize,
dbOffsetHD + SizeOf(FIELD_REC),
NamePrefix,
False)
else
HiddenInitFieldDefs( nil,
DBFFD.DBFFieldDefs,
dbOffset + dbSize,
dbOffsetHD + SizeOf(FIELD_REC),
NamePrefix,
False);
end;
end;
end;
end;
//
Inc(dbOffset, dbSize);
Inc(dbOffsetHD, SizeOf(FIELD_REC));
end;
finally
CFD.Free;
end;
end;
procedure TVKSmartDBF.InternalInitFieldDefs;
begin
FieldDefs.Clear;
FDBFFieldDefs.Clear;
if not DBFHandler.IsOpen then
raise Exception.Create('TVKSmartDBF.InternalInitFieldDefs: Can not define fields while DataSet is closed!');
DBFHandler.Seek(SizeOf(DBFHeader), soFromBeginning);
HiddenInitFieldDefs(FieldDefs, FDBFFieldDefs, 1, SizeOf(DBFHeader));
end;
procedure TVKSmartDBF.InternalInitRecord(Buffer: PChar);
begin
if Buffer <> nil then begin
FillChar(Buffer^, RecordBufferSize, #32);
pTRecInfo(Buffer + RecordSize).RecordRowID := 0;
pTRecInfo(Buffer + RecordSize).UpdateStatus := usInserted;
pTRecInfo(Buffer + RecordSize).BookmarkFlag := bfInserted;
end;
end;
procedure TVKSmartDBF.InternalLast;
var
j: Longint;
i: Integer;
LOff: Integer;
begin
FBOF := false;
FEOF := true;
FBufDir := bdFromBottom;
FCurInd := FRecordsPerBuf;
if (FIndexes = nil) or (FIndexes.ActiveObject = nil) then begin
LOff := DBFHandler.Seek(0, 2);
if LockHeader then
try
DBFHeader.last_rec := ( (LOff - DBFHeader.data_offset) div DBFHeader.rec_size );
finally
UnLockHeader;
end;
if DBFHeader.last_rec <> 0 then begin
j := DBFHeader.last_rec - FRecordsPerBuf + 1;
if j < 1 then j := 1;
FBufCnt := DBFHeader.last_rec - j + 1;
DBFHandler.Seek(DBFHeader.data_offset + ((j - 1) * FRecordSize), soFromBeginning);
DBFHandler.Read((FBuffer + (FRecordsPerBuf - FBufCnt) * FRecordSize)^, FBufCnt * FRecordSize);
for i := 0 to FBufCnt - 1 do begin
pLongint(pChar(FBufInd) + (FRecordsPerBuf - i - 1)*SizeOf(Longint))^ := DBFHeader.last_rec - i;
if Crypt.FActive then
Crypt.Decrypt(DBFHeader.last_rec - i, Pointer(FBuffer + (FRecordsPerBuf - i - 1) * FRecordSize), FRecordSize);
end;
end else begin
FBOF := true;
FEOF := true;
end;
end else begin
if FIndexes.ActiveObject.FLock then
try
FBufCnt := FIndexes.ActiveObject.FillLastBufRecords(DBFHandler, FBuffer, FRecordsPerBuf, FRecordSize, FBufInd, DBFHeader.data_offset);
finally
FIndexes.ActiveObject.FUnLock;
end
else
raise Exception.Create('TDBFDataSet: Can not read from index file (FLock is false).');
end;
end;
procedure TVKSmartDBF.InternalOpen;
var
i: Integer;
b: boolean;
oI: TIndex;
procedure CloseAllInInternalOpen;
begin
FreeRecordBuffer(FBuffer);
FRecordsPerBuf := 0;
FBuffer := nil;
VKDBFMemMgr.oMem.FreeMem(FBufInd);
FBufInd := nil;
FBufCnt := 0;
FBufDir := bdFromTop;
BindFields(false);
if DefaultFields then DestroyFields;
DBFHandler.Close;
FIndexes.CloseAll;
end;
begin
CloseLobStream;
DBFHandler.FileName := DBFFileName;
DBFHandler.AccessMode.AccessMode := AccessMode.AccessMode;
DBFHandler.ProxyStreamType := FStorageType;
DBFHandler.OuterStream := FOuterStream;
DBFHandler.OnLockEvent := FOnOuterStreamLock;
DBFHandler.OnUnlockEvent := FOnOuterStreamUnlock;
DBFHandler.Open;
if not DBFHandler.IsOpen then begin
raise Exception.Create('TVKSmartDBF.InternalOpen: Open error "' + DBFFileName + '"');
end else begin
DBFHandler.Seek(0, 0);
DBFHandler.Read(DBFHeader, SizeOf(DBF_HEAD));
if not ((DBFHeader.dbf_id = $03) or (DBFHeader.dbf_id = $07) or (DBFHeader.dbf_id = $83) or (DBFHeader.dbf_id = $8B)) then begin
DBFHandler.Close;
raise Exception.Create('TVKSmartDBF.InternalOpen: File "' + DBFFileName + '" is not DBF file');
end else begin
OpenLobStream(DBFHeader.dbf_id);
FRecordSize := DBFHeader.rec_size;
FBuffer := VKDBFMemMgr.oMem.GetMem(self, FBufferSize + 10);
FRecordsPerBuf := FBufferSize div FRecordSize;
if FRecordsPerBuf = 0 then
raise Exception.Create('TVKSmartDBF.InternalOpen: BufferSize too small!');
FBufCnt := 0;
FBufDir := bdFromTop;
FBufInd := VKDBFMemMgr.oMem.GetMem(self, FRecordsPerBuf * SizeOf(LongInt));
FLocateBuffer := VKDBFMemMgr.oMem.GetMem(self, FBufferSize);
FieldDefs.Updated := False;
FieldDefs.Update;
if DefaultFields then CreateFields;
BindFields(True);
BindDBFFieldDef;
if FVKDBFCrypt.Active then begin
FVKDBFCrypt.Active := false;
FVKDBFCrypt.Active := true;
end;
b := true;
if not FOpenWithoutIndexes then begin
if FIndexes <> nil then begin
for i := 0 to FIndexes.Count - 1 do begin
if not FIndexes.Items[i].Open then begin
b := false;
CloseAllInInternalOpen;
break;
end;
end;
if b then begin
for i := 0 to FDBFIndexDefs.Count - 1 do begin
if not FDBFIndexDefs.Items[i].IsOpen then begin
oI := TIndex(FIndexes.Add);
oI.BagName := FDBFIndexDefs.Items[i].Name;
if not oI.Open then begin
b := false;
CloseAllInInternalOpen;
break;
end;
end;
end;
end;
end;
end;
if b then begin
Changed := False;
SetRngInt;
InternalFirst;
FTempRecord := AllocRecordBuffer;
FFilterRecord := AllocRecordBuffer;
FSetKeyBuffer := AllocRecordBuffer;
FCryptBuff := AllocRecordBuffer;
if Filtered and (Filter <> '') then
FFilterParser.SetExprParams(Filter, FilterOptions, [poExtSyntax], '');
end;
end;
end;
FBOF := true;
ObjectView := true;
BookmarkSize := sizeof(Longword);
end;
procedure TVKSmartDBF.InternalPost;
var
i, l, r: Integer;
fOffset: Integer;
ActiveBuf: pChar;
RealRead: Integer;
lpMsgBuf: array [0..500] of Char;
le: DWORD;
NewKey: String;
b: boolean;
begin
b := false;
CheckActive;
GetActiveRecBuf(ActiveBuf);
l := pTRecInfo(ActiveBuf + RecordSize).RecordRowID;
if State = dsEdit then
begin
fOffset := DBFHandler.Seek(0, 1);
if RLock(l) then
try
DBFHandler.Seek(DBFHeader.data_offset + LongWord((l - 1) * FRecordSize), 0);
//Crypt
if Crypt.FActive then begin
Move(ActiveBuf^, FCryptBuff^, DBFHeader.rec_size);
Crypt.Encrypt(l, FCryptBuff, DBFHeader.rec_size);
RealRead := DBFHandler.Write(FCryptBuff^, DBFHeader.rec_size);
end else
RealRead := DBFHandler.Write(ActiveBuf^, DBFHeader.rec_size);
if RealRead = -1 then
begin
le := GetLastError();
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
nil,
le,
0, // Default language
lpMsgBuf,
500,
nil
);
raise Exception.Create('TVKSmartDBF: ' + lpMsgBuf);
end else begin
Move(ActiveBuf^, (FBuffer + GetCurIndByRec(l) * FRecordSize)^, FRecordSize);
if Indexes <> nil then
for i := 0 to Indexes.Count - 1 do begin
NewKey := Indexes[i].EvaluteKeyExpr;
if NewKey <> Indexes[i].FOldEditKey then begin
//if (Indexes.ActiveObject <> nil) and
// (Indexes.ActiveObject = Indexes[i]) and
// (Indexes[i].IsRanged) and
// (not Indexes[i].InRange(NewKey)) then b := true;
if not (
( (FAccessMode.FLast and fmShareExclusive) = fmShareExclusive ) or
( (FAccessMode.FLast and fmShareDenyWrite) = fmShareDenyWrite ) or
FFileLock
) then begin
if Indexes[i].FLock then
try
Indexes[i].StartUpdate(false);
Indexes[i].DeleteKey(Indexes[i].FOldEditKey, Indexes[i].FOldEditRec);
Indexes[i].AddKey(NewKey, l);
finally
Indexes[i].Flush;
Indexes[i].FUnLock;
end
else
raise Exception.Create('TDBFDataSet.InternalPost: Can not Delete/add key to index file (FLock is false).');
end else begin
if Indexes[i].FLock then
try
Indexes[i].DeleteKey(Indexes[i].FOldEditKey, Indexes[i].FOldEditRec);
Indexes[i].AddKey(NewKey, l);
finally
Indexes[i].FUnLock;
end
else
raise Exception.Create('TDBFDataSet.InternalPost: Can not Delete/add key to index file (FLock is false).');
end;
if ( Indexes.ActiveObject <> nil ) and
( Indexes.ActiveObject = Indexes[i] ) and
( Indexes.ActiveObject.IsUniqueIndex or Indexes.ActiveObject.IsForIndex ) and
( not FFastPostRecord ) then begin
r := Indexes.ActiveObject.FindKey(NewKey, true);
if r <> 0 then begin
if r <> l then begin
l := r;
GetBufferByRec(r);
end;
end else begin
InternalFirst;
b := true;
end;
end;
end;
end;
if not FFastPostRecord then
if not b then
RefreshBufferByRec(l);
Changed := True;
end;
finally
RUnLock(l);
DBFHandler.Seek(fOffset, 0);
end
else
raise Exception.Create('TVKSmartDBF.InternalPost: Can not lock DBF record.');
end else begin
InternalAddRecord(ActiveBuf, true);
end;
end;
procedure TVKSmartDBF.InternalSetToRecord(Buffer: PChar);
var
i: Longint;
begin
i := pTRecInfo(Buffer + RecordSize).RecordRowID;
InternalSetCurrentIndex(i);
GetBufferByRec(i);
end;
function TVKSmartDBF.IsCursorOpen: Boolean;
begin
Result := DBFHandler.IsOpen;
end;
procedure TVKSmartDBF.SetBookmarkData(Buffer: PChar; Data: Pointer);
begin
pTRecInfo(Buffer + RecordSize).RecordRowID := Longword(Data^);
end;
procedure TVKSmartDBF.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
begin
pTRecInfo(Buffer + RecordSize).BookmarkFlag := Value;
end;
procedure TVKSmartDBF.SetFieldData(Field: TField; Buffer: Pointer);
var
ss, ActiveBuf: pChar;
qq: TVKDBFFieldDef;
dd: double;
sTS: TTimeStamp;
Year, Month, Day: Word;
dInt: Integer;
dInt64: Int64;
dFloat: double;
dBool: WordBool;
q: String;
p0, p1, p2, p3: byte;
wE: boolean;
w: char;
i: Integer;
SLen: WORD;
WLen: Integer;
begin
if Field.ReadOnly and not (State in [dsSetKey, dsFilter]) then
DatabaseErrorFmt(SFieldReadOnly, [Field.DisplayName]);
Field.Validate(Buffer);
case Field.FieldKind of
fkData:
begin
qq := TVKDBFFieldDef(Pointer(Field.Tag));
GetActiveRecBuf(ActiveBuf);
if (ActiveBuf <> nil) then begin
if (Buffer <> nil) then begin
ss := ActiveBuf + qq.FOff;
case Field.DataType of
ftDataSet, ftMemo, ftFmtMemo, ftBlob:
begin
if ( qq.field_type = 'M' ) or
( ( qq.field_type = 'E' ) and
( qq.extend_type in [ dbftClob, dbftFmtMemo,
dbftBlob, dbftGraphic,
dbftDBFDataSet] )) then
Move(Buffer^, ss^, 10)
else
LongWord(Pointer(ss)^) := ( pLongWord(Buffer)^ or $80000000 );
end;
ftDate:
begin
if qq.field_type <> 'E' then begin
sTS.Date := pInteger(Buffer)^;
sTS.Time := 0;
dd := TimeStampToDateTime(sTS);
DecodeDate(dd, Year, Month, Day);
p0 := Year div 1000;
ss[0] := char( p0 + $30 );
p1 := (Year - p0 * 1000) div 100;
ss[1] := Char( p1 + $30 );
p2 := (Year - p0 * 1000 - p1 * 100) div 10;
ss[2] := Char( p2 + $30 );
p3 := (Year - p0 * 1000 - p1 * 100 - p2 * 10);
ss[3] := Char( p3 + $30 );
ss[4] := Char( (Month div 10) + $30 );
ss[5] := Char( (Month - (Month div 10) * 10 ) + $30 );
ss[6] := Char( (Day div 10) + $30 );
ss[7] := Char( (Day - (Day div 10) * 10) + $30 );
(*
dd := double(Buffer^);
sTS.Date := Trunc(dd/(3600.0*24*1000));
sTS.Time := Trunc(dd - sTS.Date*((3600.0*24*1000)));
dd := TimeStampToDateTime(sTS);
DecodeDate(dd, Year, Month, Day);
p0 := Year div 1000;
ss[0] := char( p0 + $30 );
p1 := (Year - p0 * 1000) div 100;
ss[1] := Char( p1 + $30 );
p2 := (Year - p0 * 1000 - p1 * 100) div 10;
ss[2] := Char( p2 + $30 );
p3 := (Year - p0 * 1000 - p1 * 100 - p2 * 10);
ss[3] := Char( p3 + $30 );
ss[4] := Char( (Month div 10) + $30 );
ss[5] := Char( (Month - (Month div 10) * 10 ) + $30 );
ss[6] := Char( (Day div 10) + $30 );
ss[7] := Char( (Day - (Day div 10) * 10) + $30 );
*)
end else begin
case qq.extend_type of
dbftDate: pInteger(ss)^ := pInteger(Buffer)^;
dbftDate_N:
begin
Byte(Pointer(ss)^) := 1;
pInteger(ss + 1)^ := pInteger(Buffer)^;
end;
dbftDate_NB: LongWord(Pointer(ss)^) := ( pLongWord(Buffer)^ or $80000000 );
end;
end;
end;
ftTime:
begin
case qq.extend_type of
dbftTime: pInteger(ss)^ := pInteger(Buffer)^;
dbftTime_N:
begin
Byte(Pointer(ss)^) := 1;
pInteger(ss + 1)^ := pInteger(Buffer)^;
end;
dbftTime_NB: LongWord(Pointer(ss)^) := ( pLongWord(Buffer)^ or $80000000 );
end;
end;
ftBCD:
begin
pBcd(ss)^ := pBcd(Buffer)^;
Byte(ss[1]) := ( Byte(ss[1]) or $40 );
end;
ftCurrency:
begin
case qq.extend_type of
dbftCurrency: Currency(Pointer(ss)^) := pCurrency(Buffer)^;
dbftCurrency_N:
begin
Byte(Pointer(ss)^) := 1;
Currency(Pointer(ss + 1)^) := pCurrency(Buffer)^;
end;
dbftCurrency_NB:
begin
Currency(Pointer(ss)^) := pCurrency(Buffer)^;
Byte(Pointer(ss + 7)^) := ( pByte(ss + 7)^ or $80 );
end;
end;
end;
ftWideString:
begin
WLen := pInteger(Buffer)^;
Move(Buffer^, ss^, WLen + 6);
end;
ftString:
begin
if qq.field_type <> 'E' then begin
if FullLengthCharFieldCopy then
StrMove(ss, Buffer, qq.FLen)
else begin
wE := false;
for i := 0 to qq.FLen - 1 do
begin
w := pChar(Buffer)[i];
if w = #0 then
wE := true;
if not wE then
ss[i] := w
else
ss[i] := ' ';
end;
end;
end else begin
case qq.extend_type of
dbftString:
begin
SLen := StrLen(Buffer);
WORD(Pointer(ss)^) := SLen;
ss := ss + SizeOf(WORD);
Move(Buffer^, ss^, SLen);
end;
dbftString_N:
begin
Byte(Pointer(ss)^) := 1;
SLen := StrLen(Buffer);
ss := ss + 1;
WORD(Pointer(ss)^) := SLen;
ss := ss + SizeOf(WORD);
Move(Buffer^, ss^, SLen);
end;
dbftFixedChar:
begin
SLen := StrLen(Buffer);
Move(Buffer^, ss^, SLen);
ss[SLen] := #0;
end;
end;
end;
end;
ftDateTime:
begin
case qq.extend_type of
dbftD1:
begin
dd := double(Buffer^);
sTS.Date := Trunc(dd/(3600.0*24*1000));
sTS.Time := Trunc(dd - sTS.Date*((3600.0*24*1000)));
dd := TimeStampToDateTime(sTS);
Double(Pointer(ss)^) := Double(dd);
end;
dbftD1_NB:
begin
dd := double(Buffer^);
sTS.Date := Trunc(dd/(3600.0*24*1000));
sTS.Time := Trunc(dd - sTS.Date*((3600.0*24*1000)));
dd := TimeStampToDateTime(sTS);
Double(Pointer(ss)^) := Double(dd);
Byte(Pointer(ss + 7)^) := ( pByte(ss + 7)^ or $80 );
end;
dbftD2: Double(Pointer(ss)^) := pDouble(Buffer)^;
dbftD2_NB:
begin
Double(Pointer(ss)^) := pDouble(Buffer)^;
Byte(Pointer(ss + 7)^) := ( pByte(ss + 7)^ or $80 );
end;
dbftD3:
begin
dd := double(Buffer^);
sTS.Date := Trunc(dd/(3600.0*24*1000));
sTS.Time := Trunc(dd - sTS.Date*((3600.0*24*1000)));
dd := TimeStampToDateTime(sTS);
Real48(Pointer(ss)^) := Double(dd);
end;
dbftD3_NB:
begin
Real48(Pointer(ss)^) := pDouble(Buffer)^;
Byte(Pointer(ss + 5)^) := ( pByte(ss + 5)^ or $80 );
end;
dbftD1_N:
begin
dd := double(Buffer^);
sTS.Date := Trunc(dd/(3600.0*24*1000));
sTS.Time := Trunc(dd - sTS.Date*((3600.0*24*1000)));
dd := TimeStampToDateTime(sTS);
Byte(Pointer(ss)^) := 1;
Double(Pointer(ss + 1)^) := Double(dd);
end;
dbftD2_N:
begin
Byte(Pointer(ss)^) := 1;
Double(Pointer(ss + 1)^) := pDouble(Buffer)^;
end;
dbftD3_N:
begin
dd := double(Buffer^);
sTS.Date := Trunc(dd/(3600.0*24*1000));
sTS.Time := Trunc(dd - sTS.Date*((3600.0*24*1000)));
dd := TimeStampToDateTime(sTS);
Byte(Pointer(ss)^) := 1;
Real48(Pointer(ss + 1)^) := Double(dd);
end;
end;
end;
ftSmallint:
begin
case qq.extend_type of
dbftS1: Shortint(Pointer(ss)^) := pShortint(Buffer)^;
dbftS2: Smallint(Pointer(ss)^) := pSmallint(Buffer)^;
dbftS1_N: //Shortint with NULL
begin
Byte(Pointer(ss)^) := 1;
Shortint(Pointer(ss + 1)^) := pShortint(Buffer)^;
end;
dbftS2_N: //Smallint with NULL
begin
Byte(Pointer(ss)^) := 1;
Smallint(Pointer(ss + 1)^) := pSmallint(Buffer)^;
end;
end;
end;
ftWord:
begin
case qq.extend_type of
dbftU1: Byte(Pointer(ss)^) := pByte(Buffer)^;
dbftU2: Word(Pointer(ss)^) := pWord(Buffer)^;
dbftU1_N:
begin
Byte(Pointer(ss)^) := 1;
Byte(Pointer(ss + 1)^) := pByte(Buffer)^;
end;
dbftU2_N:
begin
Byte(Pointer(ss)^) := 1;
Word(Pointer(ss + 1)^) := pWord(Buffer)^;
end;
dbftU1_NB: Byte(Pointer(ss)^) := ( pByte(Buffer)^ or $80 );
dbftU2_NB: Word(Pointer(ss)^) := ( pWord(Buffer)^ or $8000 );
end;
end;
ftInteger:
begin
if qq.field_type <> 'E' then begin
dInt := Integer(Buffer^);
Str(dInt:qq.FLen, q);
Move(pChar(q)^, ss^, qq.FLen);
end else begin
case qq.extend_type of
dbftS4, dbftU4: //Longint, Longword
begin
Integer(Pointer(ss)^) := pInteger(Buffer)^;
end;
dbftS4_N, dbftU4_N: //Longint with NULL, Longword with NULL
begin
Byte(Pointer(ss)^) := 1;
Integer(Pointer(ss + 1)^) := pInteger(Buffer)^;
end;
dbftU4_NB: LongWord(Pointer(ss)^) := ( pLongWord(Buffer)^ or $80000000 );
end;
end;
end;
ftLargeint:
begin
if qq.field_type <> 'E' then begin
dInt64 := Int64(Buffer^);
Str(dInt64:qq.FLen, q);
Move(pChar(q)^, ss^, qq.FLen);
end else begin
case qq.extend_type of
dbftS8: Int64(Pointer(ss)^) := pInt64(Buffer)^;
dbftS8_N:
begin
Byte(Pointer(ss)^) := 1;
Int64(Pointer(ss + 1)^) := pInt64(Buffer)^;
end;
end;
end;
end;
ftFloat:
begin
if qq.field_type <> 'E' then begin
dFloat := Double(Buffer^);
Str(dFloat:qq.Flen:qq.Fdec, q);
Move(pChar(q)^, ss^, qq.FLen);
end else begin
case qq.extend_type of
dbftR4: Single(Pointer(ss)^) := pDouble(Buffer)^;
dbftR4_NB:
begin
Single(Pointer(ss)^) := pDouble(Buffer)^;
Byte(Pointer(ss + 3)^) := ( pByte(ss + 3)^ or $80 );
end;
dbftR6_NB:
begin
Real48(Pointer(ss)^) := pDouble(Buffer)^;
Byte(Pointer(ss + 5)^) := ( pByte(ss + 5)^ or $80 );
end;
dbftR8_NB:
begin
Double(Pointer(ss)^) := pDouble(Buffer)^;
Byte(Pointer(ss + 7)^) := ( pByte(ss + 7)^ or $80 );
end;
dbftR6: Real48(Pointer(ss)^) := pDouble(Buffer)^;
dbftR8: Double(Pointer(ss)^) := pDouble(Buffer)^;
dbftR10: Extended(Pointer(ss)^) := pExtended(Buffer)^;
dbftR4_N:
begin
Byte(Pointer(ss)^) := 1;
Single(Pointer(ss + 1)^) := pDouble(Buffer)^;
end;
dbftR6_N:
begin
Byte(Pointer(ss)^) := 1;
Real48(Pointer(ss + 1)^) := pDouble(Buffer)^;
end;
dbftR8_N:
begin
Byte(Pointer(ss)^) := 1;
Double(Pointer(ss + 1)^) := pDouble(Buffer)^;
end;
dbftR10_N:
begin
Byte(Pointer(ss)^) := 1;
Extended(Pointer(ss + 1)^) := pExtended(Buffer)^;
end;
end;
end;
end;
ftBoolean:
begin
dBool := WordBool(Buffer^);
if dBool then
ss[0] := 'T'
else
ss[0] := 'F';
end;
end;
end else begin
ss := ActiveBuf + qq.FOff;
if qq.field_type <> 'E' then begin
for i := 0 to qq.FLen - 1 do ss[i] := ' ';
end else begin
case qq.extend_type of
dbftS1_N, //Shortint with NULL
dbftU1_N, //Byte with NULL
dbftS2_N, //Smallint with NULL
dbftU2_N, //Word with NULL
dbftS4_N, //Longint with NULL
dbftU4_N, //Longword with NULL
dbftS8_N, //Int64 with NULL
dbftR4_N, //Single with NULL
dbftR6_N, //Real48 with NULL
dbftR8_N, //Double with NULL
dbftR10_N, //Extended with NULL
dbftD1_N, //TDateTime
dbftD2_N, //DataSet DateTime
dbftD3_N, //Real48 DateTime
dbftString_N, //String
dbftString,
dbftCurrency_N,
dbftBCD,
dbftDate_N,
dbftTime_N:
begin
ss[0] := ' ';
ss[1] := ' ';
end;
dbftFixedChar: for i := 0 to qq.FLen do ss[i] := ' ';
dbftU1_NB: Byte(Pointer(ss)^) := ( pByte(ss)^ and $7F );
dbftU2_NB: Word(Pointer(ss)^) := ( pWord(ss)^ and $7FFF );
dbftU4_NB: Longword(Pointer(ss)^) := ( pLongword(ss)^ and $7FFFFFFF );
dbftR4_NB: Byte(Pointer(ss + 3)^) := ( pByte(ss + 3)^ and $7F );
dbftR6_NB: Byte(Pointer(ss + 5)^) := ( pByte(ss + 5)^ and $7F );
dbftR8_NB: Byte(Pointer(ss + 7)^) := ( pByte(ss + 7)^ and $7F );
dbftCurrency_NB: Byte(Pointer(ss + 7)^) := ( pByte(ss + 7)^ and $7F );
dbftD1_NB: Byte(Pointer(ss + 7)^) := ( pByte(ss + 7)^ and $7F );
dbftD2_NB: Byte(Pointer(ss + 7)^) := ( pByte(ss + 7)^ and $7F );
dbftD3_NB: Byte(Pointer(ss + 5)^) := ( pByte(ss + 5)^ and $7F );
dbftDate_NB: Longword(Pointer(ss)^) := ( pLongword(ss)^ and $7FFFFFFF );
dbftTime_NB: Longword(Pointer(ss)^) := ( pLongword(ss)^ and $7FFFFFFF );
dbftClob, dbftFmtMemo, dbftBlob, dbftGraphic, dbftDBFDataSet: for i := 0 to qq.FLen do ss[i] := ' ';
dbftClob_NB, dbftFmtMemo_NB, dbftBlob_NB, dbftGraphic_NB, dbftDBFDataSet_NB: LongWord(Pointer(ss)^) := ( pLongWord(ss)^ and $7FFFFFFF );
end;
end;
end;
end;
end;
fkCalculated:
begin
GetActiveRecBuf(ActiveBuf);
if ActiveBuf <> nil then begin
ss := ActiveBuf + FRecordSize + sizeof(TRecInfo) + Field.Offset;
if Buffer <> nil then
Move(Buffer^, ss^, Field.DataSize)
else
FillChar(ss^, Field.DataSize, ' ');
end;
end;
end;
if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
DataEvent(deFieldChange, Longint(Field));
end;
procedure TVKSmartDBF.SetFiltered(Value: Boolean);
begin
if Active then
begin
CheckBrowseMode;
if ((not Filtered) and Value) and (Filter <> '') then
FFilterParser.SetExprParams(Filter, FilterOptions, [poExtSyntax], '');
if Filtered <> Value then begin
inherited SetFiltered(Value);
Refresh;
end;
end else
inherited SetFiltered(Value);
end;
procedure TVKSmartDBF.SetIndexList(const Value: TIndexes);
begin
FIndexes.Assign(Value);
end;
procedure TVKSmartDBF.SetRecNo(Value: Integer);
begin
CheckBrowseMode;
if AcceptTmpRecord(Value) then SetRecNoInternal(Value);
end;
procedure TVKSmartDBF.SetSetDeleted(const Value: Boolean);
begin
if Active then
begin
CheckBrowseMode;
if FSetDeleted <> Value then FSetDeleted := Value;
Refresh;
end else
FSetDeleted := Value;
end;
function TVKSmartDBF.TranslateBuff(Src, Dest: PChar; ToOem: Boolean;
Len: Integer): Integer;
begin
if FOEM then
begin
if not ToOem then begin
if (Src <> nil) then
begin
if OemToCharBuff(Src, Dest, Len) then
Result := Len
else
Result := 0;
end else
Result := 0;
end else begin
if (Src <> nil) then
begin
if CharToOemBuff(Src, Dest, Len) then
Result := Len
else
Result := 0;
end else
Result := 0;
end;
end else
Result := Translate(Src, Dest, ToOem);
end;
function TVKSmartDBF.Translate(Src, Dest: PChar; ToOem: Boolean): Integer;
begin
if FOEM then
begin
if not ToOem then begin
if (Src <> nil) then
begin
if OemToChar(Src, Dest) then
Result := StrLen(Dest)
else
Result := 0;
end else
Result := 0;
end else begin
if (Src <> nil) then
begin
if CharToOem(Src, Dest) then
Result := StrLen(Dest)
else
Result := 0;
end else
Result := 0;
end;
end else
Result := inherited Translate(Src, Dest, ToOem);
end;
procedure TVKSmartDBF.DefineProperties(Filer: TFiler);
function WriteData: Boolean;
begin
if FIndexes <> nil then begin
if Filer.Ancestor <> nil then
Result := not FIndexes.IsEqual(TVKSmartDBF(Filer.Ancestor).FIndexes)
else
Result := (FIndexes.Count > 0);
end else
Result := false;
end;
begin
inherited DefineProperties(Filer);
Filer.DefineProperty('IndexData', ReadIndexData, WriteIndexData, WriteData);
end;
procedure TVKSmartDBF.ReadIndexData(Reader: TReader);
begin
if Indexes <> nil then begin
Reader.ReadValue;
Reader.ReadCollection(Indexes);
end;
end;
procedure TVKSmartDBF.WriteIndexData(Writer: TWriter);
begin
if Indexes <> nil then
Writer.WriteCollection(Indexes);
end;
function TVKSmartDBF.FirstByIndex(IndInd: Integer): TGetResult;
var
i: Integer;
begin
CheckBrowseMode;
CursorPosChanged;
DoBeforeScroll;
Result := grError;
if FIndexes <> nil then begin
Result := FIndexes[IndInd].GetFirstByIndex(i);
if Result = grOK then begin
GetBufferByRec(i);
Resync([]);
end;
end;
DoAfterScroll;
end;
function TVKSmartDBF.LastByIndex(IndInd: Integer): TGetResult;
var
i: Integer;
begin
CheckBrowseMode;
CursorPosChanged;
DoBeforeScroll;
Result := grError;
if FIndexes <> nil then begin
Result := FIndexes[IndInd].GetLastByIndex(i);
if Result = grOK then begin
GetBufferByRec(i);
Resync([]);
end;
end;
DoAfterScroll;
end;
function TVKSmartDBF.NextByIndex(IndInd: Integer): TGetResult;
var
i: Integer;
begin
CheckBrowseMode;
CursorPosChanged;
DoBeforeScroll;
Result := grError;
if FIndexes <> nil then begin
FIndexes[IndInd].SetToRecord;
Result := FIndexes[IndInd].GetRecordByIndex(gmNext, i);
if Result = grOK then begin
GetBufferByRec(i);
Resync([]);
end;
end;
DoAfterScroll;
end;
function TVKSmartDBF.PriorByIndex(IndInd: Integer): TGetResult;
var
i: Integer;
begin
CheckBrowseMode;
CursorPosChanged;
DoBeforeScroll;
Result := grError;
if FIndexes <> nil then begin
FIndexes[IndInd].SetToRecord;
Result := FIndexes[IndInd].GetRecordByIndex(gmPrior, i);
if Result = grOK then begin
GetBufferByRec(i);
Resync([]);
end;
end;
DoAfterScroll;
end;
function TVKSmartDBF.GetPrec(aField: TField): Integer;
begin
//Result := (DBFFieldDefs.Items[aField.FieldNo - 1]).Fdec;
Result := TVKDBFFieldDef(Pointer(aField.Tag)).Fdec;
end;
function TVKSmartDBF.GetLen(aField: TField): Integer;
begin
//Result := (DBFFieldDefs.Items[aField.FieldNo - 1]).Flen;
Result := TVKDBFFieldDef(Pointer(aField.Tag)).Flen;
end;
function TVKSmartDBF.NextBuffer: Longint;
var
i, RealRead: Integer;
OldIndex, NextRec: Longint;
OldKey: String;
OldRec: Longint;
end1a: char;
begin
if FBufCnt > 0 then begin
if (FIndexes = nil) or (FIndexes.ActiveObject = nil) then begin
if FBufDir = bdFromTop then
NextRec := pLongint(pChar(FBufInd) + SizeOf(Longint)*(FBufCnt - 1))^
else
NextRec := pLongint(pChar(FBufInd) + SizeOf(Longint)*(FRecordsPerBuf - 1))^;
DBFHandler.Seek(DBFHeader.data_offset + NextRec * FRecordSize, soFromBeginning);
end1a := FBuffer[0];
RealRead := DBFHandler.Read(FBuffer^, FRecordsPerBuf * FRecordSize);
Result := RealRead div FRecordSize;
if Result > 0 then begin
FBufCnt := Result;
FBufDir := bdFromTop;
FCurInd := 0;
for i := 0 to FBufCnt - 1 do begin
pLongint(pChar(FBufInd) + SizeOf(Longint) * i)^ := NextRec + i + 1;
if Crypt.FActive then
Crypt.Decrypt(NextRec + i + 1, Pointer(FBuffer + i * FRecordSize), FRecordSize);
end;
end else
FBuffer[0] := end1a;
end else begin
//Next buffer by index
OldIndex := FCurInd;
OldKey := FIndexes.ActiveObject.CurrentKey;
OldRec := FIndexes.ActiveObject.CurrentRec;
if FBufDir = bdFromTop then
FCurInd := FBufCnt - 1
else
FCurInd := FRecordsPerBuf - 1;
FKeyCalk := true;
try
FIndexes.ActiveObject.SetToRecord(pLongint(pChar(FBufInd) + SizeOf(Longint)*FCurInd)^);
finally
FKeyCalk := false;
end;
// Result := 0;
if FIndexes.ActiveObject.FLock then
try
Result := FIndexes.ActiveObject.NextBuffer(DBFHandler, FBuffer, FRecordsPerBuf, FRecordSize, FBufInd, DBFHeader.data_offset);
finally
FIndexes.ActiveObject.FUnLock;
end
else
raise Exception.Create('TDBFDataSet: Can not read from index file (FLock is false).');
if Result > 0 then begin
FBufCnt := Result;
FBufDir := bdFromTop;
FCurInd := 0;
end else begin
FCurInd := OldIndex;
FIndexes.ActiveObject.SetToRecord(OldKey, OldRec);
end;
end;
end else Result := 0;
end;
function TVKSmartDBF.PriorBuffer: Longint;
var
j: Longint;
i: Integer;
OldIndex, NextRec: Longint;
OldKey: String;
OldRec: Longint;
begin
if FBufCnt > 0 then begin
if (FIndexes = nil) or (FIndexes.ActiveObject = nil) then begin
if FBufDir = bdFromTop then
NextRec := FBufInd^
else
NextRec := pLongint(pChar(FBufInd) + (FRecordsPerBuf - FBufCnt) * SizeOf(Longint))^;
j := NextRec - FRecordsPerBuf;
if j < 1 then j := 1;
Result := NextRec - j;
if Result > 0 then begin
FBufCnt := Result;
DBFHandler.Seek(DBFHeader.data_offset + ((j - 1) * FRecordSize), soFromBeginning);
DBFHandler.Read((FBuffer + (FRecordsPerBuf - FBufCnt) * FRecordSize)^, FBufCnt * FRecordSize);
FBufDir := bdFromBottom;
FCurInd := FRecordsPerBuf - 1;
for i := 0 to FBufCnt - 1 do begin
pLongint(pChar(FBufInd) + (FRecordsPerBuf - i - 1) * SizeOf(LongInt))^ := NextRec - i - 1;
if Crypt.FActive then
Crypt.Decrypt(NextRec - i - 1, Pointer(FBuffer + (FRecordsPerBuf - i - 1) * FRecordSize), FRecordSize);
end;
end;
end else begin
//Prior buffer by index
OldIndex := FCurInd;
OldKey := FIndexes.ActiveObject.CurrentKey;
OldRec := FIndexes.ActiveObject.CurrentRec;
if FBufDir = bdFromTop then
FCurInd := 0
else
FCurInd := FRecordsPerBuf - FBufCnt;
FKeyCalk := true;
try
FIndexes.ActiveObject.SetToRecord(pLongint(pChar(FBufInd) + SizeOf(Longint)*FCurInd)^);
finally
FKeyCalk := false;
end;
// Result := 0;
if FIndexes.ActiveObject.FLock then
try
Result := FIndexes.ActiveObject.PriorBuffer(DBFHandler, FBuffer, FRecordsPerBuf, FRecordSize, FBufInd, DBFHeader.data_offset);
finally
FIndexes.ActiveObject.FUnLock;
end
else
raise Exception.Create('TDBFDataSet: Can not read from index file (FLock is false).');
if Result > 0 then begin
FBufCnt := Result;
FBufDir := bdFromBottom;
FCurInd := FRecordsPerBuf - 1;
FIndexes.ActiveObject.SetToRecord;
end else begin
FCurInd := OldIndex;
FIndexes.ActiveObject.SetToRecord(OldKey, OldRec);
end;
end;
end else Result := 0;
end;
procedure TVKSmartDBF.GetBufferByRec(Rec: Integer);
var
i, RealRead: Integer;
NewRec: Longint;
Result: Longint;
begin
if (FIndexes = nil) or (FIndexes.ActiveObject = nil) then begin
NewRec := Rec - ( FRecordsPerBuf div 2);
if NewRec < 1 then NewRec := 1;
DBFHandler.Seek(DBFHeader.data_offset + (NewRec - 1) * FRecordSize, soFromBeginning);
RealRead := DBFHandler.Read(FBuffer^, FRecordsPerBuf * FRecordSize);
FBufCnt := RealRead div FRecordSize;
if FBufCnt = 0 then begin
FBOF := true;
FEOF := true;
end else begin
FBOF := false;
FEOF := false;
FCurInd := 0;
end;
FBufDir := bdFromTop;
for i := 0 to FBufCnt - 1 do begin
pLongint(pChar(FBufInd) + i * SizeOf(Longint))^ := NewRec + i;
if pLongint(pChar(FBufInd) + SizeOf(Longint)*i)^ = Rec then
FCurInd := i;
if Crypt.FActive then
Crypt.Decrypt(NewRec + i, Pointer(FBuffer + i * FRecordSize), FRecordSize);
end;
end else begin
if Rec < 1 then Rec := 1;
DBFHandler.Seek(DBFHeader.data_offset + (Rec - 1) * FRecordSize, soFromBeginning);
RealRead := DBFHandler.Read(FBuffer^, FRecordSize);
if Crypt.FActive then
Crypt.Decrypt(Rec, Pointer(FBuffer), FRecordSize);
if RealRead = FRecordSize then begin
FBufInd^ := Rec;
FCurInd := 0;
FBufDir := bdFromTop;
FKeyCalk := true;
try
if not FIndexes.ActiveObject.SetToRecord(Rec) then begin
FCurInd := -1;
FBufDir := bdFromTop;
FBufCnt := 0;
FBOF := true;
FEOF := true;
Exit;
end else begin
FBOF := false;
FEOF := false;
end;
finally
FKeyCalk := false;
end;
if FIndexes.ActiveObject.CurrentRec <> DWORD(Rec) then begin
Rec := FIndexes.ActiveObject.CurrentRec;
DBFHandler.Seek(DBFHeader.data_offset + (Rec - 1) * FRecordSize, soFromBeginning);
DBFHandler.Read(FBuffer^, FRecordSize);
if Crypt.FActive then
Crypt.Decrypt(Rec, Pointer(FBuffer), FRecordSize);
FBufInd^ := Rec;
FCurInd := 0;
end;
// Result := 0;
if FIndexes.ActiveObject.FLock then
try
Result := FIndexes.ActiveObject.NextBuffer(DBFHandler, FBuffer + FRecordSize, FRecordsPerBuf - 1, FRecordSize, pLongint(pChar(FBufInd) + SizeOf(Longint)), DBFHeader.data_offset);
finally
FIndexes.ActiveObject.FUnLock;
end
else
raise Exception.Create('TDBFDataSet: Can not read from index file (FLock is false).');
FBufCnt := Result + 1
end else begin
FCurInd := -1;
FBufDir := bdFromTop;
FBufCnt := 0;
FBOF := true;
FEOF := true;
end;
end;
end;
function TVKSmartDBF.GetRecBuf: pChar;
begin
if ( 0 <= FCurInd ) and ( FCurInd <= FRecordsPerBuf ) then
Result := FBuffer + FCurInd * FRecordSize
else
Result := nil;
end;
procedure TVKSmartDBF.NextIndexBuf;
begin
FBOF := false;
Inc(FCurInd);
if FBufDir = bdFromTop then begin
if FCurInd >= FBufCnt then if NextBuffer = 0 then begin
FCurInd := FBufCnt;
FEOF := true;
end;
end else begin
if FCurInd >= FRecordsPerBuf then if NextBuffer = 0 then begin
FCurInd := FRecordsPerBuf;
FEOF := true;
end;
end;
end;
procedure TVKSmartDBF.PriorIndexBuf;
begin
FEOF := false;
Dec(FCurInd);
if FBufDir = bdFromTop then begin
if FCurInd < 0 then if PriorBuffer = 0 then begin
//FCurInd := 0;
FBOF := true;
end;
end else begin
if FCurInd < FRecordsPerBuf - FBufCnt then if PriorBuffer = 0 then begin
//FCurInd := FRecordsPerBuf - FBufCnt;
FBOF := true;
end;
end;
end;
function TVKSmartDBF.GetRecNoBuf: Longint;
begin
Result := pLongint(pChar(FBufInd) + (FCurInd)*SizeOf(Longint))^;
end;
function TVKSmartDBF.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
procedure TVKSmartDBF.SetDataSource(const Value: TDataSource);
begin
FDataLink.DataSource := Value;
SetRngInt;
end;
procedure TVKSmartDBF.SetRngInt;
begin
if FDataLink.DataSource <> nil then begin
if FMasterFields <> '' then begin
if FRange then ClearRange;
FRange := true;
ListMasterFields.Clear;
if FDataLink.DataSource.DataSet <> nil then begin
if FDataLink.DataSource.DataSet.Active then begin
FDataLink.DataSource.DataSet.GetFieldList(ListMasterFields, FMasterFields);
SetRange(FMasterFields, GetMasterFields);
end;
end;
end;
end;
end;
function TVKSmartDBF.RLock: Boolean;
begin
Result := RLock(RecNo);
end;
function TVKSmartDBF.RLock(nRec: Integer): Boolean;
var
i, k: Integer;
l: boolean;
begin
if FFileLock then
Result := true
else begin
k := FLockRecords.IndexOf(Pointer(nRec));
if k = -1 then begin
l := ( ( (FAccessMode.FLast and fmShareExclusive) = fmShareExclusive ) or ( (FAccessMode.FLast and fmShareDenyWrite) = fmShareDenyWrite ) );
if not l then begin
i := 0;
repeat
Result := DBFHandler.Lock(1000000000 + nRec, 1);
if not Result then begin
Wait(0.001, false);
Inc(i);
if i >= FWaitBusyRes then Exit;
end else
FLockRecords.Add(Pointer(nRec));
until Result;
end else
Result := true;
end else
Result := true;
end;
end;
function TVKSmartDBF.RUnLock: Boolean;
begin
Result := RUnLock(RecNo);
end;
function TVKSmartDBF.RUnLock(nRec: Integer): Boolean;
var
l: boolean;
k: Integer;
begin
l := ( ( (FAccessMode.FLast and fmShareExclusive) = fmShareExclusive ) or ( (FAccessMode.FLast and fmShareDenyWrite) = fmShareDenyWrite ) );
if not l then begin
Result := DBFHandler.UnLock(1000000000 + nRec, 1);
if Result then begin
k := FLockRecords.IndexOf(Pointer(nRec));
if k <> -1 then FLockRecords.Delete(k);
end;
end else
Result := true;
end;
function TVKSmartDBF.LockHeader: boolean;
var
i: Integer;
l: boolean;
begin
i := 0;
l := ( ( (FAccessMode.FLast and fmShareExclusive) = fmShareExclusive ) or ( (FAccessMode.FLast and fmShareDenyWrite) = fmShareDenyWrite ) );
repeat
if not l then begin
Result := DBFHandler.Lock(1000000000, 1);
if not Result then begin
Wait(0.001, false);
Inc(i);
if i >= FWaitBusyRes then Exit;
end;
end else
Result := true;
until Result;
end;
function TVKSmartDBF.UnlockHeader: boolean;
var
l: boolean;
begin
l := ( ( (FAccessMode.FLast and fmShareExclusive) = fmShareExclusive ) or ( (FAccessMode.FLast and fmShareDenyWrite) = fmShareDenyWrite ) );
if not l then
Result := DBFHandler.UnLock(1000000000, 1)
else
Result := true;
end;
function TVKSmartDBF.GetCurIndByRec(nRec: Integer): Integer;
var
i: Integer;
begin
Result := 0;
if FBufDir = bdFromTop then begin
for i := 0 to FBufCnt - 1 do
if pLongint(pChar(FBufInd) + SizeOf(Longint)*i)^ = nRec then begin
Result := i;
Break;
end;
end else begin
for i := 0 to FBufCnt - 1 do
if pLongint(pChar(FBufInd) + (FRecordsPerBuf - i - 1) * SizeOf(LongInt))^ = nRec then begin
Result := (FRecordsPerBuf - i - 1);
Break;
end;
end;
end;
function TVKSmartDBF.FLock: Boolean;
var
i: Integer;
l: boolean;
begin
Result := false;
if FFileLock then begin
Result := true;
Exit;
end else begin
try
i := 0;
l := ( ( (FAccessMode.FLast and fmShareExclusive) = fmShareExclusive ) or ( (FAccessMode.FLast and fmShareDenyWrite) = fmShareDenyWrite ) );
repeat
if not l then begin
Result := DBFHandler.Lock(1000000001, 1000000000);
if not Result then begin
Wait(0.001, false);
Inc(i);
if i = FWaitBusyRes then Exit;
end;
end else
Result := true;
until Result;
finally
FFileLock := Result;
end;
if FFileLock then
if Indexes <> nil then
for i := 0 to Indexes.Count - 1 do Indexes[i].StartUpdate;
end;
end;
function TVKSmartDBF.UnLock: Boolean;
var
l: boolean;
i: Integer;
begin
l := ( ( (FAccessMode.FLast and fmShareExclusive) = fmShareExclusive ) or ( (FAccessMode.FLast and fmShareDenyWrite) = fmShareDenyWrite ) );
if not l then
Result := DBFHandler.UnLock(1000000001, 1000000000)
else
Result := true;
FFileLock := not Result;
if Indexes <> nil then
for i := 0 to Indexes.Count - 1 do Indexes[i].Flush;
end;
procedure TVKSmartDBF.InternalEdit;
var
i, l: Integer;
ActiveBuf: pChar;
begin
GetActiveRecBuf(ActiveBuf);
l := pTRecInfo(ActiveBuf + RecordSize).RecordRowID;
if Indexes <> nil then
for i := 0 to Indexes.Count - 1 do begin
Indexes[i].FOldEditKey := Indexes[i].EvaluteKeyExpr;
Indexes[i].FOldEditRec := l;
end;
end;
procedure TVKSmartDBF.InternalRefresh;
var
ActiveBuf: pChar;
Rec: Longint;
begin
GetActiveRecBuf(ActiveBuf);
if ActiveBuf <> nil then begin
Rec := pTRecInfo(ActiveBuf + RecordSize).RecordRowID;
GetBufferByRec(Rec);
end;
end;
procedure TVKSmartDBF.SetOrder(nOrd: Integer);
begin
if (FIndexes <> nil) then begin
if ( nOrd = 0 ) and ( FIndexes.ActiveObject <> nil ) then
FIndexes.ActiveObject.Active := false;
if (( nOrd - 1 ) >= 0 ) and ( ( nOrd - 1 ) < FIndexes.Count ) then
FIndexes[nOrd - 1].Active := true;
end;
end;
procedure TVKSmartDBF.SetOrder(sOrd: ShortString);
var
i: Integer;
begin
if (FIndexes <> nil) then begin
for i := 0 to FIndexes.Count - 1 do
if UpperCase(FIndexes[i].Name) = UpperCase(sOrd) then
FIndexes[i].Active := true;
end;
end;
function TVKSmartDBF.GetCreateNow: Boolean;
begin
Result := FCreateNow;
end;
procedure TVKSmartDBF.SetCreateNow(const Value: Boolean);
begin
if (csReading in ComponentState) then
begin
FStreamedCreateNow := Value;
end else begin
if Value then begin
CreateTable;
if (csDesigning in ComponentState)
and (not (csLoading in ComponentState)) then
ShowMessage(Format('Table %s create successfully!', [DBFFileName]));
end;
FCreateNow := Value;
end;
end;
function TVKSmartDBF.LocateRecord( const KeyFields: string;
const KeyValues: Variant;
Options: TLocateOptions;
nRec: DWORD = 1;
FullScanOnly: boolean = false): Integer;
var
m, i, j, k, l, n, p, o: Integer;
FFields: TList;
procedure CntFld;
var
I: Integer;
begin
I := p;
while (I <= Length(KeyFields)) and (KeyFields[I] <> ';') do Inc(I);
Inc(o);
if (I <= Length(KeyFields)) and (KeyFields[I] = ';') then Inc(I);
p := I;
end;
function LocatePass: Integer;
var
RecPareBuf, i: Integer;
ReadSize, RealRead, BufCnt: Integer;
Ok: boolean;
Rec: Integer;
//
LowV, HiV, vj: Integer;
//
begin
IndState := true;
Result := 0;
Rec := nRec - 1;
Ok := false;
// Check empty KeyValues
if VarIsEmpty(KeyValues) or VarIsNull(KeyValues) then Exit;
if VarIsArray(KeyValues) then begin
LowV := VarArrayLowBound(KeyValues, 1);
HiV := VarArrayHighBound(KeyValues, 1);
for vj := LowV to HiV do begin
if VarIsEmpty(KeyValues[vj]) or VarIsNull(KeyValues[vj]) then Exit;
end;
end;
//
try
RecPareBuf := FBufferSize div Header.rec_size;
if RecPareBuf >= 1 then begin
ReadSize := RecPareBuf * Header.rec_size;
Handle.Seek(Header.data_offset + ((nRec - 1) * Header.rec_size), 0);
repeat
RealRead := Handle.Read(FLocateBuffer^, ReadSize);
BufCnt := RealRead div Header.rec_size;
for i := 0 to BufCnt - 1 do begin
IndRecBuf := FLocateBuffer + Header.rec_size * i;
if Crypt.FActive then
Crypt.Decrypt(Rec + 1, Pointer(IndRecBuf), FRecordSize);
Inc(Rec);
if AcceptRecordInternal then begin
if CompareLocateField(FFields, KeyValues, Options) = 0 then begin
Ok := true;
Exit;
end;
end;
end;
until ( BufCnt <= 0 );
end else raise Exception.Create('TVKSmartDBF.LocateRecord: Record size too large');
finally
IndState := false;
IndRecBuf := nil;
if Ok then
Result := Rec
else
Result := 0;
end;
end;
procedure FullScan;
begin
FFields := TList.Create;
try
GetFieldList(FFields, KeyFields);
Result := LocatePass;
finally
FFields.Free;
end;
end;
begin
if FullScanOnly then begin
FullScan;
Exit;
end;
m := 0;
k := 0;
p := 1;
o := 0;
if Indexes <> nil then begin
while p <= Length(KeyFields) do CntFld;
j := Indexes.Count - 1;
for i := 0 to j do begin
l := Indexes[i].SuiteFieldList(KeyFields, n);
if l > m then begin
m := l;
k := i;
end;
end;
end;
if (m > 0) and (o = m) then begin
if loPartialKey in Options then
Result := Indexes[k].FindKeyFields(KeyFields, KeyValues, true)
else
Result := Indexes[k].FindKeyFields(KeyFields, KeyValues);
end else
FullScan;
end;
function TVKSmartDBF.Locate(const KeyFields: string;
const KeyValues: Variant; Options: TLocateOptions): Boolean;
var
Rec: Integer;
begin
Result := false;
Rec := LocateRecord(KeyFields, KeyValues, Options);
if Rec <> 0 then begin
SetRecNoInternal(Rec);
Result := true;
end;
end;
function TVKSmartDBF.Lookup(const KeyFields: string;
const KeyValues: Variant; const ResultFields: string): Variant;
var
Rec: Integer;
begin
Rec := LocateRecord(KeyFields, KeyValues, FLookupOptions);
if Rec <> 0 then begin
Handle.Seek(Header.data_offset + (Rec - 1) * Header.rec_size, 0);
Handle.Read(FLocateBuffer^, Header.rec_size);
IndRecBuf := FLocateBuffer;
if Crypt.FActive then
Crypt.Decrypt(Rec, Pointer(IndRecBuf), FRecordSize);
IndState := true;
try
GetCalcFields(IndRecBuf);
Result := FieldValues[ResultFields];
finally
IndState := false;
IndRecBuf := nil;
end;
end else
Result := Unassigned;
end;
function TVKSmartDBF.GetMasterFields: Variant;
var
i: Integer;
begin
if ListMasterFields.Count > 0 then begin
Result := VarArrayCreate([0, ListMasterFields.Count - 1], varVariant);
for i := 0 to ListMasterFields.Count - 1 do
Result[i] := TField(ListMasterFields[i]).AsVariant;
end else
Result := Null;
end;
procedure TVKSmartDBF.SetMasterFields(const Value: String);
begin
if Value = '' then begin
FMasterFields := Value;
if FRange then ClearRange;
FRange := false;
end;
if FMasterFields <> Value then begin
FMasterFields := Value;
if FRange then ClearRange;
FRange := true;
ListMasterFields.Clear;
if DataSource <> nil then begin
if DataSource.DataSet <> nil then begin
if DataSource.DataSet.Active then begin
DataSource.DataSet.GetFieldList(ListMasterFields, FMasterFields);
SetRange(FMasterFields, GetMasterFields);
end;
end;
end;
end;
end;
procedure TVKSmartDBF.ClearRange;
begin
//
end;
procedure TVKSmartDBF.SetRange(FieldList: String;
FieldValues: array of const);
begin
//
end;
procedure TVKSmartDBF.SetRange(FieldList: String; FieldValues: variant);
begin
//
end;
procedure TVKSmartDBF.Reindex;
var
i, j: Integer;
begin
if Indexes <> nil then begin
j := Indexes.Count - 1;
for i := 0 to j do
Indexes[i].Reindex;
end;
end;
procedure TVKSmartDBF.ReindexWithOutActivated;
var
i, j: Integer;
begin
if Indexes <> nil then begin
j := Indexes.Count - 1;
for i := 0 to j do
Indexes[i].Reindex(false);
end;
end;
procedure TVKSmartDBF.SetDBFFieldDefs(const Value: TVKDBFFieldDefs);
begin
FDBFFieldDefs.Assign(Value);
end;
procedure TVKSmartDBF.SetDBFIndexDefs(const Value: TVKDBFIndexDefs);
begin
FDBFIndexDefs.Assign(Value);
end;
function TVKSmartDBF.CreateBlobStream(Field: TField;
Mode: TBlobStreamMode): TStream;
var
qq: TVKDBFFieldDef;
ss: array [0..10] of char;
iCode, dInt: Integer;
dbfBuf: array [0..511] of byte;
eof: boolean;
i: Integer;
rr, rr1: Integer;
LenLob: Integer;
begin
qq := TVKDBFFieldDef(Pointer(Field.Tag));
if Field.GetData(Pointer(@ss[0])) then
begin
if Mode = bmWrite then begin
Result := TVKDBTStream.CreateDBTStream(self, Field);
TVKDBTStream(Result).FModified := true;
Exit;
end;
if ( qq.field_type = 'M' ) or
( ( qq.field_type = 'E' ) and
( qq.extend_type in [dbftClob, dbftFmtMemo,
dbftBlob, dbftGraphic] )) then begin
ss[10] := #0;
Val(ss, dInt, iCode);
end else begin
if ( ( pLongword(@ss[0])^ and $80000000 ) = $80000000 ) then begin
dInt := ( pLongword(@ss[0])^ and $7FFFFFFF );
iCode := 0;
end else begin
dInt := 0;
iCode := 1;
end;
end;
if (iCode = 0) and (LobHandler.IsOpen) then
begin
Result := TVKDBTStream.CreateDBTStream(self, Field);
case qq.field_type of
'M':
begin
eof := false;
LobHandler.Seek(512 * dInt, 0);
repeat
rr := LobHandler.Read(dbfBuf, 512);
rr1 := rr;
for i := 0 to rr - 1 do begin
if dbfBuf[i] = $1A then begin
eof := true;
rr1 := i;
break;
end;
end;
Result.Write(dbfBuf, rr1);
until eof;
Result.Position := 0;
if TVKDBTStream(Result).Memory <> nil then
TranslateBuff(TVKDBTStream(Result).Memory, TVKDBTStream(Result).Memory, false, TVKDBTStream(Result).Size);
TVKDBTStream(Result).FModified := false;
end;
'E':
begin
case qq.extend_type of
dbftClob, dbftFmtMemo:
begin
LobHandler.Seek(512 * dInt, 0);
LobHandler.Read(LenLob, SizeOf(Integer));
Result.Size := LenLob;
LobHandler.Read(TVKDBTStream(Result).Memory^, LenLob);
Result.Position := 0;
if Crypt.FActive then
Crypt.Decrypt(512 * dInt, TVKDBTStream(Result).Memory, LenLob);
if TVKDBTStream(Result).Memory <> nil then
TranslateBuff(TVKDBTStream(Result).Memory, TVKDBTStream(Result).Memory, false, LenLob);
TVKDBTStream(Result).FModified := false;
end;
dbftBlob, dbftGraphic:
begin
LobHandler.Seek(512 * dInt, 0);
LobHandler.Read(LenLob, SizeOf(Integer));
Result.Size := LenLob;
LobHandler.Read(TVKDBTStream(Result).Memory^, LenLob);
if Crypt.FActive then
Crypt.Decrypt(512 * dInt, TVKDBTStream(Result).Memory, LenLob);
Result.Position := 0;
TVKDBTStream(Result).FModified := false;
end;
dbftClob_NB, dbftFmtMemo_NB:
begin
LobHandler.Seek(dInt, 0);
LobHandler.Read(LenLob, SizeOf(Integer));
Result.Size := LenLob;
LobHandler.Read(TVKDBTStream(Result).Memory^, LenLob);
Result.Position := 0;
if Crypt.FActive then
Crypt.Decrypt(dInt, TVKDBTStream(Result).Memory, LenLob);
if TVKDBTStream(Result).Memory <> nil then
TranslateBuff(TVKDBTStream(Result).Memory, TVKDBTStream(Result).Memory, false, LenLob);
TVKDBTStream(Result).FModified := false;
end;
dbftBlob_NB, dbftGraphic_NB:
begin
LobHandler.Seek(dInt, 0);
LobHandler.Read(LenLob, SizeOf(Integer));
Result.Size := LenLob;
LobHandler.Read(TVKDBTStream(Result).Memory^, LenLob);
if Crypt.FActive then
Crypt.Decrypt(dInt, TVKDBTStream(Result).Memory, LenLob);
Result.Position := 0;
TVKDBTStream(Result).FModified := false;
end;
else
raise Exception.Create('TVKSmartDBF: Lob stream create error!');
end;
end;
else
raise Exception.Create('TVKSmartDBF: Lob stream create error!');
end;
end else
Result := TVKDBTStream.CreateDBTStream(self, Field);
end else
Result := TVKDBTStream.CreateDBTStream(self, Field);
end;
procedure TVKSmartDBF.CreateNestedStream(NestedDataSet: TVKSmartDBF; Field: TField; NestedStream: TStream);
var
qq: TVKDBFFieldDef;
ss: array [0..10] of char;
iCode, dInt: Integer;
LenLob: Integer;
procedure CreateNewStream;
begin
NestedDataSet.DBFFieldDefs.Clear;
qq := DBFFieldDefs.FindIndex(Field.FullName);
NestedDataSet.DBFFieldDefs.Assign(qq.DBFFieldDefs);
NestedDataSet.CreateTable;
end;
begin
qq := TVKDBFFieldDef(Pointer(Field.Tag));
if Field.GetData(@ss[0]) then
begin
if ( ( qq.field_type = 'E' ) and
( qq.extend_type in [dbftDBFDataSet] )) then begin
ss[10] := #0;
Val(ss, dInt, iCode);
end else begin
if ( ( pLongword(@ss[0])^ and $80000000 ) = $80000000 ) then begin
dInt := ( pLongword(@ss[0])^ and $7FFFFFFF );
iCode := 0;
end else begin
dInt := 0;
iCode := 1;
end;
end;
if (iCode = 0) and (LobHandler.IsOpen) then
begin
case qq.field_type of
'E':
begin
case qq.extend_type of
dbftDBFDataSet:
begin
LobHandler.Seek(512 * dInt, 0);
LobHandler.Read(LenLob, SizeOf(Integer));
TMemoryStream(NestedStream).Size := LenLob;
LobHandler.Read(TMemoryStream(NestedStream).Memory^, LenLob);
TMemoryStream(NestedStream).Position := 0;
if Crypt.FActive then
Crypt.Decrypt(512 * dInt, TMemoryStream(NestedStream).Memory, LenLob);
end;
dbftDBFDataSet_NB:
begin
LobHandler.Seek(dInt, 0);
LobHandler.Read(LenLob, SizeOf(Integer));
TMemoryStream(NestedStream).Size := LenLob;
LobHandler.Read(TMemoryStream(NestedStream).Memory^, LenLob);
if Crypt.FActive then
Crypt.Decrypt(dInt, TMemoryStream(NestedStream).Memory, LenLob);
TMemoryStream(NestedStream).Position := 0;
end;
else
raise Exception.Create('TVKSmartDBF: Nested stream create error!');
end;
end;
else
raise Exception.Create('TVKSmartDBF: Nested stream create error!');
end;
end else
CreateNewStream;
end else
CreateNewStream;
end;
procedure TVKSmartDBF.SaveOnTheSamePlaceToDBT(Source: TMemoryStream; Field: TField);
begin
FSaveOnTheSamePlace := True;
try
SaveToDBT(Source, Field);
finally
FSaveOnTheSamePlace := False;
end;
end;
procedure TVKSmartDBF.SaveToDBT(Source: TMemoryStream; Field: TField);
var
qq: TVKDBFFieldDef;
ss: array [0..10] of char;
lEnd, dInt: Integer;
LenLob: Integer;
CryptContext: LongWord;
LHnd: TProxyStream;
begin
qq := TVKDBFFieldDef(Pointer(Field.Tag));
if FPackProcess then
LHnd := PackLobHandler
else
LHnd := LobHandler;
if LHnd.IsOpen then
begin
if Source.Memory <> nil then begin
lEnd := LHnd.Seek(0, 2);
if ( qq.field_type = 'M' ) or
( ( qq.field_type = 'E' ) and
( qq.extend_type in [ dbftClob, dbftFmtMemo,
dbftBlob, dbftGraphic,
dbftDBFDataSet] )) then begin
if not FSaveOnTheSamePlace then begin
dInt := lEnd div 512;
if (lEnd mod 512) > 0 then Inc(dInt);
CryptContext := dInt * 512;
LHnd.Seek(dInt * 512, 0);
Str(dInt:10, ss);
Field.SetData(Pointer(@ss[0]));
end else begin
Field.GetData(Pointer(@ss[0]));
dInt := StrToInt(ss);
CryptContext := dInt * 512;
LHnd.Seek(dInt * 512, 0);
end;
end else begin
if not FSaveOnTheSamePlace then begin
dInt := lEnd;
CryptContext := dInt;
LHnd.Seek(dInt, 0);
Field.SetData(@dInt);
end else begin
Field.GetData(@dInt);
CryptContext := dInt;
LHnd.Seek(dInt, 0);
end;
end;
case qq.field_type of
'M':
begin
//This Lob type you can not to Crypt !!!
LenLob := Source.Size;
TranslateBuff(Source.Memory, Source.Memory, true, LenLob);
LHnd.Write(Pointer(Source.Memory)^, LenLob);
ss[0] := #$1A;
LHnd.Write(ss, 1);
end;
'E':
begin
case qq.extend_type of
dbftClob, dbftFmtMemo:
begin
LenLob := Source.Size;
TranslateBuff(Source.Memory, Source.Memory, true, LenLob);
if Crypt.FActive then Crypt.Encrypt(CryptContext, Source.Memory, LenLob);
LHnd.Write(LenLob, SizeOf(Integer));
LHnd.Write(Pointer(Source.Memory)^, LenLob);
end;
dbftBlob, dbftGraphic, dbftDBFDataSet:
begin
LenLob := Source.Size;
if Crypt.FActive then Crypt.Encrypt(CryptContext, Source.Memory, LenLob);
LHnd.Write(LenLob, SizeOf(Integer));
LHnd.Write(Pointer(Source.Memory)^, LenLob);
end;
dbftClob_NB, dbftFmtMemo_NB:
begin
LenLob := Source.Size;
TranslateBuff(Source.Memory, Source.Memory, true, LenLob);
if Crypt.FActive then Crypt.Encrypt(CryptContext, Source.Memory, LenLob);
LHnd.Write(LenLob, SizeOf(Integer));
LHnd.Write(Pointer(Source.Memory)^, LenLob);
end;
dbftBlob_NB, dbftGraphic_NB, dbftDBFDataSet_NB:
begin
LenLob := Source.Size;
if Crypt.FActive then Crypt.Encrypt(CryptContext, Source.Memory, LenLob);
LHnd.Write(LenLob, SizeOf(Integer));
LHnd.Write(Pointer(Source.Memory)^, LenLob);
end;
else
raise Exception.Create('TVKSmartDBF: Lob stream save error!');
end;
end;
else
raise Exception.Create('TVKSmartDBF: Lob stream save error!');
end;
end else
Field.SetData(nil);
end;
end;
procedure TVKSmartDBF.BeginAddBuffered(RecInBuffer: Integer);
begin
if not FAddBuffered then begin
FAddBuffered := true;
FAddBufferCount := RecInBuffer;
FAddBuffer := VKDBFMemMgr.oMem.GetMem(self, FAddBufferCount * FRecordSize);
FAddBufferCrypt := VKDBFMemMgr.oMem.GetMem(self, FAddBufferCount * FRecordSize);
FAddBufferCurrent := -1; // 0 - (FAddBufferCount - 1)
end;
end;
procedure TVKSmartDBF.EndAddBuffered;
begin
if FAddBuffered then begin
if FAddBufferCount > -1 then FlushAddBuffer;
VKDBFMemMgr.oMem.FreeMem(FAddBuffer);
VKDBFMemMgr.oMem.FreeMem(FAddBufferCrypt);
FAddBuffered := false;
FAddBuffer := nil;
FAddBufferCrypt := nil;
FAddBufferCount := -1;
FAddBufferCurrent := -1;
end;
end;
procedure TVKSmartDBF.FlushAddBuffer;
var
i, j, RealRead: Integer;
lpMsgBuf: array [0..500] of Char;
le: DWORD;
NewKey: String;
NewRec: LongInt;
LockR, b: boolean;
b1, b2: pChar;
begin
if FAddBuffered then begin
if FAddBufferCurrent > -1 then begin
CheckActive;
if LockHeader then begin
try
DBFHeader.last_rec := ( (DBFHandler.Seek(0, 2) - DBFHeader.data_offset) div DBFHeader.rec_size );
NewRec := DBFHeader.last_rec + 1;
DBFHandler.Seek(0, 2);
DBFHandler.Seek(DBFHeader.data_offset + LongWord(DBFHeader.last_rec * FRecordSize), 0);
//Crypt
if Crypt.FActive then begin
for j := 0 to FAddBufferCurrent do begin
b1 := FAddBuffer + j * DBFHeader.rec_size;
b2 := FAddBufferCrypt + j * DBFHeader.rec_size;
Move(b1^, b2^, DBFHeader.rec_size);
Crypt.Encrypt(NewRec + j, b2, DBFHeader.rec_size);
end;
RealRead := DBFHandler.Write(FAddBufferCrypt^, DBFHeader.rec_size * ( FAddBufferCurrent + 1 ) );
end else
RealRead := DBFHandler.Write(FAddBuffer^, DBFHeader.rec_size * ( FAddBufferCurrent + 1 ) );
if RealRead = -1 then begin
le := GetLastError();
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
nil,
le,
0, // Default language
lpMsgBuf,
500,
nil
);
raise Exception.Create('TVKSmartDBF: ' + lpMsgBuf);
end else begin
Inc(DBFHeader.last_rec, FAddBufferCurrent + 1);
DBFHandler.Seek(0, 0); //go to the begin
RealRead := DBFHandler.Write(DBFHeader, SizeOf(DBFHeader));
if RealRead = -1 then begin
le := GetLastError();
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
nil,
le,
0, // Default language
lpMsgBuf,
500,
nil
);
raise Exception.Create('TVKSmartDBF: ' + lpMsgBuf);
end else begin
FIndState := true;
try
if Indexes <> nil then
for i := 0 to Indexes.Count - 1 do begin
b := ( (FAccessMode.FLast and fmShareExclusive) = fmShareExclusive ) or
( (FAccessMode.FLast and fmShareDenyWrite) = fmShareDenyWrite ) or
FFileLock;
LockR := Indexes[i].FLock;
if not b then Indexes[i].StartUpdate(false);
if LockR then
try
for j := 0 to FAddBufferCurrent do begin
FIndRecBuf := FAddBuffer + j * DBFHeader.rec_size;
NewKey := Indexes[i].EvaluteKeyExpr;
Indexes[i].AddKey(NewKey, NewRec + j);
end;
finally
if not b then Indexes[i].Flush;
Indexes[i].FUnLock;
end
else
raise Exception.Create('TVKSmartDBF.FlushAddBuffer: Can not add key to index file (FLock is false).');
end;
finally
FIndRecBuf := nil;
FIndState := false;
end;
end;
end;
finally
UnLockHeader;
end;
end else
raise Exception.Create('TVKSmartDBF.FlushAddBuffer: Can not lock DBF header.');
end;
FAddBufferCurrent := -1;
end;
end;
function TVKSmartDBF.GetOnEncrypt: TOnCrypt;
begin
Result := FVKDBFCrypt.FOnEncrypt;
end;
procedure TVKSmartDBF.SetOnDecrypt(const Value: TOnCrypt);
begin
FVKDBFCrypt.FOnDecrypt := Value;
end;
procedure TVKSmartDBF.SetOnEncrypt(const Value: TOnCrypt);
begin
FVKDBFCrypt.FOnEncrypt := Value;
end;
function TVKSmartDBF.GetOnDecrypt: TOnCrypt;
begin
Result := FVKDBFCrypt.FOnDecrypt;
end;
function TVKSmartDBF.GetOnCryptActivate: TNotifyEvent;
begin
Result := FVKDBFCrypt.FOnActivate;
end;
function TVKSmartDBF.GetOnCryptDeActivate: TNotifyEvent;
begin
Result := FVKDBFCrypt.FOnDeactivate;
end;
procedure TVKSmartDBF.SetOnCryptActivate(const Value: TNotifyEvent);
begin
FVKDBFCrypt.FOnActivate := Value;
end;
procedure TVKSmartDBF.SetOnCryptDeActivate(const Value: TNotifyEvent);
begin
FVKDBFCrypt.FOnDeactivate := Value;
end;
function TVKSmartDBF.SetAutoInc(const FieldName: String;
Value: DWORD): boolean;
var
oFld: TField;
begin
Result := false;
oFld := FindField(FieldName);
if oFld <> nil then
Result := SetAutoInc(oFld.FieldNo, Value);
end;
function TVKSmartDBF.SetAutoInc(const FieldNum: Integer;
Value: DWORD): boolean;
var
qq: TVKDBFFieldDef;
FR: FIELD_REC;
begin
CheckActive;
if LockHeader then begin
try
//qq := DBFFieldDefs.Items[FieldNum - 1];
qq := TVKDBFFieldDef(Pointer(FieldByNumber(FieldNum).Tag));
DBFHandler.Seek(qq.FOffHD, soFromBeginning);
DBFHandler.Read(FR, SizeOf(FIELD_REC));
FR.NextAutoInc := Value;
DBFHandler.Seek(qq.FOffHD, soFromBeginning);
DBFHandler.Write(FR, SizeOf(FIELD_REC));
Result := true;
finally
UnLockHeader;
end
end else
raise Exception.Create('TVKSmartDBF.SetAutoInc: Can not lock DBF header.');
end;
function TVKSmartDBF.GetCurrentAutoInc(const FieldName: String): DWORD;
var
oFld: TField;
begin
Result := DWORD(-1);
oFld := FindField(FieldName);
if oFld <> nil then
Result := GetCurrentAutoInc(oFld.FieldNo);
end;
function TVKSmartDBF.GetCurrentAutoInc(const FieldNum: Integer): DWORD;
var
qq: TVKDBFFieldDef;
FR: FIELD_REC;
begin
CheckActive;
if LockHeader then begin
try
//qq := DBFFieldDefs.Items[FieldNum - 1];
qq := TVKDBFFieldDef(Pointer(FieldByNumber(FieldNum).Tag));
DBFHandler.Seek(qq.FOffHD, soFromBeginning);
DBFHandler.Read(FR, SizeOf(FIELD_REC));
Result := FR.NextAutoInc;
finally
UnLockHeader;
end
end else
raise Exception.Create('TVKSmartDBF.GetCurrentAutoInc: Can not lock DBF header.');
end;
function TVKSmartDBF.GetNextAutoInc(const FieldName: String): DWORD;
var
oFld: TField;
begin
Result := DWORD(-1);
oFld := FindField(FieldName);
if oFld <> nil then
Result := GetNextAutoInc(oFld.FieldNo);
end;
function TVKSmartDBF.GetNextAutoInc(const FieldNum: Integer): DWORD;
var
qq: TVKDBFFieldDef;
FR: FIELD_REC;
begin
CheckActive;
if LockHeader then begin
try
//qq := DBFFieldDefs.Items[FieldNum - 1];
qq := TVKDBFFieldDef(Pointer(FieldByNumber(FieldNum).Tag));
DBFHandler.Seek(qq.FOffHD, soFromBeginning);
DBFHandler.Read(FR, SizeOf(FIELD_REC));
Inc(FR.NextAutoInc);
DBFHandler.Seek(qq.FOffHD, soFromBeginning);
DBFHandler.Write(FR, SizeOf(FIELD_REC));
Result := FR.NextAutoInc;
finally
UnLockHeader;
end
end else
raise Exception.Create('TVKSmartDBF.GetNextAutoInc: Can not lock DBF header.');
end;
procedure TVKSmartDBF.Truncate;
begin
CheckActive;
if LockHeader then
try
DBFHeader.last_rec := 0;
DBFHandler.Seek(0, 0);
DBFHandler.Write(DBFHeader, SizeOf(DBF_HEAD));
DBFHandler.Seek(DBFHeader.data_offset, 0);
DBFHandler.SetEndOfFile;
if LobHandler.IsOpen then begin
LobHandler.Seek(0, 0);
LobHandler.SetEndOfFile;
LobHandler.Write('This is Lob!', 12);
end;
ReindexWithOutActivated;
finally
UnLockHeader;
First;
end
else
raise Exception.Create('TVKSmartDBF.Truncate: Can not lock DBF header.');
end;
procedure TVKSmartDBF.DataConvert(Field: TField; Source, Dest: Pointer;
ToNative: Boolean);
var
Len: Integer;
begin
case Field.DataType of
ftWideString:
begin
if ToNative then begin
Len := pInteger(pChar(pWideChar(Source^)) - 4)^;
Move(Pointer(pChar(pWideChar(Source^)) - 4)^, Dest^, Len + 6);
end else begin
pWideString(Dest)^ := pWideChar(pChar(Source) + 4);
end;
end;
else
inherited DataConvert(Field, Source, Dest, ToNative);
end;
end;
procedure TVKSmartDBF.Zap;
begin
Truncate;
end;
procedure TVKSmartDBF.ReindexAll;
var
RecPareBuf, i, j: Integer;
ReadSize, RealRead, BufCnt: Integer;
Rec: Integer;
Offset: Integer;
begin
if Indexes <> nil then begin
CheckActive;
if State = dsEdit then Post;
if LockHeader then
try
for j := 0 to Indexes.Count - 1 do Indexes.Items[j].BeginCreateIndexProcess;
IndState := true;
try
RecPareBuf := FBufferSize div Header.rec_size;
if RecPareBuf >= 1 then begin
ReadSize := RecPareBuf * Header.rec_size;
Offset := Header.data_offset;
Rec := 0;
repeat
Handle.Seek(Offset, 0);
RealRead := Handle.Read(FLocateBuffer^, ReadSize);
Inc(Offset, RealRead);
BufCnt := RealRead div Header.rec_size;
for i := 0 to BufCnt - 1 do begin
IndRecBuf := FLocateBuffer + Header.rec_size * i;
if Crypt.FActive then
Crypt.Decrypt(Rec + 1, Pointer(IndRecBuf), FRecordSize);
Inc(Rec);
for j := 0 to Indexes.Count - 1 do Indexes.Items[j].EvaluteAndAddKey(Rec);
end;
until ( BufCnt <= 0 );
end else raise Exception.Create('TVKSmartDBF.ReindexAll: Record size too large');
finally
for j := 0 to Indexes.Count - 1 do Indexes.Items[j].EndCreateIndexProcess;
IndState := false;
IndRecBuf := nil;
end;
finally
UnLockHeader;
First;
end
else
raise Exception.Create('TVKSmartDBF.ReindexAll: Can not lock DBF header.');
end;
end;
function TVKSmartDBF.CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Integer;
begin
Result := 9;
if Bookmark1 = nil then
begin
if Bookmark2 <> nil then
Result := -1
else
Result := 0;
end else
if Bookmark2 = nil then
Result := 1;
if Result = 9 then
begin
Result := StrComp(PChar(BookMark1),PChar(Bookmark2));
if Result < 0 then
Result := -1
else
if Result > 0 then
Result := 1;
end;
end;
function TVKSmartDBF.BookmarkValid(Bookmark: TBookmark): Boolean;
var
q: LongWord;
begin
Result := false;
if Bookmark <> nil then begin
q := pLongWord(Bookmark)^;
if ( q > 0 ) and ( q <= LongWord(Header.last_rec) ) then Result := true;
end;
end;
procedure TVKSmartDBF.DBEval;
var
RecPareBuf, i: Integer;
ReadSize, RealRead, BufCnt: Integer;
Rec: Integer;
Offset: Integer;
FLastFastPostRecord: boolean;
begin
CheckActive;
if State = dsEdit then Post;
if LockHeader then
try
if Flock() then
try
FTmpActive := true;
FLastFastPostRecord := FFastPostRecord;
FFastPostRecord := true;
try
RecPareBuf := FBufferSize div Header.rec_size;
if RecPareBuf >= 1 then begin
ReadSize := RecPareBuf * Header.rec_size;
Offset := Header.data_offset;
Rec := 0;
repeat
Handle.Seek(Offset, 0);
RealRead := Handle.Read(FLocateBuffer^, ReadSize);
Inc(Offset, RealRead);
BufCnt := RealRead div Header.rec_size;
for i := 0 to BufCnt - 1 do begin
Inc(Rec);
if Crypt.Active then
Crypt.Decrypt(Rec, Pointer(FTempRecord), FRecordSize)
else
Move((FLocateBuffer + Header.rec_size * i)^, FTempRecord^, FRecordSize);
SetBookmarkData(FTempRecord, @Rec);
SetBookmarkFlag(FTempRecord, bfCurrent);
if Assigned(FOnDBEval) then FOnDBEval(self, Rec);
end;
until ( BufCnt <= 0 );
end else raise Exception.Create('TVKSmartDBF.DBEval: Record size too large');
finally
FTmpActive := false;
FFastPostRecord := FLastFastPostRecord;
end;
finally
UnLock;
end
else
raise Exception.Create('TVKSmartDBF.DBEval: Can not lock DBF table.');
finally
UnLockHeader;
Refresh;
end
else
raise Exception.Create('TVKSmartDBF.DBEval: Can not lock DBF header.');
end;
function TVKSmartDBF.GetOrder: ShortString;
begin
Result := '';
if (FIndexes <> nil) and ( FIndexes.ActiveObject <> nil ) then Result := FIndexes.ActiveObject.Name;
end;
procedure TVKSmartDBF.SetOrderName(sOrd: ShortString);
begin
if csReading in ComponentState then
FIndexName := sOrd
else
SetOrder(sOrd);
end;
procedure TVKSmartDBF.SetKey;
begin
FSaveState := SetTempState(dsSetKey);
InternalInitRecord(FSetKeyBuffer);
end;
procedure TVKSmartDBF.EditKey;
begin
FSaveState := SetTempState(dsSetKey);
end;
procedure TVKSmartDBF.DropEditKey;
begin
RestoreState(FSaveState);
end;
function TVKSmartDBF.GotoKey: boolean;
var
RecN: Integer;
begin
RecN := 0;
Result := false;
try
if ( Indexes <> nil ) and ( Indexes.ActiveObject <> nil ) then
RecN := Indexes.ActiveObject.FindKeyFields;
finally
RestoreState(FSaveState);
if RecN > 0 then begin
SetRecNoInternal(RecN);
Result := True;
end;
end;
end;
procedure TVKSmartDBF.GotoNearest;
var
RecN: Integer;
begin
RecN := 0;
try
if ( Indexes <> nil ) and ( Indexes.ActiveObject <> nil ) then
RecN := Indexes.ActiveObject.FindKeyFields(true);
finally
RestoreState(FSaveState);
if RecN > 0 then
SetRecNoInternal(RecN);
end;
end;
function TVKSmartDBF.FindKey(const KeyValues: array of const): Boolean;
var
RecN: Integer;
begin
Result := false;
if ( Indexes <> nil ) and ( Indexes.ActiveObject <> nil ) then begin
RecN := Indexes.ActiveObject.FindKeyFields('', KeyValues);
if RecN > 0 then begin
SetRecNoInternal(RecN);
Result := true;
end;
end;
end;
procedure TVKSmartDBF.FindNearest(const KeyValues: array of const);
var
RecN: Integer;
begin
if ( Indexes <> nil ) and ( Indexes.ActiveObject <> nil ) then begin
RecN := Indexes.ActiveObject.FindKeyFields('', KeyValues, true);
if RecN > 0 then SetRecNoInternal(RecN);
end;
end;
function TVKSmartDBF.AcceptTmpRecord(nRec: DWORD): boolean;
begin
if (not Filtered) and (Filter <> '') then
FFilterParser.SetExprParams(Filter, FilterOptions, [poExtSyntax], '');
SetTmpRecord(nRec);
try
Result := AcceptRecordInternal;
finally
CloseTmpRecord;
end;
end;
function TVKSmartDBF.AcceptRecordInternal: boolean;
begin
if not Filtered then begin
if not FSetDeleted then
Result := true
else
Result := not Deleted;
end else
Result := AcceptRecord;
if ( Result ) and
( Indexes <> nil ) and
( Indexes.ActiveObject <> nil ) and
( Indexes.ActiveObject.IsRanged ) then
Result := Indexes.ActiveObject.InRange;
end;
procedure TVKSmartDBF.SetRecNoInternal(Value: Integer);
begin
CursorPosChanged;
DoBeforeScroll;
GetBufferByRec(Value);
Resync([]);
DoAfterScroll;
end;
procedure TVKSmartDBF.Loaded;
begin
inherited Loaded;
IndexName := FIndexName;
if FStreamedCreateNow then CreateNow := True;
if FStreamedActive then Active := True;
end;
function TVKSmartDBF.GetInnerStream: TStream;
begin
Result := DBFHandler.InnerStream;
end;
procedure TVKSmartDBF.SetActive(Value: Boolean);
begin
if (csReading in ComponentState) then
begin
FStreamedActive := Value;
end
else
inherited SetActive(Value);
end;
function TVKSmartDBF.GetInnerLobStream: TStream;
begin
Result := LobHandler.InnerStream;
end;
procedure TVKSmartDBF.BindDBFFieldDef;
var
i: Integer;
FieldFullName: String;
F: TField;
function HideBindDBFFieldDef(FDS: TVKDBFFieldDefs; Prefix: String = ''): boolean;
var
i: Integer;
FD: TVKDBFFieldDef;
begin
Result := False;
for i := 0 to FDS.Count - 1 do begin
FD := FDS[i];
if FD.FFieldDefRef <> nil then begin
if Prefix + FD.Name = FieldFullName then begin
F.Tag := Integer(Pointer(FD));
Result := true;
Exit;
end;
end;
if FD.DBFFieldDefs.Count > 0 then begin
Result := HideBindDBFFieldDef(FD.DBFFieldDefs, Prefix + FD.Name + '.');
if Result then Exit;
end;
end;
end;
begin
for i := 0 to Fields.Count - 1 do begin
F := Fields[i];
FieldFullName := F.FullName;
HideBindDBFFieldDef(DBFFieldDefs);
end;
end;
procedure TVKSmartDBF.LobHandlerCreate;
begin
LobHandler := TProxyStream.Create;
end;
procedure TVKSmartDBF.LobHandlerDestroy;
begin
LobHandler.Destroy;
end;
procedure TVKSmartDBF.CreateLobStream(dbf_id: Byte);
begin
if dbf_id = $83 then begin
LobHandler.FileName := ChangeFileExt(DBFFileName, '.dbt');
LobHandler.AccessMode.AccessMode := AccessMode.AccessMode;
LobHandler.ProxyStreamType := FStorageType;
LobHandler.OuterStream := FOuterLobStream;
LobHandler.CreateProxyStream;
LobHandler.Write('This is Lob!', 12);
LobHandler.Close;
end;
end;
procedure TVKSmartDBF.CloseLobStream;
begin
if LobHandler.IsOpen then begin
LobHandler.Close;
end;
end;
procedure TVKSmartDBF.OpenLobStream(dbf_id: Byte);
begin
if dbf_id = $83 then begin
LobHandler.FileName := ChangeFileExt(DBFFileName, '.dbt');
LobHandler.AccessMode.AccessMode := AccessMode.AccessMode;
LobHandler.ProxyStreamType := FStorageType;
LobHandler.OuterStream := FOuterLobStream;
LobHandler.Open;
end;
end;
procedure TVKSmartDBF.DoAfterOpen;
var
i: Integer;
oNested: TVKNestedDBF;
begin
if Assigned(NestedDataSets) then
for i := 0 to NestedDataSets.Count - 1 do begin
oNested := TVKNestedDBF(NestedDataSets[i]);
oNested.Close;
oNested.Open;
end;
inherited DoAfterOpen;
end;
procedure TVKSmartDBF.RefreshBufferByRec(Rec: Integer);
var
NewRec: Integer;
WasEof, WasBof: boolean;
begin
InternalSetCurrentIndex(Rec);
WasEof := False;
WasBof := False;
FIndState := true;
try
repeat
FIndRecBuf := FBuffer + FCurInd * FRecordSize;
NewRec := pLongint(pChar(FBufInd) + FCurInd * SizeOf(Longint))^;
if AcceptRecordInternal then Break
else begin
NextIndexBuf;
if FEOF then begin
WasEof := True;
Break;
end;
end;
until False;
if FEOF then begin
GetBufferByRec(Rec);
repeat
FIndRecBuf := FBuffer + FCurInd * FRecordSize;
NewRec := pLongint(pChar(FBufInd) + FCurInd * SizeOf(Longint))^;
if AcceptRecordInternal then Break
else begin
PriorIndexBuf;
if FBOF then begin
WasBof := True;
Break;
end;
end;
until False;
end;
finally
FIndRecBuf := nil;
FIndState := false;
end;
if WasEof and WasBof then begin
// Clear buffer
FCurInd := -1;
FBufDir := bdFromTop;
FBufCnt := 0;
FBOF := True;
FEOF := True;
end else
GetBufferByRec(NewRec);
end;
procedure TVKSmartDBF.InternalSetCurrentIndex(i: Integer);
var
j: Integer;
begin
for j := 0 to FBufCnt - 1 do begin
if FBufDir = bdFromTop then
if pLongint(pChar(FBufInd) + j * SizeOf(Longint))^ = i then begin
FCurInd := j;
FBOF := false;
FEOF := false;
Exit;
end;
if FBufDir = bdFromBottom then
if pLongint(pChar(FBufInd) + (FRecordsPerBuf - j) * SizeOf(Longint))^ = i then begin
FCurInd := FRecordsPerBuf - j;
FBOF := false;
FEOF := false;
Exit;
end;
end;
end;
procedure TVKSmartDBF.PackLobHandlerCreate;
begin
FPackLobHandler := TProxyStream.Create;
end;
procedure TVKSmartDBF.PackLobHandlerOpen(TempLobName: String);
begin
FPackLobHandler.FileName := TempLobName;
FPackLobHandler.AccessMode.AccessMode := AccessMode.AccessMode;
FPackLobHandler.ProxyStreamType := pstFile;
FPackLobHandler.CreateProxyStream;
FPackLobHandler.Write('This is Lob!', 12);
end;
procedure TVKSmartDBF.PackLobHandlerClose(LobName, TempLobName: String);
begin
//Copy new LOB into old LOB
FPackLobHandler.Close;
LobHandler.Close;
case StorageType of
pstFile:
begin
DeleteFile(LobName);
RenameFile(TempLobName, LobName);
end;
pstInnerStream, pstOuterStream:
begin
LobHandler.LoadFromFile(TempLobName);
DeleteFile(TempLobName);
end;
end;
LobHandler.Open;
end;
procedure TVKSmartDBF.PackLobHandlerDestroy;
begin
FPackLobHandler.Free;
end;
function TVKSmartDBF.GetPackLobHandler: TProxyStream;
begin
Result := FPackLobHandler;
end;
{ TVKDBFNTX }
procedure TVKDBFNTX.ClearRange;
begin
if Indexes.ActiveObject <> nil then
TVKNTXIndex(Indexes.ActiveObject).NTXRange.Active := false;
end;
constructor TVKDBFNTX.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FIndexes := TIndexes.Create(self, TVKNTXIndex);
FDBFIndexDefs := TVKDBFIndexDefs.Create(self, TVKNTXBag);
end;
procedure TVKDBFNTX.DefineProperties(Filer: TFiler);
function WriteDBFFieldDefDataB: Boolean;
begin
if Filer.Ancestor <> nil then
Result := not FDBFFieldDefs.IsEqual(TVKSmartDBF(Filer.Ancestor).FDBFFieldDefs)
else
Result := (FDBFFieldDefs.Count > 0);
end;
function WriteDBFIndexDefDataB: Boolean;
begin
if Filer.Ancestor <> nil then
Result := not FDBFIndexDefs.IsEqual(TVKSmartDBF(Filer.Ancestor).FDBFIndexDefs)
else
Result := (FDBFIndexDefs.Count > 0);
end;
begin
inherited DefineProperties(Filer);
Filer.DefineProperty('DBFFieldDefs', ReadDBFFieldDefData, WriteDBFFieldDefData, WriteDBFFieldDefDataB);
Filer.DefineProperty('DBFIndexDefs', ReadDBFIndexDefData, WriteDBFIndexDefData, WriteDBFIndexDefDataB);
end;
destructor TVKDBFNTX.Destroy;
begin
Active := false;
FIndexes.Destroy;
FIndexes := nil;
FDBFIndexDefs.Destroy;
FDBFIndexDefs := nil;
inherited Destroy;
end;
procedure TVKDBFNTX.SetRange(FieldList: String; FieldValues: array of const);
var
m, i, j, k, l, n, p, o: Integer;
procedure CntFld;
var
I: Integer;
begin
I := p;
while (I <= Length(FieldList)) and (FieldList[I] <> ';') do Inc(I);
Inc(o);
if (I <= Length(FieldList)) and (FieldList[I] = ';') then Inc(I);
p := I;
end;
begin
m := 0;
k := 0;
o := 0;
p := 1;
while p <= Length(FieldList) do CntFld;
j := Indexes.Count - 1;
for i := 0 to j do begin
l := Indexes[i].SuiteFieldList(FieldList, n);
if l > m then begin
m := l;
k := i;
end;
end;
if (m > 0) and (o = m) then
Indexes[k].SetRangeFields(FieldList, FieldValues)
else
raise Exception.Create('TVKSmartDBF: There is no suitable index for range!');
end;
procedure TVKDBFNTX.ReadDBFFieldDefData(Reader: TReader);
begin
Reader.ReadValue;
Reader.ReadCollection(DBFFieldDefs);
end;
procedure TVKDBFNTX.SetRange(FieldList: String; FieldValues: variant);
var
m, i, j, k, l, n, p, o: Integer;
procedure CntFld;
var
I: Integer;
begin
I := p;
while (I <= Length(FieldList)) and (FieldList[I] <> ';') do Inc(I);
Inc(o);
if (I <= Length(FieldList)) and (FieldList[I] = ';') then Inc(I);
p := I;
end;
begin
m := 0;
k := 0;
o := 0;
p := 1;
while p <= Length(FieldList) do CntFld;
j := Indexes.Count - 1;
for i := 0 to j do begin
l := Indexes[i].SuiteFieldList(FieldList, n);
if l > m then begin
m := l;
k := i;
end;
end;
if (m > 0) and (o = m) then
Indexes[k].SetRangeFields(FieldList, FieldValues)
else
raise Exception.Create('TVKSmartDBF: There is no suitable index for range!');
end;
procedure TVKDBFNTX.WriteDBFFieldDefData(Writer: TWriter);
begin
Writer.WriteCollection(DBFFieldDefs);
end;
function TVKDBFNTX.GetOrdersByNum(Index: Integer): TVKNTXIndex;
begin
if (FIndexes <> nil) then
Result := TVKNTXIndex(Indexes[Index])
else
Result := nil;
end;
function TVKDBFNTX.GetOrdersByName(const Index: String): TVKNTXIndex;
var
i: Integer;
begin
Result := nil;
if (FIndexes <> nil) then begin
for i := 0 to FIndexes.Count - 1 do
if UpperCase(FIndexes[i].Name) = UpperCase(Index) then begin
Result := TVKNTXIndex(Indexes[i]);
Break;
end;
end;
end;
procedure TVKDBFNTX.ReadDBFIndexDefData(Reader: TReader);
begin
Reader.ReadValue;
Reader.ReadCollection(DBFIndexDefs);
end;
procedure TVKDBFNTX.WriteDBFIndexDefData(Writer: TWriter);
begin
Writer.WriteCollection(DBFIndexDefs);
end;
{ TVKDBFCDX }
constructor TVKDBFCDX.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FIndexes := TIndexes.Create(self, TVKCDXIndex);
FDBFIndexDefs := TVKDBFIndexDefs.Create(self, TVKCDXBag);
end;
procedure TVKDBFCDX.DefineProperties(Filer: TFiler);
function WriteDBFFieldDefDataB: Boolean;
begin
if Filer.Ancestor <> nil then
Result := not FDBFFieldDefs.IsEqual(TVKSmartDBF(Filer.Ancestor).FDBFFieldDefs)
else
Result := (FDBFFieldDefs.Count > 0);
end;
function WriteDBFIndexDefDataB: Boolean;
begin
if Filer.Ancestor <> nil then
Result := not FDBFIndexDefs.IsEqual(TVKSmartDBF(Filer.Ancestor).FDBFIndexDefs)
else
Result := (FDBFIndexDefs.Count > 0);
end;
begin
inherited DefineProperties(Filer);
Filer.DefineProperty('DBFFieldDefs', ReadDBFFieldDefData, WriteDBFFieldDefData, WriteDBFFieldDefDataB);
Filer.DefineProperty('DBFIndexDefs', ReadDBFIndexDefData, WriteDBFIndexDefData, WriteDBFIndexDefDataB);
end;
destructor TVKDBFCDX.Destroy;
begin
Active := false;
FDBFIndexDefs.Destroy;
FDBFIndexDefs := nil;
FIndexes.Destroy;
FIndexes := nil;
inherited Destroy;
end;
procedure TVKDBFCDX.ReadDBFFieldDefData(Reader: TReader);
begin
Reader.ReadValue;
Reader.ReadCollection(DBFFieldDefs);
end;
procedure TVKDBFCDX.ReadDBFIndexDefData(Reader: TReader);
begin
Reader.ReadValue;
Reader.ReadCollection(DBFIndexDefs);
end;
procedure TVKDBFCDX.WriteDBFFieldDefData(Writer: TWriter);
begin
Writer.WriteCollection(DBFFieldDefs);
end;
procedure TVKDBFCDX.WriteDBFIndexDefData(Writer: TWriter);
begin
Writer.WriteCollection(DBFIndexDefs);
end;
{ TVKDataLink }
procedure TVKDataLink.DataEvent(Event: TDataEvent; Info: Integer);
begin
inherited;
if Event = deDataSetChange then begin
if FDBFDataSet.FRange then begin
if FDBFDataSet.ListMasterFields.Count = 0 then
DataSet.GetFieldList(FDBFDataSet.ListMasterFields, FDBFDataSet.FMasterFields);
FDBFDataSet.SetRange(FDBFDataSet.FMasterFields, FDBFDataSet.GetMasterFields);
end else begin
if bof then FDBFDataSet.First;
if eof then FDBFDataSet.Last;
end;
end;
end;
procedure TVKDataLink.DataSetScrolled(Distance: Integer);
begin
inherited;
if FDBFDataSet.FRange then begin
if FDBFDataSet.ListMasterFields.Count = 0 then
DataSet.GetFieldList(FDBFDataSet.ListMasterFields, FDBFDataSet.FMasterFields);
FDBFDataSet.SetRange(FDBFDataSet.FMasterFields, FDBFDataSet.GetMasterFields);
end else
FDBFDataSet.MoveBy(Distance);
end;
{ TVKDBFFieldDefs }
procedure TVKDBFFieldDefs.AssignValues(Value: TVKDBFFieldDefs);
var
I: Integer;
P: TVKDBFFieldDef;
begin
for I := 0 to Value.Count - 1 do
begin
P := FindIndex(Value[I].Name);
if P <> nil then
P.Assign(Value[I]);
end;
end;
constructor TVKDBFFieldDefs.Create(AOwner: TPersistent);
begin
inherited Create(AOwner, TVKDBFFieldDef);
end;
function TVKDBFFieldDefs.FindIndex(const Value: string): TVKDBFFieldDef;
function HideFindIndex(FDS: TVKDBFFieldDefs; var FD: TVKDBFFieldDef): boolean;
var
i: Integer;
begin
for i := 0 to FDS.Count - 1 do
begin
FD := TVKDBFFieldDef(FDS.Items[i]);
if FD <> nil then begin
if AnsiCompareText(FD.Name, Value) = 0 then begin
Result := true;
Exit;
end;
if FD.DBFFieldDefs.Count > 0 then begin
Result := HideFindIndex(FD.DBFFieldDefs, FD);
if Result then Exit;
end;
end;
end;
Result := False;
end;
begin
Result := nil;
HideFindIndex(self, Result);
end;
{$IFDEF VER130}
function TVKDBFFieldDefs.GetCollectionOwner: TPersistent;
begin
Result := GetOwner;
end;
{$ENDIF}
function TVKDBFFieldDefs.GetItem(Index: Integer): TVKDBFFieldDef;
begin
Result := TVKDBFFieldDef(inherited Items[Index]);
end;
function TVKDBFFieldDefs.IsEqual(Value: TVKDBFFieldDefs): Boolean;
var
I: Integer;
begin
Result := (Count = Value.Count);
if Result then
for I := 0 to Count - 1 do
begin
Result := TVKDBFFieldDef(Items[I]).IsEqual(TVKDBFFieldDef(Value.Items[I]));
if not Result then Break;
end
end;
procedure TVKDBFFieldDefs.SetItem(Index: Integer; const Value: TVKDBFFieldDef);
begin
inherited SetItem(Index, TCollectionItem(Value));
end;
{ TVKDBFFieldDef }
procedure TVKDBFFieldDef.AssignTo(Dest: TPersistent);
begin
with Dest as TVKDBFFieldDef do begin
Name := self.Name;
field_type := self.field_type;
extend_type := self.extend_type;
len := self.len;
dec := self.dec;
FOff := self.FOff;
FOffHD := self.FOffHD;
FDBFFieldDefs.Assign(self.FDBFFieldDefs);
end;
end;
constructor TVKDBFFieldDef.Create(Collection: TCollection);
begin
inherited Create(Collection);
FDBFFieldDefs := TVKDBFFieldDefs.Create(self);
FTag := 0;
end;
procedure TVKDBFFieldDef.DefineProperties(Filer: TFiler);
function WriteDBFFieldDefDataB: Boolean;
begin
if Filer.Ancestor <> nil then
Result := not FDBFFieldDefs.IsEqual(TVKDBFFieldDef(Filer.Ancestor).FDBFFieldDefs)
else
Result := (FDBFFieldDefs.Count > 0);
end;
begin
inherited DefineProperties(Filer);
Filer.DefineProperty('DBFFieldDefs', ReadDBFFieldDefData, WriteDBFFieldDefData, WriteDBFFieldDefDataB);
end;
procedure TVKDBFFieldDef.ReadDBFFieldDefData(Reader: TReader);
begin
Reader.ReadValue;
Reader.ReadCollection(DBFFieldDefs);
end;
procedure TVKDBFFieldDef.WriteDBFFieldDefData(Writer: TWriter);
begin
Writer.WriteCollection(DBFFieldDefs);
end;
destructor TVKDBFFieldDef.Destroy;
begin
FDBFFieldDefs.Destroy;
inherited Destroy;
end;
function TVKDBFFieldDef.GetDataSize: Word;
begin
//C N D L M E
case FieldRec.field_type of
'C', 'N': Result := len;
'D': Result := 8;
'L': Result := 1;
'M': Result := 10;
'E':
case FieldRec.extend_type of
dbftS1: Result := 1; //Shortint
dbftU1: Result := 1; //Byte
dbftS2: Result := 2; //Smallint
dbftU2: Result := 2; //Word
dbftS4: Result := 4; //Longint
dbftU4: Result := 4; //Longword
dbftS8: Result := 8; //Int64
dbftR4: Result := 4; //Single
dbftR6: Result := 6; //Real48
dbftR8: Result := 8; //Double
dbftR10: Result := 10; //Extended
dbftD1: Result := 8; //TDateTime
dbftD2: Result := 8; //DataSet DateTime
dbftD3: Result := 6; //Real48 DateTime
dbftS1_N: Result := 2; //Shortint with NULL
dbftU1_N: Result := 2; //Byte with NULL
dbftS2_N: Result := 3; //Smallint with NULL
dbftU2_N: Result := 3; //Word with NULL
dbftS4_N: Result := 5; //Longint with NULL
dbftU4_N: Result := 5; //Longword with NULL
dbftS8_N: Result := 9; //Int64 with NULL
dbftR4_N: Result := 5; //Single with NULL
dbftR6_N: Result := 7; //Real48 with NULL
dbftR8_N: Result := 9; //Double with NULL
dbftR10_N: Result := 11; //Extended with NULL
dbftD1_N: Result := 9; //TDateTime with NULL
dbftD2_N: Result := 9; //DataSet DateTime with NULL
dbftD3_N: Result := 7; //Real48 DateTime
dbftClob: Result := 10;
dbftBlob: Result := 10;
dbftGraphic: Result := 10;
dbftFmtMemo: Result := 10;
dbftClob_NB: Result := 4;
dbftBlob_NB: Result := 4;
dbftGraphic_NB: Result := 4;
dbftFmtMemo_NB: Result := 4;
dbftString: Result := len + 2;
dbftString_N: Result := len + 3;
dbftFixedChar: Result := len + 1;
dbftWideString: Result := len * 2 + 4;
dbftCurrency: Result := 8;
dbftCurrency_N: Result := 9;
dbftCurrency_NB: Result := 8;
dbftBCD: Result := SizeOf(TBcd);
dbftDate: Result := 4; //ftDate
dbftDate_N: Result := 5; //ftDate with NULL byte
dbftTime: Result := 4; //ftTime
dbftTime_N: Result := 5; //ftTime with NULL byte
dbftU1_NB: Result := 1;
dbftU2_NB: Result := 2;
dbftU4_NB: Result := 4;
dbftR4_NB: Result := 4;
dbftR6_NB: Result := 6;
dbftR8_NB: Result := 8;
dbftD1_NB: Result := 8;
dbftD2_NB: Result := 8;
dbftD3_NB: Result := 6;
dbftDate_NB: Result := 4;
dbftTime_NB: Result := 4;
dbftDBFDataSet: Result := 10;
dbftDBFDataSet_NB: Result := 10;
else
raise Exception.Create('Extend_type incarect!');
end;
else
raise Exception.Create('Field_type incarect!');
end;
end;
function TVKDBFFieldDef.GetDisplayName: string;
begin
Result := FieldRec.field_name;
end;
function TVKDBFFieldDef.GetField: FIELD_REC;
begin
//C N D L M E
case FieldRec.field_type of
'C':
begin
FieldRec.lendth.char_len := len;
end;
'N':
begin
FieldRec.lendth.num_len.len := Byte(len);
FieldRec.lendth.num_len.dec := Byte(dec);
end;
'D':
begin
FieldRec.lendth.num_len.len := Byte(8);
FieldRec.lendth.num_len.dec := Byte(0);
end;
'L':
begin
FieldRec.lendth.num_len.len := Byte(1);
FieldRec.lendth.num_len.dec := Byte(0);
end;
'M':
begin
FieldRec.lendth.num_len.len := Byte(10);
FieldRec.lendth.num_len.dec := Byte(0);
end;
'E':
begin
if FieldRec.extend_type in [ dbftString, dbftString_N,
dbftFixedChar, dbftWideString] then begin
FieldRec.lendth.num_len.len := Byte(len);
end else if FieldRec.extend_type in [dbftBCD] then begin
FieldRec.lendth.num_len.len := Byte(len);
FieldRec.lendth.num_len.dec := Byte(dec);
end else begin
FieldRec.lendth.num_len.len := Byte(0);
FieldRec.lendth.num_len.dec := Byte(0);
end;
end;
else
raise Exception.Create('Field_type incarect!');
end;
Result := FieldRec;
end;
function TVKDBFFieldDef.IsEqual(Value: TVKDBFFieldDef): Boolean;
begin
Result := false;
if Value.Name = Name then Result := true;
if Result then begin
if ( Value.DBFFieldDefs.Count = DBFFieldDefs.Count ) then
Result := DBFFieldDefs.IsEqual(Value.DBFFieldDefs);
end;
end;
procedure TVKDBFFieldDef.SetDBFFieldDefs(const Value: TVKDBFFieldDefs);
begin
FDBFFieldDefs := Value;
end;
procedure TVKDBFFieldDef.SetDisplayName(const Value: string);
var
l: Integer;
begin
l := Length(Value);
if l > 10 then raise ERangeError.CreateFmt('Field length must be <= 10, but no %d!', [l]);
FillChar(FieldRec.field_name, 11, 0);
Move(pChar(Value)^, FieldRec.field_name, l);
end;
{ TVKDBTStream }
procedure TVKDBTStream.Clear;
begin
inherited Clear;
FModified := true;
end;
constructor TVKDBTStream.Create;
begin
inherited Create;
FModified := false;
end;
constructor TVKDBTStream.CreateDBTStream(dbf: TVKSmartDBF; field: TField);
begin
inherited Create;
FModified := false;
FSmartDBF := dbf;
FField := field;
end;
destructor TVKDBTStream.Destroy;
begin
if FModified then
SaveToDBT;
inherited Destroy;
end;
procedure TVKDBTStream.SaveToDBT;
begin
FSmartDBF.SaveToDBT(self, FField);
end;
procedure TVKDBTStream.SetSize(NewSize: Integer);
begin
inherited SetSize(NewSize);
FModified := true;
end;
function TVKDBTStream.Write(const Buffer; Count: Integer): Longint;
begin
FModified := true;
Result := inherited Write(Buffer, Count);
end;
{ TVKDBFCrypt }
constructor TVKDBFCrypt.Create;
begin
inherited Create;
FActive := false;
FCryptMethod := cmNONE;
FPassword := '';
FOnEncrypt := nil;
FOnDecrypt := nil;
end;
destructor TVKDBFCrypt.Destroy;
begin
Active := false;
inherited Destroy;
end;
procedure TVKDBFCrypt.Decrypt(Context: LongWord; Buff: Pointer; Size: Integer);
begin
if not Assigned(FOnDecrypt) then
case FCryptMethod of
cmXOR: XORDecrypt(FObjectID, Context, Buff, Size);
cmGost: GostDecrypt(FObjectID, Context, Buff, Size);
end
else
FOnDecrypt(self, Context, Buff, Size);
end;
procedure TVKDBFCrypt.Encrypt(Context: LongWord; Buff: Pointer; Size: Integer);
begin
if not Assigned(FOnEncrypt) then
case FCryptMethod of
cmXOR: XOREncrypt(FObjectID, Context, Buff, Size);
cmGost: GostEncrypt(FObjectID, Context, Buff, Size);
end
else
FOnEncrypt(self, Context, Buff, Size);
end;
procedure TVKDBFCrypt.SetActive(const Value: boolean);
begin
if Value <> FActive then begin
FActive := Value;
if FActive then begin
if Assigned(FOnActivate) then
FOnActivate(self)
else
case FCryptMethod of
cmXOR: FObjectID := XORActivate(FPassword);
cmGost: FObjectID := GostActivate(FPassword);
end;
end else begin
if Assigned(FOnDeactivate) then
FOnDeactivate(self)
else
case FCryptMethod of
cmXOR: XORDeactivate(FObjectID);
cmGost: GostDeactivate(FObjectID);
end;
end;
end;
end;
{ TVKNestedDBF }
procedure TVKNestedDBF.CloseLobStream;
begin
// Nothing to do
end;
constructor TVKNestedDBF.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
StorageType := pstInnerStream;
end;
procedure TVKNestedDBF.CreateLobStream(dbf_id: Byte);
begin
LobHandler := ParentDataSet.LobHandler;
end;
procedure TVKNestedDBF.DataEvent(Event: TDataEvent; Info: Integer);
var
i: Integer;
oNested: TVKNestedDBF;
begin
case Event of
deFieldChange: ParentDataSet.DataEvent(deFieldChange, Info);
deParentScroll:
begin
Close;
Open;
for i := 0 to NestedDataSets.Count - 1 do begin
oNested := TVKNestedDBF(NestedDataSets[i]);
oNested.DataEvent(Event, Info);
end;
end;
end;
inherited DataEvent(Event, Info);
end;
procedure TVKNestedDBF.DeleteRecallRecord(Del: boolean = true);
begin
inherited DeleteRecallRecord(Del);
SaveOnTheSamePlaceToDBT(TMemoryStream(self.InnerStream), DataSetField);
end;
function TVKNestedDBF.GetPackLobHandler: TProxyStream;
begin
Result := nil;
if ParentDataSet <> nil then Result := ParentDataSet.PackLobHandler;
end;
function TVKNestedDBF.GetParentDataSet: TVKSmartDBF;
begin
Result := nil;
if DataSetField <> nil then
Result := DataSetField.DataSet as TVKSmartDBF;
end;
procedure TVKNestedDBF.InternalOpen;
begin
ParentDataSet.CreateNestedStream(self, DataSetField, self.InnerStream);
OEM := ParentDataSet.OEM;
SetDeleted := ParentDataSet.SetDeleted;
inherited InternalOpen;
end;
procedure TVKNestedDBF.InternalPost;
begin
inherited InternalPost;
SaveToDBT(TMemoryStream(self.InnerStream), DataSetField);
end;
procedure TVKNestedDBF.LobHandlerCreate;
begin
// Nothing to do
end;
procedure TVKNestedDBF.LobHandlerDestroy;
begin
// Nothing to do
end;
procedure TVKNestedDBF.OpenLobStream(dbf_id: Byte);
begin
// Nothing to do
end;
procedure TVKNestedDBF.PackLobHandlerClose(LobName, TempLobName: String);
begin
SaveToDBT(TMemoryStream(self.InnerStream), DataSetField);
end;
procedure TVKNestedDBF.PackLobHandlerCreate;
begin
// Nothing to do
end;
procedure TVKNestedDBF.PackLobHandlerDestroy;
begin
// Nothing to do
end;
procedure TVKNestedDBF.PackLobHandlerOpen(TempLobName: String);
begin
// Nothing to do
end;
procedure TVKNestedDBF.SetDataSetField(const Value: TDataSetField);
begin
inherited SetDataSetField(Value);
if ParentDataSet <> nil then
LobHandler := ParentDataSet.LobHandler;
end;
end.