Oracle ORDS takes 2 secs (slow) to respond to simplest query - oracle

Firefox and Chrome report ~2000ms response time (localhost) to my REST API. The database executes the query in under 1ms. A static JSON file with the same content is served in 4ms.
Where is all the time going? Is ORDS.war consuming it, is it database connection time, is Tomcat using it or something else? How do I find the root cause?
Update: Win10. Stopped Apache service and tried running catalina.bat from command line and response time drops to ~30ms. Killed it and tried running as a service again - response time consistently ~170ms.
I have an ORDS 3.0.11.180.12.34 service running on Tomcat 8.5.16 (jre1.8.0_144 x64) running this query:
SELECT 1 FROM dual
as below
DECLARE
l_handler_id ords_metadata.ords_handlers.id%TYPE := NULL;
l_param_id ords_metadata.ords_parameters.id%TYPE := NULL;
l_module_name ords_metadata.ords_modules.name%type := 'rest';
l_pattern ords_metadata.ords_templates.uri_template%type := 'select_1_from_dual';
l_method ords_metadata.ords_handlers.method%type := 'GET';
BEGIN
ords.define_template (
p_module_name => l_module_name,
p_etag_type => 'QUERY',
p_etag_query => q'~SELECT dbms_random.value(0,1) FROM dual~',
p_pattern => l_pattern
);
ords.define_handler (
p_module_name => l_module_name,
p_pattern => l_pattern,
p_method => l_method,
p_source_type => ords.source_type_collection_item,
p_source => 'SELECT 1 FROM dual'
);
COMMIT;
END;
/

Related

ORA 29260: network error: TNS:connection closed

When i try to connect an sftp location from my oracle machine using a PL/SQL procedure, i got the ORA-29260: network error: TNS:connection closed error.
No problem with telnet connection
Target sftp machine is added to ACL
No problem on file transfer using ssh
Can manually connect to sftp location
DECLARE
l_conn UTL_TCP.connection;
BEGIN
l_conn := ftp.login('xx.xx.xx.xx', '22', 'myuser', 'mypass');
-- ftp.ascii(p_conn => l_conn);
-- ftp.put(p_conn => l_conn,
-- p_from_dir => 'MY_DOCS',
-- p_from_file => 'test_get.txt',
-- p_to_file => '/app/test_put.txt
dbms_output.put_line('connection done');
ftp.logout(l_conn);
END;
is there any idea ?
Thanks in advance.
Your program will never work. You are using port 22, which means that you are using SFTP, which is built on top of SSH. PLSQL does not provide an API against SSH directly from UTL_TCP.
However, it can be implemented using dbms_scheduler with external_script
To use SFTP from PL/SQL I'd do the following.
Use keypair authentication between the database server and the remote SSH service, allowing passwordless connections.
Write a shell script to perform the SFTP command.
Call the shell script from a job using the scheduler.
So, you have a script bash which runs the sftp, assuming you have exchange keys between the hosts that no passwords are needed.
#!/bin/bash
cd /directoryfiles
sftp user#host << eof
mput *.* -- or mget
eof
This is mysftp.sh. Then you need a credential and a job in dbms_scheduler
BEGIN
DBMS_CREDENTIAL.create_credential(
credential_name => 'my_cred_sftp',
username => 'myuser',
password => 'mypassword'
);
END;
/
BEGIN
DBMS_SCHEDULER.create_job(
job_name => 'MY_RUN_SFTP',
job_type => 'EXTERNAL_SCRIPT',
job_action => '/mydirectory/mysftp.sh',
credential_name => 'my_cred_sftp',
enabled => TRUE ,
auto_drop => TRUE
);
END;
/

How to terminate a POST web service call - ORDS

Please excuse my ignorance as I am a total beginner.
I have created a basic RESTful Web Services Using PL/SQL, sample code below(which works perfectly fine)
ords.define_template(
p_module_name => 'restDemo',
p_pattern => 'updateClient');
ords.define_handler(
p_module_name => 'restDemo',
p_pattern => 'updateClient',
p_method => 'POST',
p_source_type => ords.source_type_plsql,
p_source => 'declare
w_clob clob := :body_text;
begin
ws.ws_interface.update_client(w_clob);
exception
when others then
package.ws_interface.g_result_rec.result_message := SQLERRM;
end;');
When ws_interface.update_client is initiated via the post request, in the initialization of ws_interface package, I am calling a routine thats determines if the client can be updated or not (based on access of the user logged in to the DB).
If the user does not have access to execute the updateClient service - I want to terminate the service call, which I have no idea on how to go about do this.
So my question is:
How do I go about terminating the current active updateClient webservice call ?
In your ws_interface package, if the client can not be updated, then you just need to return so that the PL/SQL block in the POST definition will complete. Your code can look something like this:
---Beginning of package
...
procedure update_client (some_clob clob) is
begin
--The client can not be updated so do no more processing.
if can_update_client = false then
--Some sort of error message could also be added here
return;
end if;
--Rest of processing for updating the client
end;
...
---End of package

Oracle Advanced Queues - missing messages and best approach to debug

Env: Oracle 12c
I currently have an Oracle Advanced Queue system setup as follows:
NAME QUEUE_TABLE QID QUEUE_TYPE MAX_RETRIES RETRY_DELAY RETENTION
--------------- --------------- ------- --------------- ----------- ----------- ---------
MY_WORK_Q MY_WORK_QT 2518333 NORMAL_QUEUE 100 0 0
MY_WORK_QT_E MY_WORK_QT 2518332 EXCEPTION_QUEUE 0 0 0
I also have registered a callback that calls a PL/SQL package procedure.
For some reason, I seem to have a situation where I am losing messages or messages are not being dequeued.
Based on this, I have the following questions:
Have I setup my actual queue - MY_WORK_Q with MAX_RETRIES and other info correctly?
Is there a way to check messages that have been enqueued?
Is there a way to check messages that have been de-queued?
Is there a means of checking the EXCEPTION_QUEUE/Exception table to see if lost messages have reached there?
I just can't see why I am losing messages within my queueing system and what I could check to see what might be causing the issue.
I also increased my MAX_RETRIES to 100 but still seem to be having issues.
Update
It seems like I am getting the error ORA-25263: no message in queue.
I am not sure if this is related to a timing issue on the dbms_aq.enqueue or dbms_aq.dequeue calls but on the dbms_aq.dequeue I have this set:
l_dequeue_options.wait := dbms_aq.no_wait;
Do I require say a 10 second wait instead of no_wait? I am unsure if this possible and whether the wait needs to be on the enqueue or dequeue steps.
Here is a simple example that works. Perhaps you can use it to identify your issue?
-- DROP TYPE some_type_t FORCE;
CREATE OR REPLACE TYPE some_type_t AS OBJECT (
a NUMBER,
b VARCHAR(100),
c DATE
);
CREATE OR REPLACE PROCEDURE some_type_callback(CONTEXT IN RAW,
reginfo IN sys.aq$_reg_info,
descr IN sys.aq$_descriptor,
payload IN RAW,
payloadl IN NUMBER) AS
-- Local variables
v_dequeue_options dbms_aq.dequeue_options_t;
v_message_properties dbms_aq.message_properties_t;
v_message_handle RAW(26);
v_some_type some_type_t;
BEGIN
-- Set the dequeue options from the descriptor
v_dequeue_options.consumer_name := descr.consumer_name;
v_dequeue_options.msgid := descr.msg_id;
-- Dequeue the message
dbms_aq.dequeue(queue_name => descr.queue_name,
dequeue_options => v_dequeue_options,
message_properties => v_message_properties,
payload => v_some_type,
msgid => v_message_handle);
END some_type_callback;
/
SELECT *
FROM user_errors e
WHERE e.name = 'SOME_TYPE_CALLBACK';
BEGIN
-- dbms_aqadm.drop_queue_table(queue_table => 'some_type_qt',
-- force => TRUE);
dbms_aqadm.create_queue_table(queue_table => 'some_type_qt',
queue_payload_type => 'some_type_t',
multiple_consumers => TRUE);
dbms_aqadm.create_queue(queue_name => 'some_type_q',
queue_table => 'some_type_qt',
retention_time => 86400); -- 1 day
dbms_aqadm.start_queue(queue_name => 'some_type_q');
dbms_aqadm.add_subscriber(queue_name => 'some_type_q',
subscriber => sys.aq$_agent(NAME => 'some_type_qs',
address => NULL,
protocol => NULL));
dbms_aq.register(sys.aq$_reg_info_list(sys.aq$_reg_info('some_type_q:some_type_qs',
dbms_aq.namespace_aq,
'plsql://some_type_callback',
hextoraw('FF'))),
1);
END;
/
SELECT *
FROM aq$some_type_qt;
-- nothing
DECLARE
v_some_type some_type_t;
eopt dbms_aq.enqueue_options_t;
mprop dbms_aq.message_properties_t;
enq_msgid RAW(16);
BEGIN
v_some_type := some_type_t(a => 42,
b => 'forty-two',
c => to_date('1/1/2942',
'mm/dd/yyyy'));
dbms_aq.enqueue(queue_name => 'some_type_q',
enqueue_options => eopt,
message_properties => mprop,
payload => v_some_type,
msgid => enq_msgid);
END;
/
SELECT *
FROM aq$some_type_qt;
-- msg_state = READY => PROCESSED
One thing that will definitely help you is setting retention_time on your queue table. You can then use the aq$ reference for the queue table to look at the messages. The msg_state column will show READY for a fresh message and PROCESSED for a message that was consumed. There are some other columns on there that can be helpful: retry_count for example.
If you are getting ORA-25263 it seems instead of handling the one message you are getting provoked for in your callback that you are trying to read a different message and clashing with another job that was started to consume the queue. This is resolved by the two lines I have in my callback before calling dequeue.
If you need to trigger when a message arrives and then preserve message order you need to add some locking and additional complexity to your callback. You could take a look at Metalink 225810.1 for examples on how to do this.

REST service works via Postman, not using PL/SQL

I am new to programming with REST services, and I'm hitting a bit of a wall.
I need to be able to access a specific set of REST services from Oracle PL/SQL. The guy who knows about the services knows nothing about PL/SQL. Bridging the gap is proving difficult.
This, in POSTMAN, works:
(Apparently I'm too new to the site to post screen shots)
Action: POST
URL: http://dev-osb.sh.com/LDAP/LDAPVndrMgmt
Authorization: basic, username & password
Body: Raw, JSON
{
"requestType": "listAccounts",
"uid": "FTTestDlete100",
"vendorRole": "FreightTrackingLATA" }
And I get back all the results I expected in JSON format.
This PL/SQL should (as near as I can tell) do the same, but it doesn't.
DECLARE
l_clob clob;
l_json clob;
BEGIN
--create the JSON request body
apex_json.initialize_clob_output();
apex_json.open_object();
apex_json.write('requestType', 'listAccounts');
apex_json.write('uid', 'FTTestDlete100');
apex_json.write('vendorRole', 'FreightTrackingLATA');
apex_json.close_all();
l_json := apex_json.get_clob_output();
apex_json.free_output();
l_clob := apex_web_service.make_rest_request(
p_url => 'http://dev-osb.sh.com/LDAP/LDAPVndrMgt',
p_username => 'theUserName',
p_password => 'thepassword',
p_http_method => 'POST',
p_parm_name => apex_util.string_to_table('Content-Type'),
p_parm_value => apex_util.string_to_table('application/json'),
p_body => l_json
);
dbms_output.put_line(to_char(l_clob));
END;
As shown I get "{ "errorMessage" : "No acceptable request representation was found" }"
If I remove the /LDAP/LDAPVndrMgt portion from the URL, I get some HTML code saying:
**Error 404--Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent.If the server does not wish to make this information available to the client, the status code 403 (Forbidden) can be used instead. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address.**
So - something isn't working right. It's like the resource part (starting at /LDAP...) can't be concatenated onto the URL in the PL/SQL function, but without it I get a 404. I'm hoping to avoid having to go the UTL_HTTP route. Any suggestions?
Breakthrough - I found out that my PL/SQL was sending what should have been headers as parameters.
Here's the working code:
DECLARE
l_clob clob;
l_json clob;
BEGIN
apex_web_service.g_request_headers(1).NAME := 'Content-Type';
apex_web_service.g_request_headers(1).VALUE := 'application/json';
--create the JSON request body
apex_json.initialize_clob_output();
apex_json.open_object();
apex_json.write('requestType', 'listAccounts');
apex_json.write('uid', 'FTTestDlete100');
apex_json.write('vendorRole', 'FreightTrackingLATA');
apex_json.close_all();
l_json := apex_json.get_clob_output();
apex_json.free_output();
l_clob := apex_web_service.make_rest_request(
p_url => 'http://dev-osb.sh.com/LDAP/LDAPVndrMgt',
p_username => 'theUserName',
p_password => 'thepassword',
p_http_method => 'POST',
p_body => l_json
);
dbms_output.put_line(to_char(l_clob));
END;

Are BING geocoding & Google geocoding a web-service, or web-api?

I want to pull just the latitude and longitude (for some addresses in oracle table) from BING or Google. I want to do this from stored procedure. I tried to do this using the UTL_DBWS package, but I am not able to form a complete call as I am missing details like 'operation', 'input parameter request format' etc. I couldn't find wsdl file for both the geocoding services. So are these services actually a web-api or web-service? What is the best way to call these services from oracle stored-proc?
You can check this example which uses utl_http to get a good idea on how you can do it
Couple of things you need to take care
1)You need direct internet connection from database server
2)You need to edit your database ACL policy for this to work
3)You need to escape "&" symbol in the URL you use for searching
4)You need to validate the SSL certificate using Oracle wallet
The ACL Example
BEGIN
--You need DBA to execute this function where www.xml is the ACL Name
--SCOTT is the schemaname,my.oracle.com is the host to access the webpage
DBMS_NETWORK_ACL_ADMIN.CREATE_ACL(acl => 'www.xml',
description => 'WWW ACL',
principal => 'SCOTT',
is_grant => true,
privilege => 'connect');
DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE(acl => 'www.xml',
principal => 'SCOTT',
is_grant => true,
privilege => 'resolve');
DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL(acl => 'www.xml',
host => 'my.oracle.com');
END;
/
COMMIT;
you can add additional Host names for accessing the internet to the ACL www.xml like the below
BEGIN
DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL(acl => 'www.xml',
host => 'www.google.co.in');
END;
/
COMMIT;
here is an example of latitude and longitude search using google
declare
httpuri HttpUriType;
x clob;
address VARCHAR2(32000):='New York';
lat_long_value VARCHAR2(4000);
begin
UTL_HTTP.set_transfer_timeout(60); --set timeout to 60 seconds
httpuri := HttpUriType('http://www.google.co.in/search?q=find+latitude+and+longitude+of+' ||address||'&'||'ie=utf-'||'8&'||'oe=utf-'||'8&'||'aq=t'||'&'||'rls=org.mozilla'||':'||'en-US'||':'||'official'||'&'||'client=firefox-a');
x := httpuri.getclob();
lat_long_value := regexp_substr(x, '<div class="_Xj">(.+)</div>');
if lat_long_value is not null then
select regexp_replace(lat_long_value,
'<div class="_Xj">(.+)</div>',
'\1')
into lat_long_value
FROM dual;
end if;
dbms_output.put_line(lat_long_value);
end;
If you get the error that
Ora-29024 Certification validation failure
Kindly follow the steps required to add the google certificate to Oracle wallet here
Finally you get the output is
40.7127° N, 74.0059° W

Resources