How to sent a POST request as json in plsql - json

I have the following basic code which i use to post a plsql json request. The webservice getting executed doesnt have any response as it is simply for carrying out a certain task.
But each time i execute the block, i get the status code 400 from Apache Tomcat.
Where is it that i am going wrong?
declare
http_resp utl_http.resp;
http_req utl_http.req;
json_msg VARCHAR2(500);
begin
http_req := utl_http.begin_request('http://192.168.1.194:8080/NotificationApp/sendNotification.rest', 'POST');
utl_http.set_body_charset(http_req, 'UTF-8');
utl_http.set_header(http_req, 'Content-Type', 'application/json');
json_msg := '{"code":100,"id": "APA91bFSmD_gBsUwP_hraRZL20mt8p4ejGn5fC7tlciINT50Ad8oIod2T-64GVk_8rrjoqXGEpYuRcoQogG0L7aOKIjeeisTcmHiUUONbnZzn4_u0ED7QD_iNeVkh2RU8Pa-HBHwgJUgOT-TyvlM9hB4Yn9fvWER","data": "alert alert"}';
utl_http.write_text(http_req, dbms_lob.substr(json_msg,dbms_lob.getLength(json_msg),1));
http_resp := utl_http.get_response(http_req);
if (http_resp.status_code >= 400) and
(http_resp.status_code <= 499)
then
dbms_output.put_line(http_resp.status_code);
end if;
utl_http.end_response(http_resp);
end;
Thanks in advance

After a lot of searching, i got the following code from a blog. Works fine for me.
declare
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'http://192.168.1.194:8080/NotificationApp/sendNotification.rest';
name varchar2(4000);
buffer varchar2(4000);
content varchar2(4000) := '{"code":100,"id": "APA91bFSmD_gBsUwO_hraRZL20mt8p4ejGn5fC7tlciINT50Ad8oIod2T-64GVk_8rProqXGEpYuDcoQogG0L7a0TuyeeisTcmHiUUONbnZzn4_u0ED7QD_iNeVkh1ZgU8Pa-HRtfgJUgOT-TyvlM9hB4Yn9fvOPud","data": "alert alert"}';
begin
req := utl_http.begin_request(url, 'POST',' HTTP/1.1');
utl_http.set_header(req, 'user-agent', 'mozilla/4.0');
utl_http.set_header(req, 'content-type', 'application/json');
utl_http.set_header(req, 'Content-Length', length(content));
utl_http.write_text(req, content);
res := utl_http.get_response(req);
begin
loop
utl_http.read_line(res, buffer);
dbms_output.put_line(buffer);
end loop;
utl_http.end_response(res);
exception
when utl_http.end_of_body then
utl_http.end_response(res);
end;
end;

Now, I needed to change the line req := utl_http.begin_request(url, 'POST',' HTTP/1.1');
I did and worked:
req := utl_http.begin_request(url, 'POST');

I got this excellent answer from Jeff
From Oracle 18.3+ you can use :body_text. So if you have some column example of JSON type, you can simply SET example=:body_text.

Related

Why TFDBatchMove raises exception ELocalTimeInvalid for date field with value "03/11/2019"?

I'm using Delphi 10.3 Rio Update 1 on a Windows 7 SP1 machine.
My program's purpose is to convert a TFDMemtable into a JSON format. For a reason that I can't understand, when the date field of this TFDMemTable has the value '03/11/2019', using the DisplayFormat "day/month/year", it raises an exception:
Project ProjMemtabJSON.exe raised exception class ELocalTimeInvalid with message 'The given "03/11/2019" local time is invalid (situated within the missing period prior to DST).'.
Any other dates different than "Nov, 3rd 2019" work fine.
I have no clue what is going on here!
program ProjMemtabJSON;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Classes,
System.JSON,
FireDAC.Comp.DataSet,
FireDAC.Comp.Client,
FireDAC.Comp.BatchMove,
FireDAC.Comp.BatchMove.DataSet,
FireDAC.Comp.BatchMove.JSON,
Data.DB;
Var
Fmemtable : TFDmemtable ;
FJSONArray : TJSONArray;
FDBatchMoveJSONWriter1 : TFDBatchMoveJSONWriter;
FDBatchMoveDataSetReader1 : TFDBatchMoveDataSetReader;
FDBatchMove1 : TFDBatchMove;
procedure CreateMemtable;
begin
Fmemtable := TFDmemtable.Create(nil);
FMemTable.FieldDefs.Add('ID', ftInteger, 0, False);
FMemTable.FieldDefs.Add('Name', ftString, 20, False);
FMemTable.FieldDefs.Add('Status', ftString, 20, False);
FMemTable.FieldDefs.Add('Duedate', ftdatetime,0, False);
FMemTable.CreateDataSet;
end;
procedure FillMemtable;
begin
FMemtable.Append;
FMemtable.Fields[0].Value := 10; // ID
FMemtable.Fields[1].Value := 'John'; // Name
FMemtable.Fields[2].Value := 'Active'; // Status
{ ==> HERE IS THE PROBLEM : change this date to 03/11/2019 i.e. 03/Nov/2019 and an error will raise }
FMemtable.Fields[3].Value := StrToDate('02/11/2019'); // Due date dd/mm/yyyy
end;
procedure PrintMemtable;
begin
writeln('ID : ' ,Fmemtable.Fields[0].AsString);
writeln('Name : ' ,Fmemtable.Fields[1].AsString);
writeln('Status : ' ,Fmemtable.Fields[2].AsString);
writeln('Due Date : ' ,Fmemtable.Fields[3].AsString);
end;
function TableToJson : TJSONArray;
begin
Result := TJSONArray.Create;
try
FDBatchMoveDataSetReader1 := TFDBatchMoveDataSetReader.Create(nil);
FDBatchMoveJSONWriter1 := TFDBatchMoveJSONWriter.Create(nil);
FDBatchMove1 := TFDBatchMove.Create(nil);
FDBatchMove1.Reader := FDBatchMoveDataSetReader1 ;
FDBatchMove1.Writer := FDBatchMoveJSONWriter1;
try
if not FMemtable.Active then
FMemtable.Active := True;
FDBatchMoveDataSetReader1.DataSet := FMemtable;
FDBatchMoveJSONWriter1.JsonArray := Result;
FDBatchMove1.Execute;
except
on E: Exception do
raise Exception.Create('Error Message: ' + E.Message);
end;
finally
FDBatchMoveDataSetReader1.Free;
FDBatchMoveJSONWriter1.Free;
FDBatchMove1.Free;
end;
end;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
Creatememtable;
FillMemtable;
PrintMemtable;
FJSONArray := TableToJSON;
readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
There is a System.DateUtils routine that can check for an invalid time:
TTimeZone.IsInvalidTime(const ADateTime : TDateTime) : Boolean;
If you add DateUtils to your Uses clause, then update your FillMemTable to something like:
procedure FillMemtable;
var MyDate : tDateTime;
begin
FMemtable.Append;
FMemtable.Fields[0].Value := 10; // ID
FMemtable.Fields[1].Value := 'John'; // Name
FMemtable.Fields[2].Value := 'Active'; // Status
{ ==> HERE IS THE PROBLEM : change this date to 03/11/2019 i.e. 03/Nov/2019 and an error will raise }
MyDate := StrToDate('03/11/2019');
if TTimeZone.local.IsInvalidTime(MyDate) then MyDate := MyDate + 0.5; //noon won't be invalid
FMemtable.Fields[3].Value := MyDate; // Due date dd/mm/yyyy
end;
Or, as mentioned in the comments, if you don't want the overhead of the IF statement, just force all dates to be noon.
I had never realized that there were time zones which switched to/from DST at midnight. Unfortunate, what with how Dates (without times) are defined.

PLSQL parse json list: JSON Scanner exception

I'm parsing a json feed but when I loop the json_list I get the following error:
ORA-20100: JSON Scanner exception # line: 1 column: 33086 - string ending not found
Looking at the feed I'm unable to find anything out of the ordinary. It started to make me wonder if there's a character limitation.
my code is pretty simple..here are the relevant parts:
DECLARE
a_list json_list;
v_list clob;
obj_ json;
.....
BEGIN
....
req := utl_http.begin_request (v_url,'GET');
res := utl_http.get_response (req);
utl_http.read_text(res, v_list);
a_list := json_list(v_list);
for i in 1 .. a_list.count loop
obj_ := json(a_list.get(i));
val_source := obj_.get('source');
val_date := obj_.get('date');
el_source := val_source.get_string;
el_date := val_date.get_string;
end loop;
...
END;
Is there anything that I'm doing wrong? Or any hints out there?
I figured it out....
I read the data into a buffer string and basically worked on the data by chunks and then appended it to a clob.
dbms_lob.createtemporary(p_res_clob, false);
req := utl_http.begin_request (v_url,'GET');
res := utl_http.get_response (req);
begin
-- process the request and get the response:
loop
utl_http.read_text(res,l_buffer,32000);
dbms_lob.writeappend(p_res_clob,length(l_buffer), l_buffer);
end loop;
end;
a_list := json_list(v_list);
for i in 1 .. a_list.count loop
obj_ := json(a_list.get(i));
val_source := obj_.get('source');
val_date := obj_.get('date');
el_source := val_source.get_string;
el_date := val_date.get_string;
end loop;
...
END;
Hope this helps someone who gets stumped :)

JSON returned by TIdHTTP cannot be decoded

I have the following code:
var
MemoryStream1: TMemoryStream;
IdHTTP1: TIdHTTP;
Bytes1: TBytes;
s1: string;
begin
IdHTTP1 := TIdHTTP.Create(nil);
MemoryStream1 := TMemoryStream.Create;
IdHTTP1.Get('https://restcountries.eu/rest/v2/all', MemoryStream1);
MemoryStream1.Position := 0;
MemoryStream1.SaveToFile('C:\Temp\MemoryStream1.txt');
MemoryStream1.Position := 0;
SetLength(Bytes1, MemoryStream1.Size);
MemoryStream1.Read(Bytes1[0], MemoryStream1.Size);
s1 := TEncoding.UTF8.GetString(Bytes1);
It fails at the last line with the message "no mapping for the unicode character in the target multi-byte code page exists"
However, I can see the returned JSON clearly in HttpAnalyzer.
The file 'C:\Temp\MemoryStream1.txt' starts with the hex '1F8B0800000000000003DC9BED6F1BB7' when I am expecting something corresponding to { - a left brace - as the first character
when I try
s1 := TEncoding.Unicode.GetString(Bytes1);
String s1 contains "Chinese" characters.
I worked it out. Apparently, the gzip is not decompressed. One must do it oneself. Here goes:
var
IdHTTP1: TIdHTTP;
a1: AnsiString;
s1: string;
MemoryStream1, MemoryStream2: TMemoryStream;
begin
Screen.Cursor := crHourGlass;
IdHTTP1 := TIdHTTP.Create(nil);
MemoryStream1 := TMemoryStream.Create;
MemoryStream2 := TMemoryStream.Create;
IdHTTP1.Get('https://restcountries.eu/rest/v2/all', MemoryStream1);
MemoryStream1.Position := 0;
IdCompressorZLib1.DecompressGZipStream(MemoryStream1, MemoryStream2);
FreeAndNil(MemoryStream1);
MemoryStream2.Position := 0;
SetLength(a1, MemoryStream2.Size);
MemoryStream2.Read(a1[1], MemoryStream2.Size);
// AnsiString a1 now contains the decompressed data

ORACLE: How to parse json UTF8

When parsing json, the special characters do not consider, how do I solve it?
declare
str varchar2(4000) := '[{"id":"1","PRM_CODID":"R","PRM_TIPID":"REGISTRO UNICO CONTRIBUYENTE"},{"id":"2","PRM_CODID":"C","PRM_TIPID":"**CÉDULA DE IÑENTIDAD**"},{"id":"3","PRM_CODID":"P","PRM_TIPID":"PASAPORTE"}]';
l_obj json_list;
l_results json_list;
l_tempobj json;
l_addr_comps json_list;
l_addr json;
ls varchar2(100);
begin
l_obj := json_list(str);
FOR i IN 1 .. l_obj.count
LOOP
l_addr := json(l_obj.get(i));
ls := JSON_EXT.PP(l_addr, 'PRM_TIPID') ;
Dbms_output.put_line(ls);
END LOOP;
end;
/
Result:
"REGISTRO UNICO CONTRIBUYENTE"
"C\u00C9DULA DE I\u00D1ENTIDAD"
"PASAPORTE"
PL/SQL procedure successfully completed.
As per my understanding Oracle provides PL/SQL DOM APIs for JSON handling.You can check the below link for more details.
Link
You can use UNISTR function:
select unistr( replace('C\u00C9DULA DE I\u00D1ENTIDAD', '\u', '\') ) as x
from dual;
X
-------------------
CÉDULA DE IÑENTIDAD

Getting MySQL process output

I want to play with MySQL process and get what ever it write to console so I write this code in FreePascal:
I want to control MySQl and read & write whatever.
Process := TProcess.Create(nil);
with Process do
begin
Executable := 'C:\Program Files (x86)\MySQL\MySQL Server 5.5\bin\mysql.exe';
with Parameters do
begin
Options := [poUsePipes];
Add('-u');
Add('root');
Add('-p');
end;
Execute;
sleep(1000);
WriteLn(Process.Output.NumBytesAvailable); // will be 0 but it write "Enter password"
WriteLn(Process.Stderr.NumBytesAvailable); // will be 0 but it write "Enter password"
end;
TProcess is a component that control executing other programs,I even test Delphi codes but all result are the same.
But the problem is that this will freeze because there is no output but console window write :
Enter password:
How can I get this in my application and all others?
As I said I want to work with MySQL executable and read from and write in it, So I dont want to use its library or any other DB component.
EDIT:
Here is a Delphi version of my test from here with the same result :
function GetDosOutput(CommandLine: string; Work: string = 'C:\'): string;
var
SA: TSecurityAttributes;
SI: TStartupInfo;
PI: TProcessInformation;
StdOutPipeRead, StdOutPipeWrite: THandle;
WasOK: Boolean;
Buffer: array[0..255] of AnsiChar;
BytesRead: Cardinal;
WorkDir: string;
Handle: Boolean;
begin
Result := '';
with SA do begin
nLength := SizeOf(SA);
bInheritHandle := True;
lpSecurityDescriptor := nil;
end;
CreatePipe(StdOutPipeRead, StdOutPipeWrite, #SA, 0);
try
with SI do
begin
FillChar(SI, SizeOf(SI), 0);
cb := SizeOf(SI);
dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
wShowWindow := SW_HIDE;
hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
hStdOutput := StdOutPipeWrite;
hStdError := StdOutPipeWrite;
end;
WorkDir := Work;
Handle := CreateProcess(nil, PChar('cmd.exe /C ' + CommandLine),
nil, nil, True, 0, nil,
PChar(WorkDir), SI, PI);
CloseHandle(StdOutPipeWrite);
if Handle then
try
repeat
WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
if BytesRead > 0 then
begin
Buffer[BytesRead] := #0;
Result := Result + Buffer;
end;
until not WasOK or (BytesRead = 0);
WaitForSingleObject(PI.hProcess, INFINITE);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
finally
CloseHandle(StdOutPipeRead);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
memo1.text:=GetDosOutput('"C:\Program Files (x86)\MySQL\MySQL Server 5.5\bin\mysql.exe" -u root -p');
end;
It will freeze in WasOK line .
Also I tested many other codes for this subject and neither worked.