Introduction
Vous savez qu'avec une commande DDL un Commit implicite est effectué. OK, mais savez-vous qu'en réalité il peut y en avoir deux, un avant et un après? Non? Alors ce post est pour vous!

La règle est la suivante : un Commit a lieu normalement après une commande DDL (si elle n'échoue pas) mais aussi avant cette commande si un ordre DML non validé/non annulé a eu lieu avant la commande DDL.
En résumé :
          commande DML de nom C01
          COMMIT implicite si la commande C01 n'a été ni commitée ni rollbackée
          commande DDL de nom C02
          COMMIT implicite si la commande C02 n'échoue pas

Mais là où ça devient assez vicieux, c'est que le Commit avant le DDL est lié au Parsing de cet ordre DDL. Et là, tenez-vous bien, si le parsing DDL échoue, ce Commit a ou n'a pas lieu selon que l'erreur est syntaxique ou sémantique!

En résumé, un DDL peut être lié à zéro, un ou deux Commit selon que le DDL échoue ou non et qu'il suit ou non un DML non validé ou non annulé.

Ca vous semble confus? OK, on va voir ça en détail!



Points d'attention
Pour reproduire ce que j'écris, pensez à bien faire deux tests DDL, l'un avec une erreur syntaxique et l'autre avec une erreur sémantique.



Base de tests
N'importe quelle base Oracle.



 
Exemples
============================================================================================
Commande DDL KO pour une raison sémantique : le premier Commit est exécuté.
============================================================================================
Je crée une table test01 avec  un champ number et y insère une valeur.
         SQL> select * from test01;
         aucune ligne sélectionnée

         SQL> INSERT INTO TEST01 VALUES (1);
         1 ligne créée.

Je provoque maintenant une erreur sémantique sur un ordre DDL et non pas une erreur syntaxique. Pour cela je fais un CTAS (CREATE TABLE AS SELECT) sur une table inexistante MAIS dont le nom ne pose pas de problème syntaxique. Dans ce cas là, le premier COMMIT est fait : nous le prouvons avec le fait que la valeur insérée ne peut pas être supprimée avec un ROLLBACK suite à l'échec du DDL.
         SQL> CREATE TABLE TEST AS SELECT * FROM TARATATA;
         CREATE TABLE TEST AS SELECT * FROM TARATATA
                       *
         ERREUR à la ligne 1 :
         ORA-00942: Table ou vue inexistante

         SQL> SELECT * FROM TEST01;
         ID
         ----------
         1

Nous voyons que la valeur insérée n'a pas été annulée : suite à l'échec du CTAS, il y a eu un ROLLBACK implicite sur l'ordre DDL mais portant que sur l'ordre DDL, pas sur la transaction. Si je fais maintenant un ROLLBACK explicit, l'INSERT n'est pas annulé car le premier COMMIT lié au DDL a déjà été exécuté; en effet, le CTAS a échoué pour une cause sémantique et pas syntaxique.
         SQL> rollback;
         Annulation (rollback) effectuée.

         SQL> SELECT * FROM TEST01;
         ID
         ----------
         1

============================================================================================
Commande DDL KO pour une raison syntaxique : le premier Commit n'est pas exécuté.
============================================================================================

Maintenant on va exécuter un DDL avec une erreur non pas sémantique mais syntaxique. C'est possible en créant une table avec un nom interdit par Oracle car commençant par $. Dans ce cas là, le premier COMMIT n'est pas exécuté comme le prouvera l'annulation de l'INSERT par un ROLLBACK explicite.
         SQL> INSERT INTO TEST01 VALUES (2);
         1 ligne créée.

         SQL> CREATE TABLE $TEST (id number);
         CREATE TABLE $TEST (id number)
         *
         ERREUR à la ligne 1 :
         ORA-00911: caractère non valide

         SQL> SELECT * FROM TEST01;
         ID
         ----------
         1
         2

La donnée insérée est encore présente dans la table car il n'y a pas eu de ROLLBACK de niveau transaction suite à l'échec du DDL. Maintenant, si je fais un ROLLBACK explicit, j'annule la transaction et la donnée insérée est supprimée de la table. Ceci prouve que le DDL a été annulé avant que le premier COMMIT ne soit exécuté, à la différence du test précédent. C'est lié au fait que, dans ce test, on a provoqué une erreur syntaxique et non sémantique et que Oracle ne les traite pas de la même façon.
         SQL> rollback;
         Annulation (rollback) effectuée.

         SQL> SELECT * FROM TEST01;
         ID
         ----------
         1

============================================================================================
Liens Internet sur le sujet.

============================================================================================
Pour ceux qui veulent en savoir plus, quelques liens Internet vers des sites de référence.


Sur le site Ask Tom, un post de 2002 dit bien que pour un DDL, un Commit est fait AVANT et APRES le DDL!
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:7072180788422
          "DDL is done conceptually like this:
         begin
                  COMMIT;
                  do the ddl;
                  COMMIT;
         exception
                  when others then
                  ROLLBACK;
         raise;
         end;

En cherchant sur le net, je tombe sur un post de Steven Feuerstein, le responsable chez Oracle du PL/SQL qui a écrit je ne sais combien de livres dessus. Il dit la même chose mais en 2016, en reconnaissant, en toute humilité, qu'après 20 ans passés sur Oracle, il apprends encore des choses.
http://stevenfeuersteinonplsql.blogspot.fr/2016/10/execution-of-ddl-in-plsql-commits-twice.html
         "You'd think that after working with Oracle Database and PL/SQL since 1990, I'd know everything.
         What I'd somehow missed was that a commit is also performed before the DDL statement is executed. Oracle Database issues a commit before a DDL statement is executed, and then afterwards as well.

Et puis, en cherchant encore, je tombe sur la doc officielle d'Oracle qui dit la même chose, en expliquant comment est gérée une transaction.
https://docs.oracle.com/cd/B19306_01/server.102/b14220/transact.htm
         "Overview of Transaction Management
         A transaction ends when any of the following occurs:
         A user runs a DDL statement such as CREATE, DROP, RENAME, or ALTER. If the current transaction contains any DML statements, Oracle first commits the transaction, and then runs and commits the DDL statement as a new, single statement transaction."