CopyfromDataSet and Copying from stream lazarus / 16-Databases ---------------------------------------------------------------------- egsuh · 2024-03-18 05:26 From my programming job, I found followings happen. First I open a TSQLQuery for Firebird table and copy it to TBufDataSet. There are two ways, via TStream and direct copy. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SQLQuery1.Open;  // method 1 - via TStreamSQLQuery1.SaveToStream(AStream); BufDataSet1.LoadFromStream(AStream);  // method 2 - copy from data setBufDataSet1.CopyFromDataSet(SQLQuery1); Normally both methods are fine, but when any method is linked to BufDataSet1's events, then the second method calls the event --- which will end in exception saying "no operation can be done on inactive dataset".  No problem with the first method. I think we cannot call this as bug, but during copying the events should not be called. (Of course I disable it before copying). ---------------------------------------------------------------------- rvk · 2024-03-18 06:43 Quote from: egsuh on March 18, 2024, 06:26:48 amNormally both methods are fine, but when any method is linked to BufDataSet1's events, then the second method calls the event --- which will end in exception saying "no operation can be done on inactive dataset".  No problem with the first method. I think we cannot call this as bug, but during copying the events should not be called. (Of course I disable it before copying). Isn't that the difference between TBufDataSet.LoadFromStream and CopyFromDataSet?? The second uses the normal TBufDataSet.Append/Post so it should also trigger the events. ---------------------------------------------------------------------- TRon · 2024-03-18 06:52 Quote from: rvk on March 18, 2024, 07:43:31 amIsn't that the difference between TBufDataSet.LoadFromStream and CopyFromDataSet?? It is  QuoteThe second uses the normal TBufDataSet.Append/Post so it should also trigger the events. As is stated by the documentation. Probably also reason why it was written "I think we cannot call this as bug" but it is certainly something to be aware of as it is able to "catch you off-guard". ---------------------------------------------------------------------- egsuh · 2024-03-18 07:05 QuoteThe second uses the normal TBufDataSet.Append/Post so it should also trigger the events. Theoretically or logically it should trigger events but problem is it raises exceptions, as the dataset itself is inactive until whole data set is created. ---------------------------------------------------------------------- rvk · 2024-03-18 07:15 Quote from: egsuh on March 18, 2024, 08:05:06 amQuoteThe second uses the normal TBufDataSet.Append/Post so it should also trigger the events. Theoretically or logically it should trigger events but problem is it raises exceptions, as the dataset itself is inactive until whole data set is created. That's strange. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i         Dataset.Open;        Dataset.First;        While not Dataset.EOF do      begin          Append;          // ...          Try            Post;          except            Cancel;            Raise;          end;          Dataset.Next;        end; During copying the TBufDataSet shouldn't be inactive. ---------------------------------------------------------------------- egsuh · 2024-03-18 07:58 QuoteDuring copying the TBufDataSet shouldn't be inactive. Anyway the exception comes from "inactive database". When I deactivate OnAfterPost event, the exception disappear. ---------------------------------------------------------------------- rvk · 2024-03-18 07:59 BTW. For me the Dataset in TBufDatset.BeforePost is active in TBufDatset.CopyFromDataset. So if you still have the problem... maybe you can write a small standalone example where the error occurs. ---------------------------------------------------------------------- rvk · 2024-03-18 08:02 Here is my small example (I adjusted a previous standalone sqlite3 example). Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1; {$mode objfpc}{$H+} uses  SysUtils, sqldb, DB, sqlite3conn, bufdataset; type  TDummy = class  public    procedure foo(DataSet: TDataSet);  end;   procedure TDummy.foo(DataSet: TDataSet);  begin    if DataSet.Active then      writeln(DataSet.FieldByName('LOL').AsString);  end; var  SQLite3Connection1: TSQLite3Connection;  SQLTransaction1: TSQLTransaction;  SQLQuery1: TSQLQuery;  SQL: string;  I: integer;  Buf: TBufDataSet;  Dummy: TDummy;begin   SQLite3Connection1 := TSQLite3Connection.Create(nil);  SQLTransaction1 := TSQLTransaction.Create(SQLite3Connection1);  SQLQuery1 := TSQLQuery.Create(SQLite3Connection1);  try    SQLite3Connection1.DatabaseName := 'test.db';    SQLite3Connection1.Transaction := SQLTransaction1;    SQLTransaction1.Database := SQLite3Connection1;     DeleteFile('test.db'); // just for testing    if not FileExists('test.db') then    begin      writeln('create table');    SQL := 'CREATE TABLE TESTTABLE(ID INTEGER PRIMARY KEY AUTOINCREMENT, LOL VARCHAR(25));';      SQLite3Connection1.ExecuteDirect(SQL);      writeln(format('writing %d records', [10]));      for I := 1 to 10 do      begin        SQL := format('INSERT INTO TESTTABLE VALUES (%d, "lol_%s");', [i, i.toString]);        SQLite3Connection1.ExecuteDirect(SQL);      end;      if SQLite3Connection1.Transaction.Active then        SQLite3Connection1.Transaction.Commit;    end;     SQLite3Connection1.Connected := True;    SQLQuery1.Database := SQLite3Connection1;    SQLQuery1.Transaction := SQLTransaction1;    SQLQuery1.SQL.Text := 'SELECT * FROM TESTTABLE';    SQLQuery1.Open;  while not SQLQuery1.EOF do    begin      writeln(SQLQuery1.FieldByName('LOL').AsString);      SQLQuery1.Next;  end;    SQLQuery1.Close;     writeln('trying tbufdataset.afterpost, press enter');    readln;    SQLQuery1.Open;    Dummy := TDummy.Create;    Buf := TBufDataSet.Create(nil);    try      Buf.AfterPost := @Dummy.foo;      Buf.CopyFromDataset(SQLQuery1, True);    finally      Buf.Free;      Dummy.Free;    end;   finally  SQLite3Connection1.Free;  end;  writeln('done');  readln; end. Quotecreate table writing 10 records lol_1 lol_2 lol_3 lol_4 lol_5 lol_6 lol_7 lol_8 lol_9 lol_10 trying tbufdataset.afterpost, press enter lol_1 lol_2 lol_3 lol_4 lol_5 lol_6 lol_7 lol_8 lol_9 lol_10 done