Oracle Trigger: raise_application_error - database

I want to use the raise_application_error-procedure to stop the login process.
I wrote a trigger, that checks the TERMINAL String, if it is right (I know that isn't realy secure, but at first, it is enough)
So the Trigger works fine and does what i want, but the raise_application_error causes an rollback and sends not the exception that I want. Whenn I log into the DB with my Application, the raise_application_error doesnt stop the app.
First question: Is this the right way, to stop logon the db with the wrong application?
Second question: If yes, what is wrong?
create or replace
TRIGGER after_logon_on_database
AFTER LOGON ON DATABASE
BEGIN
IF sys_context('USERENV', 'TERMINAL')='IAS' THEN
INSERT INTO event_log
(event_date, event_time, username, event_case, event_comment)
VALUES
(SYSDATE, to_char(sysdate, 'hh24:mi:ss'), USER, 'LOGON-SUCCESS', sys_context('USERENV', 'TERMINAL'));
ELSE
INSERT INTO event_log
(event_date, event_time, username, event_case, event_comment)
VALUES
(SYSDATE, to_char(sysdate, 'hh24:mi:ss'), USER, 'LOGON-FAILURE', sys_context('USERENV', 'TERMINAL'));
RAISE_APPLICATION_ERROR(-20001, 'Access denied!');
END IF;
END after_logon_on_database;

Read this ask tom-thread: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:3236035522926

In the second part of the IF/ELSE add a commit; statement between the Insert and the Raise. This will ensure that the Login failure message is inserted into the database correctly.
You are aware the the on-logon trigger won't stop the user from logging in if they are a DBA (have the DAB role). This is a feature to ensure that someone can always get access to the database to fix a broken on-logon trigger.
You are also correct in that the trigger won't raise (as the first error message returned by Oracle) the error -20001. It will instead return a -604 (ORA-00604: error occurred at recursive SQL level 1). You are not directly executing the trigger at login, it's executed at a few steps removed. You will want your application to handle this error properly.

Related

Understand login logout events on SQL Server extended events after upgrading compatibility level

After upgrading the compatibility level of our SQL Server to 150, we're facing some random issues getting the SCOPE_IDENTITY after an INSERT. To find the issue, we create an event session like this :
CREATE EVENT SESSION [QuickSessionTSQL] ON SERVER
ADD EVENT sqlserver.error_reported(
ACTION(package0.callstack,sqlserver.database_id,sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_stack)
WHERE ([severity]>=(20) OR ([error_number]=(17803) OR [error_number]=(701) OR [error_number]=(802) OR [error_number]=(8645) OR [error_number]=(8651) OR [error_number]=(8657) OR [error_number]=(8902) OR [error_number]=(41354) OR [error_number]=(41355) OR [error_number]=(41367) OR [error_number]=(41384) OR [error_number]=(41336) OR [error_number]=(41309) OR [error_number]=(41312) OR [error_number]=(41313)))),
ADD EVENT sqlserver.existing_connection(
ACTION(package0.event_sequence,sqlserver.client_hostname,sqlserver.session_id)),
ADD EVENT sqlserver.login(SET collect_options_text=(1)
ACTION(package0.event_sequence,sqlserver.client_hostname,sqlserver.session_id)),
ADD EVENT sqlserver.logout(
ACTION(package0.event_sequence,sqlserver.session_id)),
ADD EVENT sqlserver.rpc_starting(
ACTION(package0.event_sequence,sqlserver.database_name,sqlserver.session_id)
WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)))),
ADD EVENT sqlserver.sql_batch_starting(
ACTION(package0.event_sequence,sqlserver.database_name,sqlserver.session_id)
WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0))))
WITH (MAX_MEMORY=16384 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=PER_CPU,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF)
GO
And we see our INSERT statements and the SELECT SCOPE_IDENTITY but with strange behavior. Depending on the sqlserver.session_id, we notice one logout event and one login event after each SQL statement. Whereas on the other sqlserver.session_id we just see the usual statements.
First scenario (the good one) :
session_id : 10
INSERT INTO MyTable VALUES....
SELECT SCOPE_IDENTIY()...
INSERT INTO MyOtherTable...
The second scenario (the bad one) :
session_id : 98
login
logout
INSERT INTO MyTable VALUES....
login
logout
SELECT SCOPE_IDENTIY()...
login
logout
INSERT INTO MyOtherTable...
There is a different behavior depending on the session, but why? And what means the lot of login/logout events in this case?
Microsoft SQL Server 2019 (KB4583458) - 15.0.2080.9 (X64)

How to write connect user/password in procedure in oracle?

I try to create a procedure to allow the user (with the username 'c##administrator' and password 'addm')to login into the oracle using the connect <user_name>/<password_name> like this. But it said that click here to see the errors that oracle said. When I try to detect what is wrong on my script, I realize that the script cannot execute the command EXECUTE IMMEDIATE 'connect c##administrator/addm;'; and said that it is invalid sql command :<. But I don't know why it said that. I'm sure my password and my username is both correct.
Please help me fix it :( Thank you so much
CREATE OR REPLACE PROCEDURE system.SYS_KTraTaiKhoanAdmin (adUsername IN varchar2, adPassword IN varchar2)
IS
ex EXCEPTION;
BEGIN
IF (adUsername != 'c##administrator' AND adPassword != 'addm') THEN
dbms_output.put_line('PLEASE LOG IN AGAIN');
ELSE
dbms_output.put_line('LOG IN SUCCESSFULLY!');
EXECUTE IMMEDIATE 'connect c##administrator/addm;';
END IF;
EXCEPTION
WHEN ex THEN
Raise_application_error(-1, 'Error');
END;
/
BEGIN
system.SYS_KTraTaiKhoanAdmin('c##administrator', 'addm');
--rollback;
END;
/

SQL Server Log out / Terminate session of logged in user in a query

Without going into why I would like to do this, is it possible (I'll be using a login trigger) to log out a user that has no write permissions to a certain database?
I am able to find the currently logged in users permission, I just need to know if it's possible to log them out?
DECLARE #HasPermission bit
SELECT #HasPermission = HAS_PERMS_BY_NAME('RTEST2.dbo.TestTableSize', 'OBJECT', 'INSERT');
IF #HasPermission = 0
SELECT 'Now this is where id want to log out the user'
One can prevent a user from logging in by executing a ROLLBACK from within a login trigger. As #DavidBrowneMicrosoft mentioned in his comment, it's also a good practice to use a PRINT or RAISERROR statement so that reason for the login failure is logged. This message will not be returned to the client but may be useful for troubleshooting.
IF #HasPermission = 0
BEGIN
PRINT 'User does not have permissions to login';
ROLLBACK;
END;

Missing Insert Record on the table with Trigger (Oracle DB)

The scenario is the following -
OrderTable with Columns "OrderId" and "OrderType"
OrderRelationTable with Columns "OrderId" and "CustId"
OrderProcessTable with Columns "OrderId", "OrderType", "CustId", and "ProcessFlag"
The flow goes like this-
Application1 creates the record in OrderTable -> Then pass the record to Application2 by using MQ protocol, Application 2 in this case insert/create the record passed in the OrderRelationTable -> Then a trigger is called in Oracle DB to create the record in OrderProcessTable
Problem
Sometimes the record is not inserted into table 3 OrderProcessTable. Not sure if it is cause by timing or there is something that is not correct with the trigger?
Application1 Code
boolean updated = false;
/** JDBC prepare statement execution insert into OrderTable in Java**/
int rowCount = ps.executeUpdate();
if(rowCount>0){
updated=true;
}
log.log("updated flag:"+updated);
/** I am able to see the log shows the flag is true, and recored inserted into OrderTable **/
Application2 Code
This doesn't really matter much assuming that it is some Java JDBC code that does the insert into OrderRelationTable and it is successful.
The Trigger
Assuming the syntax is correct.
CREATE OR REPLACE TRIGGER INSERTINTOOrderProcessTable
AFTER INSERT ON OrderRelationTable
FOR EACH ROW DECLEAR
v_order_type := null;
BEGIN
SELECT OrderType INTO v_order_type FROM OrderTable
WHERE OrderId = :new.OrderId
AND OrderType IS NOT NULL
AND rownum=1;
IF v_order_type IS NOT NULL THEN
INSERT INTO OrderProcessTable VALUES (:new.OrderId, v_order_type, :new.CustId, 'N');
END IF;
END;
Questions -
After the Application 1 Code is executed is guaranteed DB will have the OrderTable record avaliable for SELECT statement? (Assume that updated flag is true)
Is there a timing issue with the app code and trigger? for example when trigger calls the SELECT statement from OrderTable? (of course the order id is matching in the OrderRelationTable and OrderTable)
Basically right now my problem is that sometimes (rarely) the record is not inserted into OrderProcessTable via the trigger even though it should (Order Type is not null)? Any idea?
There's no timing issue, as far as I can tell.
As of trigger code: what is the purpose of and rownum = 1 condition? I'm not saying that it is wrong, I'm just asking. Do you expect several rows to be returned by that query? If so, is that a legal situation? Wouldn't you rather handle it with the WHEN TOO_MANY_ROWS exception handler (i.e. instead of using the ROWNUM condition)?
What happens if SELECT returns nothing? It raises then NO_DATA_FOUND exception and trigger fails and certainly doesn't insert anything. Is it propagated so that someone (human being) or something (error logging procedure) sees / catches it so that you'd know that something went wrong?
And, of course, the fact that V_ORDER_TYPE remains NULL which causes INSERT to fail (as P. Salmon already suggested).

Delphi Database Connection Using ACCESS and ADO connections

Okay so basically I've been working on my computing project for a while now and I've got 90% of it working however I'm having a problem with Delphi where is says that my database is not connected/ there is a problem connecting however I've already tried writing the information to the screen and this showed me that the items I was looking to pick up where in fact being picked up so the failure is when the items are being input in to the database. This however shouldn't be happening as the System already has database information displayed from that table and the user can physically select things from the database tables within the program however when trying to store the information back into the database it just breaks. Me and my computing teacher can not work it out, any help would be appreciated.
The problem appears on the new orders page. If you'd rather look at the system then you can download it from here https://drive.google.com/folderview?id=0B_iRfwwM9QpHVXJnSkx4U1FjMlk&usp=sharing
procedure Tform1.btnSaveClick(Sender: TObject);
var orderID:integer;
count:integer;
begin
try
//save into the order table first
tblOrder.Open;
tblOrder.Insert;
tblOrder.FieldByName('CustomerID').value:= strtoint(cboCustomer.Text);
tblOrder.Close;
tblOrder.Open;
tblOrder.Last;
orderID:=tblOrder.FieldByName('OrderID').Value;
showmessage(inttostr(orderID));
for count := 1 to nextFree-1 do
begin
if itemOrdered[count,1]<>0 then
begin
tblOrderLine.Open;
tblOrderLine.AppendRecord([orderID, itemOrdered[count,1],itemOrdered[count,2]]);
end;
end;
showmessage('The order has been saved');
except
showmessage('There was a problem connecting to the database');
end;
end;
You're doing far too much open, do something, close, open. Don't do that, because it's almost certain that is the cause of your problem. If the data is already being displayed, the database is open already. If you want it to keep being displayed, the database has to remain open.
I also removed your try..except. You can put it back in if you'd like; I personally like to allow the exception to occur so that I can find out why the database operation failed from the exception message, rather than hide it and have no clue what caused it not to work.
procedure Tform1.btnSaveClick(Sender: TObject);
var
orderID: integer;
count: integer;
begin
//save into the order table first
tblOrder.Insert;
tblOrder.FieldByName('CustomerID').value:= strtoint(cboCustomer.Text);
tblOrder.Post;
orderID:=tblOrder.FieldByName('OrderID').Value;
showmessage(inttostr(orderID));
for count := 1 to nextFree-1 do
begin
if itemOrdered[count, 1] <> 0 then
begin
tblOrderLine.AppendRecord([orderID, itemOrdered[count,1],itemOrdered[count,2]]);
tblOrderLine.Post;
end;
end;
showmessage('The order has been saved');
end;

Resources