get statement which triggered trigger. Or other identifiers - sql-server-2008

I have a table (items in stock) which gets updated from several applications.
All queries are supposed to also set a field 'src' with some audit information (user and form), but some queries are not doing that.
I intend to create a trigger on update, which checks if the 'src' field is changed.
I would like to rollback the update and fire an error if the 'src' is not set, but also to log the query, so I better can identify the offending application.
Is the actual query text available to the trigger?
Or any other identifier?
All connections to the database are done via scripts on webservers, with one of two logins, but from a handfull of servers, so the ip of the server might be useful.

The connection information available is:
select *
from sys.dm_exec_connections as EC inner join
sys.dm_exec_sessions as ES on ES.session_id = EC.session_id
where EC.session_id = ##SPID
AFAIK you cannot get the triggering statement within a trigger.

Related

MySQL - Enforcing update of row to ONLY be possible when a certain key is provided

This is something I can't seem to find information on.
Let's say I have a table users, and for security purposes, I want any SQL query to only executable if a reference to the id columns is made.
E.g. this should NOT work:
UPDATE users SET source="google" WHERE created_time < 20210303;
The above update statement is syntactically valid, but because it isn't making a reference to the id column, it should not be executable.
Only the below would be executable:
UPDATE users SET source="google" WHERE id in (45,89,318);
Is there any way to enforce this from the MySQL server's end?
I think the only way you can really do what you want is to use a stored procedure, where you pass in the ids and to the update there. You would set up the security as:
Turn off updates to the underlying table for all-but-one user.
Run the stored procedure as the user with permissions to modify the table (using DEFINER).
This will be cumbersome because you will need to pass in all the values in the table.
You can come close with safe update mode. However, that also allows LIMIT as well as key comparisons, so that is not sufficient for your purposes.
Note: This sort of issue is usually handled in another way. Most users would not have permissions to modify such a table. Then "special" users who do would be assumed to be more knowledgable and careful about changes. If the data is sensitive, then the changes would be logged, so it would be (relatively) easy to undo changes that have been made.

Mysql trigger that can notify the c code about change in table

I have been searching for a way that can help me notify the C code about successful INSERT operation fired over a Mysql table.
So the insert query is already there in other component code, now in an independent component I want to get notified when Insert on a particular table takes place so that I could fire select on the table. Currently I fire select query on particular interval, need to avoid that and instead do it after an insert query.
Don't give users INSERT privilege to tables. Instead, make the go through an API -- either a Stored Procedure or a client API. There do any monitoring/etc you need.
Note that MySQL cannot (for security reasons) launch anything outside itself -- no email, callbacks, etc. There is an exception: UDFs (User Defined Functions).

Log all events on all tables with MySQL

I need to log all events on all tables in table database_log (id, user, timestamp, tablename, old_value, new_value).
I thought I can create the same trigger on all tables (~25) with a little php script dynamically replace the name's table. But in this case I can retrieve the old and new value, because all tables haven't the same columns so I can't just concat all field for store in the "old_value" and "new_value" (even if I retrieve fields in schema because I can't use a concat() on it for select all value and store in variable).
For exemple a :
SELECT * into v_myvar FROM my_table where id=OLD.id;
CALL addLog(v_myvar)
Where addLog is procedure taking my old value and add a line with other informations, could save my life.
So, I'm looking for a sexy solution with one trigger and/or one procedure (by table) or a useful tool. Someone have a solution ?
Thanks
SET GLOBAL general_log_file = '/var/log/mysql/mysql.log';
The general query log is a general record of what mysqld is doing. The server writes information to this log when clients connect or disconnect, and it logs each SQL statement received from clients.
See the MySql Documentation

Is there any alternative to "last_update_ID()" for mySQL?

I am currently working on a big web project using ASP and MySQL.
When inserting into multiple tables I've been using last_update_ID(), but after some research I've found that that SQL statement isn't safe.
So. the problem:
I use two different computers, with different internet connections.
Both computers are logged onto the system I am currently building. I have made a page that prints the connection_id(), and last_update_id.
If I update any table with one of the computers the other one also gets that last_update_ID.
Both computers have the same connection_ID.
What can I do to get around this?
I don't want to (if it's not necessary) do a select statement after the first INSERT; to search for the row that I inserted, to get the correct ID of that row.
It's not my server I am using so I can't make any large changes of the database.
I guess that this problem occurs because the webpages use the same loginName & password to connect to the database, is that true?
Is there any other alternative to get the last update ID? that is totally safe..
I close every connection at the end of the asp page. but that doesn't change the connection_ID.
The connection ID is the for a few minutes even thou I open up different web pages on the server.
I believe the LAST_INSERT_ID() is correct for the current session. So each session receives it's own correct value. Either I don't understand your question or you think you have a problem but you don't.
I am not aware of any LAST_UPDATE_ID() function, on an update you can easily retrieve the updated rows by SELECTing them with the same WHERE clause (before the update)?
reference: http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
For LAST_INSERT_ID(), the most
recently generated ID is maintained in
the server on a per-connection basis.
It is not changed by another client.
It is not even changed if you update
another AUTO_INCREMENT column with a
nonmagic value (that is, a value that
is not NULL and not 0). Using
LAST_INSERT_ID() and AUTO_INCREMENT
columns simultaneously from multiple
clients is perfectly valid. Each
client will receive the last inserted
ID for the last statement that
client executed.
If you want to retrieve the LAST_INSERT_ID from an INSERT query with an ON DUPLICATE KEY UPDATE clause, you can also use the LAST_INSERT_ID() function to retrieve the value of the AUTO_INCREMENT column that was updated:
reference: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
If a table contains an AUTO_INCREMENT
column and INSERT ... UPDATE inserts a
row, the LAST_INSERT_ID() function
returns the AUTO_INCREMENT value. If
the statement updates a row instead,
LAST_INSERT_ID() is not meaningful.
However, you can work around this by
using LAST_INSERT_ID(expr). Suppose
that id is the AUTO_INCREMENT column.
To make LAST_INSERT_ID() meaningful
for updates, insert rows as follows:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;
Your server appears to have connection pooling turned on. What this means is that the database connection is held open after a script finishes, and the next script that comes along uses it, and thus can see any variables that were set on that connection, including LAST_INSERT_ID().
What can't happen is two script instances sharing a connection at the same time. Thus, if your server is busy enough to need to run two script instances at exactly the same time, it will simply create a second database connection, with its own separate LAST_INSERT_ID() variable, and won't interfere with the first.
In short, as long as the INSERT and the LAST_INSER_ID() request happen within the same script (and you don't somehow close the database connection between them), they're completely safe, as your script has exclusive use of that connection.

table locked or in use when calling RunSQL

I have some code which re-arranges some items on a form, but only one SQL query. All my tables aren't locked before the code runs but for some reason I get an error when running:
DoCmd.RunSQL ("Select * Into MasterTable From Year07 Where 'ClassName' = '7A'")
Error:
The database engine could not lock table because it is already in use by another person or process. (Error 3211) To complete this operation, a table currently in use by another user must be locked. Wait for the other user to finish working with the table, and then try the operation again.
Any ideas what I can do to stop the table being locked?
Is MasterTable included in your form's Record Source? If so, you can't replace it, or modify its structure, while the form is open.
Apart from the table lock issue, there is a logic error in the SELECT statement.
Where 'ClassName' = '7A'
The string, ClassName, will never be equal to the string, 7A. Therefore your SELECT can never return any records. If ClassName is the name of a field in your Year07 table, discard the quotes which surround the field name.
Where ClassName = '7A'
I'm guessing, but if you're using a form that is bound to MasterTable, you can't run a query to replace it with a new MasterTable while you've got it open in the form.
I would suggest that you get rid of the MakeTable query (SELECT INTO) and instead use a plain append query (INSERT). You'll want to clean out the old data before appending the new, though.
Basically, a MakeTable query is, in my opinion, something that does not belong in a production app, and any process that you've automated with a MakeTable query should be replaced instead with a persistent temp table that is cleared before the new data is appended to it.
I have seen this when you re-open a database after Access has crashed. Typically for me a reboot has fixed this.
What version of MSAccess? Not sure about newer ones, but for Access 2003 and previous, if you were sure nobody was in the database, you could clear up locks after a crash by deleting the .ldb file.