连接到 Oracle DB 时出现外部:SIGSEGV 错误

When connecting to Oracle DB I get External: SIGSEGV error

我会说我是如何在 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.        

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

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 语句对数据库执行某些操作的地方 这不涉及 SELECTing 记录。需要 ExecSQL 的最常见 SQL 语句是

UPDATE
INSERT
DELETE

虽然还有其他的,例如在 SQL 服务器上执行存储过程的语句 (请注意,某些存储过程 return 结果集等需要 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 一个您已经 Open 编辑过的数据集,因为它可以确保磁盘上的数据是最新的。如果最后一个 SQL 操作是 ExecSQL,则不需要关闭数据集。

如果按照我的方式设置查询的文本 属性,使用 ZQuery1.SQL.Text,则不需要使用 Clear。在任何情况下,它只等同于执行 ZQuery1.SQL.Text := '' 并且它不会影响数据集的状态 - 它只会在您调用 ExecSQLOpen.

时执行任何操作