Rollback DML after DDL fails - sql

I have a situation where I must:
Disable FK constraints for some tables,
Change field values for primary keys which are referenced by foreign keys (which are also updated to match),
Re-enable FK constraints from step 1.
The problem is that re-enabling the constraints in step 3 might fail if changes from step 2 done to primary key fields are not consistent with fields referenced by foreign keys. I'd like to catch that case and rollback the changes done in step 2. As far as I know, running a DDL statement like enabling a constraint would first issue a commit, after which I cannot rollback the changes made in step 2.
Is there any way to achieve this in one standalone script? The process should either completely pass or rollback as if nothing happened. Or is there an alternative to transactions which could revert to the previous state, without doing backup/restore of the whole database?

The way I'd work around this would be to lock each table before doing the update, run queries to manually check for any violations before re-enabling the constraint. If there are any violations you can rollback the update, otherwise the constraint re-enable will do the commit and release the table lock.

You could try doing the DDL in an autonomous transaction. That way, it will be isolated from your DML. If the DDL fails, you could still rollback the DML. However, if the DDL has to "see" the uncommitted DML changes, then you're stuck. I don't think you can get where you want to go.

Related

Is there a way to do a checking on truncate table?

Sometimes I try test scenarios between several schemas , deleting/modifying tables , inserting/updating/deleting queries , some schemas are testing and the others are Important for production. so sometimes by accident I run queries in wrong schemas. so the commit functionality does really help in this scenario.
however Truncate table tab1 doesnt need commit, and if I execute it in a wrong schema .. well you know the scneario.
My question: Is there a workarround like the commit for truncate table like the DML Statment ? If you delete a statment you have to include a commit, or in plsql you have to click the green button to commit.
I use such check , its really annoying every time I want to truncate I have to modify the condition.
select count(1) into cnt from tab1 if cnt =0 then execute'Truncate table tab1'; end if;
I am not searching for flashback. I need a checking on truncate table
As #Boneist said, truncate is DDL statement which implicitly commits. If you are not sure of the action you do in a schema, and want to commit only after a manual verification, then do not TRUNCATE, use DELETE instead.
With DELETE statement, you could control the commit. Having said that, TRUNCATE resets the high watermark back to zero, however, DELETE doesn't. Even if you delete all the rows from the table, Oracle would scan all the blocks under the HWM. Have a look at this AskTom link.
If you are looking to bring back the truncated data, and if you are on 11gR2 and up, you could use the Flashback support for DDL statements.
TRUNCATE is a DDL statement, not DML, and DDL statements automatically include commits. See https://asktom.oracle.com/pls/asktom/f?p=100:11:0%3A%3A%3A%3AP11_QUESTION_ID:7072180788422 for more info.
I'm not entirely sure I understand what it is you're trying to do - you could, as Tom suggests, perhaps use an autonomous transaction to keep the truncate separate? If you're after the ability to separate the commit part from the truncate part (ie. to rollback the truncate if you decide you called it in error), then I'm afraid you're out of luck.

How to Logically DELETE a record in SQLite

I would like to mark a record as deleted instead of actually deleting a record.
My intention is to use an instead of trigger, but I am getting an SQLException that neither I nor Google know how to solve this.
My code:
CREATE TRIGGER IF NOT EXISTS <Trigger>
INSTEAD OF DELETE ON <Table>
FOR EACH ROW
BEGIN
UPDATE <Table>
SET Status = 'D'
WHERE ID = old.ID;
END
My Error:
java.sql.SQLException: cannot create INSTEAD OF trigger on table: main.<Table>
at org.sqlite.NativeDB.throwex(NativeDB.java:210)
at org.sqlite.NativeDB._exec(Native Method)
at org.sqlite.Stmt.executeUpdate(Stmt.java:152)
Assist me, please?
EDIT:
What I really wanted was to activate foreign key enforcement.
Refer here: How do you enforce foreign key constraints in SQLite through Java?
You cannot use INSTEAD OF triggers on tables, and when RAISE-ing an error in BEFORE/AFTER triggers, any updates done in the trigger would also be rolled back.
You could rename your table, create a view for that table, and create lots of INSTEAD OF triggers to implement all the INSERT/UPDATE/DELETE operations.
However, it would be much easier to change your program to just execute the UPDATE when it wants to mark some record.
Instead of triggers are intended for use with views so that you can specify the underlying tables that an action should be carried out on when an insert, update our delete is issued on the view itself.
One thing you could try is to do a before delete trigger then raise an exception. The only thing is I'm not sure if this would also interfere with the update. Maybe worth a try though:
SELECT RAISE(ABORT, 'Prevent delete');

How Do I Ignore Errors When Deleting Records

I'm in the process of testing a large number of schema changes to upgrade our db to run with the latest version of a packaged product we have.
At this point I'm not interested in the data contained in the db, only the schema (i.e. the tables, views, constraints, keys, stored procedures, etc.).
My testing entails running scripts, resolving errors, an re-running the scripts. If I want to re-run the scripts I need to first restore the db to get it back to a known state. Restoring the db is very time consuming as it has lots of data. I would like to "slim down" the db and remove as much data as possible. That way it will be quicker to restore the db and re-run my scripts
When I attempt to delete records from many of the tables ("delete from table-name") I run into constraint errors and the command stops.
Is there a way to allow the command to continue and, in effect, delete all the records in the table where there aren't constraint issues? In other words I'd like the command to ignore errors and continue to delete all the records it can.
Any Suggestions would be greatly appreciated.
Byron above makes a good point; you can disable FOREIGN KEY or CHECK constraints with the ALTER TABLE command:
ALTER TABLE TableName NOCHECK CONSTRAINT ALL
Then do your work, and when finished,
ALTER TABLE TableName CHECK CONSTRAINT ALL
to re-enable constraints. Be careful, though: if you leave your data in an inconsistent state that violates constraints once you re-enable them, future updates can fail due to constraint errors.
Sources:
http://weblogs.sqlteam.com/joew/archive/2008/10/01/60719.aspx
http://technet.microsoft.com/en-us/library/ms190273.aspx

Ensure that tables are not dropped from database

I need to ensure that tables are not dropped from my database. Should I..
Create DDL(or DML ?) trigger that contains COMMIT or create DDL (or DML ?) trigger that contains ROLLBACK ?
Assuming SQL Server there is an example of doing this in BOL
CREATE TRIGGER safety
ON DATABASE
FOR DROP_TABLE, ALTER_TABLE
AS
PRINT 'You must disable Trigger "safety" to drop or alter tables!'
ROLLBACK
;
You would be better off removing permissions from anyone that might DROP the tables inappropriately however. DDL triggers are after triggers, not instead of triggers so a drop table statement might still cause problems even if eventually rolled back.
You can use a DDL trigger to ROLLBACK. DDL is itself a transaction, the trigger is pasrt of the transaction, so you can roll it back.
A better way would be to remove permissions so folk can't delete objects in the first place. With rights to drop objects comes the right to drop triggers too (usually)

Oracle performance - disabling FKs to make DELETE statement work faster?

When deleting from a large table in Oracle - let's call it table X - does it make sense to disable table X's FKs that do not have ON DELETE CASCADE? I'm not referring to disabling FKs on other tables that link to table X, but just disabling FKs on table X to improve the performance of the DELETE statements.
I'm making the indexes on table X unusable, but the DELETE still takes a while.
I think that those FKs don't matter to the performance of the DELETE statement since we're just deleting, and not inserting or updating, so the FKs don't need to be checked. What do you think?
That seems like a really bad idea. No matter what you do, you'll have a period where referential integrity is not enforced on your database. Then you go to put the FKs back in place and, oops, someone has inserted an invalid row.
Furthermore, ALTER TABLE is a DDL statement, so executing it will commit any work up to that point. You'll lose the ability to rollback if something goes wrong elsewhere in your transaction.
Can you look through the explain plan to see why your DELETE statement is taking so long?
Eventually I didn't have to disable those FKs before the archive process starts and enable them when the process ends. But instead, in order to improve performance of the DELETE statements, we had to drop indexes before the archive process starts and recreate them after the archive process finishes. We also committed more often.