ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/journaling/runtime/nongui/IBCustomDataSet.pas
(Generate patch)

Comparing ibx/trunk/runtime/nongui/IBCustomDataSet.pas (file contents):
Revision 209 by tony, Wed Mar 14 12:48:51 2018 UTC vs.
Revision 311 by tony, Mon Aug 24 09:32:58 2020 UTC

# Line 49 | Line 49 | interface
49   uses
50   {$IFDEF WINDOWS }
51    Windows,
52 < {$ELSE}
52 > {$ENDIF}
53 > {$IFDEF UNIX}
54    unix,
55   {$ENDIF}
56    SysUtils, Classes, IBDatabase, IBExternals, IB,  IBSQL, Db,
57 <  IBUtils, IBBlob, IBSQLParser, IBDatabaseInfo, fpTimer;
57 <
58 < const
59 <  BufferCacheSize    =  1000;  { Allocate cache in this many record chunks}
60 <  UniCache           =  2;     { Uni-directional cache is 2 records big }
57 >  IBUtils, IBBlob, IBSQLParser, IBDatabaseInfo, IBTypes;
58  
59   type
60    TIBCustomDataSet = class;
# Line 87 | Line 84 | type
84      property RefreshSQL: TStrings read FRefreshSQL write SetRefreshSQL;
85    end;
86  
90  TBlobDataArray = array[0..0] of TIBBlobStream;
91  PBlobDataArray = ^TBlobDataArray;
87    TIBArrayField = class;
88  
89    { TIBArray }
# Line 107 | Line 102 | type
102      property ArrayIntf: IArray read FArray;
103    end;
104  
110  TArrayDataArray = array [0..0] of TIBArray;
111  PArrayDataArray = ^TArrayDataArray;
112
113  { TIBCustomDataSet }
114
115  TCachedUpdateStatus = (
116                         cusUnmodified, cusModified, cusInserted,
117                         cusDeleted, cusUninserted
118                        );
119  TIBDBKey = record
120    DBKey: array[0..7] of Byte;
121  end;
122  PIBDBKey = ^TIBDBKey;
123
124  PFieldData = ^TFieldData;
125  TFieldData = record
126   fdIsNull: Boolean;
127   fdDataLength: Short;
128 end;
129
130 PColumnData = ^TColumnData;
131 TColumnData = record
132  fdDataType: Short;
133  fdDataScale: Short;
134  fdNullable: Boolean;
135  fdDataSize: Short;
136  fdDataOfs: Integer;
137  fdCodePage: TSystemCodePage;
138 end;
139
140 PFieldColumns = ^TFieldColumns;
141 TFieldColumns =  array[1..1] of TColumnData;
142
143  TRecordData = record
144    rdBookmarkFlag: TBookmarkFlag;
145    rdFieldCount: Short;
146    rdRecordNumber: Integer;
147    rdCachedUpdateStatus: TCachedUpdateStatus;
148    rdUpdateStatus: TUpdateStatus;
149    rdSavedOffset: DWORD;
150    rdDBKey: TIBDBKey;
151    rdFields: array[1..1] of TFieldData;
152  end;
153  PRecordData = ^TRecordData;
154
105    { TIBArrayField }
106  
107    TIBArrayField = class(TField)
# Line 299 | Line 249 | type
249    private
250      FDataSet: TIBCustomDataSet;
251      FDelayTimerValue: integer;
252 <    FTimer: TFPTimer;
252 >    FTimer: TIBTimerInf;
253      procedure HandleRefreshTimer(Sender: TObject);
254 +    procedure SetDelayTimerValue(AValue: integer);
255    protected
256      procedure ActiveChanged; override;
257      procedure RecordChanged(Field: TField); override;
# Line 310 | Line 261 | type
261      constructor Create(ADataSet: TIBCustomDataSet);
262      destructor Destroy; override;
263      property DelayTimerValue: integer {in Milliseconds}
264 <            read FDelayTimerValue write FDelayTimerValue;
264 >            read FDelayTimerValue write SetDelayTimerValue;
265    end;
266  
267    TIBGeneratorApplyOnEvent = (gaeOnNewRecord,gaeOnPostRecord);
# Line 364 | Line 315 | type
315  
316    TIBAutoCommit = (acDisabled, acCommitRetaining);
317  
367  { TIBCustomDataSet }
368
318    TIBUpdateAction = (uaFail, uaAbort, uaSkip, uaRetry, uaApply, uaApplied);
319  
320    TIBUpdateErrorEvent = procedure(DataSet: TDataSet; E: EDatabaseError;
# Line 374 | Line 323 | type
323    TIBUpdateRecordEvent = procedure(DataSet: TDataSet; UpdateKind: TUpdateKind;
324                                     var UpdateAction: TIBUpdateAction) of object;
325  
377  TIBUpdateRecordTypes = set of TCachedUpdateStatus;
378
326    TDataSetCloseAction = (dcDiscardChanges, dcSaveChanges);
327  
328    TOnValidatePost = procedure (Sender: TObject; var CancelPost: boolean) of object;
329  
330    TOnDeleteReturning = procedure (Sender: TObject; QryResults: IResults) of object;
331  
332 +  { TIBCustomDataSet }
333 +
334    TIBCustomDataSet = class(TDataset)
335    private
336 +    const
337 +      BufferCacheSize    =  1000;  { Allocate cache in this many record chunks}
338 +      UniCache           =  2;     { Uni-directional cache is 2 records big }
339 +
340 +      {Buffer cache constants for record selection}
341 +      FILE_BEGIN = 0;
342 +      FILE_CURRENT = 1;
343 +      FILE_END = 2;
344 +
345 +      {internal type declarations}
346 +    type
347 +      TArrayDataArray = array [0..0] of TIBArray;
348 +      PArrayDataArray = ^TArrayDataArray;
349 +
350 +      TBlobDataArray = array[0..0] of TIBBlobStream;
351 +      PBlobDataArray = ^TBlobDataArray;
352 +
353 +      TCachedUpdateStatus = (
354 +                         cusUnmodified, cusModified, cusInserted,
355 +                         cusDeleted, cusUninserted
356 +                        );
357 +      TIBUpdateRecordTypes = set of TCachedUpdateStatus;
358 +
359 +      PFieldData = ^TFieldData;
360 +      TFieldData = record
361 +        fdIsNull: Boolean;
362 +        fdDataLength: Short;
363 +      end;
364 +
365 +      PColumnData = ^TColumnData;
366 +      TColumnData = record
367 +        fdDataType: Short;
368 +        fdDataScale: Short;
369 +        fdNullable: Boolean;
370 +        fdDataSize: Short;
371 +        fdDataOfs: Integer;
372 +        fdCodePage: TSystemCodePage;
373 +      end;
374 +
375 +      PFieldColumns = ^TFieldColumns;
376 +      TFieldColumns =  array[1..1] of TColumnData;
377 +
378 +  protected
379 +    type
380 +      TIBDBKey = record
381 +        DBKey: array[0..7] of Byte;
382 +      end;
383 +      PIBDBKey = ^TIBDBKey;
384 +
385 +    TRecordData = record
386 +      rdBookmarkFlag: TBookmarkFlag;
387 +      rdFieldCount: Short;
388 +      rdRecordNumber: Integer;
389 +      rdCachedUpdateStatus: TCachedUpdateStatus;
390 +      rdUpdateStatus: TUpdateStatus;
391 +      rdSavedOffset: DWORD;
392 +      rdDBKey: TIBDBKey;
393 +      rdFields: array[1..1] of TFieldData;
394 +    end;
395 +    PRecordData = ^TRecordData;
396 +
397 +  private
398      FAllowAutoActivateTransaction: Boolean;
399      FArrayFieldCount: integer;
400      FArrayCacheOffset: integer;
401      FAutoCommit: TIBAutoCommit;
402 +    FCaseSensitiveParameterNames: boolean;
403      FEnableStatistics: boolean;
404      FGenerateParamNames: Boolean;
405      FGeneratorField: TIBGenerator;
# Line 429 | Line 441 | type
441      FRecordCount: Integer;
442      FRecordSize: Integer;
443      FDataSetCloseAction: TDataSetCloseAction;
444 +    FSQLFiltered: boolean;
445 +    FSQLFilterParams: TStrings;
446      FUniDirectional: Boolean;
447      FUpdateMode: TUpdateMode;
448      FUpdateObject: TIBDataSetUpdateObject;
# Line 463 | Line 477 | type
477        FieldIndex: integer; Buffer: PChar);
478      procedure InitModelBuffer(Qry: TIBSQL; Buffer: PChar);
479      function GetSelectStmtIntf: IStatement;
480 +    procedure SetCaseSensitiveParameterNames(AValue: boolean);
481 +    procedure SetSQLFiltered(AValue: boolean);
482 +    procedure SetSQLFilterParams(AValue: TStrings);
483      procedure SetUpdateMode(const Value: TUpdateMode);
484      procedure SetUpdateObject(Value: TIBDataSetUpdateObject);
485  
# Line 496 | Line 513 | type
513      function GetModifySQL: TStrings;
514      function GetTransaction: TIBTransaction;
515      function GetParser: TSelectSQLParser;
516 +    procedure HandleSQLFilterParamsChanged(Sender: TObject);
517      procedure InternalDeleteRecord(Qry: TIBSQL; Buff: Pointer); virtual;
518      function InternalLocate(const KeyFields: string; const KeyValues: Variant;
519                              Options: TLocateOptions): Boolean; virtual;
# Line 580 | Line 598 | type
598      procedure DoBeforeInsert; override;
599      procedure DoAfterInsert; override;
600      procedure DoBeforeClose; override;
583    procedure DoBeforeOpen; override;
601      procedure DoBeforePost; override;
602      procedure DoAfterPost; override;
603      procedure FreeRecordBuffer(var Buffer: PChar); override;
# Line 641 | Line 658 | type
658      property SelectStmtHandle: IStatement read GetSelectStmtIntf;
659  
660      {Likely to be made published by descendant classes}
661 +    property CaseSensitiveParameterNames: boolean read FCaseSensitiveParameterNames
662 +                                                  write SetCaseSensitiveParameterNames;
663      property BufferChunks: Integer read FBufferChunks write SetBufferChunks;
664      property CachedUpdates: Boolean read FCachedUpdates write SetCachedUpdates;
665      property UniDirectional: Boolean read FUniDirectional write SetUniDirectional default False;
# Line 654 | Line 673 | type
673      property ParamCheck: Boolean read FParamCheck write FParamCheck default True;
674      property Parser: TSelectSQLParser read GetParser;
675      property BaseSQLSelect: TStrings read FBaseSQLSelect;
676 +    property SQLFiltered: boolean read FSQLFiltered write SetSQLFiltered;
677 +    property SQLFilterParams: TStrings read FSQLFilterParams write SetSQLFilterParams;
678  
679      property BeforeDatabaseDisconnect: TNotifyEvent read FBeforeDatabaseDisconnect
680                                                   write FBeforeDatabaseDisconnect;
# Line 705 | Line 726 | type
726      function IsSequenced: Boolean; override;
727      procedure Post; override;
728      function ParamByName(ParamName: String): ISQLParam;
729 +    function FindParam(ParamName: String): ISQLParam;
730      property ArrayFieldCount: integer read FArrayFieldCount;
731      property DatabaseInfo: TIBDatabaseInfo read FDatabaseInfo;
732      property UpdateObject: TIBDataSetUpdateObject read FUpdateObject write SetUpdateObject;
# Line 762 | Line 784 | type
784                                                     write FOnDeleteReturning;
785    end;
786  
787 +  { TIBParserDataSet }
788 +
789    TIBParserDataSet = class(TIBCustomDataSet)
790 +  protected
791 +    procedure DoBeforeOpen; override;
792    public
793      property Parser;
794    end;
# Line 799 | Line 825 | type
825      property AutoCommit;
826      property BufferChunks;
827      property CachedUpdates;
828 +    property CaseSensitiveParameterNames;
829      property EnableStatistics;
830      property DeleteSQL;
831      property InsertSQL;
# Line 812 | Line 839 | type
839      property UniDirectional;
840      property Filtered;
841      property DataSetCloseAction;
842 +    property SQLFiltered;
843 +    property SQLFilterParams;
844  
845      property BeforeDatabaseDisconnect;
846      property AfterDatabaseDisconnect;
# Line 895 | Line 924 | type
924    end;
925  
926   const
927 < DefaultFieldClasses: array[TFieldType] of TFieldClass = (
927 >  DefaultFieldClasses: array[TFieldType] of TFieldClass = (
928      nil,                { ftUnknown }
929      TIBStringField,     { ftString }
930      TIBSmallintField,   { ftSmallint }
# Line 952 | Line 981 | DefaultFieldClasses: array[TFieldType] o
981  
982   implementation
983  
984 < uses Variants, FmtBCD, LazUTF8, FBMessages, IBQuery;
956 <
957 < const FILE_BEGIN = 0;
958 <      FILE_CURRENT = 1;
959 <      FILE_END = 2;
984 > uses Variants, FmtBCD, LazUTF8, IBMessages, IBQuery;
985  
986   type
987  
# Line 1018 | Line 1043 | type
1043      Result := str;
1044    end;
1045  
1046 + { TIBParserDataSet }
1047 +
1048 + procedure TIBParserDataSet.DoBeforeOpen;
1049 + var i: integer;
1050 + begin
1051 +  if assigned(FParser) then
1052 +     FParser.RestoreClauseValues;
1053 +  if SQLFiltered then
1054 +    for i := 0 to SQLFilterParams.Count - 1 do
1055 +      Parser.Add2WhereClause(SQLFilterParams[i]);
1056 +  for i := 0 to FIBLinks.Count - 1 do
1057 +    TIBControlLink(FIBLinks[i]).UpdateSQL(self);
1058 +  inherited DoBeforeOpen;
1059 +  for i := 0 to FIBLinks.Count - 1 do
1060 +    TIBControlLink(FIBLinks[i]).UpdateParams(self);
1061 + end;
1062 +
1063   { TIBLargeIntField }
1064  
1065   procedure TIBLargeIntField.Bind(Binding: Boolean);
# Line 1156 | Line 1198 | begin
1198         3, {Assume UNICODE_FSS is really UTF8}
1199         4: {Include GB18030 - assuming UTF8 routines work for this codeset}
1200           if DisplayWidth = 0 then
1201 +           {$if declared(Utf8EscapeControlChars)}
1202 +           Result := Utf8EscapeControlChars(TextToSingleLine(Result))
1203 +           {$else}
1204             Result := ValidUTF8String(TextToSingleLine(Result))
1205 +           {$endif}
1206           else
1207           if UTF8Length(Result) > DisplayWidth then {Show truncation with elipses}
1208 +           {$if declared(Utf8EscapeControlChars)}
1209 +           Result := Utf8EscapeControlChars(TextToSingleLine(UTF8Copy(Result,1,DisplayWidth-3))) + '...';
1210 +           {$else}
1211             Result := ValidUTF8String(TextToSingleLine(UTF8Copy(Result,1,DisplayWidth-3))) + '...';
1212 +           {$endif}
1213         end;
1214     end
1215   end;
# Line 1264 | Line 1314 | begin
1314      IBFieldDef := FieldDef as TIBFieldDef;
1315      CharacterSetSize := IBFieldDef.CharacterSetSize;
1316      CharacterSetName := IBFieldDef.CharacterSetName;
1317 <    FDataSize := IBFieldDef.DataSize + 1;
1317 >    FDataSize := IBFieldDef.DataSize;
1318      if AutoFieldSize then
1319        Size := IBFieldDef.Size;
1320      CodePage := IBFieldDef.CodePage;
# Line 1307 | Line 1357 | var
1357    s: RawByteString;
1358   begin
1359    Buffer := nil;
1360 <  IBAlloc(Buffer, 0, DataSize);
1360 >  IBAlloc(Buffer, 0, DataSize + 1); {allow for trailing #0}
1361    try
1362      Result := GetData(Buffer);
1363      if Result then
# Line 1316 | Line 1366 | begin
1366        SetCodePage(s,CodePage,false);
1367        if (CodePage <> CP_NONE) and (CodePage <> CP_UTF8) then
1368          SetCodePage(s,CP_UTF8,true);  {LCL only accepts UTF8}
1369 <      Value := s;
1369 >
1370 >      if (CodePage = CP_UTF8) and (UTF8Length(s) > Size) then
1371 >        {truncate to max. number of UTF8 characters - usually a problem with
1372 >         fixed width columns right padded with white space}
1373 >        Value := UTF8Copy(s,1,Size)
1374 >      else
1375 >        Value := s;
1376 >
1377   //      writeln(FieldName,': ', StringCodePage(Value),', ',Value);
1378        if Transliterate and (Value <> '') then
1379          DataSet.Translate(PChar(Value), PChar(Value), False);
# Line 1332 | Line 1389 | var
1389    s: RawByteString;
1390   begin
1391    Buffer := nil;
1392 <  IBAlloc(Buffer, 0, DataSize);
1392 >  IBAlloc(Buffer, 0, DataSize + 1); {allow for trailing #0}
1393    try
1394      s := Value;
1395      if StringCodePage(s) <> CodePage then
1396        SetCodePage(s,CodePage,CodePage<>CP_NONE);
1397 <    StrLCopy(Buffer, PChar(s), DataSize-1);
1397 >    StrLCopy(Buffer, PChar(s), DataSize);
1398      if Transliterate then
1399        DataSet.Translate(Buffer, Buffer, True);
1400      SetData(Buffer);
# Line 1409 | Line 1466 | constructor TIBDataLink.Create(ADataSet:
1466   begin
1467    inherited Create;
1468    FDataSet := ADataSet;
1469 <  FTimer := TFPTimer.Create(nil);
1470 <  FTimer.Enabled := true;
1471 <  FTimer.Interval := 0;
1472 <  FTimer.OnTimer := HandleRefreshTimer;
1469 >  if assigned(IBGUIInterface) then
1470 >  begin
1471 >    FTimer := IBGUIInterface.CreateTimer;
1472 >    if FTimer <> nil then
1473 >    begin
1474 >      FTimer.Enabled := false;
1475 >      FTimer.Interval := 0;
1476 >      FTimer.OnTimer := HandleRefreshTimer;
1477 >    end;
1478 >  end;
1479    FDelayTimerValue := 0;
1480   end;
1481  
1482   destructor TIBDataLink.Destroy;
1483   begin
1484    FDataSet.FDataLink := nil;
1422  if assigned(FTimer) then FTimer.Free;
1485    inherited Destroy;
1486   end;
1487  
1488   procedure TIBDataLink.HandleRefreshTimer(Sender: TObject);
1489   begin
1490 <  FTimer.Interval := 0;
1491 <  FDataSet.RefreshParams;
1490 >  FTimer.Enabled := false;
1491 >  if FDataSet.Active then
1492 >    FDataSet.RefreshParams;
1493 > end;
1494 >
1495 > procedure TIBDataLink.SetDelayTimerValue(AValue: integer);
1496 > begin
1497 >  if FDelayTimerValue = AValue then Exit;
1498 >  if assigned(FTimer) then
1499 >    FTimer.Enabled := false;
1500 >  FDelayTimerValue := AValue;
1501   end;
1502  
1503   procedure TIBDataLink.ActiveChanged;
1504   begin
1505 <  if FDataSet.Active then
1505 >  if DetailDataSet.Active and DataSet.Active then
1506      FDataSet.RefreshParams;
1507   end;
1508  
# Line 1445 | Line 1516 | procedure TIBDataLink.RecordChanged(Fiel
1516   begin
1517    if (Field = nil) and FDataSet.Active then
1518    begin
1519 <    if FDelayTimerValue > 0 then
1519 >    if assigned(FTimer) and (FDelayTimerValue > 0) then
1520 >    with FTimer do
1521      begin
1522 +      FTimer.Enabled := false;
1523        FTimer.Interval := FDelayTimerValue;
1524 <      FTimer.StartTimer;
1524 >      FTimer.Enabled := true;
1525      end
1526      else
1527        FDataSet.RefreshParams;
# Line 1513 | Line 1586 | begin
1586      if AOwner is TIBTransaction then
1587        Transaction := TIBTransaction(AOwner);
1588    FBaseSQLSelect := TStringList.Create;
1589 +  FSQLFilterParams := TStringList.Create;
1590 +  TStringList(FSQLFilterParams).OnChange :=  HandleSQLFilterParamsChanged;
1591   end;
1592  
1593   destructor TIBCustomDataSet.Destroy;
# Line 1535 | Line 1610 | begin
1610    FMappedFieldPosition := nil;
1611    if assigned(FBaseSQLSelect) then FBaseSQLSelect.Free;
1612    if assigned(FParser) then FParser.Free;
1613 +  if assigned(FSQLFilterParams) then FSQLFilterParams.Free;
1614    inherited Destroy;
1615   end;
1616  
# Line 2676 | Line 2752 | begin
2752      ActivateTransaction;
2753      FBase.CheckDatabase;
2754      FBase.CheckTransaction;
2755 <    if HasParser and (FParser.SQLText <> FQSelect.SQL.Text) then
2755 >    if HasParser and not FParser.NotaSelectStmt and (FParser.SQLText <> FQSelect.SQL.Text) then
2756      begin
2757        FQSelect.OnSQLChanged := nil; {Do not react to change}
2758        try
# Line 2957 | Line 3033 | procedure TIBCustomDataSet.SetUniDirecti
3033   begin
3034    CheckDatasetClosed;
3035    FUniDirectional := Value;
3036 +  inherited SetUniDirectional(Value);
3037   end;
3038  
3039   procedure TIBCustomDataSet.SetUpdateRecordTypes(Value: TIBUpdateRecordTypes);
# Line 3066 | Line 3143 | end;
3143  
3144   function TIBCustomDataSet.ParamByName(ParamName: String): ISQLParam;
3145   begin
3146 +  Result := FindParam(ParamName);
3147 +  if Result = nil then
3148 +    IBError(ibxeParameterNameNotFound,[ParamName]);
3149 + end;
3150 +
3151 + function TIBCustomDataSet.FindParam(ParamName: String): ISQLParam;
3152 + begin
3153    ActivateConnection;
3154    ActivateTransaction;
3155    if not FInternalPrepared then
# Line 3419 | Line 3503 | begin
3503      ApplyUpdates;
3504   end;
3505  
3422 procedure TIBCustomDataSet.DoBeforeOpen;
3423 var i: integer;
3424 begin
3425  if assigned(FParser) then
3426     FParser.Reset;
3427  for i := 0 to FIBLinks.Count - 1 do
3428    TIBControlLink(FIBLinks[i]).UpdateSQL(self);
3429  inherited DoBeforeOpen;
3430  for i := 0 to FIBLinks.Count - 1 do
3431    TIBControlLink(FIBLinks[i]).UpdateParams(self);
3432 end;
3433
3506   procedure TIBCustomDataSet.DoBeforePost;
3507   begin
3508    inherited DoBeforePost;
# Line 3571 | Line 3643 | begin
3643          Data := Buff + fdDataOfs;
3644          if (fdDataType = SQL_VARYING) or (fdDataType = SQL_TEXT) then
3645          begin
3646 <          if fdDataLength < Field.DataSize then
3646 >          if fdDataLength <= Field.DataSize then
3647            begin
3648              Move(Data^, Buffer^, fdDataLength);
3649              PChar(Buffer)[fdDataLength] := #0;
# Line 3580 | Line 3652 | begin
3652              IBError(ibxeFieldSizeError,[Field.FieldName])
3653          end
3654          else
3655 <          Move(Data^, Buffer^, Field.DataSize);
3655 >        if fdDataLength <= Field.DataSize then
3656 >          Move(Data^, Buffer^, Field.DataSize)
3657 >        else
3658 >          IBError(ibxeFieldSizeError,[Field.FieldName,Field.DataSize,fdDataLength])
3659        end;
3660    end;
3661   end;
# Line 3751 | Line 3826 | var
3826    Buff: PChar;
3827    CurRec: Integer;
3828    pda: PArrayDataArray;
3829 +  pbd: PBlobDataArray;
3830    i: integer;
3831   begin
3832    inherited InternalCancel;
# Line 3758 | Line 3834 | begin
3834    if Buff <> nil then
3835    begin
3836      pda := PArrayDataArray(Buff + FArrayCacheOffset);
3837 +    pbd := PBlobDataArray(Buff + FBlobCacheOffset);
3838      for i := 0 to ArrayFieldCount - 1 do
3839        pda^[i].ArrayIntf.CancelChanges;
3840      CurRec := FCurrentRecord;
3841      AdjustRecordOnInsert(Buff);
3842      if (State = dsEdit) then begin
3843        CopyRecordBuffer(FOldBuffer, Buff);
3844 +      for i := 0 to BlobFieldCount - 1 do
3845 +        pbd^[i] := nil;
3846        WriteRecordCache(PRecordData(Buff)^.rdRecordNumber, Buff);
3847      end else begin
3848        CopyRecordBuffer(FModelBuffer, Buff);
# Line 3843 | Line 3922 | end;
3922   procedure TIBCustomDataSet.InternalFirst;
3923   begin
3924    FCurrentRecord := -1;
3925 +  if Unidirectional then GetNextRecord;
3926   end;
3927  
3928   procedure TIBCustomDataSet.InternalGotoBookmark(Bookmark: Pointer);
# Line 3868 | Line 3948 | begin
3948   procedure TIBCustomDataSet.FieldDefsFromQuery(SourceQuery: TIBSQL);
3949   const
3950    DefaultSQL = 'Select F.RDB$COMPUTED_BLR, ' + {do not localize}
3951 <               'F.RDB$DEFAULT_VALUE, R.RDB$FIELD_NAME ' + {do not localize}
3951 >               'F.RDB$DEFAULT_VALUE, Trim(R.RDB$FIELD_NAME) as RDB$FIELD_NAME ' + {do not localize}
3952                 'from RDB$RELATION_FIELDS R, RDB$FIELDS F ' + {do not localize}
3953                 'where R.RDB$RELATION_NAME = :RELATION ' +  {do not localize}
3954                 'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize}
# Line 3876 | Line 3956 | const
3956                 '     (not F.RDB$DEFAULT_VALUE is NULL)) '; {do not localize}
3957  
3958    DefaultSQLODS12 = 'Select F.RDB$COMPUTED_BLR, ' + {do not localize}
3959 <               'F.RDB$DEFAULT_VALUE, R.RDB$FIELD_NAME, R.RDB$IDENTITY_TYPE ' + {do not localize}
3959 >               'F.RDB$DEFAULT_VALUE, Trim(R.RDB$FIELD_NAME) as RDB$FIELD_NAME, R.RDB$IDENTITY_TYPE ' + {do not localize}
3960                 'from RDB$RELATION_FIELDS R, RDB$FIELDS F ' + {do not localize}
3961                 'where R.RDB$RELATION_NAME = :RELATION ' +  {do not localize}
3962                 'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize}
# Line 4575 | Line 4655 | begin
4655            fdIsNull := True
4656          else
4657          begin
4658 <          Move(Buffer^, Buff[fdDataOfs],fdDataSize);
4658 >          if fdDataSize >= Field.DataSize then
4659 >            Move(Buffer^, Buff[fdDataOfs],fdDataSize)
4660 >          else
4661 >            IBError(ibxeDBBufferTooSmall,[fdDataSize,Field.FieldName,Field.DataSize]);
4662 >
4663            if (fdDataType = SQL_TEXT) or (fdDataType = SQL_VARYING) then
4664              fdDataLength := StrLen(PChar(Buffer));
4665            fdIsNull := False;
# Line 4719 | Line 4803 | begin
4803    Result := FQSelect.Statement;
4804   end;
4805  
4806 + procedure TIBCustomDataSet.SetCaseSensitiveParameterNames(AValue: boolean);
4807 + begin
4808 +  if FCaseSensitiveParameterNames = AValue then Exit;
4809 +  FCaseSensitiveParameterNames := AValue;
4810 +  if assigned(FQSelect) then
4811 +    FQSelect.CaseSensitiveParameterNames := AValue;
4812 + end;
4813 +
4814 + procedure TIBCustomDataSet.SetSQLFiltered(AValue: boolean);
4815 + begin
4816 +  if FSQLFiltered = AValue then Exit;
4817 +  FSQLFiltered := AValue;
4818 +  if Active then
4819 +  begin
4820 +    Active := false;
4821 +    Active := true;
4822 +  end;
4823 + end;
4824 +
4825 + procedure TIBCustomDataSet.SetSQLFilterParams(AValue: TStrings);
4826 + begin
4827 +  if FSQLFilterParams = AValue then Exit;
4828 +  FSQLFilterParams.Assign(AValue);
4829 + end;
4830 +
4831   procedure TIBCustomDataSet.SetMasterDetailDelay(AValue: integer);
4832   begin
4833    FDataLink.DelayTimerValue := AValue;
# Line 4731 | Line 4840 | begin
4840    Result := FParser
4841   end;
4842  
4843 + procedure TIBCustomDataSet.HandleSQLFilterParamsChanged(Sender: TObject);
4844 + begin
4845 +  Active := false;
4846 + end;
4847 +
4848   procedure TIBCustomDataSet.ResetParser;
4849   begin
4850    if assigned(FParser) then
# Line 5075 | Line 5189 | end;
5189   function TIBDataSetUpdateObject.GetRowsAffected(
5190    var SelectCount, InsertCount, UpdateCount, DeleteCount: integer): boolean;
5191   begin
5192 +  Result := true;
5193    SelectCount := 0;
5194    InsertCount := 0;
5195    UpdateCount := 0;
# Line 5184 | Line 5299 | end;
5299  
5300   procedure TIBGenerator.SetQuerySQL;
5301   begin
5302 <  FQuery.SQL.Text := Format('Select Gen_ID(%s,%d) From RDB$Database',[FGeneratorName,Increment]);
5302 >  if Database <> nil then
5303 >    FQuery.SQL.Text := Format('Select Gen_ID(%s,%d) From RDB$Database',
5304 >      [QuoteIdentifierIfNeeded(Database.SQLDialect,FGeneratorName),Increment]);
5305   end;
5306  
5307   function TIBGenerator.GetDatabase: TIBDatabase;
# Line 5200 | Line 5317 | end;
5317   procedure TIBGenerator.SetDatabase(AValue: TIBDatabase);
5318   begin
5319    FQuery.Database := AValue;
5320 +  SetQuerySQL;
5321   end;
5322  
5323   procedure TIBGenerator.SetGeneratorName(AValue: string);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines