【问题标题】:When connecting to Oracle DB I get External: SIGSEGV error连接到 Oracle DB 时出现 External: SIGSEGV 错误
【发布时间】:2021-09-24 21:41:33
【问题描述】:

我会说我如何在 lazarus 上重现这个问题。 我有一个表单和一个使用 zeos 的数据模块来建立与本地 oracle 数据库的连接。 当我将一些代码与数据库对话时出现的问题。 这是一个例子:

OracleMng.ZQuery1.SQL.Clear;      

这正是出错的那一行。 以下是表格的完整代码:

 unit form1;

    {$mode objfpc}{$H+}
    
    interface
    
    uses
      Classes, SysUtils, Forms, Controls, Graphics, Dialogs, DBGrids, StdCtrls,
      datamodule2;
    
    type
    
      { TLogin }
    
      TLogin = class(TForm)
        Button1: TButton;
        DBGrid1: TDBGrid;
        procedure Button1Click(Sender: TObject);
      private
    
      public
    
      end;
    
    var
      Login: TLogin;
    
    implementation
    
    {$R *.lfm}
    
    { TLogin }
    
    procedure TLogin.Button1Click(Sender: TObject);
    begin
    
      OracleMng.ZQuery1.SQL.Clear;
    
    end;
    
    end.

这是数据模块的代码:

unit datamodule2;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, DB, ZConnection, ZDataset, ZSqlMonitor;

type

  { TOracleMng }

  TOracleMng = class(TDataModule)
    DataSource1: TDataSource;
    ZConnection1: TZConnection;
    ZQuery1: TZQuery;
  private

  public

  end;

var
  OracleMng: TOracleMng;

implementation

{$R *.lfm}

{ TOracleMng }



end.

我在努力

    if (OracleMng <>  Nil) and (OracleMng.Zquery1 <> Nil) then OracleMng.ZQuery1.SQL.add('select * from help');
  if (OracleMng <>  Nil) and (OracleMng.Zquery1 <> Nil) then OracleMng.ZQuery1.ExecSQL;
   dbgrid1.refresh; 

我没有更多错误,但 DBGrid1 未填充。

这是我的项目 lpr 文件:

program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms, zcomponent, datamodule2, form1
  { you can add units after this };

{$R *.res}

begin
  RequireDerivedFormResource:=True;
  Application.Scaled:=True;
  Application.Initialize;
  Application.CreateForm(TLogin, Login);
  Application.Run;
end.        

【问题讨论】:

  • 出现该错误的最可能原因是没有创建 OracleMng 或 ZQuery1。将您的代码更改为if (OracleMng &lt;&gt; Nil) and (OracleMng.Zquery1 &lt;&gt; Nil) then OracleMng.ZQuery1.SQL.Clear。您仍然收到错误消息吗?
  • @MartynA 它没有给出错误,但 DBGrid1 没有显示查询结果。我正在使用 dbgrid1.refresh;但是现在对于每个查询我都应该这样做“如果”?
  • 我认为您需要将minimal, reproducible example 添加到您的 q 中,包括您希望填充 DBGrid 的查询。
  • 我添加了我在问题中使用的 3 行。在Delphi中,我使用了这段代码并且它正在工作(使用dbexpress):DataModule1.SQLQuery1.Close;数据模块1.SQLQuery1.SQL.清除; DataModule1.SQLQuery1.sql.add('update help set topic = :topic where info like :call'); DataModule1.SQLQuery1.ParamByName('topic').AsString := 'LAKO';//uso per forza ParamByName DataModule1.SQLQuery1.ParamByName('call').AsString := '%call from the local%';数据模块1.SQLQuery1.ExecSQL;
  • 同样不适用于 zeos connect 的 lazarus。

标签: freepascal lazarus


【解决方案1】:

我在评论中建议的更改,即

if (OracleMng <>  Nil) and (OracleMng.Zquery1 <> Nil) then
  OracleMng.ZQuery1.SQL.Clear

显然阻止了您收到 SIGSEGV 错误,这表明您的 DataModule 和 表单的创建顺序错误,即表单优先。去看看这个 项目 |在 IDE 中查看源代码。如果你看到类似的东西

program MyProgram;

[...]

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TDataModule1, DataModule1);
  Application.Run;
end.

它们的顺序错误,因此交换两条 CreateForm 行

  Application.CreateForm(TDataModule1, DataModule1);
  Application.CreateForm(TForm1, Form1);

有了这个改变,你应该不再需要

if (OracleMng <>  Nil) and (OracleMng.Zquery1 <> Nil) then`

接下来的事情:你似乎对何时使用感到困惑

ZQuery1.ExecSQL

和

ZQuery1.Open

Open 用于当您使用的 SQL 语句生成结果集时,即 可以在 TDBGrid 中查看的记录集合。最常用的方法 是使用 SELECT 语句,如

ZQuery1.SQL.Text := 'select * from MyTable';
ZQuery1.Open;

ExecQuery 用于您的 SQL 语句对数据库执行某些操作的地方 这不涉及选择记录。最常见的需要 ExecSQL 的 SQL 语句是

UPDATE
INSERT
DELETE

虽然还有其他的,例如在 SQL Server 上执行存储过程的语句 (注意有些存储过程返回结果集,所以需要Open,而不是ExecSQL)。

请注意,ExecSQL 将清除数据集中 (ZQuery1) 中的所有记录,因此在 您需要使用合适的 SQL 语句再次打开

var
  S : String;
begin
  S := 'update MyTable set number = number +1 where id = 5';
  ZQuery.SQL.Text := S;
  ZQuery1.ExecSQL;    // no records shown in DBGrid1 from here

  S := 'select * from MyTable';
  ZQuery.SQL.Text := S;
  ZQuery1.Open;    // records shown in DBGrid1 again
end;

请注意我这样做

  S := 'select * from MyTable';
  ZQuery.SQL.Text := S;

而不是

  ZQuery1.SQL.Clear;
  ZQuery1.SQL.Add('select * from myTable');

这样做的原因是在调试器中查看整个 SQL 语句要容易得多 检查变量 S 比检查 ZQuery1.SQL.Text 属性更容易 查看任何语法错误。

您应该始终Close 一个数据集,一旦您完成了对它的使用Opened,因为它可以确保磁盘上的数据是最新的。如果最后一个 SQL 操作是 ExecSQL,则不需要关闭数据集。

如果按照我的方式设置查询的 Text 属性,使用 ZQuery1.SQL.Text,则不需要使用 Clear。无论如何,它只相当于做ZQuery1.SQL.Text := '',它不会影响数据集的状态——它只会在你调用ExecSQL或Open时做任何事情。

【讨论】:

  • 这是我的项目lpr文件:program project1; {$mode objfpc}{$H+} 使用 {$IFDEF UNIX}{$IFDEF UseCThreads} cthreads, {$ENDIF}{$ENDIF} Interfaces, // 这包括 LCL widgetset Forms, zcomponent, datamodule2, form1 { 可以添加此之后的单位 }; {$R *.res} 开始 RequireDerivedFormResource:=True; Application.Scaled:=真;应用程序。初始化; Application.CreateForm(TLogin, 登录);应用程序。运行;结束。
  • 该代码不会创建您的数据模块,它应该这样做,在它创建您的登录表单之前。
  • 我将它添加到“问题”中以获得良好的格式。无论如何,由于您的回答,我注意到了这一点,但是如果我感到奇怪,为什么 lazarus 没有自动执行此操作(将 create datamodule 行放入该文件中)。我会写它并重新编译。谢谢
  • 现在一切正常。你真的很珍贵!你的例子终于解决了我很多疑惑。我还想知道在执行查询后何时使用 .close 和 .clear。
  • 您应该始终在完成使用后关闭已打开的数据集,因为它可以确保磁盘上的数据是最新的。如果最后一个 SQL 操作是 ExecSQL,则不需要关闭数据集如果按照我的方式设置查询的 Text 属性,使用 ZQuery1.SQL.Text,则不需要使用 Clear。无论如何,它只相当于设置 ZQuery1.SQL.Text := '。 ' 并且它不会影响数据集的状态 - 它只会在您调用 ExecSQL 或 Open 时执行任何操作。
猜你喜欢
  • 2013-08-31
  • 2022-07-06
  • 2022-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-07
  • 2010-11-29
  • 2020-04-26
相关资源
最近更新 更多