?? rxmemds.pas
字號:
{*******************************************************}
{ }
{ Delphi VCL Extensions (RX) }
{ }
{ Copyright (c) 1998 Master-Bank }
{ }
{*******************************************************}
unit RxMemDS;
{$I RX.INC}
interface
{$IFDEF RX_D3}
uses Windows, SysUtils, Classes, Controls, DB, DBUtils, Variants;
{ TRxMemoryData }
type
TMemBlobData = string;
TMemBlobArray = array[0..0] of TMemBlobData;
PMemBlobArray = ^TMemBlobArray;
TMemoryRecord = class;
TLoadMode = (lmCopy, lmAppend);
TCompareRecords = function (Item1, Item2: TMemoryRecord): Integer of object;
TRxMemoryData = class(TDataSet)
private
FRecordPos: Integer;
FRecordSize: Integer;
FBookmarkOfs: Integer;
FBlobOfs: Integer;
FRecBufSize: Integer;
FOffsets: PWordArray;
FLastID: Integer;
FAutoInc: Longint;
FActive: Boolean;
FRecords: TList;
FIndexList: TList;
FCaseInsensitiveSort: Boolean;
FDescendingSort: Boolean;
function AddRecord: TMemoryRecord;
function InsertRecord(Index: Integer): TMemoryRecord;
function FindRecordID(ID: Integer): TMemoryRecord;
procedure CreateIndexList(const FieldNames: string);
procedure FreeIndexList;
procedure QuickSort(L, R: Integer; Compare: TCompareRecords);
procedure Sort;
function CalcRecordSize: Integer;
function FindFieldData(Buffer: Pointer; Field: TField): Pointer;
function GetMemoryRecord(Index: Integer): TMemoryRecord;
function GetCapacity: Integer;
function RecordFilter: Boolean;
procedure SetCapacity(Value: Integer);
procedure ClearRecords;
procedure InitBufferPointers(GetProps: Boolean);
protected
procedure AssignMemoryRecord(Rec: TMemoryRecord; Buffer: PChar);
function GetActiveRecBuf(var RecBuf: PChar): Boolean; virtual;
procedure InitFieldDefsFromFields;
procedure RecordToBuffer(Rec: TMemoryRecord; Buffer: PChar);
procedure SetMemoryRecordData(Buffer: PChar; Pos: Integer); virtual;
procedure SetAutoIncFields(Buffer: PChar); virtual;
function CompareRecords(Item1, Item2: TMemoryRecord): Integer; virtual;
function GetBlobData(Field: TField; Buffer: PChar): TMemBlobData;
procedure SetBlobData(Field: TField; Buffer: PChar; Value: TMemBlobData);
function AllocRecordBuffer: PChar; override;
procedure FreeRecordBuffer(var Buffer: PChar); override;
{$IFNDEF RX_D5}
function BCDToCurr(BCD: Pointer; var Curr: Currency): Boolean; override;
function CurrToBCD(const Curr: Currency; BCD: Pointer; Precision,
Decimals: Integer): Boolean; override;
{$ENDIF}
procedure InternalInitRecord(Buffer: PChar); override;
procedure ClearCalcFields(Buffer: PChar); override;
function GetRecord(Buffer: PChar; GetMode: TGetMode;
DoCheck: Boolean): TGetResult; override;
function GetRecordSize: Word; override;
procedure SetFiltered(Value: Boolean); override;
procedure SetOnFilterRecord(const Value: TFilterRecordEvent); override;
procedure SetFieldData(Field: TField; Buffer: Pointer); override;
procedure CloseBlob(Field: TField); override;
procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;
function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;
procedure InternalGotoBookmark(Bookmark: TBookmark); override;
procedure InternalSetToRecord(Buffer: PChar); override;
procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;
procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override;
function GetIsIndexField(Field: TField): Boolean; override;
procedure InternalFirst; override;
procedure InternalLast; override;
procedure InitRecord(Buffer: PChar); override;
procedure InternalAddRecord(Buffer: Pointer; Append: Boolean); override;
procedure InternalDelete; override;
procedure InternalPost; override;
procedure InternalClose; override;
procedure InternalHandleException; override;
procedure InternalInitFieldDefs; override;
procedure InternalOpen; override;
procedure OpenCursor(InfoQuery: Boolean); override;
function IsCursorOpen: Boolean; override;
function GetRecordCount: Integer; override;
function GetRecNo: Integer; override;
procedure SetRecNo(Value: Integer); override;
property Records[Index: Integer]: TMemoryRecord read GetMemoryRecord;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function BookmarkValid(Bookmark: TBookmark): Boolean; override;
function CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Integer; override;
function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override;
function GetCurrentRecord(Buffer: PChar): Boolean; override;
function IsSequenced: Boolean; override;
function Locate(const KeyFields: string; const KeyValues: Variant;
Options: TLocateOptions): Boolean; override;
procedure SortOnFields(const FieldNames: string;
{$IFDEF RX_D4}
CaseInsensitive: Boolean = True; Descending: Boolean = False);
{$ELSE}
CaseInsensitive, Descending: Boolean);
{$ENDIF}
procedure EmptyTable;
procedure CopyStructure(Source: TDataSet);
function LoadFromDataSet(Source: TDataSet; RecordCount: Integer;
Mode: TLoadMode): Integer;
function SaveToDataSet(Dest: TDataSet; RecordCount: Integer): Integer;
published
property Capacity: Integer read GetCapacity write SetCapacity default 0;
property Active;
property AutoCalcFields;
property Filtered;
{$IFDEF RX_D4}
property FieldDefs;
property ObjectView default False;
{$ENDIF}
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;
end;
{ TMemBlobStream }
TMemBlobStream = class(TStream)
private
FField: TBlobField;
FDataSet: TRxMemoryData;
FBuffer: PChar;
FMode: TBlobStreamMode;
FOpened: Boolean;
FModified: Boolean;
FPosition: Longint;
FCached: Boolean;
function GetBlobSize: Longint;
function GetBlobFromRecord(Field: TField): TMemBlobData;
public
constructor Create(Field: TBlobField; Mode: TBlobStreamMode);
destructor Destroy; override;
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
function Seek(Offset: Longint; Origin: Word): Longint; override;
procedure Truncate;
end;
{ TMemoryRecord }
TMemoryRecord = class(TPersistent)
private
FMemoryData: TRxMemoryData;
FID: Integer;
FData: Pointer;
FBlobs: Pointer;
function GetIndex: Integer;
procedure SetMemoryData(Value: TRxMemoryData; UpdateParent: Boolean);
protected
procedure SetIndex(Value: Integer); virtual;
public
constructor Create(MemoryData: TRxMemoryData); virtual;
constructor CreateEx(MemoryData: TRxMemoryData; UpdateParent: Boolean); virtual;
destructor Destroy; override;
property MemoryData: TRxMemoryData read FMemoryData;
property ID: Integer read FID write FID;
property Index: Integer read GetIndex write SetIndex;
property Data: Pointer read FData;
end;
{$ENDIF RX_D3}
implementation
{$IFDEF RX_D3}
uses Forms, DbConsts {$IFDEF RX_D5}, ComObj {$ENDIF};
resourcestring
SMemNoRecords = 'No data found';
{$IFNDEF RX_D4}
SInvalidFields = 'No fields defined';
{$ENDIF}
const
ftBlobTypes = [ftBlob, ftMemo, ftGraphic, ftFmtMemo, ftParadoxOle,
ftDBaseOle, ftTypedBinary {$IFDEF RX_D5}, ftOraBlob, ftOraClob {$ENDIF}];
ftSupported = [ftString, ftSmallint, ftInteger, ftWord, ftBoolean, ftFloat,
ftCurrency, ftDate, ftTime, ftDateTime, ftAutoInc, ftBCD, ftBytes,
ftVarBytes {$IFDEF RX_D4}, ftADT, ftFixedChar, ftWideString,
ftLargeint {$ENDIF} {$IFDEF RX_D5}, ftVariant, ftGuid {$ENDIF}] +
ftBlobTypes;
fkStoredFields = [fkData];
{$IFDEF RX_D5}
GuidSize = 38;
{$ENDIF}
{ Utility routines }
function CompareFields(Data1, Data2: Pointer; FieldType: TFieldType;
CaseInsensitive: Boolean): Integer;
begin
Result := 0;
case FieldType of
ftString:
if CaseInsensitive then
Result := AnsiCompareText(PChar(Data1), PChar(Data2))
else
Result := AnsiCompareStr(PChar(Data1), PChar(Data2));
ftSmallint:
if SmallInt(Data1^) > SmallInt(Data2^) then Result := 1
else if SmallInt(Data1^) < SmallInt(Data2^) then Result := -1;
ftInteger, ftDate, ftTime, ftAutoInc:
if Longint(Data1^) > Longint(Data2^) then Result := 1
else if Longint(Data1^) < Longint(Data2^) then Result := -1;
ftWord:
if Word(Data1^) > Word(Data2^) then Result := 1
else if Word(Data1^) < Word(Data2^) then Result := -1;
ftBoolean:
if WordBool(Data1^) and not WordBool(Data2^) then Result := 1
else if not WordBool(Data1^) and WordBool(Data2^) then Result := -1;
ftFloat, ftCurrency:
if Double(Data1^) > Double(Data2^) then Result := 1
else if Double(Data1^) < Double(Data2^) then Result := -1;
ftDateTime:
if TDateTime(Data1^) > TDateTime(Data2^) then Result := 1
else if TDateTime(Data1^) < TDateTime(Data2^) then Result := -1;
{$IFDEF RX_D4}
ftFixedChar:
if CaseInsensitive then
Result := AnsiCompareText(PChar(Data1), PChar(Data2))
else
Result := AnsiCompareStr(PChar(Data1), PChar(Data2));
ftWideString:
if CaseInsensitive then
Result := AnsiCompareText(WideCharToString(PWideChar(Data1)),
WideCharToString(PWideChar(Data2)))
else
Result := AnsiCompareStr(WideCharToString(PWideChar(Data1)),
WideCharToString(PWideChar(Data2)));
ftLargeint:
if Int64(Data1^) > Int64(Data2^) then Result := 1
else if Int64(Data1^) < Int64(Data2^) then Result := -1;
{$ENDIF}
{$IFDEF RX_D5}
ftVariant:
Result := 0;
ftGuid:
Result := AnsiCompareText(PChar(Data1), PChar(Data2));
{$ENDIF}
end;
end;
function CalcFieldLen(FieldType: TFieldType; Size: Word): Word;
begin
if not (FieldType in ftSupported) then
Result := 0
else if (FieldType in ftBlobTypes) then
Result := SizeOf(Longint)
else begin
Result := Size;
case FieldType of
ftString: Inc(Result);
ftSmallint: Result := SizeOf(SmallInt);
ftInteger: Result := SizeOf(Longint);
ftWord: Result := SizeOf(Word);
ftBoolean: Result := SizeOf(WordBool);
ftFloat: Result := SizeOf(Double);
ftCurrency: Result := SizeOf(Double);
ftBCD: Result := 34;
ftDate, ftTime: Result := SizeOf(Longint);
ftDateTime: Result := SizeOf(TDateTime);
ftBytes: Result := Size;
ftVarBytes: Result := Size + 2;
ftAutoInc: Result := SizeOf(Longint);
{$IFDEF RX_D4}
ftADT: Result := 0;
ftFixedChar: Inc(Result);
ftWideString: Result := (Result + 1) * 2;
ftLargeint: Result := SizeOf(Int64);
{$ENDIF}
{$IFDEF RX_D5}
ftVariant: Result := SizeOf(Variant);
ftGuid: Result := GuidSize + 1;
{$ENDIF}
end;
end;
end;
procedure CalcDataSize(FieldDef: TFieldDef; var DataSize: Integer);
{$IFDEF RX_D4}
var
I: Integer;
{$ENDIF}
begin
with FieldDef do begin
if (DataType in ftSupported - ftBlobTypes) then
Inc(DataSize, CalcFieldLen(DataType, Size) + 1);
{$IFDEF RX_D4}
for I := 0 to ChildDefs.Count - 1 do
CalcDataSize(ChildDefs[I], DataSize);
{$ENDIF}
end;
end;
procedure Error(const Msg: string);
begin
DatabaseError(Msg);
end;
procedure ErrorFmt(const Msg: string; const Args: array of const);
begin
DatabaseErrorFmt(Msg, Args);
end;
type
TBookmarkData = Integer;
PMemBookmarkInfo = ^TMemBookmarkInfo;
TMemBookmarkInfo = record
BookmarkData: TBookmarkData;
BookmarkFlag: TBookmarkFlag;
end;
{ TMemoryRecord }
constructor TMemoryRecord.Create(MemoryData: TRxMemoryData);
begin
CreateEx(MemoryData, True);
end;
constructor TMemoryRecord.CreateEx(MemoryData: TRxMemoryData;
UpdateParent: Boolean);
begin
inherited Create;
SetMemoryData(MemoryData, UpdateParent);
end;
destructor TMemoryRecord.Destroy;
begin
SetMemoryData(nil, True);
inherited Destroy;
end;
function TMemoryRecord.GetIndex: Integer;
begin
if FMemoryData <> nil then Result := FMemoryData.FRecords.IndexOf(Self)
else Result := -1;
end;
procedure TMemoryRecord.SetMemoryData(Value: TRxMemoryData; UpdateParent: Boolean);
var
I: Integer;
DataSize: Integer;
begin
if FMemoryData <> Value then begin
if FMemoryData <> nil then begin
FMemoryData.FRecords.Remove(Self);
if FMemoryData.BlobFieldCount > 0 then
Finalize(PMemBlobArray(FBlobs)[0], FMemoryData.BlobFieldCount);
ReallocMem(FBlobs, 0);
ReallocMem(FData, 0);
FMemoryData := nil;
end;
if Value <> nil then begin
if UpdateParent then begin
Value.FRecords.Add(Self);
Inc(Value.FLastID);
FID := Value.FLastID;
end;
FMemoryData := Value;
if Value.BlobFieldCount > 0 then begin
ReallocMem(FBlobs, Value.BlobFieldCount * SizeOf(Pointer));
Initialize(PMemBlobArray(FBlobs)[0], Value.BlobFieldCount);
end;
DataSize := 0;
for I := 0 to Value.FieldDefs.Count - 1 do
CalcDataSize(Value.FieldDefs[I], DataSize);
ReallocMem(FData, DataSize);
end;
end;
end;
procedure TMemoryRecord.SetIndex(Value: Integer);
var
CurIndex: Integer;
begin
CurIndex := GetIndex;
if (CurIndex >= 0) and (CurIndex <> Value) then
FMemoryData.FRecords.Move(CurIndex, Value);
end;
{ TRxMemoryData }
constructor TRxMemoryData.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FRecordPos := -1;
FLastID := Low(Integer);
FAutoInc := 1;
FRecords := TList.Create;
end;
destructor TRxMemoryData.Destroy;
begin
inherited Destroy;
FreeIndexList;
ClearRecords;
FRecords.Free;
ReallocMem(FOffsets, 0);
end;
{ Records Management }
function TRxMemoryData.GetCapacity: Integer;
begin
if FRecords <> nil then Result := FRecords.Capacity
else Result := 0;
end;
procedure TRxMemoryData.SetCapacity(Value: Integer);
begin
if FRecords <> nil then FRecords.Capacity := Value;
end;
function TRxMemoryData.AddRecord: TMemoryRecord;
begin
Result := TMemoryRecord.Create(Self);
end;
function TRxMemoryData.FindRecordID(ID: Integer): TMemoryRecord;
var
I: Integer;
begin
for I := 0 to FRecords.Count - 1 do begin
Result := TMemoryRecord(FRecords[I]);
if Result.ID = ID then Exit;
end;
Result := nil;
end;
function TRxMemoryData.InsertRecord(Index: Integer): TMemoryRecord;
begin
Result := AddRecord;
Result.Index := Index;
end;
function TRxMemoryData.GetMemoryRecord(Index: Integer): TMemoryRecord;
begin
Result := TMemoryRecord(FRecords[Index]);
end;
{ Field Management }
{$IFNDEF RX_D5}
function TRxMemoryData.BCDToCurr(BCD: Pointer; var Curr: Currency): Boolean;
begin
Move(BCD^, Curr, SizeOf(Currency));
Result := True;
end;
function TRxMemoryData.CurrToBCD(const Curr: Currency; BCD: Pointer; Precision,
Decimals: Integer): Boolean;
begin
Move(Curr, BCD^, SizeOf(Currency));
Result := True;
end;
{$ENDIF RX_D5}
procedure TRxMemoryData.InitFieldDefsFromFields;
var
I: Integer;
Offset: Word;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -