Multiple APEX_PUBLIC_USER sessions - oracle

I have an ORACLE database and ORACLE APEX 5.1 is installed there.
It has worked well in previous days.
In recent days, the server has crashed due to many sessions generated by the user APEX_PUBLIC_USER.
Seeing the current statement, this:
/* Formatted on 30/12/2022 05:19:20 p. m. (QP5 v5.336) */
DECLARE
rc__ NUMBER;
simple_list__ OWA_UTIL.vc_arr;
complex_list__ OWA_UTIL.vc_arr;
BEGIN
OWA.init_cgi_env ( :n__, :nm__, :v__);
HTP.HTBUF_LEN := 63;
NULL;
NULL;
simple_list__ (1) := 'sys.%';
simple_list__ (2) := 'dbms\_%';
simple_list__ (3) := 'utl\_%';
simple_list__ (4) := 'owa\_%';
simple_list__ (5) := 'owa.%';
simple_list__ (6) := 'htp.%';
simple_list__ (7) := 'htf.%';
simple_list__ (8) := 'wpg_docload.%';
simple_list__ (9) := 'ctxsys.%';
simple_list__ (10) := 'mdsys.%';
IF ( (wwv_flow_epg_include_modules.authorize ('wwv_flow.ajax') = FALSE)
OR (owa_match.match_pattern (p_string => 'wwv_flow.ajax'/* */
,
p_simple_pattern => simple_list__,
p_complex_pattern => complex_list__,
p_use_special_chars => FALSE)))
THEN
rc__ := 2;
ELSE
NULL;
NULL;
wwv_flow.ajax (p_flow_id => :p_flow_id,
p_flow_step_id => :p_flow_step_id,
p_instance => :p_instance,
p_debug => :p_debug,
p_request => :p_request,
p_json => :p_json);
IF (WPG_DOCLOAD.is_file_download)
THEN
rc__ := 1;
WPG_DOCLOAD.get_download_file ( :doc_info);
NULL;
NULL;
NULL;
COMMIT;
ELSE
rc__ := 0;
NULL;
NULL;
NULL;
COMMIT;
OWA.get_page ( :data__, :ndata__);
END IF;
END IF;
:rc__ := rc__;
END;
I delete the sessions and they are recreated.
What solution could it be?
Migrate from DB?
New version of APEX?

Related

Sending SSL HTTP request from Windows Server 2012 R2

i'm having the problem only in the version of windows, server 2012 R2. when i send an SSL GET request, i dont receive anything, not even an error message. i dont know if its compatibility of DLLs problem or what, i tried every single one of these versions : https://indy.fulgan.com/SSL/ . maybe its the problem in my code ?
procedure TForm5.FormCreate(Sender: TObject);
var
LJSONArray : TJSONArray;
Temp : TStrings;
IdSSL: TIdSSLIOHandlerSocketOpenSSL;
lHTTP: TIdHTTP;
K : Boolean;
pw : PwideChar;
begin
TThread.CreateAnonymousThread(procedure () var I :Integer;
begin
try
Temp := TStringList.Create;
lHTTP := TIdHTTP.Create(nil);
IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(lHTTP);
lHTTp.ReadTimeout := 60000;
IdSSL.SSLOptions.Method := sslvTLSv1_1;
IdSSL.SSLOptions.Mode := sslmClient;
lHTTP.IOHandler := IdSSL;
lHTTP.HandleRedirects := True;
LJSONArray := System.JSON.TJSONArray.Create;
lhttp.Request.Accept := 'application/json, text/plain; q=0.9, text/html;q=0.8';
lHTTP.Request.Host := 'baas.kinvey.com';
lHTTP.Request.CustomHeaders.Values['Connection'] := 'Keep-Alive';
lHTTP.Request.CustomHeaders.Values['Authorization'] := 'Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
LHTTP.Request.ContentType := 'application/x-www-form-urlencoded; charset=UTF-8';
lHTTP.Request.UserAgent := 'Embarcadero RESTClient/1.0';
Reply := lhttp.Get('https://baas.kinvey.com/appdata/kid_xxxxxTEst/');
LJSONArray := TJSONObject.ParseJSONValue(Reply, True) as TJSONArray;
for I := 0 to LJSONArray.Count -1 do
begin
Temp.Add(LJSonArray.Items[I].GetValue<string>('KEY'));
end;
LJSONArray.Free;
K := False;
PW := pChar(Temp.text);
K := ExistWordInString(PW,'YES',[soWholeWord,soDown]);
if K = True then
begin
TThread.Synchronize (TThread.CurrentThread,
procedure ()
begin
Left:=(Screen.Width-Width) div 2;
end);
end;
if K = False then
begin
TThread.Synchronize (TThread.CurrentThread,
procedure ()
begin
Form5.Caption := '';
end);
end;
except on E :exception do
begin
TThread.Synchronize (TThread.CurrentThread,
procedure ()
begin
memo1.lines.add(E.Message);
end);
end;
end;
end).Start;
end;
Note : the code works in any other machine except Win server 2012 R2

Why My server application freeze after several clients connected?

i am using indy TidTcpserver inside my server application its working good but some times after 10 clients connected my server application got a deadlock and stop from response here is my server execute and broadcast protocol codes
Tcp server execute
procedure TfMain.TCPServerExecute(AContext: TIdContext);
var
Connection: TConnection;
Command: String;
Params: array[1..10] of String;
ParamsCount, P: Integer;
PackedParams: TPackedParams;
IdBytes: TIdBytes;
MS: TMemoryStream;
ReceiveParams, ReceiveStream: Boolean;
Size: Int64;
begin
Connection := Pointer(AContext.Data);
MS := TMemoryStream.Create;
ReceiveParams := False;
ReceiveStream := False;
Command := AContext.Connection.Socket.ReadLn; //read command
if Command[1] = '1' then //command with params
begin
Command := Copy(Command, 2, Length(Command));
ReceiveParams := True;
end
else if Command[1] = '2' then //command + memorystream
begin
Command := Copy(Command, 2, Length(Command));
ReceiveStream := True;
MS.Position := 0;
end
else if Command[1] = '3' then //command with params + memorystream
begin
Command := Copy(Command, 2, Length(Command));
ReceiveParams := True;
ReceiveStream := True;
end;
if ReceiveParams then //params is incomming
begin
AContext.Connection.Socket.ReadBytes(IdBytes, SizeOf(PackedParams), False);
BytesToRaw(IdBytes, PackedParams, SizeOf(PackedParams));
ParamsCount := 0;
repeat
Inc(ParamsCount);
p := Pos(Sep, String(PackedParams.Params));
Params[ParamsCount] := Copy(String(PackedParams.Params), 1, P - 1);
Delete(PackedParams.Params, 1, P + 4);
until PackedParams.Params = '';
end;
if ReceiveStream then //stream is incomming
begin
Size := AContext.Connection.Socket.ReadInt64;
AContext.Connection.Socket.ReadStream(MS, Size, False);
MS.Position := 0;
end;
if Command = 'LOGIN' then
begin
usrnm := Params[1];
passwd := params[2];
if not userexists(usrnm, passwd) then
AContext.Connection.Socket.WriteLn('INVALIDPASSWORD')
else
begin
userslq.Close;
userslq.SQL.Clear;
userslq.SQL.Add('SELECT * FROM `users` WHERE `username` = "'+ trim(usrnm) +'" AND `password` = "' + trim(passwd) + '"');
userslq.Open;
if NOT userslq.IsEmpty then
begin
SendCommandWithParams(Connection, 'SENDYOURINFO', IntToStr(Connection.UniqueID) + Sep);
userslq.Close;
end;
userslq.Close;
userslq.SQL.Clear;
userslq.SQL.Add('UPDATE `users` SET `lastlogin` = :Date, `timeslogin`=(`timeslogin`+1) WHERE `users`.`username` = :uname;');
userslq.ParamByName('uname').AsString := trim(usrnm);
userslq.ParamByName('Date').AsDate := Now;
userslq.ExecSQL;
userslq.Close;
end;
end;
if Command = 'TAKEMYINFO' then //login ok, add to listview
begin
Connection.Name := Params[1];
Connections.Add(Connection);
AddConnectionToListView(Connection);
end;
if Command = 'TEXTMESSAGE' then
begin
BroadCastTextMessage(Params[1], Connection.UniqueID, Connection.Name, Connection.IP);
end;
if Command = 'DISCONNECTED' then
begin
DeleteConnectionFromList(Connection.UniqueID);
DeleteConnectionFromListView(Connection.UniqueID);
end;
MS.Free;
end;
broadcast Protocol and used procedures
procedure TfMain.AddConnectionToListView(Connection: TConnection);
begin
with lwConnections.Items.Add do
begin
Caption := Connection.Name;
SubItems.Add(Connection.IP);
SubItems.Add(FormatDateTime('hh:mm:ss', Connection.Connected));
SubItems.Add(IntToStr(Connection.UniqueID));
end;
end;
procedure TfMain.DeleteConnectionFromListView(UniqueID: DWord);
var
I: Integer;
begin
for I := 0 to lwConnections.Items.Count - 1 do
begin
if lwConnections.Items.Item[I].SubItems.Strings[2] = IntToStr(UniqueID) then
begin
lwConnections.Items.Delete(I);
Break;
end;
end;
end;
procedure TfMain.DeleteConnectionFromList(UniqueID: DWord);
var
I, Pos: Integer;
begin
Pos := -1;
for I := 0 to Connections.Count - 1 do
begin
if TConnection(Connections.Items[I]).UniqueID = UniqueID then
begin
Pos := I;
Break;
end;
end;
if Pos <> -1 then
Connections.Delete(Pos);
end;
procedure TfMain.BroadCastTextMessage(const TextMessage: String; const FromUniqueID: DWord;
const FromName: string; const dip: string);
var
I: Integer;
Connection: TConnection;
begin
for I := 0 to Connections.Count - 1 do
begin
Connection := Connections.Items[I];
if Connection.UniqueID <> FromUniqueID then
SendCommandWithParams(Connection, 'TEXTMESSAGE', FromName + Sep + TextMessage + Sep + dip + Sep);
end;
end;
procedure TfMain.SendCommandWithParams(Connection: TConnection; Command, Params:String);
var
PackedParams: TPackedParams;
begin
if not TIdContext(Connection.Thread).Connection.Socket.Connected then
Exit;
TCPServer.Contexts.LockList;
try
PackedParams.Params := ShortString(Params);
with TIdContext(Connection.Thread).Connection.Socket do
begin
WriteLn('1' + Command);
Write(RawToBytes(PackedParams, SizeOf(PackedParams)));
end;
finally
TCPServer.Contexts.UnlockList;
end;
end;
on connect server event
procedure Tfmain.TcpServerConnect(AContext: TIdContext);
var
Connection : TConnection;
begin
Connection := TConnection.Create;
Connection.IP := AContext.Connection.Socket.Binding.PeerIP;
Connection.Connected := Now;
Connection.UniqueID := GetTickCount;
if Connection.UniqueID = LastUniqueID then
Connection.UniqueID := GetTickCount + 1000;
LastUniqueID := Connection.UniqueID;
Connection.Thread := AContext;
AContext.Data := Connection;
end;
Updated
by following remy answer and his great details i started to do synchronize but in remy answer i am confused about TCriticalSection also i will have to rewrite the client code to be able to do same as his code doing , so i had to go with thread synchronize first here is example of what i did by following remy code i did some manage and removed database temporarily to avoid confusing here is the code of trying synchronization UI inside server execute
if Command = 'LOGIN' then
begin
if Password <> Params[1] then
AContext.Connection.Socket.WriteLn('INVALIDPASSWORD')
else
SendCommandWithParams(Connection, 'SENDYOURINFO', IntToStr(Connection.UniqueID) + Sep);
end;
if Command = 'TAKEMYINFO' then //login ok, add to listview
begin
Connection.Name := Params[1];
Connections.Add(Connection);
AddConnectionToListView(Connection);// this is not safe i know and thats what makes me confused so in this procedure call i do same as remy doing
end;
procedure TfMain.AddConnectionToListView(Connection: TConnection);
begin
TThread.Queue(nil,
procedure
var
Item: TListItem;
begin
Item := lwConnections.Items.Add;
try
Item.Caption := Connection.Name;
Item.SubItems.Add(Connection.IP);
Item.SubItems.Add(FormatDateTime('hh:mm:ss', Connection.Connected));
Item.SubItems.Add(IntToStr(Connection.UniqueID));
except
Item.Delete;
raise;
end;
end
);
end;
is this correct to synchronize ? whats makes me confused is this thread synchronize by itself ? i mean there is no thread class to execute and synchronize is this correct way ?
Updates about synchronize
Remy answer helps me i thanks him too much , but iam trying to understand thus synchronize part i found some ways on google as example include
idsync in my uses
and call it like this as example
uses
idsync;
// and in server execute i call TiDNotify To synchronize what ever i want ?
procedure TfMain.DeleteConnectionFromListView;
var
I: Integer;
begin
for I := 0 to lwConnections.Items.Count - 1 do
begin
if lwConnections.Items.Item[I].SubItems.Strings[2] = IntToStr(linetToID) then
begin
DeleteConnectionFromList(linetToID);
lwConnections.Items.Delete(I);
Break;
end;
end;
end;
procedure TfMain.TCPServerExecute(AContext: TIdContext);
var
Connection: TConnection;
Command: String;
Params: array[1..10] of String;
ParamsCount, P: Integer;
PackedParams: TPackedParams;
IdBytes: TIdBytes;
MS: TMemoryStream;
ReceiveParams, ReceiveStream: Boolean;
Size: Int64;
begin
Connection := Pointer(AContext.Data);
MS := TMemoryStream.Create;
ReceiveParams := False;
ReceiveStream := False;
Command := AContext.Connection.Socket.ReadLn; //read command
if Command[1] = '1' then //command with params
begin
Command := Copy(Command, 2, Length(Command));
ReceiveParams := True;
end
else if Command[1] = '2' then //command + memorystream
begin
Command := Copy(Command, 2, Length(Command));
ReceiveStream := True;
MS.Position := 0;
end
else if Command[1] = '3' then //command with params + memorystream
begin
Command := Copy(Command, 2, Length(Command));
ReceiveParams := True;
ReceiveStream := True;
end;
if ReceiveParams then //params is incomming
begin
AContext.Connection.Socket.ReadBytes(IdBytes, SizeOf(PackedParams), False);
BytesToRaw(IdBytes, PackedParams, SizeOf(PackedParams));
ParamsCount := 0;
repeat
Inc(ParamsCount);
p := Pos(Sep, String(PackedParams.Params));
Params[ParamsCount] := Copy(String(PackedParams.Params), 1, P - 1);
Delete(PackedParams.Params, 1, P + 4);
until PackedParams.Params = '';
end;
if ReceiveStream then //stream is incomming
begin
Size := AContext.Connection.Socket.ReadInt64;
AContext.Connection.Socket.ReadStream(MS, Size, False);
MS.Position := 0;
end;
if Command = 'LOGIN' then
begin
if Password <> Params[1] then
AContext.Connection.Socket.WriteLn('INVALIDPASSWORD')
else
SendCommandWithParams(Connection, 'SENDYOURINFO', IntToStr(Connection.UniqueID) + Sep);
end;
if Command = 'TAKEMYINFO' then //login ok, add to listview
begin
Connection.Name := Params[1];
Connections.Add(Connection);
TIdNotify.NotifyMethod(Connection.AddToListView);
end;
if Command = 'TEXTMESSAGE' then
begin
BroadCastTextMessage(Params[1], Connection.UniqueID);
end;
if Command = 'GETLIST' then
begin
SendClientsListTo(Connection.UniqueID);
end;
if Command = 'DISCONNECTED' then
begin
linetToID := Connection.UniqueID;// fmain private string variable
TIdNotify.NotifyMethod(DeleteConnectionFromListView);
end;
MS.Free;
end;
TIdTCPServer is a multi-threaded component. Its OnExecute event is triggered in the context of a worker thread. But your TAKEMYINFO and DISCONNECTED command handlers are directly accessing UI controls without synchronizing with the main UI thread. That can easily cause deadlocks (amongst other problems, including crashes, killing the UI, etc). You MUST sync!
Also, is userexists() thread-safe? Is userslq? Your use of the Connections list is definitely not thread-safe.
Why is SendCommandWithParams() locking the server's Contexts list, especially when called by OnExecute? You don't need to do that. You should be locking it in BroadCastTextMessage() instead.
Try something more like this:
type
TConnnection = class(TIdServerContext)
private
WriteLock: TCriticalSection;
public
Name: String;
IP: String;
Connected: TDateTime;
UniqueID: Dword;
constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
destructor Destroy; override;
procedure AddToListView;
procedure DeleteFromListView;
procedure BroadcastTextMessage(const TextMessage: String);
procedure SendCommandWithParams(const Command, Params: String);
procedure SendLn(const S: String);
function UserExists(const User, Passwd: string): Boolean;
procedure UpdateLastLogin(const User: String);
end;
constructor TConnection.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil);
begin
inherited;
WriteLock := TCriticalSection.Create;
end;
destructor TConnection.Destroy;
begin
WriteLock.Free;
inherited;
end;
procedure TConnection.AddToListView;
var
LName: string;
LIP: string;
LConnected: TDateTime;
LUniqueID: Dword;
begin
// in case the client disconnects and destroys this object before
// TThread.Queue() can update the ListView, capture the values so
// this object's fields are not accessed directly...
//
LName := Self.Name;
LIP := Self.IP;
LConnected := Self.Connected;
LUniqueID := Self.UniqueID;
TThread.Queue(nil,
procedure
var
Item: TListItem;
begin
if (fMain = nil) or (fMai.lwConnections = nil) then Exit;
Item := fMain.lwConnections.Items.Add;
try
Item.Data := Self;
Item.Caption := LName;
Item.SubItems.Add(LIP);
Item.SubItems.Add(FormatDateTime('hh:mm:ss', LConnected));
Item.SubItems.Add(IntToStr(LUniqueID));
except
Item.Delete;
raise;
end;
end
);
end;
procedure TConnection.DeleteFromListView;
begin
TThread.Queue(nil,
procedure
var
Item: TListItem;
begin
if (fMain = nil) or (fMai.lwConnections = nil) then Exit;
Item := fMain.lwConnections.FindData(0, Self, True, False);
if Item <> nil then Item.Delete;
end
);
end;
procedue TConnection.BroadCastTextMessage(const TextMessage: String);
var
List: TList; // or TIdContextList if using a modern Indy version
I: Integer;
Connection: TConnection;
begin
List := Server.Contexts.LockList;
try
for I := 0 to List.Count - 1 do
begin
Connection := TConnection(List.Items[I]);
if Connection <> Self then
begin
try
Connection.SendCommandWithParams('TEXTMESSAGE', FromName + Sep + TextMessage + Sep + dip + Sep);
except
end;
end;
finally
Server.Contexts.UnlockList;
end;
end;
procedure TConnection.SendCommandWithParams(const Command, Params: String);
var
PackedParams: TPackedParams;
begin
PackedParams.Params := ShortString(Params);
WriteLock.Enter;
try
with Connection.Socket do
begin
WriteLn('1' + Command);
Write(RawToBytes(PackedParams, SizeOf(PackedParams)));
end;
finally
WriteLock.Leave;
end;
end;
procedure TConnection.SendLn(const S: String);
begin
WriteLock.Enter;
try
Connection.Socket.WriteLn(S);
finally
WriteLock.Leave;
end;
end;
function TConnection.UserExists(const User, Passwd: string): Boolean;
var
Exists: Boolean;
begin
// if you give each client its own DB connection, or use
// a thread-safe DB pool, you don't have to sync this ...
//
TThread.Synchronize(nil,
procedure
if (fMain = nil) or (fMai.userslq = nil) then Exit;
with fMain.userslq do
begin
Close;
SQL.Text := 'SELECT * FROM `users` WHERE `username` = :uname AND `password` = :passwd;';
ParamByName('uname').AsString := Trim(User);
ParamByName('passwd').AsString := Trim(Passwd);
Open;
try
Exists := not IsEmpty;
finally
Close;
end;
end;
end
);
Result := Exists;
end;
procedure TConnection.UpdateLastLogin(const User: String);
begin
// if you give each client its own DB connection, or use
// a thread-safe DB pool, you don't have to sync this ...
//
TThread.Synchronize(nil,
procedure
if (fMain = nil) or (fMai.userslq = nil) then Exit;
with fMain.userslq do
begin
Close;
SQL.Text := 'UPDATE `users` SET `lastlogin` = :Date, `timeslogin`=(`timeslogin`+1) WHERE `users`.`username` = :uname;';
ParamByName('uname').AsString := Trim(User);
ParamByName('Date').AsDate := Now;
ExecSQL;
Close;
end;
end
);
end;
procedure TfMain.FormCreate(Sender: TObject);
begin
// set this before activating the server
TCPServer.ContextClass := TConnection;
end;
procedure TfMain.TCPServerConnect(AContext: TIdContext);
var
Connection: TConnection;
begin
Connection := AContext as TConnection;
Connection.Name := '';
Connection.IP := AContext.Binding.PeerIP;
Connection.Connected := Now;
Connection.UniqueID := ...;
end;
procedure TfMain.TCPServerDisconnect(AContext: TIdContext);
var
Connection: TConnection;
begin
Connection := AContext as TConnection;
Connection.DeleteFromListView;
end;
procedure TfMain.TCPServerExecute(AContext: TIdContext);
var
Connection: TConnection;
Command: String;
Params: array[1..10] of String;
ParamsCount, P: Integer;
PackedParams: TPackedParams;
IdBytes: TIdBytes;
MS: TMemoryStream;
ReceiveParams, ReceiveStream: Boolean;
S: String;
begin
Connection := AContext as TConnection;
Command := AContext.Connection.Socket.ReadLn; //read command
if Command = '' then Exit;
ReceiveParams := False;
ReceiveStream := False;
if Command[1] = '1' then //command with params
begin
Command := Copy(Command, 2, MaxInt);
ReceiveParams := True;
end
else if Command[1] = '2' then //command + memorystream
begin
Command := Copy(Command, 2, MaxInt);
ReceiveStream := True;
end
else if Command[1] = '3' then //command with params + memorystream
begin
Command := Copy(Command, 2, MaxInt);
ReceiveParams := True;
ReceiveStream := True;
end;
if ReceiveParams then //params is incomming
begin
AContext.Connection.Socket.ReadBytes(IdBytes, SizeOf(PackedParams), False);
BytesToRaw(IdBytes, PackedParams, SizeOf(PackedParams));
S := String(PackedParams.Params);
ParamsCount := 0;
while (S <> '') and (ParamsCount < 10) do
begin
Inc(ParamsCount);
p := Pos(Sep, S);
if p = 0 then
Params[ParamsCount] := S
else
begin
Params[ParamsCount] := Copy(S, 1, P - 1);
Delete(S, 1, P + 4);
end;
end;
end;
MS := nil;
try
if ReceiveStream then //stream is incomming
begin
MS := TMemoryStream.Create;
AContext.Connection.Socket.LargeStream := True;
AContext.Connection.Socket.ReadStream(MS, -1, False);
MS.Position := 0;
end;
if Command = 'LOGIN' then
begin
if ParamsCount <> 2 then
begin
Connection.SendLn('INVALIDPARAMS');
Exit;
end;
if not Connection.UserExists(Params[1], Params[2]) then
begin
Connection.SendLn('INVALIDPASSWORD');
Exit;
end;
Connection.UpdateLastLogin(Params[1]);
Connection.SendCommandWithParams('SENDYOURINFO', IntToStr(Connection.UniqueID) + Sep);
end
else if Command = 'TAKEMYINFO' then //login ok, add to listview
begin
if ParamsCount <> 1 then
begin
Connection.SendLn('INVALIDPARAMS');
Exit;
end;
Connection.Name := Params[1];
Connection.AddToListView;
end
else if Command = 'TEXTMESSAGE' then
begin
if ParamsCount <> 1 then
begin
Connection.SendLn('INVALIDPARAMS');
Exit;
end;
Connection.BroadCastTextMessage(Params[1]);
end
else if Command = 'DISCONNECTED' then
begin
AContext.Connection.Disconnect;
Exit;
end;
finally
MS.Free;
end;
end;

Exception block in PLSQL exiting the block

I am using the following code block to update my front end segment.
But when i am compiling this
DECLARE
p_person_id NUMBER := NULL;
p_business_group_id NUMBER;
p_id_flex_num NUMBER;
------------------
p_analysis_criteria_id NUMBER := NULL;
p_person_analysis_id NUMBER := NULL;
p_per_object_version_number NUMBER := NULL;
v_err VARCHAR2 (1000) := NULL;
p_medical_id VARCHAR2 (100) := NULL;
BEGIN
FOR i IN (SELECT *
FROM xx_hr_upload_master_data_new
WHERE person_id IS NOT NULL
AND business_group_id IS NOT NULL
AND medical_id IS NOT NULL)
LOOP
p_id_flex_num := 50530;
BEGIN
SELECT sv.segment1, NVL (sit.object_version_number, 1),
sit.analysis_criteria_id, MAX (sit.person_analysis_id)
INTO p_medical_id, p_per_object_version_number,
p_analysis_criteria_id, p_person_analysis_id
FROM fnd_id_flex_structures_tl sttl,
fnd_id_flex_structures st,
per_person_analyses sit,
per_analysis_criteria sv
WHERE sttl.id_flex_structure_name = 'ISPs Medical Data'
AND sttl.LANGUAGE = USERENV ('LANG')
AND st.id_flex_code = sttl.id_flex_code
AND st.id_flex_num = sttl.id_flex_num
AND st.id_flex_num = sit.id_flex_num
AND st.id_flex_num = sv.id_flex_num
AND sit.analysis_criteria_id = sv.analysis_criteria_id
AND sit.person_id = i.person_id
--and sv.SEGMENT1 = '4602001140'
GROUP BY sv.segment1,
NVL (sit.object_version_number, 1),
sit.analysis_criteria_id;
EXCEPTION
WHEN OTHERS
THEN
p_medical_id := NULL;
p_per_object_version_number := 1;
p_person_analysis_id := NULL;
p_analysis_criteria_id := NULL;
p_person_analysis_id := NULL;
p_per_object_version_number := NULL;
p_person_id := NULL;
END;
BEGIN
------------------------------------------------
IF (p_medical_id IS NULL AND p_analysis_criteria_id IS NULL)
THEN
-- create a new record in the SIT (Special Information Type)table .
p_person_id := i.person_id;
p_medical_id := TO_CHAR (i.medical_id);
-----------------------------
hr_sit_api.create_sit
(p_validate => FALSE,
p_person_id => p_person_id,
p_business_group_id => i.business_group_id,
p_id_flex_num => p_id_flex_num,
p_effective_date => TRUNC (SYSDATE),
p_date_from => TRUNC (SYSDATE),
p_segment1 => p_medical_id,
p_analysis_criteria_id => p_analysis_criteria_id,
p_person_analysis_id => p_person_analysis_id,
p_pea_object_version_number => p_per_object_version_number
);
ELSE
-- employee has previous Billing_Acc_Num then update that number in the SIT table .
hr_sit_api.update_sit
(p_validate => FALSE,
p_person_analysis_id => p_person_analysis_id,
p_pea_object_version_number => p_per_object_version_number,
p_date_from => TRUNC (SYSDATE),
p_segment1 => p_medical_id,
p_analysis_criteria_id => p_analysis_criteria_id
);
END IF;
UPDATE xx_hr_upload_master_data_new xx
SET xx.error_msg = 'Done',
xx.emp_data = 'Done'
WHERE xx.business_group_id = i.business_group_id
AND xx.employee_number = i.employee_number;
EXCEPTION
WHEN OTHERS
THEN
p_analysis_criteria_id := NULL;
p_person_analysis_id := NULL;
p_per_object_version_number := NULL;
p_person_id := NULL;
p_medical_id := NULL;
v_err := NULL;
v_err := SQLERRM;
UPDATE xx_hr_upload_master_data_new xx
SET xx.error_msg = v_err
WHERE xx.business_group_id = i.business_group_id
AND xx.employee_number = i.employee_number;
END;
END LOOP;
COMMIT;
END;
Now when the select query is not fetching anything, the exception block is entered where all the variables are initiated to null.
I want that after this the begin where the create api is called inside the condition IF (p_medical_id IS NULL AND p_analysis_criteria_id IS NULL)
should be entered. But this is not happening and the program exits after this exception block after entering the exception block.
A hint might be:
The first select will not raise any exception if it gets no result. If it gets no result then the for-loop just won't be entered, so the only thing that will happen is the commit.
(The select inside the for-loop will raise an exception if it gets 0 rows or more than 1 row. The reason is 'select ... into ...': When using 'into' the select must return exact 1 row.)

ClientDataSet TBCDField rounding

I'm using Delphi 5 + BDE + Oracle. I have the following function:
class function TClientDataSetFactory.GetClientDataSet(
const qryGen: TDataSet): TClientDataSet;
var
dspDados: TDataSetProvider;
begin
Result := nil;
try
try
Result := TClientDataSet.Create(nil);
dspDados := TDataSetProvider.Create(Result);
dspDados.DataSet := qryGen;
qryGen.Active := True;
qryGen.First;
Result.Data := dspDados.Data;
Result.First;
except
on E: Exception do
begin
raise;
end;
end;
finally
end;
end;
so, when a run this:
var
qryGen: TQuery;
cdsGen: TClientDataSet;
begin
qryGen := nil;
try
try
qryGen := CriaQuery();
qryGen.SQL.Text :=
'SELECT SUM(TOTAL) AS TOTAL FROM MYTABLE';
cdsGen := TClientDataSetFactory.GetClientDataSet(qryGen);
ShowMessageFmt('Total: %f', [cdsGen.FieldByName('TOTAL').AsFloat]);
except
on E: Exception do
begin
raise;
end;
end;
finally
if Assigned(qryGen) then FreeAndNil(qryGen);
end;
end;
i got "159,00" but, if i run this:
ShowMessageFmt('Total: %f', [qryGen.FieldByName('TOTAL').AsFloat]);
i got "159,25".
can someone help me?
I solved the problem with another solution.
type
TInternalQuery = class(TQuery)
protected
procedure InternalInitFieldDefs; override;
public
constructor Create(AOwner: TComponent; const qryGen: TQuery); reintroduce;
end;
constructor TInternalQuery.Create(AOwner: TComponent; const qryGen: TQuery);
var
intCont: Integer;
begin
inherited Create(AOwner);
Self.DatabaseName := qryGen.DatabaseName;
Self.UpdateObject := qryGen.UpdateObject;
Self.SQL.Text := qryGen.SQL.Text;
for intCont := 0 to Self.ParamCount - 1 do
begin
Self.Params[intCont].Value := qryGen.Params[intCont].Value;
end;
end;
procedure TInternalQuery.InternalInitFieldDefs;
var
intCont: Integer;
begin
inherited InternalInitFieldDefs;
for intCont := 0 to FieldDefs.Count - 1 do
begin
if (FieldDefs[intCont].Size = 0) and (FieldDefs[intCont].DataType = ftBCD) then
begin
FieldDefs[intCont].Precision := 64;
FieldDefs[intCont].Size := 32;
end;
end;
end;
the problem is ((FieldDefs[intCont].Size = 0) and (FieldDefs[intCont].DataType = ftBCD)). when ClientDataSet is created, the field is truncated, because when oracle has a function like "SUM(TOTAL)" the result field is created with size 0, so the clientdataset handle the field as Integer field.
Try with
ShowMessageFmt('Total: %n', [cdsGen.FieldByName('TOTAL').AsFloat])
or this
cdsGen := TClientDataSetFactory.GetClientDataSet(qryGen);
**(cdsGen.FieldByName('Total') as TFloatField).DisplayFormat := '0.00';**
ShowMessageFmt('Total: %f', [cdsGen.FieldByName('TOTAL').AsFloat])

Oracle Streams: ORA-0001 on dequeue?

In production every now and then we get an ORA-0001 error when dequeuing a message. We use:
Solaris 10
Oracle 10g
C++ application
PROC*C with dbms_aq package for queuing operations
Queues with XML payload
We handle a large volume of messages (1K/min).
Any clue why would a dequeue result in an ORA-0001 (unique constraint) error?
Update: adding code per request.
EXEC SQL EXECUTE
DECLARE
message_properties dbms_aq.message_properties_t;
dequeue_options dbms_aq.dequeue_options_t;
message_payload xmltype;
tmpclob clob;
dynamic_sql_string varchar2(512);
BEGIN
dequeue_options.wait := :iReadTimeout;
dequeue_options.dequeue_mode := dbms_aq.REMOVE;
dequeue_options.visibility := dbms_aq.ON_COMMIT;
IF :iBuffered = 1 then
dequeue_options.delivery_mode := dbms_aq.buffered;
dequeue_options.visibility := dbms_aq.immediate;
:iNavigationMode := 0;
END IF;
IF :iDequeueOnly = 1 and :iQueueType <> 1 THEN
dequeue_options.dequeue_mode := dbms_aq.REMOVE_NODATA;
dequeue_options.wait := dbms_aq.NO_WAIT;
dequeue_options.msgid := hextoraw(:pszDequeueMsgId);
ELSE
IF :iNavigationMode = 0 THEN
dequeue_options.navigation := dbms_aq.FIRST_MESSAGE;
ELSE
dequeue_options.navigation := dbms_aq.NEXT_MESSAGE;
END IF;
END IF;
dequeue_options.deq_condition := :pszDeqCondition;
dbms_aq.dequeue(queue_name => :pszQueueName,
message_properties => message_properties,
dequeue_options => dequeue_options,
payload => message_payload,
msgid => :msgid );
IF dequeue_options.dequeue_mode <> dbms_aq.REMOVE_NODATA THEN
EXECUTE IMMEDIATE dynamic_sql_string USING OUT tmpclob, IN message_payload;
:gpoXmlClob := tmpclob;
ELSE
:gpoXmlClob := message_payload.getclobval();
END IF;
END;

Resources