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: 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
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