use a db2 trigger to identify the user initiating - triggers

When creating a DB2 trigger (db2 version 10.1 LUW), I am looking to capture the userid that initiating the trigger.
For example, if a user inserts data, the after insert trigger should write to a log on who inserted the data. This not meant for production purposes - just is to identify who is updating / inserting test data.

You can obtain the value of the SESSION_USER special registry variable. As an alternative look at the SYSTEM_USER registry. There are differences if you use features like SET SESSION AUTHORIZATION or use TRUSTED CONTEXTS.
Try this as a quick test:
select session_user from sysibm.sysdummy1;
select system_user from sysibm.sysdummy1;

Related

Is there a way to access one database from another in Postgresql? [duplicate]

I'm going to guess that the answer is "no" based on the below error message (and this Google result), but is there anyway to perform a cross-database query using PostgreSQL?
databaseA=# select * from databaseB.public.someTableName;
ERROR: cross-database references are not implemented:
"databaseB.public.someTableName"
I'm working with some data that is partitioned across two databases although data is really shared between the two (userid columns in one database come from the users table in the other database). I have no idea why these are two separate databases instead of schema, but c'est la vie...
Note: As the original asker implied, if you are setting up two databases on the same machine you probably want to make two schemas instead - in that case you don't need anything special to query across them.
postgres_fdw
Use postgres_fdw (foreign data wrapper) to connect to tables in any Postgres database - local or remote.
Note that there are foreign data wrappers for other popular data sources. At this time, only postgres_fdw and file_fdw are part of the official Postgres distribution.
For Postgres versions before 9.3
Versions this old are no longer supported, but if you need to do this in a pre-2013 Postgres installation, there is a function called dblink.
I've never used it, but it is maintained and distributed with the rest of PostgreSQL. If you're using the version of PostgreSQL that came with your Linux distro, you might need to install a package called postgresql-contrib.
dblink() -- executes a query in a remote database
dblink executes a query (usually a SELECT, but it can be any SQL
statement that returns rows) in a remote database.
When two text arguments are given, the first one is first looked up as
a persistent connection's name; if found, the command is executed on
that connection. If not found, the first argument is treated as a
connection info string as for dblink_connect, and the indicated
connection is made just for the duration of this command.
one of the good example:
SELECT *
FROM table1 tb1
LEFT JOIN (
SELECT *
FROM dblink('dbname=db2','SELECT id, code FROM table2')
AS tb2(id int, code text);
) AS tb2 ON tb2.column = tb1.column;
Note: I am giving this information for future reference. Reference
I have run into this before an came to the same conclusion about cross database queries as you. What I ended up doing was using schemas to divide the table space that way I could keep the tables grouped but still query them all.
Just to add a bit more information.
There is no way to query a database other than the current one. Because PostgreSQL loads database-specific system catalogs, it is uncertain how a cross-database query should even behave.
contrib/dblink allows cross-database queries using function calls. Of course, a client can also make simultaneous connections to different databases and merge the results on the client side.
PostgreSQL FAQ
Yes, you can by using DBlink (postgresql only) and DBI-Link (allows foreign cross database queriers) and TDS_LInk which allows queries to be run against MS SQL server.
I have used DB-Link and TDS-link before with great success.
I have checked and tried to create a foreign key relationships between 2 tables in 2 different databases using both dblink and postgres_fdw but with no result.
Having read the other peoples feedback on this, for example here and here and in some other sources it looks like there is no way to do that currently:
The dblink and postgres_fdw indeed enable one to connect to and query tables in other databases, which is not possible with the standard Postgres, but they do not allow to establish foreign key relationships between tables in different databases.
If performance is important and most queries are read-only, I would suggest to replicate data over to another database. While this seems like unneeded duplication of data, it might help if indexes are required.
This can be done with simple on insert triggers which in turn call dblink to update another copy. There are also full-blown replication options (like Slony) but that's off-topic.
see https://www.cybertec-postgresql.com/en/joining-data-from-multiple-postgres-databases/ [published 2017]
These days you also have the option to use https://prestodb.io/
You can run SQL on that PrestoDB node and it will distribute the SQL query as required. It can connect to the same node twice for different databases, or it might be connecting to different nodes on different hosts.
It does not support:
DELETE
ALTER TABLE
CREATE TABLE (CREATE TABLE AS is supported)
GRANT
REVOKE
SHOW GRANTS
SHOW ROLES
SHOW ROLE GRANTS
So you should only use it for SELECT and JOIN needs. Connect directly to each database for the above needs. (It looks like you can also INSERT or UPDATE which is nice)
Client applications connect to PrestoDB primarily using JDBC, but other types of connection are possible including a Tableu compatible web API
This is an open source tool governed by the Linux Foundation and Presto Foundation.
The founding members of the Presto Foundation are: Facebook, Uber,
Twitter, and Alibaba.
The current members are: Facebook, Uber, Twitter, Alibaba, Alluxio,
Ahana, Upsolver, and Intel.
In case someone needs a more involved example on how to do cross-database queries, here's an example that cleans up the databasechangeloglock table on every database that has it:
CREATE EXTENSION IF NOT EXISTS dblink;
DO
$$
DECLARE database_name TEXT;
DECLARE conn_template TEXT;
DECLARE conn_string TEXT;
DECLARE table_exists Boolean;
BEGIN
conn_template = 'user=myuser password=mypass dbname=';
FOR database_name IN
SELECT datname FROM pg_database
WHERE datistemplate = false
LOOP
conn_string = conn_template || database_name;
table_exists = (select table_exists_ from dblink(conn_string, '(select Count(*) > 0 from information_schema.tables where table_name = ''databasechangeloglock'')') as (table_exists_ Boolean));
IF table_exists THEN
perform dblink_exec(conn_string, 'delete from databasechangeloglock');
END IF;
END LOOP;
END
$$

Postgres: auto-populating an `INSERT` field based on session variable

I have a web app backed by Postgres.
Each web app request should only read/write data for the current logged-in user.
Every table with user data has a user_id column.
I occasionally have bugs where I forget to add user_id = ? to the WHERE clause of an SQL request. To protect against this problem in a general way, I'm looking into Postgres row-level security (article):
Set a policy on every user data table: CREATE POLICY table_policy ON table USING (user_id::TEXT = current_setting('app.user_id'))
In the web app, when a request begins, set the current logged-in user ID on the request's connection: SET app.user_id = ?.
This allows me to completely ignore user_id when writing SELECT and UPDATE requests.
My remaining problem is INSERTs. Is there a way to avoid having to provide user_id on INSERTs?
Just having a look at the manual :
Existing table rows are checked against the expression specified in USING, while new rows that would be created via INSERT or UPDATE are
checked against the expression specified in WITH CHECK
it seems that you just have to add a WITH CHECK clause to your policy in addition of the USING clause, and which will apply to the INSERT and UPDATE statements.

DB2 iseries materialized view refresh

I have created the following materialized query table:
CREATE TABLE SCHEMA.TABLE AS
(SELECT * FROM SCHEMA.TABLEEXAMPLE)
DATA INITIALLY DEFERRED
REFRESH DEFERRED
MAINTAINED BY USER
DISABLE QUERY OPTIMIZATION;
When I execute a REFRESH TABLE SCHEMA.TABLE it get locked for others users to read from it.
Reading this doc from IBM https://www.ibm.com/support/knowledgecenter/en/SSEPGG_9.7.0/com.ibm.db2.luw.sql.ref.doc/doc/r0000977.html
I tried to execute this statement:
REFRESH TABLE SCHEMA.TABLE ALLOW READ ACCESS
But I get the following error: SQL State: 42601 Unexpected keyword ALLOW
What I'm missing on statement? Is there other way to allow read access to materialized query table while it is beign updated?
MQTs on Db2 for IBM i lag behind the functionality available in Db2 for LUW.
I've never bother with them, instead an encoded vector index (EVI) with computed columns meets every need I've every considered. (Note that Db2 LUW doesn't have EVIs)
Per Mao's comment, you might try deleting an recreating the MQT with the following:
CREATE TABLE SCHEMA.TABLE AS
(SELECT * FROM SCHEMA.TABLEEXAMPLE)
DATA INITIALLY DEFERRED
REFRESH DEFERRED
MAINTAINED BY USER
DISABLE QUERY OPTIMIZATION
with NC;
But I think a refresh would still require exclusive access to the MQT.
The only options I can think of for "refreshing" an MQT while it is being used
programmatically , using either triggers on the base tables or perhaps a process that uses SQL to update a few rows at a time.
removing the DISABLE QUERY OPTIMIZATION and not accessing the MQT directly. Instead depend on the optimizer to access it when appropriate. Now you can create a version of it every few hours and the Db should start using the newer version for new queries. Once the older one is no longer being used, you delete it (or REFRESH it)

(MON_OBJ_METRICS) in db2

I am very much new to db2. My requirement is I just want to remove tracking system on a user table. I mean tracking of all kind of DML operations on a particular table. I read some thing from the google, according to my understanding this can be done by this parameter in (MON_OBJ_METRICS) parameter at db level.does my understanding is worth ?
How can i disable this parameter ? If i disable this parameter at db level, does all the tables under this particular database are quit from tracking ?
On sql server we can do this by set_change_tracking parameter. I am looking for same functionality in db2luw.
Kindly help me out & please excuse me , as i m a kid in db2
MON_OBJ_METRICS (and DFT_MON_TABLE, from your other post) are used for performance monitoring only. The keep track of the number of rows read, inserted, deleted and updated (among other things), but do not track actual data changes.
Change tracking in MS SQL Server is used for data capture to feed replication processes, not monitoring.
In DB2 you can set the DATA CAPTURE table parameter to NONE, but be aware that this is its default value. You can check the current value for a table with the following query:
SELECT datacapture
FROM syscat.tables
WHERE tabschema = <schema>
AND tabname = <tablename>
You can modify the setting using:
ALTER TABLE <schema>.<tablename> DATA CAPTURE NONE
In addition to the DATA CAPTURE option that Ian described, DB2 v10.1 and newer can also track changes made to tables that are enabled for system-period temporal versioning. System-period versioning is not enabled by default, but if it is, every DML change to the table is automatically captured into a designated history table with the same column layout. Unlike SQL Server's retention policy for tracking changes, the DBA is responsible for pruning old row versions out of DB2 temporal history tables.
The SYSCAT.TABLES view will reveal which tables are enabled for system-period versioning:
SELECT tabschema, tabname FROM syscat.tables
WHERE temporaltype IN ( 'B', 'S' )
The following statement will disable whichever temporal features are enabled ( system-period, business-period, or both):
ALTER TABLE <schema>.<tablename> DROP VERSIONING

Specify max number of databases a user can own

Is this possible?
I would like to have a limit for a user, lets say 5 databases.
So when he tries to issue a CREATE query to create a 6th an exception is thrown.
No, you cannot do this - at least not in a declarative way (just simply specify the max number of databases owned for each user).
The closest you could get with standard SQL Server functionality would be to create a DDL trigger for CREATE DATABASE and in that trigger, check to see if the current user already owns five databases, and in that case, let the trigger fail the operation.
Something along the lines of this (taken from TechNet sample):
CREATE TRIGGER ddl_trig_database
ON ALL SERVER
FOR CREATE_DATABASE
AS
-- here, check to see if current user already owns five databases
-- and if so, fail the trigger by using RAISERROR
GO
look into DDL triggers, with a trigger like this one below you can trap the CREATE DATABASE statement
CREATE TRIGGER ddl_trig_database
ON ALL SERVER
FOR CREATE_DATABASE
AS
--do something here
-- select count(*)from sys.sysdatabases where sid = ???
GO