HSQLDB - Get current table name inside a trigger - hsqldb

Is there a way to programmatically get the current table's name inside a trigger's body? I mean the table the trigger is defined for.
I'm looking for a way to do it in SQL but a workaround in Java would be fine too.

There is no SQL function that returns the name of the table during the execution of a TRIGGER. It is easy to define a SQL constant with the table name inside the trigger's SQL code. With triggers defined in the Java language, the fire() method is called by the system. This method has a parameter for the table name which can be accessed in the Java trigger code. http://hsqldb.org/doc/guide/triggers-chapt.html#trc_trigger_action_java

Related

SQL audit to capture which method called a stored procedure

We have a audit log table which captures the following data:
old value
new value
table name
field name
changed by
changed on
The audit log is implemented via a SQL trigger.
In our application one stored procedure is called by multiple .NET functions. We want to add a new field in the log which will store the name of the .NET function which called the SP, but we're not sure how this can be passed from .NET to a SQL trigger. Does anyone know to a way to do this?

Can dynamic SQL be called from a trigger in Oracle?

I have a dozen tables of whom I want to keep the history of the changes. For every one I created a second table with the ending _HISTO and added fields modtime, action, user.
At the moment before I insert, modify or delete a record in this tables I call ( from my delphi app ) a oracle procedure that copies the actual values to the histo table and then do the operation.
My procedure generates a dynamic sql via DBA_TAB_COLUMNS and then executes the generated ( insert into tablename_histo ( fields s ) select fields, sysdate, 'acition', userid from table_name
I was told that I can not call this procedure from a trigger because it has to select the table the trigger is triggered on. Is this true ? Is it possible to implement what I need ?
Assuming you want to maintain history using triggers (rather than any of the other methods of tracking history data in Oracle-- Workspace Manager, Total Recall, Streams, Fine_Grained Auditing etc.), you can use dynamic SQL in the trigger. But the dynamic SQL is subject to the same rules that static SQL is subject to. And even static SQL in a row-level trigger cannot in general query the table that the trigger is defined on without generating a mutating table exception.
Rather than calling dynamic SQL from your trigger, however, you can potentially write some dynamic SQL that generates the trigger in the first place using the same data dictionary tables. The triggers themselves would statically refer to :new.column_name and :old.column_name. Of course, you would have to either edit the trigger or re-run the procedure that dynamically creates the trigger when a new column gets added. Since you, presumably, need to add the column to both the main table and the history table, however, this generally isn't too big of a deal.
Oracle does not allow a trigger to execute a SELECT against the table on which the trigger is defined. If you try it you'll get the dreaded "mutating table" error (ORA-04091), and while there are ways to get around that error they add a lot of complexity for little value. If you really want to build a dynamic query every time your table is updated (IMO this is a bad idea from the standpoint of performance - I find that metadata queries are often slow, but YMMV) it should end up looking something like
strAction := CASE
WHEN INSERTING THEN 'INSERT'
WHEN UPDATING THEN 'UPDATE'
WHEN DELETING THEN 'DELETE'
END;
INSERT INTO TABLENAME_HISTO
(ACTIVITY_DATE, ACTION, MTC_USER,
old_field1, new_field1, old_field2, new_field2)
VALUES
(SYSDATE, strAction, USERID,
:OLD.field1, :NEW.field1, :OLD.field2, :NEW.field2)
Share and enjoy.

rewriting query in PostgreSQL

After a db schema change, what was a column is now computed in stored procedure. Is it possible to make this change seamless for application programs?
So that when a program sends a query like
SELECT id,
value
FROM table
...it instead gets a result of
SELECT id,
compute_value() AS value
FROM table
I thought I could use a RULE, but it is not possible to create SELECT rule on existing table.
So the only other option seems to me to create a new table and a view with the name of the existing one. Which, because of the need for INSERT/UPDATE triggers for the view is too complicated. Then I'd rather update all the client applications.
If you know you want to return value, you use a function rather than a stored procedure. Then you'd reference it like:
SELECT id,
your_function_name(parameter) AS value
FROM TABLE
There's an example under "SQL Functions on Composite Types" in the documentation.
Creating a view using the statement above is ideal if your application needs the computed value constantly, otherwise I wouldn't bother.

Force SQL Server column to a specific value

Is it possible to force a column in a SQL Server 2005 table to a certain value regardless of the value used in an insert or update statement is? Basically, there is a bug in an application that I don't have access to that is trying to insert a date of 1/1/0001 into a datetime column. This is producing a SqlDateTime overflow exception. Since this column isn't even used for anything, I'd like to somehow update the constraints on the columns or something in the database to avoid the error. This is obviously just a temporary emergency patch to avoid the problem... Ideas welcome...
How is the value being inserted? If it's through a stored proc... you could just modify the Sproc to ignore that input parameter.
if it's through client-side generated SQL, or an ORM tool, otoh, then afaik, the only option is a "Before" Trigger that "replaces" the value with an acceptable one...
If you're using SQL 2005 you can create an INSTEAD OF trigger.
The code in this trigger wil run in stead of the original insert/update
-Edoode
I'd create a trigger to check and change the value
If it is a third party application then I will assume you don't have access to the Stored Procedure, or logic used to generate and insert that value (it is still worth checking the SPs for the application's database though, to see if you can modify them).
As Charles suggested, if you don't have access to the source, then you need to have a trigger on the insert.
The Microsoft article here will give you some in depth information on creating triggers.
However, SQL Server doesn't have a true 'before insert' trigger (to my knowledge), so you need to try INSTEAD OF. Have a look here for more information. In that article, pay particular note of section 37.7, and the following example (again from that article):
CREATE TRIGGER T_InsertInventory ON CurrentInventory
INSTEAD OF INSERT AS
BEGIN
INSERT INTO Inventory (PartNumber, Description, QtyOnOrder, QtyInStock)
SELECT PartNumber, Description, QtyOnOrder, QtyInStock
FROM inserted
END
Nick.
the simplest hack would be to make it a varchar, and let it insert that as a string into the column.
The more complicated answer is, you can massage the data with a trigger, but it would still have to be valid in the first place. For instance I can reset a fields value in an update/insert trigger, but it would still have to get through the insert first.

Oracle why does creating trigger fail when there is a field called timestamp?

I've just wasted the past two hours of my life trying to create a table with an auto incrementing primary key bases on this tutorial, The tutorial is great the issue I've been encountering is that the Create Target fails if I have a column which is a timestamp and a table that is called timestamp in the same table...
Why doesn't oracle flag this as being an issue when I create the table?
Here is the Sequence of commands I enter:
Creating the Table:
CREATE TABLE myTable
(id NUMBER PRIMARY KEY,
field1 TIMESTAMP(6),
timeStamp NUMBER,
);
Creating the Sequence:
CREATE SEQUENCE test_sequence
START WITH 1
INCREMENT BY 1;
Creating the trigger:
CREATE OR REPLACE TRIGGER test_trigger
BEFORE INSERT
ON myTable
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT test_sequence.nextval INTO :NEW.ID FROM dual;
END;
/
Here is the error message I get:
ORA-06552: PL/SQL: Compilation unit analysis terminated
ORA-06553: PLS-320: the declaration of the type of this expression is incomplete or malformed
Any combination that does not have the two lines with a the word "timestamp" in them works fine. I would have thought the syntax would be enough to differentiate between the keyword and a column name.
As I've said I don't understand why the table is created fine but oracle falls over when I try to create the trigger...
CLARIFICATION
I know that the issue is that there is a column called timestamp which may or may not be a keyword. MY issue is why it barfed when I tried to create a trigger and not when I created the table, I would have at least expected a warning.
That said having used Oracle for a few hours, it seems a lot less verbose in it's error reporting, Maybe just because I'm using the express version though.
If this is a bug in Oracle how would one who doesn't have a support contract go about reporting it? I'm just playing around with the express version because I have to migrate some code from MySQL to Oracle.
There is a note on metalink about this (227615.1) extract below:
# symptom: Creating Trigger fails
# symptom: Compiling a procedure fails
# symptom: ORA-06552: PL/SQL: %s
# symptom: ORA-06553: PLS-%s: %s
# symptom: PLS-320: the declaration of the type of this expression is incomplete or malformed
# cause: One of the tables being references was created with a column name that is one of the datatypes (reserved key word). Even though the field is not referenced in the PL/SQL SQL statements, this error will still be produced.
fix:
Workaround:
1. Rename the column to a non-reserved word.
2. Create a view and alias the column to a different name.
TIMESTAMP is not listed in the Oracle docs as a reserved word (which is surprising).
It is listed in the V$RESERVED_WORDS data dictionary view, but its RESERVED flag is set to 'N'.
It might be a bug in the trigger processing. I would say this is a good one for Oracle support.
You've hinted at the answer yourself. You're using timestamp as a column name but it's also a keyword. Change the column name to something else (eg xtimestamp) and the trigger compiles.
Well, I'm not totally sure about it, but I think this happens because the SQL code used to manipulate and access database objects is interpreted by some interpreter different form the one used to interpret PL/SQL code.
Have in mind that SQL an PL/SQL are different things, and so they are processed differently. So, I think there is some error in one interpreter, just not sure which one is.
Instead of having Oracle maintain a view, use EXECUTE IMMEDIATE (i.e. if 'Rename the column to a non-reserved word' is not an option.
You can execute via EXECUTE IMMEDIATE. IT's not better way but work's and avoid column rename.
In my case rename column will be a caotic way