Informix - capture user ID in delete trigger - asp.net

I have an ASP.NET (C#) web application that connects to Informix 12.x database. The web application uses a database connection string with username and password. Users are given login accounts to use the web application and they can delete records in the database.
The database tables have "LastModifiedBy" which contains the user ID. Now, I need to implement auditing using database triggers. I need to capture what records were updated or deleted and who did it (i.e. logged in user) and save these in an audit table.
For the delete trigger, how can I capture the user ID of the logged in user and save this in the audit table?

The database user (available via the keyword USER) is always going to be the username associated with the shared database credentials. Your question is not very clear, but are you saying the existing LastModifiedBy attribute contains the named user or the database user? If it's the named user, I think you should probably look at your ASP.NET code to see how that gets passed into the UPDATE statement.
I'm no expert on ASP.NET, but assuming a single page request uses the same database connection throughout its processing cycle, then you could maintain a table keyed on the session ID, available via DBINFO('sessionid'), where you capture the named user at the top of the request, and then you have it available at any point throughout the process for inclusion in your audit. But if the web-server processes are using a pool of database connections and any statement could go to a different connection, even that won't work.
Ultimately, I don't think database triggers are the right solution here, not least because you'll have to write and maintain a trigger for every table in your application. If I was faced with this problem I would be more inclined to have a common Audit function within the web-app, where the named user is always available.
At the OP's request, a bit more detail. The Session ID is exactly the same concept as you see in SSMS - just a unique number that identifies the connection.
Imagine you have the following table and procedures:
CREATE TABLE session_user (
sessionid INTEGER NOT NULL,
username VARCHAR(20),
conn_date DATE,
PRIMARY KEY (sessionid)
);
CREATE PROCEDURE set_user(v_username VARCHAR(20))
UPDATE session_user SET username = v_username, conn_date = TODAY
WHERE sessionid = DBINFO('sessionid');
IF DBINFO('sqlca.sqlerrd2') = 0 THEN
INSERT INTO session_user VALUES (DBINFO('sessionid'), v_username, TODAY);
END PROCEDURE;
CREATE PROCEDURE get_user()
DEFINE v_username VARCHAR(20);
SELECT username INTO v_username
FROM session_user
WHERE sessionid = DBINFO('sessionid');
IF v_username IS NULL THEN
LET v_username = USER;
-- return system user if no record found in session_user table
END IF;
RETURN v_username;
END PROCEDURE;
NB: None of this code is tested, it's just to show the principle. I don't have an Informix instance to hand to test this on.
At the top of the request, however you execute your SQL, you would run:
EXECUTE PROCEDURE set_user($the_web_user);
Your triggers could then use get_user() wherever you want to capture that info. You'll get the actual web user if it's been recorded in the session_user table, otherwise the database user (which will be the shared database credentials if the triggering DML has come from the web-app, or the physically logged in user if the trigger is via a DB-Access session).
I still don't think this is a particularly maintainable solution - every table needs its own trigger(s). An OO audit method in the web-app would be a more DRY approach, or have a look at Informix's preexisting audit capabilities.
Note: the date field was included in the session_user table so you run a clean-up over it, because depending on how often new connections get created by the web-app, your session_user table could grow like topsy.

Related

ORACLE APEX CREATE LOGON TRIGGER

I want to update a status to my table with specific criteria (where clause) when any user logs on..
create or replace TRIGGER AUTO_COMPLETE
AFTER LOGON ON SCHEMA
BEGIN
UPDATE SESSIONS
SET SESSIONS.STATUS = 5
WHERE SESSIONS.STATUS =2
AND TO_CHAR(SESSIONS.SESSION_DATE, 'MM-DD-YYYY HH24.MM') < TO_CHAR (SYSDATE, 'MM-DD-YYYY HH24.MM');
END AUTO_COMPLETE;
Unfortunately this trigger is not fired and i have no errors!!
Apex is stateless, see first paragraph here. That means that a new database session is created for every page render or post process. I think that would make that logon trigger fire constantly when the user navigates around the application.
You could create an application process with point "After Authentication" in your application. That will fire only once for the application after the user authenticates.
Keeping this functionality separate from your database makes sense. A logon trigger will fire when you connect through sqldeveloper or over rest as well - and it will affect performance.
I think the best way is in your app settings, you can user bind variables to verify the username or another stuff.
Shared components / Security Attributes / Database Session
Or another option is to create a process after authentication

SQLite INSERT or UDATE with a custom condition

I know there is a lot of question already asked and answered on this subject but they don't seem to fit my situation.
I have a distant sqlite database — DB server — and a local one — DB local containing photo album entries. DB local updates whenever needed from DB server. DB server has a primary key called identifier, which is stored in DB local to prevent duplicates, but DB local also has its own primary key column called id
If I need to create a new album on my phone I insert an entry in DB local with identifier set to -1 and when DB server will be reachable ask for a proper identifier.
My issue is : I do a lot of refresh and don't want to increment my primary key each time.
When I refresh DB local from DB server I would like to INSERT new albums, and UPDATE existing ones.
I read about the INSERT OR REPLACE statement but it would require my identifier column in DB local to be set as unique. Unfortunately I cannot do so since I can have multiple identifierset to -1.
Is there any way to perform an INSERT or UPDATE conditionally in a single request ?
Thanks !
EDIT : the update is done this way : the DB local is updated from DB server. DB local data is never pushed to DB server, the only way to add a new item is to call an API on the server which will create an empty entry on DB server and get its identifier. But since server is not always reachable (EDGE/3G) some entries in DB local have identifier set to -1. Once the API call have returned with the corresponding identifier we store it instead of -1 for the corresponding entry in DB local

Trace the Cause for update of Sql Table

I have a table Product which have Quantity column, This table get updated thru .net application using Stored procedure based on flag variable. Now im having problem reported from user that even though the flag variable is not set table is getting updated with new values.
Now i need to isolated the cause for the issue.How will i check which update and through which application this table is getting modified. I have no idea about it.
What is the best approach to resolve this issue?
Assuming you are using SQL Server:
You can monitor calls to SQL Server using SQL Server Profiler. You can setup a filter to monitor queries affecting the Product table. The log will show what the query looked like, when the query was executed, the database user executing the query, the name of the application (if that is specified in the connection string) and a bunch of other things.

SQL Server load balancing optimizing Hits or Optimize the query

When we developers write data access code what should we really worry about if the application should scale well and handle the load / Hits.
Given this simple problem , how would you solve it in scalable manner.
1.ProjectResource is a Class ( Encapsulating resources assigned to a Project)
2.Each resource assigned to Project is User Class
3.Each User in the Project also has ReportingHead and ProjectManager who are also instance of User
4.Finally there is a Project class containing project details
Legend of classes used
User
Project
ProjectResource
Table Diagram
ProjectResource
ResourceId
ProjectId
UserId
ReportingHead
ProjectManager
Class Diagram
ProjectResource
ResourceId : String / Guid
Project : Project
User : User
ReportingHead : User
ProjectManager : User
note:
All the user information is stored in the User table
All the Project information is stored in the project table
Here's the Problem
When the application requests for Resource In a Project operations below are followed
First Get the Records for the Project
Get the UserId , make the request(using Users DAL) to get the user instance
Get the ProjectId, make the request(using Projects DAL) to get the project information
Finally assign Users and Project to instance of ProjectResource
clearly you can see 3 Db Calls are made here for populating single ProjectResource but the concerns and who manages the objects are clearly defined. This is the way i have planned to , since there is also connection pooling available in Sql Server & ADO.net
There is also another way where all the details are retrieved in single hit using Table Inner Joins and then Populating.
Which way should i really be taking and Why?
Extras:
.NET 2.0,ASP.net 2.0,C#,Sql Server 2005,DB on same machine hosting application.
For best performance and scalability, you should minimize the number of round-trips to the DB. To prove that to yourself, just run some benchmarks; it becomes clear very quickly.
One approach to a single round-trip is to use joins. Another is to return multiple result sets. The latter can be helpful in eliminating possible duplicate data.

How to clear SQL session state for all users in ASP.NET

I use SQLServer SessionState mode to store session in my ASP.NET application. It stores certain objects that are serialized/deserialized every time they are used.
If I make any changes in code of the structure of those objects and I put a new version live, any logged user will get an error, as their session objects (the old version ones) do not match the structure that the new version expects while deserializing.
Is there a way to clear all sessions at once in DB so that all active sessions expire and users are forced to log in again (and therefore all session objects are created from scratch)?
Or... Is there any other way to solve this situation?
You may try using stored procedure in SQL Server to clear all the sessions:
CREATE PROCEDURE [dbo].[DeleteSessions]
AS
DELETE [ASPState].dbo.ASPStateTempSessions
RETURN 0
You can call Session.Abandon, or Clear for every user when they hit the invalid Session object.
You can also loop through the per-user Session collection, and clear the keys that can contain "old" objects. Maybe you have a login ticket and such that you don't want to clear.
foreach (string key in Session.Keys)
{
if (!key.Equals("login"))
{
Session.Remove(key);
}
}

Resources