Question

If you're halfway through a transaction and perform a DDL statement, such as truncating a table, then the transaction commits.

I was wondering whether this was always the case and by definition, or is there a setting hidden somewhere that would rollback the transaction instead of committing.

Thanks.

Edit to clarify...

I'm not looking to rollback after a truncate. I just want to confirm that statements already carried out are absolutely always going to be committed before a DDL. Just want to make sure there isn't a system property somewhere that someone could set to wreck my code.

I understand the need to commit before and after a DDL, but conceptually I'd have thought the same consistency requirement could be achieved with a rollback before the DDL and a commit after.

Was it helpful?

Solution

No, it will always commit.

If you want to rollback, you'll have to do it before the DDL.

If you want to isolate the DDL from your existing transaction, then you will have to execute it in its' own, separate transaction.

OTHER TIPS

Technically DDL does a commit BEFORE it executes and AFTER it executes.

Yes same link from Cookie but this is a different aspect of the same issue. It's crucial to understand it's not just one commit, there are two and they happen just before and just after.

Actually it will commit IF IT CAN. If it can't successfully commit, the DDL will fail. One way to stop it committing is have a deferred constraint violated.

create table fred (id number);
alter table fred add constraint id_ck check (id >0) initially deferred;
insert into fred values (-1);
SQL> create table junk(val number);
create table junk(val number)
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02290: check constraint (GC_REF.ID_CK) violated
SQL> desc junk
ERROR:
ORA-04043: object junk does not exist

So if you want to prevent an implicit commit, have a dummy table with a deferred constraint. Insert a violating row in it, and you can make sure the transaction can't be committed until that violation is resolved (eg row deleted).

A truncate table or an alter table or a create table do always cause a commit.

Why do you want to rollback when you do a truncate table?

Here is an AskTom article that may help. From the article:

"I was wondering why DDL statements are not executed inside an autonomous transaction (like sequences do), so they wouldn´t affect any pending user transaction...

Can you clarify?

Followup June 24, 2003 - 7am US/Eastern:

that would be as "confusing" as not doing it that way. anyway, you have atrans so if you want to, you can. "

So, if you really need to, you can stick your DDL inside an Autonomous Transaction and do what you want.

EDIT: Bottom line is that unless you go to explicit lengths to "subvert" Oracle, DDL is going to perform a commit. That said, if you absolutely require that a commit is performed at a certain point, why not just perform it explicitly?

DDL statements always performs auto commit,after the execution.

If you want it to rollback in case of failure(in server side), then you can set certain flags to indicate the failure and take the appropriate action.

eg: if you have created a table table1. and at the same time you are inserting a record in other table.

but insertion has failed due to certain reason(set flag=true).Then in that case you can't rollback as create statement is a ddl statement,so you can undo the changes in the database by dropping the table(table1) depending on the value of flag,by Drop statement.

I agree with DCookie and Tom about the autonomous transaction. I was going to state this also.

Example pseudocode:

Do some DML
Call autonomous function, that performs DDL
Do some more DML
rollback or commit all the DML - your choice

I don't see this as being very useful though. If the initial DML and the DDL touch the same table/object, it's not going to work. You'll get contention when you try to perform the DDL. Just like any two transactions blocking each other. And if they're independent objects, I guess I don't see why the execution order matters.

"Always/never" is too strong. For example DDL like CREATE PRIVATE TEMPORARY TABLE from Oracle 18c won't COMMIT your transaction.

Normal scenario:

CREATE TABLE t(i INT);
INSERT INTO t(i) VALUES(21);

CREATE TABLE x(i INT);   -- same for CREATE GLOBAL TEMPORARY TABLE y(i INT); 
ROLLBACK;

SELECT * FROM t;
-- Output:
-- 21

But if you create private table:

CREATE TABLE t(i INT);
INSERT INTO t(i) VALUES(21);

CREATE PRIVATE TEMPORARY TABLE ORA$PTT_temp(i INT);  
-- or
CREATE PRIVATE TEMPORARY TABLE ORA$PTT_tab
AS
SELECT 1 AS c FROM dual;

ROLLBACK;
SELECT * FROM t;
-- Output:
-- no data found

db<>fiddle demo

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top