Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Forum related to Oracle Server

Moderators: gto, EgonHugeist, mdaems

Post Reply
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 796
Joined: 18.11.2018, 17:37
Location: Hungary

Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Post by aehimself »

Hello,

I just faced a deadlock when I was trying to connect to an Oracle database. It happened in TZOracleConnection.HandleErrorOrWarning, this cycle:

Code: Select all

          while true do begin
            NewStatus := FPlainDriver.OCIErrorGet(ErrorHandle, I, nil, ErrorCode,
              @FByteBuffer[0], SizeOf(TByteBuffer)-1, OCI_HTYPE_ERROR);
            if NewStatus = OCI_NO_DATA then
              Break;
            [...]
          end;
The only way to exit this loop is if OCIErrorGet returns OCI_NO_DATA but in my case it was continuously returning -1 (OCI_ERROR).
I'm not really familiar with what exactly is happening here, if simply adding a second value to the exit condition is fine or not... but the thing is, this cycle poses a high chance of deadlock.
Delphi 12.2, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmysql.dll 8.0.40 x64 5.7.19 x68, libmariadb.dll 3.3.11
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.15
- MSSQL 2012, 2019; sybdb.dll FreeTDS_3102
- SQLite 3.47
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 796
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Post by aehimself »

Simply breaking out of the cycle is not going to help as the error message will be empty and no exception will be raised.
We can "hack" it around in the same cycle, a little bit further down:

Code: Select all

            L := StrLen(PAnsiChar(@fByteBuffer[0]));

            If L = 0 Then
            Begin
              WriterA.AddText(@AnsiString(Logmessage)[1], Length(Logmessage), {$IFNDEF UNICODE}ErrorMessage{$ELSE}ErrorMessageA{$ENDIF});
              Break;
            End;

            WriterA.AddText(@FByteBuffer[0], L, {$IFNDEF UNICODE}ErrorMessage{$ELSE}ErrorMessageA{$ENDIF});
This way a nice error message appears instead of the deadlock:

EZSQLException was raised with the message SQL Error: EnvNlsCreate failed.
Code: -1 Message: EnvNlsCreate failed.

I'm not going to create a pull request from this as though it works it feels dirty... maybe Michael knows a better solution? :)
Delphi 12.2, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmysql.dll 8.0.40 x64 5.7.19 x68, libmariadb.dll 3.3.11
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.15
- MSSQL 2012, 2019; sybdb.dll FreeTDS_3102
- SQLite 3.47
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 796
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Post by aehimself »

I also managed to find out the reason: you can not open two oracle connections with different oci.dll-s, otherwise the second DLL type will fail...

I connected to an Oracle database where the driver library was set to the 12.1 version. After this I still could connect everywhere, as long as I used the same 12.1 version.
In the moment I attempted an other connection with the default, 19.x oci.dll things collapsed.

I'm not sure but I guess this is caused by the "driver caching" "feature" of Zeos, as the 12.1 connection can be freed already and the next 19.x will still fail.
I'd be really happy if this caching would be overridden... makes driver dll updates a pain :)
Delphi 12.2, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmysql.dll 8.0.40 x64 5.7.19 x68, libmariadb.dll 3.3.11
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.15
- MSSQL 2012, 2019; sybdb.dll FreeTDS_3102
- SQLite 3.47
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 796
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Post by aehimself »

Well, damn it. Pull request created on GitHub. If Michael doesn't like it, he can roll it back anytime :)
Delphi 12.2, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmysql.dll 8.0.40 x64 5.7.19 x68, libmariadb.dll 3.3.11
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.15
- MSSQL 2012, 2019; sybdb.dll FreeTDS_3102
- SQLite 3.47
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1956
Joined: 17.01.2011, 14:17

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Post by marsupilami »

I merged it. Can you check if we have to do something similar on Zeos 7.2? My knowledge about the oracle driver isn't good enough to find this out in a reasonable time. :/
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 796
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Post by aehimself »

Jan,

There's no need. I checked out the 7.2-patches branch, HandleErrorOrWarning does not even exist there, only CheckOracleError in ZDbcOracleUtils. This method is handling error messages completely different, without using any cycles:

Code: Select all

    OCI_ERROR:
      begin
        if PlainDriver.ErrorGet(ErrorHandle, 1, nil, ErrorCode, @ErrorBuffer.Buf[0], SizeOf(ErrorBuffer.Buf)-1, OCI_HTYPE_ERROR) = 100
        then ErrorMessage := 'OCI_ERROR: Unkown(OCI_NO_DATA)'
        else begin
          ErrorMessage := 'OCI_ERROR: ';
          ErrorBuffer.Pos := StrLen(@ErrorBuffer.Buf[0])+1;
      end;
      end;
As far as I see an exception will be raised in any case so 7.2 is not affected by this issue.
Delphi 12.2, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmysql.dll 8.0.40 x64 5.7.19 x68, libmariadb.dll 3.3.11
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.15
- MSSQL 2012, 2019; sybdb.dll FreeTDS_3102
- SQLite 3.47
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1956
Joined: 17.01.2011, 14:17

Re: Possible deadlock in TZOracleConnection.HandleErrorOrWarning

Post by marsupilami »

Ok, thank you. :)
Post Reply