Dequeue does not give result

Discussion of open issues, suggestions and bugs regarding ODAC (Oracle Data Access Components) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
MDrueck
Posts: 18
Joined: Fri 01 Apr 2011 14:06
Location: Germany

Dequeue does not give result

Post by MDrueck » Fri 15 Jul 2016 14:00

Hi,

I still have trouble to get an application running using ODAC components. What seems to work ist the enqueuing, see line "[15.07.2016 13:01:45,803] OraSession.LastError: [0]" in my log file. Even the dequeuing gives no error, but I don't get any data back from the queue also.

The problem I have is, I don't run the Oracle database, I also did not created the queue, I'm only the user of the queue. And to make things worse, I don't have any access to the database/queue on my system. Only on our customers PC I do have access to the database/queue.

Most of the code is not written by me, but from another developer, but he quit his contract. Anybody here who can help making this code run?

TIA, Markus D

I use:
Delphi Seattle 10
ODAC Professional Edition 9.6.21 for RAD Studio 10
Windows 10, 64 bit

Components:

Code: Select all

object OraSession: TOraSession
  Options.Charset = 'AL32UTF8'
  Options.UseUnicode = True
  Username = 'am'
  Server = 'FARMSMQ'
  LoginPrompt = False
  HomeName = 'OraClient11g_home1'
  Left = 32
  Top = 472
end
object OraQueue: TOraQueue
  DequeueOptions.WaitTimeout = 0
  OnMessage = OraQueueMessage
  Left = 360
  Top = 471
end
Code:

Code: Select all

function TfrmMainAOS.DequeueFARMS : Boolean;
begin
  AddResults('Start DequeueFARMS');

  Result := False;
  try
    if OraSession.Connected then begin
      OraSession.Disconnect;
    end;

    OraSession.ConnectString            := edtConnectString.Text;
    OraQueue.Session                    := OraSession;
    OraQueue.QueueName                  := edtQueueTo.Text;
    OraQueue.DequeueOptions.WaitTimeout := AQ_NO_WAIT;
    OraQueue.DequeueOptions.Navigation  := qnNextMessage;
    OraQueue.DequeueOptions.DequeueMode := dqmRemove;

    OraSession.Connect;
    if OraSession.Connected then begin
      // kann nur gesetzt werden bei einer aktiven Session
      // wann immer ein neuer Eintrag in die Queue gemacht wird, erhalten wir jetzt eine notification
      // und OnMessage wird ausgelöst
      OraQueue.AsyncNotification := True;
    end;

    Result := True;
  except
    on E : Exception do
    begin
      HandleExceptionPrim(E, E.message, 4, 'DequeueFARMS');
    end;
  end;
  AddResults('Stop  DequeueFARMS');
end;  // DequeueFARMS

function TfrmMainAOS.EnqueueFARMS : Boolean;
var
  OraSQL           : TOraSQL;
  PayLoad          : string;
begin
  AddResults('Start EnqueueFARMS');

  Result := False;
  try
    OraSession.ConnectString := edtConnectString.Text;

    PayLoad := Format(mom_out.Lines.Text, [
        XMLDateTimeStrWithMS(Int(FStartDate)), XMLDateTimeStrWithMS(Int(FEndDate)), XMLDateTimeStrWithMS(Now)]);
    AddResults(Format('PayLoad: [%s]', [PayLoad]));

    // Hier wird das SQL direkt an die Oracle übergeben, und dann anschließend ausgeführt
    // Das SQL Statement muss hierbei natürlich der PL/SQL Syntax folgen
    // Hierfür ist folgender Link recht hilfreich :
    // http://download.oracle.com/docs/cd/B13789_01/appdev.101/b10802/d_aqadm.htm#1014384
    try
      OraSQL          := TOraSQL.Create(nil);
      OraSQL.Session  := OraSession;
      OraSQL.SQL.Text := 'declare' + #13 +
        '  message       SYS.AQ$_JMS_TEXT_MESSAGE;' + #13 +
        '  agent         sys.aq$_agent   := sys.aq$_agent('' '', null, 0);'+ #13 +
        '  queue_options DBMS_AQ.ENQUEUE_OPTIONS_T;' + #13 +
        '  msg_props     DBMS_AQ.MESSAGE_PROPERTIES_T;' + #13 +
        '  msgid         raw(16);' + #13 +
        'begin' + #13 +
        '  message := sys.aq$_jms_text_message.construct;' + #13 +
        '  message.set_replyto(agent);' + #13 +      // Nur der Vollständigkeit als Beispiel mit befüllt, nicht notwendig
        '  message.set_type(''farms'');' + #13 +     // Nur der Vollständigkeit als Beispiel mit befüllt, nicht notwendig
        '  message.set_userid(''aquser'');' + #13 +  // Nur der Vollständigkeit als Beispiel mit befüllt, nicht notwendig
        '  message.set_appid(''am'');' + #13 +       // Nur der Vollständigkeit als Beispiel mit befüllt, nicht notwendig
        '  message.set_text(:text);' + #13 +         // Das ist die Payload, ist der Text größer als die max. Größe eines Varchar2
                                                     // wird daraus automatisch ein CLOB
        '  DBMS_AQ.ENQUEUE( queue_name         => :FromQueue' + #13 +
        '                 , enqueue_options    => queue_options' + #13 +
        '                 , message_properties => msg_props' + #13 +
        '                 , payload            => message' + #13 +
        '                 , msgid              => msgid);' + #13 +
        'end;';
      OraSQL.Prepare;
      OraSQL.ParamByName('text').AsString      := PayLoad;
      OraSQL.ParamByName('FromQueue').AsString := edtQueueFrom.Text;

      AddResults(Format('SQL.Text:' + #13#10 + '[%s]', [OraSQL.SQL.Text]));
      AddResults('Start: OraSQL.Execute');

      OraSQL.Execute;
      OraSession.Commit;
      AddResults(Format('OraSession.LastError: [%d]', [OraSession.LastError]));
      AddResults(Format('ENQUEUE: Payload:' + #13#10 + '%s' + 'Length: %d', [PayLoad, Length(PayLoad)]));
      AddResults('Stop: OraSQL.Execute');
      Result := True;
    except
      on E : Exception do begin
        HandleExceptionPrim(E, E.message, 4, 'EnqueueFARMS');
      end;
    end;
  finally
    FreeAndNil(OraSQL);
  end;
  AddResults('Stop  EnqueueFARMS');
end;  // EnqueueFARMS

procedure TfrmMainAOS.OraQueueMessage(Sender: TOraQueue; const MessageId: string;
  const MessageProperties: TQueueMessageProperties);
  { . }
var
  ObjectPayload   : TOraObject;
  FileName        : string;
  MsgId           : string;
  PayLoad         : string;
  StartTime       : TDateTime;
  EnqueueTime     : TDateTime;
begin
  // in MessageID steht die ID der Message, diesen ID an
  // dann das dequeueing starten
  OraQueue.DequeueOptions.MessageId        := MessageId;
  OraQueue.DequeueOptions.DeliveryMode     := qdmPersistentOrBuffered;
  OraQueue.DequeueOptions.DequeueCondition := EmptyStr;
  EnqueueTime                              := MessageProperties.EnqueueTime;

  // kann die Message gleich nach dem Enqueueing abgerufen werden, dann ist MessageProperties.Delay = 0
  // ansonsten abwarten bis delay abgelaufen ist
  // man könnte hier auch die Enqueueing Time mit der aktuellen vergleichen und dann enstsprechend abwarten
  if MessageProperties.Delay > AQ_NO_DELAY then begin
    MWWait(MessageProperties.Delay * 1000);
  end;

  // Message ist abgelaufen, wenn ich es richtig verstehe dann ist es bei FARMS immer 0
  // MessageProperties.State eignet sich besser zum abprüfen als expire zeit
  if {(IncSecond(EnqueueTime,MessageProperties.Expiration) <= now) and } (MessageProperties.State = qmsReady) then begin
    try
      StartTime     := Now;
      ObjectPayload := TOraObject.Create;

      try
        memXMLData.Lines.Clear;
        FileName := Format('%s\FARMS To AM %s.xml', [edtTxtImportUpdateFolder.Text, FormatDateTime('YYYY DD MM - HH NN SS', Now)]);
        AddResults(Format(#13#10 + ' Message ID: [%d]', [MessageId]));
        AddResults(Format(#13#10 + ' Enqueue Time : [%d]', [FormatDateTime('YYYY DD MM - HH NN SS', EnqueueTime)]));
        // wie oft wurde versucht die Message zu holen
        AddResults(Format(#13#10 + ' Dequeue Attempts : [%d]', [IntToStr(MessageProperties.Attempts)]));

        try
          // hier jetzt die richtige Message holen, die über das Event übergeben wurde (MessageId)
          MsgId := OraQueue.Dequeue(ObjectPayload);
        except
          on E : Exception do begin
            AddResults(Format('ERROR: OraQueue.Empty; [%s]', [E.Message]));
          end;
        end;

        // hier die Daten holen die in der Payload stehen
        if ObjectPayload.AttrIsNull['text_lob'] then begin
          PayLoad := ObjectPayload.AttrAsString['text_vc']
        end else begin
          PayLoad := ObjectPayload.AttrAsLob['text_lob'].AsWideString;
        end;

        AddResults(Format('DEQUEUE: MsgId: [%s]; Length: [%d]', [MsgId, ObjectPayload.AttrAsInteger['text_len']]));
        memXMLData.Lines.Add(PayLoad);
        OraQueue.Session.Commit;
        AddResults(Format('OraSession.LastError: [%d]', [OraSession.LastError]));
      finally
        FreeAndNil(PayLoad);
        memXMLData.Lines.SaveToFile(FileName);
      end;
    except
      on E : Exception do begin
        HandleExceptionPrim(E, E.message, 4, 'DequeueFARMS');
      end;
    end;

  end else begin
    // error handling hier dann gesondert abhandeln, eventuell löschen
    AddResults(Format(#13#10 + ' Error message expired -> Message ID: [%d]', [MessageId]));
  end;
end;  // OraQueueMessage
What is logged with "AddResults":

Code: Select all

[15.07.2016 13:01:40,846] Start EnqueueFARMS
[15.07.2016 13:01:40,846] PayLoad: [<soap-env:Envelope 
  xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:aodb="urn:com.tsystems.ac.aodb">
  <soap-env:Header>
    <aodb:control>
      <aodb:message-id>q4de3msys11:7384cfc6:125feac3cf8:-7fe7</aodb:message-id>
      <aodb:message-version>1.3</aodb:message-version>
      <aodb:message-type>DATASET</aodb:message-type>
      <aodb:request>
        <aodb:datatype>op_turn</aodb:datatype>
        <aodb:start-time>2016-07-14T00:00:00.000</aodb:start-time>
        <aodb:end-time>2016-07-19T00:00:00.000</aodb:end-time>
      </aodb:request>
      <aodb:timestamp>2016-07-15T13:01:40.846</aodb:timestamp>
      <aodb:sender>AM</aodb:sender>
    </aodb:control>
  </soap-env:Header>
  <soap-env:Body/>
</soap-env:Envelope>
]
[15.07.2016 13:01:45,753] SQL.Text:
[declare
  message       SYS.AQ$_JMS_TEXT_MESSAGE;
  agent         sys.aq$_agent   := sys.aq$_agent(' ', null, 0);
  queue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
  msg_props     DBMS_AQ.MESSAGE_PROPERTIES_T;
  msgid         raw(16);
begin
  message := sys.aq$_jms_text_message.construct;
  message.set_replyto(agent);
  message.set_type('farms');
  message.set_userid('aquser');
  message.set_appid('am');
  message.set_text(:text);
  DBMS_AQ.ENQUEUE( queue_name         => :FromQueue
                 , enqueue_options    => queue_options
                 , message_properties => msg_props
                 , payload            => message
                 , msgid              => msgid);
end;
]
[15.07.2016 13:01:45,753] Start: OraSQL.Execute
[15.07.2016 13:01:45,803] OraSession.LastError: [0]
[15.07.2016 13:01:45,803] ENQUEUE: Payload:
<soap-env:Envelope 
  xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:aodb="urn:com.tsystems.ac.aodb">
  <soap-env:Header>
    <aodb:control>
      <aodb:message-id>q4de3msys11:7384cfc6:125feac3cf8:-7fe7</aodb:message-id>
      <aodb:message-version>1.3</aodb:message-version>
      <aodb:message-type>DATASET</aodb:message-type>
      <aodb:request>
        <aodb:datatype>op_turn</aodb:datatype>
        <aodb:start-time>2016-07-14T00:00:00.000</aodb:start-time>
        <aodb:end-time>2016-07-19T00:00:00.000</aodb:end-time>
      </aodb:request>
      <aodb:timestamp>2016-07-15T13:01:40.846</aodb:timestamp>
      <aodb:sender>AM</aodb:sender>
    </aodb:control>
  </soap-env:Header>
  <soap-env:Body/>
</soap-env:Envelope>
Length: 768
[15.07.2016 13:01:45,803] Stop: OraSQL.Execute
[15.07.2016 13:01:45,803] Stop  EnqueueFARMS
[15.07.2016 13:01:45,803] Start DequeueFARMS
[15.07.2016 13:01:48,213] Stop  DequeueFARMS

AlexP
Devart Team
Posts: 5530
Joined: Tue 10 Aug 2010 11:35

Re: Dequeue does not give result

Post by AlexP » Mon 18 Jul 2016 06:41

Hello,

Please send the full sample to support*devart*com.

MDrueck
Posts: 18
Joined: Fri 01 Apr 2011 14:06
Location: Germany

Re: Dequeue does not give result

Post by MDrueck » Tue 26 Jul 2016 05:27

AlexP wrote:Hello,

Please send the full sample to support*devart*com.
I did sent you source by private mail "Re: [Devart #179514]: Re: Dequeue does not give result", 18.07.2016 15:30. Is there something you found out what is wrong?

TIA, Markus

AlexP
Devart Team
Posts: 5530
Joined: Tue 10 Aug 2010 11:35

Re: Dequeue does not give result

Post by AlexP » Mon 12 Sep 2016 09:17

I received your scripts, however it is quite difficult to deal with these objects due to their volume. Please compose a SIMPLE sample, including only the objects, that are used to reproduce the problem situation.

MDrueck
Posts: 18
Joined: Fri 01 Apr 2011 14:06
Location: Germany

Re: Dequeue does not give result

Post by MDrueck » Mon 26 Sep 2016 08:52

AlexP wrote:I received your scripts, however it is quite difficult to deal with these objects due to their volume. Please compose a SIMPLE sample, including only the objects, that are used to reproduce the problem situation.
I sent a private mail with a simple sample.

TIA, Markus

AlexP
Devart Team
Posts: 5530
Joined: Tue 10 Aug 2010 11:35

Re: Dequeue does not give result

Post by AlexP » Mon 14 Nov 2016 11:37

I have answered you via email.

MDrueck
Posts: 18
Joined: Fri 01 Apr 2011 14:06
Location: Germany

Re: Dequeue does not give result

Post by MDrueck » Wed 16 Nov 2016 08:58

AlexP wrote:I have answered you via email.
Yes, I know. I really appreciate your persistence in this case. But I don't have a simpler example at hand. All of the database definition is done by another company, not by me. And I don't have any knowledge with Oracle database at all, specially with queues. And my own Delphi code originates in parts from another developer who is out of business.

I tried to get help in this case in other (Delphi) forums, with no avail. I would pay for a solution because I think that the code to query an oracle queue should not be to hard to implement.

Any help is highly appreciated. Thanks, Markus

AlexP
Devart Team
Posts: 5530
Joined: Tue 10 Aug 2010 11:35

Re: Dequeue does not give result

Post by AlexP » Thu 24 Nov 2016 09:38

Unfortunately, we can't fix the problem without having reproduced it. If you could give us access to your server, we would try to reproduce the problem on it.

Post Reply