📄 dblocali.pas
字号:
{*******************************************************}
{ }
{ Borland Delphi Visual Component Library }
{ Local Client DataSet - IB }
{ }
{ Copyright (c) 1997,01 Inprise Corporation }
{ }
{*******************************************************}
unit DBLocalI;
{$R-,T-,H+,X+}
interface
{$IFDEF MSWINDOWS}
uses Windows, SysUtils, Variants, Classes, Db, DBCommon, Midas,
IBQuery, IBDatabase, IB, DBClient, DBLocal, Provider;
{$ENDIF}
{$IFDEF LINUX}
uses Libc, SysUtils, Variants, Classes, DB, DBCommon, Midas,
IBCustomDataset, IBDatabase, IB, DBClient, DBLocal, Provider;
{$ENDIF}
type
{ TIBCDSDataset }
TIBCDSQuery = class(TIBQuery)
private
FKeyFields: string;
protected
function PSGetDefaultOrder: TIndexDef; override;
end;
{ TIBClientDataSet }
TIBClientDataSet = class(TCustomCachedDataSet)
private
FCommandText : String;
FDataSet: TIBCDSQuery;
FLocalParams: TParams;
FStreamedActive: Boolean;
procedure CheckMasterSourceActive(MasterSource: TDataSource);
procedure SetDetailsActive(Value: Boolean);
function GetConnection: TIBDatabase;
function GetMasterFields: String;
function GetMasterSource: TDataSource;
function GetTransaction: TIBTransaction;
procedure SetConnection(Value: TIBDatabase);
procedure SetDataSource(const Value: TDataSource);
procedure SetInternalCommandText(Value: string);
procedure SetLocalParams;
procedure SetMasterFields(const Value: String);
procedure SetParamsFromSQL(const Value: string);
procedure SetTransaction(const Value: TIBTransaction);
protected
function GetCommandText: String; override;
procedure Loaded; override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure SetActive(Value: Boolean); override;
procedure SetCommandText(Value: string); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure CloneCursor(Source: TCustomClientDataSet; Reset: Boolean;
KeepSettings: Boolean = False); override;
function GetQuoteChar: String;
published
property Active;
property CommandText: string read GetCommandText write SetCommandText;
property DBConnection: TIBDatabase read GetConnection write SetConnection;
property DBTransaction : TIBTransaction read GetTransaction write SetTransaction;
property MasterFields : String read GetMasterFields write SetMasterFields;
property MasterSource: TDataSource read GetMasterSource write SetDataSource;
end;
implementation
uses MidConst, IBUtils;
type
{ TIBCDSParams }
TIBCDSParams = class(TParams)
private
FFieldName: TStrings;
protected
procedure ParseSelect(SQL: string);
public
constructor Create(Owner: TPersistent);
Destructor Destroy; override;
end;
constructor TIBCDSParams.Create(Owner: TPersistent);
begin
inherited;
FFieldName := TStringList.Create;
end;
destructor TIBCDSParams.Destroy;
begin
FreeAndNil(FFieldName);
inherited;
end;
procedure TIBCDSParams.ParseSelect(SQL: string);
const
SSelect = 'select'; {Do not localize}
var
FWhereFound: Boolean;
Start: PChar;
FName, Value: string;
SQLToken, CurSection, LastToken: TSQLToken;
Params: Integer;
begin
if Pos(' ' + SSelect + ' ', LowerCase(string(PChar(SQL)+8))) > 1 then Exit; // can't parse sub queries
Start := PChar(ParseSQL(PChar(SQL), True));
CurSection := stUnknown;
LastToken := stUnknown;
FWhereFound := False;
Params := 0;
repeat
repeat
SQLToken := NextSQLToken(Start, FName, CurSection);
if SQLToken in [stWhere] then
begin
FWhereFound := True;
LastToken := stWhere;
end else if SQLToken in [stTableName] then
begin
{ Check for owner qualified table name }
if Start^ = '.' then {Do not localize}
NextSQLToken(Start, FName, CurSection);
end else
if (SQLToken = stValue) and (LastToken = stWhere) then
SQLToken := stFieldName;
if SQLToken in SQLSections then CurSection := SQLToken;
until SQLToken in [stFieldName, stEnd];
if FWhereFound and (SQLToken in [stFieldName]) then
repeat
SQLToken := NextSQLToken(Start, Value, CurSection);
if SQLToken in SQLSections then CurSection := SQLToken;
until SQLToken in [stEnd,stValue,stIsNull,stIsNotNull,stFieldName];
if Value='?' then {Do not localize}
begin
FFieldName.Add(FName);
Inc(Params);
end;
until (Params = Count) or (SQLToken in [stEnd]);
end;
{ TIBCDSQuery }
function TIBCDSQuery.PSGetDefaultOrder: TIndexDef;
begin
if FKeyFields = '' then
Result := inherited PSGetDefaultOrder
else
begin // detail table default order
Result := TIndexDef.Create(nil);
Result.Options := [ixUnique]; // keyfield is unique
Result.Name := StringReplace(FKeyFields, ';', '_', [rfReplaceAll]); {Do not localize}
Result.Fields := FKeyFields;
end;
end;
{ TIBClientDataSet }
constructor TIBClientDataSet.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FDataSet := TIBCDSQuery.Create(nil);
FDataSet.Name := Self.Name + 'DataSet1'; {Do not localize}
Provider.DataSet := FDataSet;
SqlDBType := typeIBX;
FLocalParams := TParams.Create;
end;
destructor TIBClientDataSet.Destroy;
begin
inherited Destroy;
FDataSet.Close;
FreeAndNil(FDataSet);
FreeAndNil(FLocalParams);
end;
function TIBClientDataSet.GetCommandText: String;
begin
Result := FCommandText;
end;
procedure TIBClientDataSet.SetCommandText(Value: String);
begin
if Value <> CommandText then
begin
CheckInactive;
FCommandText := Value;
if not (csLoading in ComponentState) then
begin
FDataSet.FKeyFields := '';
IndexFieldNames := '';
MasterFields := '';
IndexName := '';
IndexDefs.Clear;
Params.Clear;
if (csDesigning in ComponentState) and (Value <> '') then
SetParamsFromSQL(Value);
end;
end;
end;
function TIBClientDataSet.GetConnection: TIBDatabase;
begin
Result := FDataSet.Database;
end;
procedure TIBClientDataSet.SetConnection(Value: TIBDatabase);
begin
if FDataSet.Database <> Value then
begin
CheckInactive;
FDataSet.Database := Value;
end;
end;
function TIBClientDataSet.GetQuoteChar: String;
begin
Result := '';
if Assigned(FDataSet.Database) then
if FDataSet.Database.SQLDialect = 3 then
Result := '"' {Do not localize}
end;
procedure TIBClientDataSet.SetTransaction(const Value: TIBTransaction);
begin
FDataSet.Transaction := Value;
end;
function TIBClientDataSet.GetTransaction: TIBTransaction;
begin
Result := FDataSet.Transaction;
end;
procedure TIBClientDataSet.CloneCursor(Source: TCustomClientDataSet; Reset,
KeepSettings: Boolean);
begin
if not (Source is TIBClientDataSet) then
DatabaseError(SInvalidClone);
Provider.DataSet := TIBClientDataSet(Source).Provider.DataSet;
DBConnection := TIBClientDataSet(Source).DBConnection;
DBTransaction := TIBClientDataSet(Source).DBTransaction;
CommandText := TIBClientDataSet(Source).CommandText;
inherited CloneCursor(Source, Reset, KeepSettings);
end;
procedure TIBClientDataSet.SetDetailsActive(Value: Boolean);
var
DetailList: TList;
I: Integer;
begin
DetailList := TList.Create;
try
GetDetailDataSets(DetailList);
for I := 0 to DetailList.Count -1 do
if TDataSet(DetailList[I]) is TIBClientDataSet then
TIBClientDataSet(TDataSet(DetailList[I])).Active := Value;
finally
DetailList.Free;
end;
end;
procedure TIBClientDataSet.CheckMasterSourceActive(
MasterSource: TDataSource);
begin
if Assigned(MasterSource) and Assigned(MasterSource.DataSet) then
if not MasterSource.DataSet.Active then
DatabaseError(SMasterNotOpen);
end;
function TIBClientDataSet.GetMasterSource: TDataSource;
begin
Result := inherited GetDataSource;
end;
procedure TIBClientDataSet.SetDataSource(const Value: TDataSource);
begin
inherited MasterSource := Value;
if Assigned(Value) then
begin
if PacketRecords = -1 then
PacketRecords := 0;
end
else
if PacketRecords = 0 then
PacketRecords := -1;
end;
function TIBClientDataSet.GetMasterFields: String;
begin
Result := inherited MasterFields;
end;
procedure TIBClientDataSet.SetMasterFields(const Value: String);
begin
inherited MasterFields := Value;
if Value <> '' then
IndexFieldNames := Value;
FDataSet.FKeyFields := '';
end;
procedure TIBClientDataSet.SetActive(Value: Boolean);
var
FCurrentCommand: string;
begin
if Value then
begin
if csLoading in ComponentState then
begin
FStreamedActive := True;
exit;
end;
if MasterFields <> '' then
begin
if not (csLoading in ComponentState) then
CheckMasterSourceActive(MasterSource);
SetLocalParams;
FCurrentCommand := AddIBParamSQLForDetail(FLocalParams, CommandText, false, FDataset.Database.SQLDialect);
SetInternalCommandText(FCurrentCommand);
Params := FLocalParams;
FetchParams;
end else
begin
SetInternalCommandText(FCommandText);
if Params.Count > 0 then
begin
FDataSet.Params := Params;
FetchParams;
end;
end;
end;
if Value and (FDataSet.ObjectView <> ObjectView) then
FDataSet.ObjectView := ObjectView;
inherited SetActive(Value);
SetDetailsActive(Value);
end;
procedure TIBClientDataSet.SetInternalCommandText(Value: string);
begin
if Assigned(Provider.DataSet) then
begin
if Assigned(TIBCDSQuery(Provider.DataSet).Database) and (Value <> TIBCDSQuery(Provider.DataSet).SQL.Text) then
begin
TIBCDSQuery(Provider.DataSet).SQL.Text := Value;
inherited SetCommandText(TIBCDSQuery(Provider.DataSet).SQL.Text);
end;
end
else
DataBaseError(SNoDataProvider);
end;
procedure TIBClientDataSet.SetParamsFromSQL(const Value: string);
var
DataSet: TIBCDSQuery;
TableName, TempQuery, Q: string;
List: TIBCDSParams;
I: Integer;
Field: TField;
begin
TableName := GetTableNameFromSQL(Value);
if TableName <> '' then
begin
TempQuery := Value;
List := TIBCDSParams.Create(Self);
try
List.ParseSelect(TempQuery);
List.AssignValues(Params);
for I := 0 to List.Count - 1 do
List[I].ParamType := ptInput;
DataSet := TIBCDSQuery.Create(FDataSet.Database);
try
if Assigned(FDataSet) then
Q := FDataSet.PSGetQuoteChar
else
Q := '';
DataSet.SQL.Add('select * from ' + Q + TableName + Q + ' where 0 = 1'); { do not localize }
try
DataSet.Open;
for I := 0 to List.Count - 1 do
begin
if List.FFieldName.Count > I then
begin
try
Field := DataSet.FieldByName(List.FFieldName[I]);
except
Field := nil;
end;
end else
Field := nil;
if Assigned(Field) then
begin
if Field.DataType <> ftString then
List[I].DataType := Field.DataType
else if TStringField(Field).FixedChar then
List[I].DataType := ftFixedChar
else
List[I].DataType := ftString;
end;
end;
except
// ignore all exceptions
end;
finally
DataSet.Free;
end;
finally
if List.Count > 0 then
Params.Assign(List);
List.Free;
end;
end;
end;
procedure TIBClientDataSet.Loaded;
begin
inherited Loaded;
if FStreamedActive then
begin
try
SetActive(True);
FStreamedActive := False;
except
if csDesigning in ComponentState then
InternalHandleException
else
Raise;
end;
end;
end;
procedure TIBClientDataSet.Notification(AComponent: TComponent;
Operation: TOperation);
begin
if Operation = opRemove then
if AComponent = FDataset.Database then
begin
FDataSet.DataBase := nil;
SetActive(False);
end
else
if AComponent = FDataSet.Transaction then
begin
FDataSet.Transaction := nil;
SetActive(False);
end;
end;
procedure TIBClientDataSet.SetLocalParams;
procedure CreateParamsFromMasterFields(Create: Boolean);
var
I: Integer;
List: TStrings;
begin
List := TStringList.Create;
try
if Create then
FLocalParams.Clear;
FDataSet.FKeyFields := MasterFields;
List.CommaText := MasterFields;
for I := 0 to List.Count -1 do
begin
if Create then
FLocalParams.CreateParam( ftUnknown, MasterSource.DataSet.FieldByName(List[I]).FieldName,
ptInput);
FLocalParams[I].AssignField(MasterSource.DataSet.FieldByName(List[I]));
end;
finally
List.Free;
end;
end;
begin
if (MasterFields <> '') and Assigned(MasterSource) and Assigned(MasterSource.DataSet) then
CreateParamsFromMasterFields(True);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -