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

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;
/

Related

Raising exception in others on Snowflake

I'm migrating some stored procedures from Oracle to Snowflake and I need to raise an exception in others segment of exception on snowflake exception including a column from cursor. Here is an example from oracle:
create or replace PROCEDURE sp
AS
CURSOR SCGR
IS
SELECT SP.REQUEST_NUM,
…
from table;
BEGIN
FOR I IN SCGR
LOOP
BEGIN
INSERT
INTO table(…)
VALUES
(…);
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,'An error was encountered in CUST_GROUP_REQUEST insert for - '||I.REQUEST_NUM||' - '||SQLCODE||' -ERROR- '||SQLERRM);
EXIT;
END;
END;
With this part I'm having troubles in Snowflake:
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,'An error was encountered in CUST_GROUP_REQUEST insert for - '||I.REQUEST_NUM||' - '||SQLCODE||' -ERROR- '||SQLERRM);
EXIT;
Can someone help me?
If you check the RAISE command, you will see that it accepts an exception name, not a string expression which you can build dynamically.
https://docs.snowflake.com/en/sql-reference/snowflake-scripting/raise.html
Do you really need to raise an exception, or want to return a result cotaining the exception details?
https://docs.snowflake.com/en/developer-guide/snowflake-scripting/exceptions.html?_ga=2.186509665.956198205.1648142906-1409600040.1607023304#handling-an-exception
return object_construct('Error type', 'Other error',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);

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;

obtain the real identity of the connected user

dxStatusbar1.Panels1.Text :=
DataModule2.UniConnectDialog1.Connection.Username;
...gives me the username that has connected to sql server.
However the connected user has a different name in the actual database.
Example:
His login name for the sql server is 'John' and is user mapped to 'Northwind' database.
However in 'Northwind' database he is called 'John Smith'.
And this is the name (John Smith) I am trying to have displayed in dxStatusbar1.Panels1.Text
after he connects.
How can I get that ?
edit :
Tried Victoria suggestion :
UserName := DataModule2.UniConnection1.ExecSQL('SELECT :Result = CURRENT_USER', ['Result']);
dxStatusbar1.Panels[1].Text := UserName;
but get :
I couldn't find any UniDAC API way to get currently connected user name (not even for SDAC), so I would just issue a SQL command querying CURRENT_USER and grab the name from the result:
SELECT CURRENT_USER;
Or in the Unified SQL way with the USER function:
SELECT {fn USER};
Since you've mentioned stored procedure in your comment, it sounds to me like you probably want to get this information directly from a connection object without using query object. If that is so, you don't even need to have a stored procedure but execute directly command like this:
var
UserName: string;
begin
UserName := UniConnection1.ExecSQL('SELECT :Result = CURRENT_USER', ['Result']);
...
end;
Or in unified way:
var
UserName: string;
begin
UserName := UniConnection1.ExecSQL('SELECT :Result = {fn USER}', ['Result']);
...
end;
One of these might do the job for you. Haven't tested.
SELECT ORIGINAL_LOGIN()
SELECT SYSTEM_USER
SELECT SUSER_SNAME()
Hope it helps.
ORIGINAL_LOGIN: Returns the name of the login that connected to the instance of SQL Server. You can use this function to return the identity of the original login in sessions in which there are many explicit or implicit context switches.
SYSTEM_USER: Allows a system-supplied value for the current login to be inserted into a table when no default value is specified.
SUSER_SNAME: Returns the login name associated with a security identification number (SID).

How to resume/retry a broken TADOConnection across the application?

I have a data module with a global TADOConnection (with the default KeepConnection set the true).
There are numerous datasets and queries in my existing application that use this global TADOConnection.
I was wondering if there is some smart way to resume/retry the ado connection in case of a short network disconnection? (this situation happens sometimes with clients who have a not so stable connections).
Its easy to reproduce what I need. simply open TADOConnection on start-up. open some TADODataSet, and then disable and enable your "Local Area Connection". if you try to refresh the dataset, an EOleException exception is raised
"Connection failure"
or
"[DBNETLIB][ConnectionWrite (send()).]General network error. Check
your network documentation"
If I restart the application all is good.
No events are fired by the TADOConnection at the time of network disconnections. and TADOConnection.Connectedremains true
of course I could use a try/catch for every TDataSet.Open or Execute but I'm looking for some "centralized" solution for my large application.
so in case of "Connection failure" I could know which dataset is trying to open, and retry.
No never firing at the time of network disconnections. But you can check connection before every command. So if AdoConnection disconnected, you can reconnect and execute your command after this.
If you wanna centralized solution and you have 1 Connection, you can do that like this;
Const
ConnectionTestString=' '; //Yes, it's work on Sql Server. If doesnt your db, you can use 'Select 1'
Procedures;
Procedure TDM.GetCommandResult_Conn(CText:String;Connection : TAdoConnection);
var Ado_Ds_Tmp:TAdoCommand;
Begin
Ado_Ds_Tmp:=TAdoCommand.Create(self);
try
Ado_Ds_Tmp.Connection:=Connection;
Ado_Ds_Tmp.ParamCheck := False;
Ado_Ds_Tmp.CommandText:=CText;
try
Ado_Ds_Tmp.Execute;
except
DM.RaiseExceptionCreate('Error ! Command, ('+StrToList(CText, ' ')[0]+')');
end;
finally
Ado_Ds_Tmp.Destroy;
end;
end;
procedure TDM.ADOConnection1WillExecute(Connection: TADOConnection;
var CommandText: WideString; var CursorType: TCursorType;
var LockType: TADOLockType; var CommandType: TCommandType;
var ExecuteOptions: TExecuteOptions; var EventStatus: TEventStatus;
const Command: _Command; const Recordset: _Recordset);
var
ErrorLogFileName : string;
ErrorFile : TextFile;
ErrorData : string;
Msg : String;
begin
try
if (CommandText<>ConnectionTestString) then begin
DM.GetCommandResult_Conn(ConnectionTestString, Connection);
end;
except
try
try
Connection.Connected := False;
except
end;
try
Connection.ConnectionString := AdoConnectionString;
Connection.Mode:=cmShareDenyNone;
finally
try
Connection.Connected := True;
// If you wanna log for frequency
ErrorLogFileName := ChangeFileExt(Application.ExeName,'.error.log');
AssignFile(ErrorFile, ErrorLogFileName);
if FileExists(ErrorLogFileName) then
Append(ErrorFile)
else
Rewrite(ErrorFile);
try
ErrorData := Format('%s : %s : %s (%s / %s)',[DateTimeToStr(Now), 'Disconnected but we reconnect.', '', 'UserName : '+DBUser, 'Client : '+GetComputerNetName]);
WriteLn(ErrorFile,ErrorData);
finally
CloseFile(ErrorFile)
end;
except
DM.RaiseExceptionCreate('ReConnection Failed!');
end;
end;
except
end;
end;
end;
Any question?
The idea could be to catch the connection error then manage it with retries.
The Suggestion:
This function returns the exception descripion
function GetStrException(ExceptObject: TObject; ExceptAddr: Pointer):String;
var
Buffer: array[0..1023] of Char;
begin
ExceptionErrorMessage(ExceptObject, ExceptAddr, Buffer, SizeOf(Buffer));
Result:=Buffer;
end;
this is a simple idea to test!
procedure TForm1.Button2Click(Sender: TObject);
var
s,error:String;
begin
//a select as an example
S := 'SELECT COUNT(*) FROM MyTable';
TRY
WITH ADOQuery1 DO BEGIN SQL.Clear; SQL.Add(s);OPEN;END;
Memo1.Lines.ADD(ADOQuery1.Fields[0].AsString);
EXCEPT
error:=(GetStrException(ExceptObject,ExceptAddr));
//using MySql my error case is when the connection is lost, so the error is "Server has gone away"
if pos(error,'has gone away')>0 then
begin
Showmessage('Connection Error, please try again');
try
sleep(1000)
AdoConnection1.close;
AdoConnection1.open;
except
Showmessage('The connection Error persists, please contact the support');
end;
end;
END;
end;
A good solution is centralize the insert/update and select procedure, then
catch the error and try to adjust the situation one or two times before
show message to the user

Oracle Trigger: raise_application_error

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.

Resources