Recent

Author Topic: [SOLVED, fixed in svn] TSqlite3Dataset, delete field in edit mode: SIGSEGV  (Read 4621 times)

totya

  • Hero Member
  • *****
  • Posts: 577
Hi!

I found the second bug in this great component... I use the latest svn, why: http://forum.lazarus.freepascal.org/index.php?topic=28203.0

See attached sample, or source here:

Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, db, Sqlite3DS, FileUtil, Forms, Controls, Graphics, Dialogs, DBGrids, StdCtrls,
  Menus;

type

  { TForm1 }

  TForm1 = class(TForm)
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    MainMenu1: TMainMenu;
    DeleteMenuItem: TMenuItem;
    Sqlite3Dataset1: TSqlite3Dataset;
    procedure DeleteMenuItemClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.DeleteMenuItemClick(Sender: TObject);
begin
  with Sqlite3Dataset1 do
  if RecordCount > 0
  then Delete;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i: integer;

begin
    with Sqlite3Dataset1 do
    begin
      FileName:='test.db';
      Tablename:='test_table';

      DeleteFileUTF8(Filename);

      if not(TableExists) then
      begin
        FieldDefs.Clear;

        FieldDefs.Add('id', ftAutoInc);
        FieldDefs.Add('id2', ftInteger);
        FieldDefs.Add('selected', ftBoolean);

        CreateTable;
      end;

      Open;

      for i:=0 to 5 do
      begin
        Append;
          FieldByName('id2').AsInteger := i;
          FieldByName('selected').AsBoolean:=false;
        Post;
      end;

    end;
end;

end.


Compile and run. Click to "selected" field column in any row. The result is, field state changed to checked. This is okay. Then click to delete button. The result see attached picture.

Thanks...
« Last Edit: May 09, 2015, 10:49:00 pm by totya »

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: TSqlite3Dataset, delete selected boolean field -> SIGSEGV error
« Reply #1 on: April 30, 2015, 04:55:19 pm »
Just FYI... If you're planning to delete all selected records this is not the way to do it.
Your delete-button only deletes the current records (and I think there lies the problem somehow).

If you want to delete all selected records you need to loop over them (first to last) and delete the ones selected with the checkbox.

totya

  • Hero Member
  • *****
  • Posts: 577
Re: TSqlite3Dataset, delete selected boolean field -> SIGSEGV error
« Reply #2 on: April 30, 2015, 04:57:02 pm »
Just FYI... If you're planning to delete all selected records this is not the way to do it.
Your delete-button only deletes the current records (and I think there lies the problem somehow).

If you want to delete all selected records you need to loop over them (first to last) and delete the ones selected with the checkbox.

Hi!

This is only sample application, when I want to delete one (1) record (selected record), and this is cause crash...

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: TSqlite3Dataset, delete selected boolean field -> SIGSEGV error
« Reply #3 on: April 30, 2015, 05:02:25 pm »
You're correct in saying it shouldn't crash (code/libraries should never crash).
So it does need to be fixed.

When testing I noticed that when setting Option - dgEditing and + dgRowSelect it does work (but you can't check the checkbox).

But your problem is when you do check the checkbox you're already IN EDIT MODE !!!
The following delete gives the error.

When doing this it will be fine:
Code: [Select]
procedure TForm1.DeleteMenuItemClick(Sender: TObject);
begin
  if Sqlite3Dataset1.RecordCount > 0 then
  begin
    Sqlite3Dataset1.Cancel;  // <---- Add this to cancel the EDIT-mode !!
    Sqlite3Dataset1.Delete;
  end;
end;

totya

  • Hero Member
  • *****
  • Posts: 577
Re: TSqlite3Dataset, delete selected boolean field -> SIGSEGV error
« Reply #4 on: April 30, 2015, 05:17:09 pm »
But your problem is when you do check the checkbox you're already IN EDIT MODE !!!

Hi!

If I click to id2 field, I think this is "edit mode" too, but I don't get crash. This problem appear seems to me only with the boolean field.

Your code is certainly working Master, I use it before patch is arrived :)

I hope I will not to get more any errors from this component...

Thank you!
« Last Edit: April 30, 2015, 05:19:18 pm by totya »

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: TSqlite3Dataset, delete selected boolean field -> SIGSEGV error
« Reply #5 on: April 30, 2015, 08:59:51 pm »
If I click to id2 field, I think this is "edit mode" too, but I don't get crash. This problem appear seems to me only with the boolean field.
No, when you click a cell the cell/field becomes active but the dataset doesn't enter Edit-mode yet. Only when you're really changing the cell (i.e. type data) does the dataset enter edit-mode. You can see this from the pointer in front of the first column. When it's a triangle (i.e. "▶") your dataset is in browse-mode. When the triangle changes in a caret (i.e. "Ꮖ" ) then your dataset is in edit-mode.

B.T.W. Canceling (dataset.cancel) is no problem here. If the dataset is not yet in edit-mode cancel does nothing.

I hope I will not to get more any errors from this component...
Well... the other bug was handled quite quickly. So it's at least maintained. And other can also benefit from bugs you find when they are resolved.

As a further note... are you going to use this field "selected" to select multiple records to do something with them. There are also other ways of doing this (other than a selected-field). The plus-side of a selected field is that it is persistent. When closing your program and opening it again your selected records will still be selected. This could be a plus but it could also be unintentional and undesirable (it depends on your situation and design). The DBGrid also as a SelectedRows property with bookmarks of the records the user has selected with Ctrl+Click. You can loop that list and delete the selected records that way too. It's the same way (Ctrl+Click) you select multiple file in the explorer so users should be familiar with it.


totya

  • Hero Member
  • *****
  • Posts: 577
Hi!

First section of your post: okay, I understand it, under edit mode, delete cause crash. :)

Second section: I mean, this is important component, data handle/store etc. Critical component.  I don't like if any problem found with this.

I don't know what is the "plus side of selected field".
"When closing your program and opening it again your selected records will still be selected" lol, I can't do it. Where store DBGrid this selected data?

Thanks for the answer!




rvk

  • Hero Member
  • *****
  • Posts: 3842
I don't know what is the "plus side of selected field".
"When closing your program and opening it again your selected records will still be selected" lol, I can't do it. Where store DBGrid this selected data?
I meant the way you did it now has the plus-side that it is persistent. When you select the records you could do a commit and the selected boolean is stored in the database thus a restart of your application would mean you still have those records selected.

The way I meant it was using the SelectedRows of DBGrid. That doesn't store the selected-property. It is held inside the component itself. But it has the upside that it is like Windows Explorer in selecting records the same way (Ctrl+Click). Here is an example of looping through the records: http://forum.lazarus.freepascal.org/index.php?topic=16612.0

There is also another option. Using a checkbox but without a stored field. This uses the first column (when clicked) to add a bookmark.
http://wiki.lazarus.freepascal.org/Grids_Reference_Page#Selecting_Records_in_a_DBGrid_using_checkboxes

So... three possible selection-methods for you to choose from:
  • Stored field and checkbox = persistent
  • Ctrl+Click for selecting (like Explorer) = not persistent
  • Checkbox without stored field = not persistent

LuizAmérico

  • Sr. Member
  • ****
  • Posts: 458

totya

  • Hero Member
  • *****
  • Posts: 577
I meant the way you did it now has the plus-side that it is persistent. When you select the records you could do a commit and the selected boolean is stored in the database thus a restart of your application would mean you still have those records selected.

Hi!

Thanks for the detailed answer, the problem is my weak English, but now I understand what is it mean: "plus-side". About: positive thing/good thing. I think before this is the part of the cell... lol %)

totya

  • Hero Member
  • *****
  • Posts: 577
Seems a bug in TDataset: http://bugs.freepascal.org/view.php?id=28006

Hi!

Thanks for your job, and thanks for the bug report! Elsewhere I do not think that is the minor problem...

I think very much time needed while corrected freepascal code state will be stable and usable (and shipped with stable lazarus), so I must need rvk code before I want to use the delete command.

rvk

  • Hero Member
  • *****
  • Posts: 3842
Seems a bug in TDataset: http://bugs.freepascal.org/view.php?id=28006
Are you sure this is a bug in TDataset?
I've tried this code with a TSQLQuery and it worked correctly.

Looking at the code for TDataset.Delete:

Code: [Select]
Procedure TDataset.Delete;

begin
  If Not CanModify then
    DatabaseError(SDatasetReadOnly,Self);
  If IsEmpty then
    DatabaseError(SDatasetEmpty,Self);
  if State in [dsInsert] then
  begin
    Cancel;
  end else begin
    DataEvent(deCheckBrowseMode,0);
{$ifdef dsdebug}
    writeln ('Delete: checking required fields');
{$endif}
    DoBeforeDelete;
    DoBeforeScroll;
    If Not TryDoing(@InternalDelete,OnDeleteError) then exit;
{$ifdef dsdebug}
    writeln ('Delete: Internaldelete succeeded');
{$endif}
    FreeFieldBuffers;
    SetState(dsBrowse);
{$ifdef dsdebug}
    writeln ('Delete: Browse mode set');
{$endif}
    SetCurrentRecord(FActiveRecord);
    Resync([]);
    DoAfterDelete;
    DoAfterScroll;
  end;
end;

Doesn't that DataEvent(deCheckBrowseMode,0); do the job in case of dsEdit?

And the call to InternalDelete should be after the Dataevent for CheckBrowseMode.

LuizAmérico

  • Sr. Member
  • ****
  • Posts: 458
Quote
I've tried this code with a TSQLQuery and it worked correctly.

Probably works by accident.

I can patch SqliteDataset but is better to fix the root cause

Quote
Doesn't that DataEvent(deCheckBrowseMode,0); do the job in case of dsEdit?

No. It does nothing.


LuizAmérico

  • Sr. Member
  • ****
  • Posts: 458
The problem was really in Sqlite3ds.
Fixed in svn