Page 1 of 1

ZDbcOracleResultSet ReadBlob is NOT worked. Lazarus

Posted: 21.05.2010, 05:49
by Inferno
Problem 1.Original procedure ReadBlob from ZDbcOracleResultSet is not worked with CLOB data where length higher some ~4Kb. Error:OCI_NEED_DATA
Lazarus.Oracel 9i. NLS_LANG=RUSSIAN_CIS.UTF8
revision 807 from trunk

But, my procedure is worked:

Code: Select all

procedure TZOracleBlob.ReadBlob;
const
  MemDelta = 1 shl 12;  // read page (2^...)
  iBufferSize = 4096;
var
  Status: integer;
  Buf: PByteArray;
  ReadNum, Offset, Cap: ub4;
  Connection: IZOracleConnection;
  atmp: integer;
  i: integer;
  ond: boolean;

{$IFDEF FPC}
  function GetSizeAtmpLast(Abuf:Pointer;SizeBuf:integer):integer;
  Var
    gi: Integer;
    chLen: LongInt;
  begin
    result := 0;
    gi:=0;
    while gi<SizeBuf do
    begin
      chLen:=UTF8CharacterLength(Pchar(Abuf));
      if chlen<=0 then
        break;
      Inc(Abuf,chLen);
      Inc(gi,chLen);
      if Pchar(Abuf)='' then break;
    End;
    result:=gi;
  End;
{$ENDIF}

begin
  if not Updated and (FLobLocator <> nil) and (BlobData = nil) and
    (not FTemporary) then
  begin
    Connection := FHandle as IZOracleConnection;

    { Opens a large object or file for read. }
    Status := FPlainDriver.LobOpen(Connection.GetContextHandle,
      Connection.GetErrorHandle, FLobLocator, OCI_LOB_READONLY);
    CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
      Status, lcOther, 'Open Large Object');
    try
      { Reads data in chunks by MemDelta or more }
      Offset := 0;
      Cap := 0;
      Buf := nil;
      try     
        atmp := 0;
        Status := OCI_SUCCESS;
        ond := False;
        while (Status = OCI_NEED_DATA) or (Status = OCI_SUCCESS) do
        begin
          Cap := Cap + iBufferSize;
          ReallocMem(Buf, Cap);
          FillByte(Buf[Offset],iBufferSize,0);
          ReadNum := iBufferSize;
          Status := FPlainDriver.LobRead(Connection.GetContextHandle,
            Connection.GetErrorHandle, FLobLocator, atmp, Offset +
            1, @Buf[Offset], ReadNum, nil, nil, 0, SQLCS_IMPLICIT);
          case Status of
            OCI_NEED_DATA:
            begin
              ond := True;
              if (atmp > 0) then
                Inc(Offset, ReadNum);
            end;
            OCI_SUCCESS:
            begin
              {$IFDEF FPC}
              if ond then
                Inc(Offset,GetSizeAtmpLast(@Buf[Offset],iBufferSize))
              else
                Inc(Offset, atmp);
              {$ELSE}
              Inc(Offset, atmp);
              {$ENDIF}
              Break;
            end;
            else
              break;
          end;
        end;
        CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
          Status, lcOther, 'Read Large Object');
      except
        FreeMem(Buf);
        raise;
      end;
      ReallocMem(Buf, Offset);
    finally
      { Closes large object or file. }
      Status := FPlainDriver.LobClose(Connection.GetContextHandle,
        Connection.GetErrorHandle, FLobLocator);
      CheckOracleError(FPlainDriver, Connection.GetErrorHandle,
        Status, lcOther, 'Close Large Object');
    end;
    { Assigns data }
    InternalSetData(Buf, Offset);
  end;
end;
Problem 2. The LobLocator for all records of the table same

Posted: 26.05.2010, 23:17
by mdaems
Hi,

Do you know the reason why there's a difference between Delphi and FPC handling? Doesn't Delphi need GetSizeAtmpLast?

Mark

Posted: 31.05.2010, 03:50
by Inferno
mdaems wrote:Hi,

Do you know the reason why there's a difference between Delphi and FPC handling? Doesn't Delphi need GetSizeAtmpLast?

Mark
Hi, Mark.

The method GetSizeAtmpLast it is necessary for Delphi. But I don't use Delphi, I use FreePascal and rewrited the ReadBlob method under the project. Maybe you can realise this method more correctly.
And what with are identical LobLocator to different records?

Alexei.

Posted: 14.06.2010, 22:56
by mdaems
Hi Alexei,

I tried your code and except for the line

Code: Select all

FillByte(Buf[Offset],iBufferSize,0); 
it compiles fine for al compilers and the testsuite didn't give any more errors.

However, I don't know how to change GetSizeAtmpLast so it also compiles on Delphi either. Is your version worse for Delhi than the old version?

Concerning The identical Loblocator for all records seems to be a known problem. The reason may be that a pointer to a loblocator is stored inside the Blob object, and maybe the OCI uses the same address for each LOB again? Needs debugging... Feel like giving it a go?

Mark