I was wondering if there was a way to detect the log in name of the user executing the query which triggers a stored procedure? Say, I have a trigger on table_a that fires when a particular column is changed. I would like to retrieve the name of the logged in user who executed the query which triggered the stored procedure running.
Is this possible?
Turns out there is a recognized keyword called current_user that does the exact thing I want - holds the username of the current user executing the query.
Related
I've got a table called proc_logs that is intended to be used for logging/troubleshooting stored procs. I'd like to create a stored proc that inserts into this table and adds a timestamp. I'd like any stored proc in any other database in my account to have rights to call this procedure.
First attempt at this is:
grant USAGE on procedure WRITELOG(string,string) to PUBLIC
However I think this would only apply to the PUBLIC schema in the same database. Is this "cross-database" proc considered a terrible idea? How can I grant usage on that proc to any other proc executing in my account? Do I need to create a "logger" role and grant that role to all of my functional roles or do procedures use a special role? Also keep in mind that anyone who has the usage rights on that proc also needs to be able to select from it.
Besides using Usage Privilege Then why not use CREATE PROCEDURE WITH EXECUTE OWNERS RIGHT , with this Statement the procedure would be executed with Owner's right ; even if Caller has no privilege to insert the data into table proc_logs the procedure would execute with Ownwer's right and Caller would be able to Insert the data into this table.
Read this material when to use Execute Procedure With Owner right or Caller right.
https://docs.snowflake.com/en/sql-reference/stored-procedures-rights.html
I need to call a vendor procedure that searches the database for possible matches. The input parameters are entered in a global temp table, then a procedure needs to be called that fills another global temp table with possible matches. Any thoughts on the best way to do this with APEX?
This is a vendor database. I really can't change anything. The vendor procedure requires that I load parameters into their GTT, run their procedure, then get the results from their result GTT. I'm new to APEX and just trying to figure out the best way to handle that...what type of apex object do I use to load the parameters to the parameter GTT? How do I call the procedure when the parameter row is saved? What apex object should I use to display the result GTT...a report, a grid...?
As data in a global temporary table (GTT) is "private", i.e. can be accessed in the same transaction or a session (which would probably be your choice, so you'd create a GTT with the ON COMMIT PRESERVE ROWS), as long as you do everything in the same session, that would work.
On the other hand, if there are several sessions involved, you're probably out of luck and will have to change the approach. The most obvious is to use a normal table (not a global temporary one), or - if possible - Apex collections.
I have a (Firebird) DB. For most of my tables I have a trigger which fires before insert which will create the Primary Key (PK) for me via a generator as well as write to the newly inserted records a Created Date value and a Created By value. I also have an update trigger which writes to an Updated Date field and an Updated By field.
eg (Client is a table in my DB):
create trigger t_client_id for client
active before insert
as begin
new.client_id = gen_id(gen_client_id, 1);
new.created = current_timestamp;
new.created_by = current_user;
new.lock_vn = 1;
end ^
create trigger t_client_update for client
active before update
as begin
new.updated = current_timestamp;
new.updated_by = current_user;
end ^
When I apply updates thru my ClientDataSet (CDS) - which are attached to remote TDataSetProviders via a TDSProviderConnection, how can I "retrieve" these generated values? If I edit an existing one (which will in turn call the t_client_update trigger, calling RefreshRecord will get the updated and updated_by fields. However, the Doco says to use that method cautiously, so that may not be the correct way to achieve this. I call it straight after I've called ApplyUpdates(-1).
The CDS I use only contains the one record I am attempting to Edit. For a New record, the CDS is in dsInsert mode. Everything is written to the DB ok so I just need to get this new data back out again. I have also tried using a CDS which contains ALL records in the table too to see if it was any simpler but didn't make any difference - unsurprisingly. The reason I need this information is simply to show to the user in DB Aware controls these values. They are read only.
I could call a Get on the record I guess when editing an existing record, using the PK, but that won't help for an Insert as I don't know what the new PK is.
Example of where I attempt to ApplyUpdates to my CDS (actDSSave is a TDataSetPost action)
dsState := actDSSave.DataSource.DataSet.State;
DoApplyUpdates(-1);
if dsState = dsEdit then
TClientDataSet(actDSSave.DataSource.DataSet).RefreshRecord;
I am using TIBQuery for my dataset attached to the remote DataSetProvider. This query SQL is a simple select * from client where client_id = :client_id. I have tried associating this query with a TIBUpdateSQL too as well as trying to set poAutoRefresh to true in the DataSetProvider.
So is it possible to obtain these Trigger generated values this way or do I need to approach it in a different way? Another way I can think of, is to create stored procedures which do CRUD against each table and use that instead (with appropriate in/out params to return this new data) but hopefully I don't have to go down that track. Hopefully I have provided sufficient info here to explain and replicate the issue.
Thanks
EDIT
Realised in above, DoApplyUpdates(-1) is my own method. It's implementation at the moment is simply:
FdatCommon.cdsClient.ApplyUpdates(MaxErrorCount);
FdatCommon is a TDataModule containing my CDS.
You simply can't get "generated" values without new requery (RefreshRecord) of data after Post.
It's because triggers runs on server side when you call ApplyUpdates, but TClientDataSet does not refresh by default posted record. For example other libraries FIBPlus have an option to do it automatically.
About inserts, TIBDataSet have GeneratorField property. Using it, dataset query and increment generator value separatelly before insert. So you will have PK values after post even on inserts. But avoid using it again in trigger.
MIDAS (TClientDataSet) is a great library, but his general / universal architecture loose DB specific features (such as retriving values from inserts) compared to dedicated libraries for specific DBMS, such as FibPlus. By the way I saw TpFIBClientDataSet. It work in conjunction with TpFibDataSet.
I have an event posted from firebird database in a trigger after a new record is inserted like this: post_event 'SPOOL' + new.username;
I want to register this event with SIBfibEventAlerter (FIBPlus) in a Delphi application and run a procedure. Problem is that event name depends on user name added the record.
You could read the usernames from the user table (if new.username is actually a field and not some FB system value) and create the eventalerters components dynamically, one per user name.
Since events don't really support parameters, one way would be to add extra fields to table, which contain auto incremental id (or timestamp) and the data you need as a parameter.
So, here is the situation -
I insert an item in the database calling the AddtoObject() and then call SaveChanges().
Then, I call a stored procedure to update the currently inserted record.
Then, I call the Save changes() again.
The database when I query it has the correct updated value, but the entity framework
context does not have the updated values..the first time..whenever I refresh the page it gets the value..but the first time it never gets the updated values.
So has anyone faced a similar issue anytime ? What am I doing wrong here ?
The problem is that the EF does not know what your stored procedure is doing, how could it? That work is done at the SQL Server. So after your stored procedure executes, you need to ask EF to update that (and other related) instance by issuing a Refresh() call:
context.Refresh(RefreshMode.StoreWins, myObject);
The StoreWins tells the framework to overwrite values in the instance with values from the database.