work with json in oracle - json

Is there an easy way to work with JSON within oracle? I have a standard procedure that I use to call web services quite often, JSON is a format that I am familiar with in web development context, but what is the best way to work with json within a stored procedure? For instance take the CLOB response from the URI, convert that to a JSON object and get a value from that?
For reference sake, here is the procedure I used to fetch URLs
create or replace procedure macp_URL_GET(url_resp in out clob, v_url in varchar2) is
req Utl_Http.req;
resp Utl_Http.resp;
NAME VARCHAR2 (255);
VALUE VARCHAR2 (1023);
v_msg VARCHAR2 (80);
v_ans clob;
-- v_url VARCHAR2 (32767) := 'http://www.macalester.edu/';
BEGIN
/* request that exceptions are raised for error Status Codes */
Utl_Http.set_response_error_check (ENABLE => TRUE );
/* allow testing for exceptions like Utl_Http.Http_Server_Error */
Utl_Http.set_detailed_excp_support (ENABLE => TRUE );
/*
Utl_Http.set_proxy (
proxy => 'www-proxy.us.oracle.com',
no_proxy_domains => 'us.oracle.com'
);
*/
req := Utl_Http.begin_request (url => v_url, method => 'GET');
/*
Alternatively use method => 'POST' and Utl_Http.Write_Text to
build an arbitrarily long message
*/
/*
Utl_Http.set_authentication (
r => req,
username => 'SomeUser',
PASSWORD => 'SomePassword',
scheme => 'Basic',
for_proxy => FALSE --this info is for the target Web server
);
*/
Utl_Http.set_header (r => req, NAME => 'User-Agent', VALUE => 'Mozilla/4.0');
resp := Utl_Http.get_response (r => req);
/*
DBMS_OUTPUT.put_line ('Status code: ' || resp.status_code);
DBMS_OUTPUT.put_line ('Reason phrase: ' || resp.reason_phrase);
FOR i IN 1 .. Utl_Http.get_header_count (r => resp)
LOOP
Utl_Http.get_header (r => resp, n => i, NAME => NAME, VALUE => VALUE);
DBMS_OUTPUT.put_line (NAME || ': ' || VALUE);
END LOOP;
*/
--test
BEGIN
LOOP
Utl_Http.read_text (r => resp, DATA => v_msg);
--DBMS_OUTPUT.put_line (v_msg);
v_ans := v_ans || v_msg;
url_resp := url_resp || v_msg;
END LOOP;
EXCEPTION
WHEN Utl_Http.end_of_body
THEN
NULL;
END;
--test
Utl_Http.end_response (r => resp);
--url_resp := v_ans;
EXCEPTION
/*
The exception handling illustrates the use of "pragma-ed" exceptions
like Utl_Http.Http_Client_Error. In a realistic example, the program
would use these when it coded explicit recovery actions.
Request_Failed is raised for all exceptions after calling
Utl_Http.Set_Detailed_Excp_Support ( ENABLE=>FALSE )
And it is NEVER raised after calling with ENABLE=>TRUE
*/
WHEN Utl_Http.request_failed
THEN
DBMS_OUTPUT.put_line (
'Request_Failed: ' || Utl_Http.get_detailed_sqlerrm
);
url_resp :='Request_Failed: ' || Utl_Http.get_detailed_sqlerrm;
/* raised by URL http://xxx.oracle.com/ */
WHEN Utl_Http.http_server_error
THEN
DBMS_OUTPUT.put_line (
'Http_Server_Error: ' || Utl_Http.get_detailed_sqlerrm
);
url_resp := 'Http_Server_Error: ' || Utl_Http.get_detailed_sqlerrm;
/* raised by URL http://otn.oracle.com/xxx */
WHEN Utl_Http.http_client_error
THEN
DBMS_OUTPUT.put_line (
'Http_Client_Error: ' || Utl_Http.get_detailed_sqlerrm
);
url_resp := 'Http_Client_Error: ' || Utl_Http.get_detailed_sqlerrm;
/* code for all the other defined exceptions you can recover from */
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (SQLERRM);
url_resp := SQLERRM;
END;
Then to test it
begin
macp_url_get(url_resp => :url_resp,
'http://maps.googleapis.com/maps/api/geocode/json?address=55105&sensor=false');
end;
(I know that the googleapi will allow xml response, but there are other web APIs that I use regularly that default to JSON)

I have started using this library, and it seems promising:
https://github.com/pljson/pljson
Easy to install, and the examples are good.
To use the library in your example, add these variables to your procedure..
mapData json;
results json_list;
status json_value;
firstResult json;
geometry json;
....
Then you can manipulate the response as a json object.
-- convert the result from the get to a json object, and show some results.
mapData := json(v_ans);
-- Show the status of the request
status := mapData.get('status');
dbms_output.put_line('Status = ' || status.get_string());
IF (status.get_string() = 'OK') THEN
results := json_list(mapData.get('results'));
-- Grab the first item in the list
resultObject := json(results.head);
-- Show the human readable address
dbms_output.put_line('Address = ' || resultObject.get('formatted_address').to_char() );
-- Show the json location data
dbms_output.put_line('Location = ' || resultObject.get('geometry').to_char() );
END IF;
Running this code will output this to the dbms output:
Status = OK
Address = "St Paul, MN 55105, USA"
Location = {
"bounds" : {
"northeast" : {
"lat" : 44.9483849,
"lng" : -93.1261959
},
"southwest" : {
"lat" : 44.9223829,
"lng" : -93.200307
}
},
"location" : {
"lat" : 44.9330076,
"lng" : -93.16290629999999
},
"location_type" : "APPROXIMATE",
"viewport" : {
"northeast" : {
"lat" : 44.9483849,
"lng" : -93.1261959
},
"southwest" : {
"lat" : 44.9223829,
"lng" : -93.200307
}
}
}

It should be noted that as of Oracle 12c there is some native support of JSON. However i don't think in the current form it's as useful as the like of PLJSON included in another answer.
To use the feature you create a table with a BLOB, CLOB or Varchar2 field and add a constraint against it "column IS JSON". This enforces JSON syntax checking on that column.
As long as the "IS JSON" constraint is in place you can access the JSON values within using dot notation from SQL. To me, it doesn't seem to provide as powerful manipulation as PLJSON. You can also create an XMLType and then convert to JSON.
Useful links:
Oracle docs
Good tutorial and examples
Tutorial including XML to JSON

I wrote this library : http://reseau.erasme.org/pl-sql-library-for-JSON?lang=en, and this works great to get some json response into a plsql table.
If you only want to extract Oracle data and transform it in Json, this library is a bit "Heavy to use"...
I can propose you another code doing it better and faster :
create or replace package jsonfly as
procedure open_object(k varchar2 default null);
procedure close_object;
procedure open_array (k varchar2 default null);
procedure close_array;
procedure separation;
procedure member(k varchar2, v varchar2);
procedure member(k varchar2, n number);
procedure send;
end;
/
create or replace package body jsonfly as
--------------------------------------------------------------------------------
-- package pour générer du JSON, envoyé à la volé
--------------------------------------------------------------------------------
type tCache is table of varchar2(2000) index by binary_integer;
g_openBrace constant varchar2(2) := '{ ';
g_closeBrace constant varchar2(2) := ' }';
g_openBracket constant varchar2(2) := '[ ';
g_closeBracket constant varchar2(2) := ' ]';
g_stringDelimiter constant varchar2(1) := '"';
g_Affectation constant varchar2(3) := ' : ';
g_separation constant varchar2(3) := ', ';
g_CR constant varchar2(1) := Chr(10); -- used to indent the JSON object correctly
g_spc constant varchar2(2) := ' '; -- used to indent the JSON object correctly
g_js_comment_open constant varchar2(20) := '/*-secure-\n'; -- used to prevent from javascript hijacking
g_js_comment_close constant varchar2(20) := '\n*/'; -- used to prevent from javascript hijacking
--isObjectOpened boolean := false;
--isArrayOpened boolean := false;
t tCache;
i number := 1;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure p(s varchar2) is
begin
t(i) := s;
i := i + 1;
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
function encap (s varchar2) return varchar2 is
begin
return g_stringdelimiter || s || g_stringdelimiter;
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
function encode_string(p_string varchar2) return varchar2 is
begin
return replace(replace(replace(replace(replace(replace(replace(replace(p_string,
'\', '\\'),
'"', '\"'),
'/', '\/'),
chr(8), '\b'),
chr(9), '\t'),
chr(10), '\n'),
chr(12), '\f'),
chr(13), '\r');
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure open_object(k varchar2 default null) is
begin
if ( k is null ) then
p(g_openbrace);
else
p( encap(k) || g_affectation || g_openbrace);
end if;
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure close_object is
begin
if (t(i-1) = g_separation) then
i := i - 1;
end if;
p(g_closebrace);
separation();
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure open_array (k varchar2 default null) is
begin
if ( k is null ) then
p(g_openbracket);
else
p( encap(k) || g_affectation || g_openbracket);
end if;
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure close_array is
begin
if (t(i-1) = g_separation) then
i := i - 1;
end if;
p(g_closebracket);
separation();
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure separation is
begin
p(g_separation);
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure key(k varchar2) is
begin
p( encap(k) || g_affectation);
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure value(v varchar2) is
begin
p(v);
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure member(k varchar2, v varchar2) is
begin
p( encap(k) || g_affectation || encap(encode_string(v)));
p(g_separation);
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure member(k varchar2, n number) is
begin
p( encap(k) || g_affectation || n );
p(g_separation);
end;
--------------------------------------------------------------------------------
--
--------------------------------------------------------------------------------
procedure send is
begin
if (t(i-1) = g_separation) then
t.delete(i-1);
end if;
i := t.first;
while (i is not null) loop
htp.p(t(i));
i := t.next(i);
end loop;
end;
end jsonfly;
/

Oracle 12c now have native JSON support:
Oracle Database supports JavaScript Object Notation (JSON) data natively with relational database features, including transactions, indexing, declarative querying, and views
JSON data and XML data can be used in Oracle Database in similar ways. Unlike relational data, both can be stored, indexed, and queried without any need for a schema that defines the data. Oracle Database supports JSON natively with relational database features, including transactions, indexing, declarative querying, and views.
JSON data has often been stored in NoSQL databases such as Oracle NoSQL Database and Oracle Berkeley DB. These allow for storage and retrieval of data that is not based on any schema, but they do not offer the rigorous consistency models of relational databases.
To compensate for this shortcoming, a relational database is sometimes used in parallel with a NoSQL database. Applications using JSON data stored in the NoSQL database must then ensure data integrity themselves.
Native support for JSON by Oracle Database obviates such workarounds. It provides all of the benefits of relational database features for use with JSON, including transactions, indexing, declarative querying, and views.
Oracle Database queries are declarative. You can join JSON data with relational data. And you can project JSON data relationally, making it available for relational processes and tools. You can also query, from within the database, JSON data that is stored outside the database in an external table.
You can access JSON data stored in the database the same way you access other database data, including using OCI, .NET, and JDBC.
Unlike XML data, which is stored using SQL data type XMLType, JSON data is stored in Oracle Database using SQL data types VARCHAR2, CLOB, and BLOB. Oracle recommends that you always use an is_json check constraint to ensure that column values are valid JSON instances

Oracle APEX 5.0 has support for JSON using APEX_JSON package. I haven't used it but it looks interesting and I have asked my team to explore it. Our use case is to be able to pass JSON data as input parameter to stored procedure from nodejs application.

Life is happy try this:
CLOB or 20000000 characters JSON
with data as
( select
xmlelement(e,regexp_replace('{"name":"'||colname||'"}', '[[:cntrl:]]', ''),',') col1
from tblname
)
select
rtrim(replace(replace(replace(xmlagg(col1).getclobval(),'&'||'quot;','"'),'<E>',''),'</E>',''),',')
as very_long_json
from data;

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.

Adding a filter expression to a JSONIterator Find function call

What is the correct syntax for a filter expression to query a JSON object with a specific attribute string value inside an array, using bracket notation?
I am limited to bracket notation because dot notation won't work in Delphi when there is a quote or apostrophe inside the filter expression.
Use [] to access object properties that do contain a quoting character
in their name. For example, use root['child.name'] or
root["child.name"] to access the child.name property of the root
object.
I've used an online JSON path evaluator against this JSON and come up with the expression result["elements"][?(#.name == 'Training Seminar - Nov 9')]. In the online evaluator, this path works fine and returns the exact object I'm looking for. However, when I run it in Delphi I get an exception that says
EJSONPathException: Invalid index for array: ?(#.name == 'Training
Seminar - Nov 9')
My question is, what is the correct syntax for a filter expression to query a JSON object with a specific attribute string value inside an array, using bracket notation?
MCVE for this as a console application, including the JSON.
program Project3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.Classes, System.JSON.Builders, System.JSON.Readers, System.JSON.Types;
const JsonStr = '{' +
' "result":{ ' +
' "elements":[ ' +
' { ' +
' "id":"ML_1HMloeUjEFgKaC9",' +
' "name":"Utilization Survey",' +
' },' +
' {' +
' "id":"ML_1zQjGtGXFPkEo6N",' +
' "name":"Training Seminar - Nov 9",' +
' }' +
' ]' +
' },' +
' "meta":{' +
' "httpStatus":"200 - OK",' +
' "requestId":"ef2afd6e-3fd9-4fdf-a8fe-c935c147a0af"' +
' }' +
'}';
procedure RunIt;
var Reader : TJsonTextReader;
Iterator : TJsonIterator;
StringReader : TStringReader;
Found : Boolean;
begin
StringReader := TStringReader.Create(JsonStr);
Reader := TJsonTextReader.Create(StringReader);
Iterator := TJsonIterator.Create(Reader);
try
Found := Iterator.Find('result["elements"][?(#.name == ''Training Seminar - Nov 9'')]');
//The value of Found is false or an exception is raised because of bad syntax in the filter expression
WriteLn(BoolToStr(Found));
ReadLn;
finally
Iterator.Free;
Reader.Free;
StringReader.Free;
end;
end;
begin
try
RunIt;
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
Readln;
end
end;
end.
You can't use expressions at all, because they are not implemented. Whether in dot notation or bracket notation. Excerpt from official documentation of System.JSON.TJSONPathParser.
These operators do not support special expressions, they only
support actual values (object properties or array indexes).
However in this case, it can be achieved in a slightly more complicated way.
procedure RunIt;
var
lJSON, lValue, lName: TJSONValue;
lFound : Boolean;
begin
lFound := False;
lJSON := TJSONObject.ParseJSONValue(JsonStr);
if Assigned(lJSON) then
try
if lJSON.TryGetValue('result.elements', lValue) and (lValue is TJSONArray) then
begin
for lValue in TJSONArray(lValue) do
begin
lFound := lValue.TryGetValue('name', lName) and (lName.Value = 'Training Seminar - Nov 9');
if lFound then
Break;
end;
end;
finally
lJSON.Free;
end;
WriteLn(BoolToStr(lFound));
ReadLn;
end;

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

Oracle 12c does not recognize JSON type

I am working on parsing JSON CLOB in oracle. I am trying to retrieve and parse individual JSON elements.
Main issue I isolated is that compiler is unable recognize the JSON type here. However, I am able to insert and access individual JSON elements in the po_document field(declared as CLOB). This is the JSON I am trying to access
'{"PONumber" : 1600,
"Reference" : "ABULL-20140421",
"Requestor" : "Alexis Bull",
"User" : "ABULL",
"CostCenter" : "A50",
"ShippingInstructions" : "no such",
"Special Instructions" : null,
"AllowPartialShipment" : true,
"LineItems" : "no line"}'
I just took a standard Pl/SQL block to parse the JSON object:
DECLARE
vCONTENT CLOB;
v_parent_json json;
v_json_message_list json_list;
v_json_message_list_value json_value;
v_parent_json_value json_value;
BEGIN
SELECT po_document INTO vCONTENT FROM j_purchaseorder;
v_parent_json := json(vCONTENT);
v_parent_json := json(v_parent_json.get(1));
v_json_message_list := json_list(v_parent_json.get('LineItems'));
DBMS_OUTPUT.PUT_LINE(v_json_message_list.count);
for message_loop_counter in 1 ..v_json_message_list.count loop
v_parent_json_value := json(v_json_message_list.get(message_loop_counter)).get(1);
DBMS_OUTPUT.PUT_LINE(v_parent_json_value.mapname);
END LOOP;
END;
The compiler log generates the error message: Error(3,8): PLS-00201: identifier 'JSON' must be declared
Output from v$version:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
I was trying different things initially. I was using PL/JSON functions in my questions but if I want to use Oracle functions, this could be a small demo to read JSON and print values:
declare
l_has_data_level_co BOOLEAN := FALSE; -- TRUE is for R12C
jdemo CLOB;
l_name varchar2(2000):='';
l_location varchar2(2000):='';
begin
jdemo := '{"PONumber" : 1600,
"Reference" : "ABULL-20140421",
"Requestor" : "Alexis Bull",
"User" : "ABULL",
"CostCenter" : "A50",
"ShippingInstructions" : "no such",
"Special Instructions" : null,
"AllowPartialShipment" : true,
"LineItems" : "no line"}';
SELECT
json_value(jdemo, '$.PONumber'),
json_value(jdemo, '$.Reference')
into
l_name,
l_location
FROM dual;
--DBMS_OUTPUT.PUT_LINE (SYSDATE||' '||jdemo);
DBMS_OUTPUT.PUT_LINE ('Name :'||l_name||' Location :'||l_location);
end;

Delphi 2010 : UniDAC vs Indy-MultiThread safety handleing method

I am doing develop Indy based application.
Server has several Indy TCP Server components.
So It works under multi-threads and handles mysql db.
I have faced one problem.
That is about the exceptions of MySQL DB in threads.
When serveral threads attack to same db table, then It says me like follows
UniQuery_Mgr: Duplicate field name 'id'
UniQuery_Mgr: Field 'grp_id' not found //of course grp_id field is really existed.
Assertion failure (C:\Program Files (x86)\unidac539src\Source\CRVio.pas, line 255)
Commands out of sync; You can't run this command now
ReceiveHeader: Net packets out of order: received[0], expected[1]
UniQuery_Mgr: Cannot perform this operation on a closed dataset
How to do I ? UniQuery_Mgr is TUniQuery component.
and my query handling code is normally like this
Code 1
sql := 'SELECT * FROM data_writed;';//for example
UniQuery_Mgr.SQL.Clear;
UniQuery_Mgr.SQL.Add(sql);
UniQuery_Mgr.ExecSQL;
Code 2
try
sql := 'SELECT * FROM gamegrp_mgr;';
UniQuery_Mgr.SQL.Clear;
UniQuery_Mgr.SQL.Add(sql);
UniQuery_Mgr.ExecSQL;
if UniQuery_Mgr.RecordCount > 0 then
begin
MAX_GAME_GROUP_COUNT := UniQuery_Mgr.RecordCount + 1;
UniQuery_Mgr.First;
i := 1;
while not UniQuery_Mgr.Eof do
begin
Game_Group_ID[i] := UniQuery_Mgr.FieldByName('grp_id').AsInteger;
Game_Game_ID[i] := UniQuery_Mgr.FieldByName('game_id').AsInteger;
UniQuery_Mgr.Next;
Inc(i);
end;
end;
except
on E : Exception do
begin
EGAMEMSG := Format('GAME group read error: <%s> # %s',[ E.ToString, DateTimeToStr(now)]);
Exit;
end;
end;
Code 3
try
sql := 'UPDATE data_writed SET write_gamegrp = ' + QuotedStr('0') + ';';
UniQuery_Mgr.SQL.Clear;
UniQuery_Mgr.SQL.Add(sql);
UniQuery_Mgr.ExecSQL;
except
on E : Exception do
begin
EGAMEMSG := Format('data updating error: <%s> # %s',[ E.ToString, DateTimeToStr(now)]);
Exit;
end;
end;
My handling DB components is bad ? Other thread-safe method is existed???