lazarus-ccr/components/rx/dbutils.pas
alexs75 d7d4a207dc new components
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@704 8e941d3f-bd1b-0410-a28a-d453659cc2b4
2009-02-12 19:47:57 +00:00

916 lines
25 KiB
ObjectPascal

{*******************************************************}
{ }
{ Delphi VCL Extensions (RX) }
{ }
{ Copyright (c) 1995, 1996 AO ROSNO }
{ Copyright (c) 1997, 1998 Master-Bank }
{ }
{*******************************************************}
unit dbutils;
{$I rx.inc}
interface
uses
LCLType, LCLProc, LCLIntf, Registry, Classes, SysUtils, DB, IniFiles;
const
IntegerDataTypes = [ftSmallint, ftInteger, ftWord, ftLargeint];
NumericDataTypes = IntegerDataTypes + [ftFloat, ftCurrency, ftBCD];
const
TimeDataTypes = [ftTime, ftDateTime, ftTimeStamp];
type
{ TLocateObject }
TLocateObject = class(TObject)
private
FDataSet: TDataSet;
FLookupField: TField;
FLookupValue: string;
FLookupExact, FCaseSensitive: Boolean;
FBookmark: TBookmark;
FIndexSwitch: Boolean;
procedure SetDataSet(Value: TDataSet);
protected
function MatchesLookup(Field: TField): Boolean;
procedure CheckFieldType(Field: TField); virtual;
procedure ActiveChanged; virtual;
function LocateFilter: Boolean; virtual;
function LocateKey: Boolean; virtual;
function LocateFull: Boolean; virtual;
function UseKey: Boolean; virtual;
function FilterApplicable: Boolean; virtual;
property LookupField: TField read FLookupField;
property LookupValue: string read FLookupValue;
property LookupExact: Boolean read FLookupExact;
property CaseSensitive: Boolean read FCaseSensitive;
property Bookmark: TBookmark read FBookmark write FBookmark;
public
function Locate(const KeyField, KeyValue: string; Exact,
ACaseSensitive: Boolean): Boolean;
property DataSet: TDataSet read FDataSet write SetDataSet;
property IndexSwitch: Boolean read FIndexSwitch write FIndexSwitch;
end;
type
TCreateLocateObject = function: TLocateObject;
const
CreateLocateObject: TCreateLocateObject = nil;
function CreateLocate(DataSet: TDataSet): TLocateObject;
{ Utility routines }
function IsDataSetEmpty(DataSet: TDataSet): Boolean;
procedure RefreshQuery(Query: TDataSet);
function DataSetSortedSearch(DataSet: TDataSet; const Value,
FieldName: string; CaseInsensitive: Boolean): Boolean;
function DataSetSectionName(DataSet: TDataSet): string;
procedure InternalSaveFields(DataSet: TDataSet; IniFile: TObject;
const Section: string);
procedure InternalRestoreFields(DataSet: TDataSet; IniFile: TObject;
const Section: string; RestoreVisible: Boolean);
{procedure InternalSaveFields(DataSet: TDataSet; IniFile: TIniFile;
const Section: string);
procedure InternalRestoreFields(DataSet: TDataSet; IniFile: TObject;
const Section: string; RestoreVisible: Boolean);}
function DataSetLocateThrough(DataSet: TDataSet; const KeyFields: string;
const KeyValues: Variant; Options: TLocateOptions): Boolean;
procedure SaveFieldsReg(DataSet: TDataSet; IniFile: TRegIniFile);
procedure RestoreFieldsReg(DataSet: TDataSet; IniFile: TRegIniFile;
RestoreVisible: Boolean);
procedure SaveFields(DataSet: TDataSet; IniFile: TIniFile);
procedure RestoreFields(DataSet: TDataSet; IniFile: TIniFile;
RestoreVisible: Boolean);
procedure AssignRecord(Source, Dest: TDataSet; ByName: Boolean);
function ConfirmDelete: Boolean;
procedure ConfirmDataSetCancel(DataSet: TDataSet);
procedure CheckRequiredField(Field: TField);
procedure CheckRequiredFields(const Fields: array of TField);
function ExtractFieldName(const Fields: string; var Pos: Integer): string;
procedure FillValueForField(const Field: TField; Value:Variant);
{ SQL expressions }
function DateToSQL(Value: TDateTime): string;
function FormatSQLDateRange(Date1, Date2: TDateTime;
const FieldName: string): string;
function FormatSQLDateRangeEx(Date1, Date2: TDateTime;
const FieldName: string): string;
function FormatSQLNumericRange(const FieldName: string;
LowValue, HighValue, LowEmpty, HighEmpty: Double; Inclusive: Boolean): string;
function StrMaskSQL(const Value: string): string;
function FormatSQLCondition(const FieldName, AOperator, Value: string;
FieldType: TFieldType; Exact: Boolean): string;
function FormatAnsiSQLCondition(const FieldName, AOperator, Value: string;
FieldType: TFieldType; Exact: Boolean): string;
const
TrueExpr = '0=0';
const
{ Server Date formats}
sdfStandard16 = '''"''mm''/''dd''/''yyyy''"'''; {"mm/dd/yyyy"}
sdfStandard32 = '''''''dd/mm/yyyy'''''''; {'dd/mm/yyyy'}
sdfOracle = '"TO_DATE(''"dd/mm/yyyy"'', ''DD/MM/YYYY'')"';
sdfInterbase = '"CAST(''"mm"/"dd"/"yyyy"'' AS DATE)"';
sdfMSSQL = '"CONVERT(datetime, ''"mm"/"dd"/"yyyy"'', 103)"';
const
ServerDateFmt: string[50] = sdfStandard16;
{const
ftBlobTypes = [Low(TBlobType)..High(TBlobType)];}
procedure _DBError(const Msg: string);
implementation
uses Forms, Controls, Dialogs, RXDConst, VCLUtils, FileUtil,
AppUtils, RxAppUtils, RxStrUtils, Math, DateUtil;
{ Utility routines }
procedure _DBError(const Msg: string);
begin
DatabaseError(Msg);
end;
function ConfirmDelete: Boolean;
begin
Screen.Cursor := crDefault;
Result := MessageDlg(SDeleteRecordQuestion, mtConfirmation,
[mbYes, mbNo], 0) = mrYes;
end;
procedure ConfirmDataSetCancel(DataSet: TDataSet);
begin
if DataSet.State in [dsEdit, dsInsert] then begin
DataSet.UpdateRecord;
if DataSet.Modified then begin
case MessageDlg(SConfirmSave, mtConfirmation, mbYesNoCancel, 0) of
mrYes: DataSet.Post;
mrNo: DataSet.Cancel;
else SysUtils.Abort;
end;
end
else DataSet.Cancel;
end;
end;
function SetToBookmark(ADataSet: TDataSet; ABookmark: TBookmark): Boolean;
begin
Result := False;
with ADataSet do
if Active and (ABookmark <> nil) and not (Bof and Eof) and
BookmarkValid(ABookmark) then
try
ADataSet.GotoBookmark(ABookmark);
Result := True;
except
end;
end;
{ Refresh Query procedure }
procedure RefreshQuery(Query: TDataSet);
var
BookMk: TBookmark;
begin
with Query do
begin
DisableControls;
try
if Active then
BookMk := GetBookmark
else
BookMk := nil;
try
Close;
Open;
SetToBookmark(Query, BookMk);
finally
if BookMk <> nil then
FreeBookmark(BookMk);
end;
finally
EnableControls;
end;
end;
end;
{ TLocateObject }
procedure TLocateObject.SetDataSet(Value: TDataSet);
begin
ActiveChanged;
FDataSet := Value;
end;
function TLocateObject.LocateFull: Boolean;
begin
Result := False;
with DataSet do
begin
First;
while not EOF do
begin
if MatchesLookup(FLookupField) then
begin
Result := True;
Break;
end;
Next;
end;
end;
end;
function TLocateObject.LocateKey: Boolean;
begin
Result := False;
end;
function TLocateObject.FilterApplicable: Boolean;
begin
Result := FLookupField.FieldKind in [fkData, fkInternalCalc];
end;
function TLocateObject.LocateFilter: Boolean;
var
SaveCursor: TCursor;
Options: TLocateOptions;
Value: Variant;
begin
// SaveCursor := Screen.Cursor;
// Screen.Cursor := crHourGlass;
try
Options := [];
if not FCaseSensitive then Include(Options, loCaseInsensitive);
if not FLookupExact then Include(Options, loPartialKey);
if (FLookupValue = '') then
Value:=null //VarClear(Value)
else
Value := FLookupValue;
Result := DataSet.Locate(FLookupField.FieldName, Value, Options);
finally
// Screen.Cursor := SaveCursor;
end;
end;
procedure TLocateObject.CheckFieldType(Field: TField);
begin
end;
function TLocateObject.Locate(const KeyField, KeyValue: string;
Exact, ACaseSensitive: Boolean): Boolean;
var
LookupKey: TField;
begin
if DataSet = nil then
begin
Result := False;
Exit;
end;
DataSet.CheckBrowseMode;
LookupKey := DataSet.FieldByName(KeyField);
DataSet.CursorPosChanged;
FLookupField := LookupKey;
FLookupValue := KeyValue;
FLookupExact := Exact;
FCaseSensitive := ACaseSensitive;
if FLookupField.DataType <> ftString then
begin
FCaseSensitive := True;
try
CheckFieldType(FLookupField);
except
Result := False;
Exit;
end;
end;
FBookmark := DataSet.GetBookmark;
try
DataSet.DisableControls;
try
Result := MatchesLookup(FLookupField);
if not Result then
begin
if UseKey then
Result := LocateKey
else
begin
{ if FilterApplicable then Result := LocateFilter
else} Result := LocateFull;
end;
if not Result then SetToBookmark(DataSet, FBookmark);
end;
finally
DataSet.EnableControls;
end;
finally
FLookupValue := EmptyStr;
FLookupField := nil;
DataSet.FreeBookmark(FBookmark);
FBookmark := nil;
end;
end;
function TLocateObject.UseKey: Boolean;
begin
Result := False;
end;
procedure TLocateObject.ActiveChanged;
begin
end;
function TLocateObject.MatchesLookup(Field: TField): Boolean;
var
Temp: string;
begin
Temp := Field.AsString;
if not FLookupExact then
SetLength(Temp, Min(Length(FLookupValue), Length(Temp)));
if FCaseSensitive then Result := AnsiCompareStr(Temp, FLookupValue) = 0
else Result := AnsiCompareText(Temp, FLookupValue) = 0;
end;
function CreateLocate(DataSet: TDataSet): TLocateObject;
begin
if Assigned(CreateLocateObject) then Result := CreateLocateObject()
else Result := TLocateObject.Create;
if (Result <> nil) and (DataSet <> nil) then
Result.DataSet := DataSet;
end;
{ DataSet locate routines }
function DataSetLocateThrough(DataSet: TDataSet; const KeyFields: string;
const KeyValues: Variant; Options: TLocateOptions): Boolean;
var
FieldCount: Integer;
Fields: TList;
Bookmark: TBookmarkStr;
function CompareField(Field: TField; Value: Variant): Boolean;
var
S,S1: string;
begin
if Field.DataType = ftString then
begin
S := Field.AsString;
S1:=Value;
if (loPartialKey in Options) then
Delete(S, Length(S1) + 1, MaxInt);
if (loCaseInsensitive in Options) then
Result := AnsiCompareText(S, S1) = 0
else
Result := AnsiCompareStr(S, S1) = 0;
end
// else Result := false //(Field.Value = Value);
else Result := (Field.Value = Value);
end;
function CompareRecord: Boolean;
var
I: Integer;
begin
if FieldCount = 1 then
Result := CompareField(TField(Fields.First), KeyValues)
else begin
Result := True;
for I := 0 to FieldCount - 1 do
Result := Result and CompareField(TField(Fields[I]), KeyValues[I]);
end;
end;
begin
Result := False;
with DataSet do begin
CheckBrowseMode;
if BOF and EOF then Exit;
end;
Fields := TList.Create;
try
DataSet.GetFieldList(Fields, KeyFields);
FieldCount := Fields.Count;
Result := CompareRecord;
if Result then Exit;
DataSet.DisableControls;
try
Bookmark := DataSet.Bookmark;
try
with DataSet do begin
First;
while not EOF do begin
Result := CompareRecord;
if Result then Break;
Next;
end;
end;
finally
if not Result and DataSet.BookmarkValid(PChar(Bookmark)) then
DataSet.Bookmark := Bookmark;
end;
finally
DataSet.EnableControls;
end;
finally
Fields.Free;
end;
end;
procedure SaveFields(DataSet: TDataSet; IniFile: TIniFile);
begin
InternalSaveFields(DataSet, IniFile, DataSetSectionName(DataSet));
end;
procedure RestoreFields(DataSet: TDataSet; IniFile: TIniFile;
RestoreVisible: Boolean);
begin
InternalRestoreFields(DataSet, IniFile, DataSetSectionName(DataSet),
RestoreVisible);
end;
procedure SaveFieldsReg(DataSet: TDataSet; IniFile: TRegIniFile);
begin
InternalSaveFields(DataSet, IniFile, DataSetSectionName(DataSet));
end;
procedure RestoreFieldsReg(DataSet: TDataSet; IniFile: TRegIniFile;
RestoreVisible: Boolean);
begin
InternalRestoreFields(DataSet, IniFile, DataSetSectionName(DataSet),
RestoreVisible);
end;
{ DataSetSortedSearch. Navigate on sorted DataSet routine. }
function DataSetSortedSearch(DataSet: TDataSet; const Value,
FieldName: string; CaseInsensitive: Boolean): Boolean;
var
L, H, I: Longint;
CurrentPos: Longint;
CurrentValue: string;
BookMk: TBookmark;
Field: TField;
function UpStr(const Value: string): string;
begin
if CaseInsensitive then Result := AnsiUpperCase(Value)
else Result := Value;
end;
function GetCurrentStr: string;
begin
Result := Field.AsString;
if Length(Result) > Length(Value) then
SetLength(Result, Length(Value));
Result := UpStr(Result);
end;
begin
Result := False;
if DataSet = nil then Exit;
Field := DataSet.FindField(FieldName);
if Field = nil then Exit;
if Field.DataType = ftString then begin
DataSet.DisableControls;
BookMk := DataSet.GetBookmark;
try
L := 0;
DataSet.First;
CurrentPos := 0;
H := DataSet.RecordCount - 1;
if Value <> '' then begin
while L <= H do begin
I := (L + H) shr 1;
if I <> CurrentPos then DataSet.MoveBy(I - CurrentPos);
CurrentPos := I;
CurrentValue := GetCurrentStr;
if (UpStr(Value) > CurrentValue) then
L := I + 1
else begin
H := I - 1;
if (UpStr(Value) = CurrentValue) then Result := True;
end;
end; { while }
if Result then begin
if (L <> CurrentPos) then DataSet.MoveBy(L - CurrentPos);
while (L < DataSet.RecordCount) and
(UpStr(Value) <> GetCurrentStr) do
begin
Inc(L);
DataSet.MoveBy(1);
end;
end;
end
else Result := True;
if not Result then SetToBookmark(DataSet, BookMk);
finally
DataSet.FreeBookmark(BookMk);
DataSet.EnableControls;
end;
end
else
DatabaseErrorFmt(SFieldTypeMismatch, [Field.DisplayName]);
end;
{ Save and restore DataSet Fields layout }
function DataSetSectionName(DataSet: TDataSet): string;
begin
with DataSet do
if (Owner <> nil) and (Owner is TCustomForm) then
Result := GetDefaultSection(Owner as TCustomForm)
else Result := Name;
end;
function CheckSection(DataSet: TDataSet; const Section: string): string;
begin
Result := Section;
if Result = '' then Result := DataSetSectionName(DataSet);
end;
procedure InternalSaveFields(DataSet: TDataSet; IniFile: TObject;
const Section: string);
var
I: Integer;
begin
with DataSet do begin
for I := 0 to FieldCount - 1 do begin
IniWriteString(IniFile, CheckSection(DataSet, Section),
Name + Fields[I].FieldName,
Format('%d,%d,%d', [Fields[I].Index, Fields[I].DisplayWidth,
Integer(Fields[I].Visible)]));
end;
end;
end;
procedure InternalRestoreFields(DataSet: TDataSet; IniFile: TObject;
const Section: string; RestoreVisible: Boolean);
type
TFieldInfo = packed record
Field: TField;
EndIndex: Integer;
end;
PFieldArray = ^TFieldArray;
TFieldArray = array[0..(65528 div SizeOf(TFieldInfo)) - 1] of TFieldInfo;
const
Delims = [' ',','];
var
I, J: Integer;
S: string;
FieldArray: PFieldArray;
begin
{ with DataSet do begin
FieldArray := AllocMem(FieldCount * SizeOf(TFieldInfo));
try
for I := 0 to FieldCount - 1 do begin
S := IniReadString(IniFile, CheckSection(DataSet, Section),
Name + Fields[I].FieldName, '');
FieldArray^[I].Field := Fields[I];
FieldArray^[I].EndIndex := Fields[I].Index;
if S <> '' then begin
FieldArray^[I].EndIndex := StrToIntDef(ExtractWord(1, S, Delims),
FieldArray^[I].EndIndex);
Fields[I].DisplayWidth := StrToIntDef(ExtractWord(2, S, Delims),
Fields[I].DisplayWidth);
if RestoreVisible then
Fields[I].Visible := Boolean(StrToIntDef(ExtractWord(3, S, Delims),
Integer(Fields[I].Visible)));
end;
end;
for I := 0 to FieldCount - 1 do begin
for J := 0 to FieldCount - 1 do begin
if FieldArray^[J].EndIndex = I then begin
FieldArray^[J].Field.Index := FieldArray^[J].EndIndex;
Break;
end;
end;
end;
finally
FreeMemo(Pointer(FieldArray));
end;
end;}
end;
(*
procedure InternalSaveFields(DataSet: TDataSet; IniFile: TIniFile;
const Section: string);
var
I: Integer;
begin
with DataSet do
begin
for I := 0 to FieldCount - 1 do
begin
IniWriteString(IniFile, CheckSection(DataSet, Section),
Name + Fields[I].FieldName,
Format('%d,%d,%d', [Fields[I].Index, Fields[I].DisplayWidth,
Integer(Fields[I].Visible)]));
end;
end;
end;
procedure InternalRestoreFields(DataSet: TDataSet; IniFile: TObject;
const Section: string; RestoreVisible: Boolean);
type
TFieldInfo = packed record
Field: TField;
EndIndex: Integer;
end;
PFieldArray = ^TFieldArray;
TFieldArray = array[0..(65528 div SizeOf(TFieldInfo)) - 1] of TFieldInfo;
const
Delims = [' ',','];
var
I, J: Integer;
S: string;
FieldArray: PFieldArray;
begin
{ with DataSet do
begin
FieldArray := AllocMemo(FieldCount * SizeOf(TFieldInfo));
try
for I := 0 to FieldCount - 1 do begin
S := IniReadString(IniFile, CheckSection(DataSet, Section),
Name + Fields[I].FieldName, '');
FieldArray^[I].Field := Fields[I];
FieldArray^[I].EndIndex := Fields[I].Index;
if S <> '' then begin
FieldArray^[I].EndIndex := StrToIntDef(ExtractWord(1, S, Delims),
FieldArray^[I].EndIndex);
Fields[I].DisplayWidth := StrToIntDef(ExtractWord(2, S, Delims),
Fields[I].DisplayWidth);
if RestoreVisible then
Fields[I].Visible := Boolean(StrToIntDef(ExtractWord(3, S, Delims),
Integer(Fields[I].Visible)));
end;
end;
for I := 0 to FieldCount - 1 do begin
for J := 0 to FieldCount - 1 do begin
if FieldArray^[J].EndIndex = I then begin
FieldArray^[J].Field.Index := FieldArray^[J].EndIndex;
Break;
end;
end;
end;
finally
FreeMemo(Pointer(FieldArray));
end;
end;
}
end;
*)
{
procedure SaveFields(DataSet: TDataSet; IniFile: TIniFile);
begin
InternalSaveFields(DataSet, IniFile, DataSetSectionName(DataSet));
end;
procedure RestoreFields(DataSet: TDataSet; IniFile: TIniFile;
RestoreVisible: Boolean);
begin
InternalRestoreFields(DataSet, IniFile, DataSetSectionName(DataSet),
RestoreVisible);
end;
}
function IsDataSetEmpty(DataSet: TDataSet): Boolean;
begin
with DataSet do Result := (not Active) or (Eof and Bof);
end;
{ SQL expressions }
function DateToSQL(Value: TDateTime): string;
begin
Result := IntToStr(Trunc(Value));
end;
function FormatSQLDateRange(Date1, Date2: TDateTime;
const FieldName: string): string;
begin
Result := TrueExpr;
if (Date1 = Date2) and (Date1 <> NullDate) then
begin
Result := Format('%s = %s', [FieldName, FormatDateTime(ServerDateFmt,
Date1)]);
end
else
if (Date1 <> NullDate) or (Date2 <> NullDate) then
begin
if Date1 = NullDate then
Result := Format('%s < %s', [FieldName,
FormatDateTime(ServerDateFmt, IncDay(Date2, 1))])
else if Date2 = NullDate then
Result := Format('%s > %s', [FieldName,
FormatDateTime(ServerDateFmt, IncDay(Date1, -1))])
else
Result := Format('(%s < %s) AND (%s > %s)',
[FieldName, FormatDateTime(ServerDateFmt, IncDay(Date2, 1)),
FieldName, FormatDateTime(ServerDateFmt, IncDay(Date1, -1))]);
end;
end;
function FormatSQLDateRangeEx(Date1, Date2: TDateTime;
const FieldName: string): string;
begin
Result := TrueExpr;
if (Date1 <> NullDate) or (Date2 <> NullDate) then begin
if Date1 = NullDate then
Result := Format('%s < %s', [FieldName,
FormatDateTime(ServerDateFmt, IncDay(Date2, 1))])
else if Date2 = NullDate then
Result := Format('%s >= %s', [FieldName,
FormatDateTime(ServerDateFmt, Date1)])
else
Result := Format('(%s < %s) AND (%s >= %s)',
[FieldName, FormatDateTime(ServerDateFmt, IncDay(Date2, 1)),
FieldName, FormatDateTime(ServerDateFmt, Date1)]);
end;
end;
function FormatSQLNumericRange(const FieldName: string;
LowValue, HighValue, LowEmpty, HighEmpty: Double; Inclusive: Boolean): string;
const
Operators: array[Boolean, 1..2] of string[2] = (('>', '<'), ('>=', '<='));
begin
Result := TrueExpr;
if (LowValue = HighValue) and (LowValue <> LowEmpty) then begin
Result := Format('%s = %g', [FieldName, LowValue]);
end
else if (LowValue <> LowEmpty) or (HighValue <> HighEmpty) then begin
if LowValue = LowEmpty then
Result := Format('%s %s %g', [FieldName, Operators[Inclusive, 2], HighValue])
else if HighValue = HighEmpty then
Result := Format('%s %s %g', [FieldName, Operators[Inclusive, 1], LowValue])
else begin
Result := Format('(%s %s %g) AND (%s %s %g)',
[FieldName, Operators[Inclusive, 2], HighValue,
FieldName, Operators[Inclusive, 1], LowValue]);
end;
end;
end;
function StrMaskSQL(const Value: string): string;
begin
if (Pos('*', Value) = 0) and (Pos('?', Value) = 0) and (Value <> '') then
Result := '*' + Value + '*'
else Result := Value;
end;
function FormatSQLCondition(const FieldName, AOperator, Value: string;
FieldType: TFieldType; Exact: Boolean): string;
var
EmptyValue: Boolean;
FieldValue: string;
DateValue: TDateTime;
LogicOperator: string;
begin
FieldValue := '';
DateValue := NullDate;
Exact := Exact or not (FieldType in
[ftString, ftDate, ftTime, ftDateTime]);
if FieldType in [ftDate, ftTime, ftDateTime] then
begin
DateValue := StrToDateDef(Value, NullDate);
EmptyValue := (DateValue = NullDate);
FieldValue := FormatDateTime(ServerDateFmt, DateValue);
end
else begin
FieldValue := Value;
EmptyValue := FieldValue = '';
if not (Exact or EmptyValue) then
FieldValue := ReplaceStr(ReplaceStr(StrMaskSQL(FieldValue),
'*', '%'), '?', '_');
if FieldType = ftString then FieldValue := '''' + FieldValue + '''';
end;
LogicOperator := AOperator;
if LogicOperator = '' then begin
if Exact then LogicOperator := '='
else begin
if FieldType = ftString then LogicOperator := 'LIKE'
else LogicOperator := '>=';
end;
end;
if EmptyValue then Result := TrueExpr
else if (FieldType = ftDateTime) and Exact then begin
DateValue := IncDay(DateValue, 1);
Result := Format('(%s >= %s) and (%s < %s)', [FieldName, FieldValue,
FieldName, FormatDateTime(ServerDateFmt, DateValue)]);
end
else Result := Format('%s %s %s', [FieldName, LogicOperator, FieldValue]);
end;
function FormatAnsiSQLCondition(const FieldName, AOperator, Value: string;
FieldType: TFieldType; Exact: Boolean): string;
var
S, Esc: string;
begin
Esc := '';
if not Exact and (FieldType = ftString) then begin
S := ReplaceStr(ReplaceStr(ReplaceStr(Value, '/', '//'),
'_', '/_'), '%', '/%');
if S <> Value then Esc := ' ESCAPE''/''';
end
else S := Value;
Result := FormatSQLCondition(FieldName, AOperator, S, FieldType, Exact) + Esc;
end;
procedure CheckRequiredField(Field: TField);
begin
with Field do
if not ReadOnly and not Calculated and IsNull then
begin
FocusControl;
DatabaseErrorFmt(SFieldRequired, [DisplayName]);
end;
end;
procedure CheckRequiredFields(const Fields: array of TField);
var
I: Integer;
begin
for I := Low(Fields) to High(Fields) do
CheckRequiredField(Fields[I]);
end;
procedure AssignRecord(Source, Dest: TDataSet; ByName: Boolean);
var
I: Integer;
F, FSrc: TField;
begin
if not (Dest.State in dsEditModes) then _DBError(SNotEditing);
if ByName then begin
for I := 0 to Source.FieldCount - 1 do begin
F := Dest.FindField(Source.Fields[I].FieldName);
if F <> nil then begin
if (F.DataType = Source.Fields[I].DataType) and
(F.DataSize = Source.Fields[I].DataSize) then
F.Assign(Source.Fields[I])
else F.AsString := Source.Fields[I].AsString;
end;
end;
end
else begin
for I := 0 to Min(Source.FieldDefs.Count - 1, Dest.FieldDefs.Count - 1) do
begin
F := Dest.FindField(Dest.FieldDefs[I].Name);
FSrc := Source.FindField(Source.FieldDefs[I].Name);
if (F <> nil) and (FSrc <> nil) then begin
if F.DataType = FSrc.DataType then F.Assign(FSrc)
else F.AsString := FSrc.AsString;
end;
end;
end;
end;
function ExtractFieldName(const Fields: string; var Pos: Integer): string;
var
I: Integer;
begin
I := Pos;
while (I <= Length(Fields)) and (Fields[I] <> ';') do Inc(I);
Result := Trim(Copy(Fields, Pos, I - Pos));
if (I <= Length(Fields)) and (Fields[I] = ';') then Inc(I);
Pos := I;
end;
procedure FillValueForField(const Field: TField; Value: Variant);
var
DS:TDataSet;
P:TBookmarkStr;
begin
DS:=Field.DataSet;
DS.DisableControls;
P:=DS.Bookmark;
try
DS.First;
while not DS.EOF do
begin
DS.Edit;
Field.Value:=Value;
DS.Post;
DS.Next;
end;
finally
DS.Bookmark:=P;
DS.EnableControls;
end;
end;
end.