Introduction
SYS est le user le plus puissant sous Oracle! Mais cela ne signifie pas pour autant qu'il puisse TOUT faire! Même lui a des limites, fixées par les développeurs du SGBD et c'est l'objet de cet article.



Points d'attention
En tant que SYS vous pouvez facilement casser votre base, donc faites bien attention si vous vous connectez avec ce user. A noter que parmi les bonnes pratiques d'Oracle, il est dit qu'il ne faut quasiment jamais se connecter comme AS SYSDBA (user SYS) ou AS SYSOPER (user PUBLIC) mais plutôt avec un user ayant le rôle dba, ce qui est largement suffisant pour les opérations quotidiennes d'administration.

Néanmoins, dans certains cas, la connexion en SYS est indispensable (arrêt/relance de la base par exemple).




Base de tests
N'importe quelle base Oracle.



Exemples
Le logiciel Oracle ne permet pas de faire tout et n'importe quoi, des limites sont posées par les concepteurs du SGBD. Même si vous êtes SYS, plusieurs actions sont impossibles à faire; certaines interdictions sont évidentes comme supprimer le tablespace SYSTEM, d'autres plus étonnantes comme l'impossibilité de supprimer le DB Link d'un autre user,mêmesi cela concerne tous les users.

============================================================================================
Suppression du tablespace SYSTEM : KO

============================================================================================
On commence avec une opération interdite : supprimer le tablespace SYSTEM d'Oracle n'a pas de sens, cela revient à scier la branche sur laquelle on est assis et, fort heureusement, Oracle refuse cette opération. En revanche Unix permet de supprimer les fichiers de ce tablespace même si la base est ouverte mais c'est une autre histoire :-) .
          SQL> show user
          USER is "SYS"

          SQL> drop tablespace SYSTEM;
          drop tablespace SYSTEM
          *
          ERROR at line 1:
          ORA-01550: cannot drop system tablespace


============================================================================================
Annuler une modification sur une table du dictionnaire de données : KO
============================================================================================

On vous a dit et redit de ne jamais rien créer dans le schéma SYS car cela revient à modifier le dictionnaire de données. Donc cela signifie que SYS en a le pouvoir mais, vous allez voir, c'est risqué.

ATTENTION : modifier le dictionnaire de données d'Oracle ne devrait jamais se faire, sauf à des fins de test et ce sur une base qu'on est prêt à sacrifier! Pour plus de prudence, je ne vais pas modifier une table constamment utilisée par Oracle comme DBA_TABLES mais une petite table, toute simple, la fameuse table DUAL.

Récupérons d'abord le code DDL de cette table si nous devions la recréer.
          SQL> desc dual                                 
          Name                       Null?    Type
          ----------------------------------------- -------- ----------------------------
          DUMMY                            VARCHAR2(1)

          SQL> set long 1000000
          SQL> select dbms_metadata.get_ddl('TABLE', 'DUAL') from dual
          DBMS_METADATA.GET_DDL('TABLE','DUAL')
          --------------------------------------------------------------------------------
          CREATE TABLE "SYS"."DUAL" SHARING=METADATA
          (    "DUMMY" VARCHAR2(1)
          ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
          NOCOMPRESS LOGGING
          STORAGE(INITIAL 16384 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
          PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
          BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
          TABLESPACE "SYSTEM"

On modifie la table DUAL en lui ajoutant une colonne. Tiens, sur la 12c cette opération n'est pas possible quand on est dans une PDB. OK, on va basculer vers le CDB$ROOT.
          SQL> alter table dual add TEST_COL VARCHAR2(10 CHAR)
          alter table dual add TEST_COL VARCHAR2(10 CHAR)
          *
          ERROR at line 1:
          ORA-65040: operation not allowed from within a pluggable database

          SQL> alter session set container = CDB$ROOT;
          Session altered.

Dans le CDB$ROOT la modification d'une table du dictionnaire de données est OK si on est SYS.
          SQL> alter table dual add TEST_COL VARCHAR2(10 CHAR);
          Table altered.

          SQL> desc dual
          Name                       Null?    Type
          ----------------------------------------- -------- ----------------------------
          DUMMY                            VARCHAR2(1)
          TEST_COL                        VARCHAR2(10 CHAR)

Je veux maintenant revenir en arrière et, surprise, la suppression de la colonne que j'ai ajoutée est impossible! Le message dit clairement qu'on ne peut pas supprimer une colonne d'une table appartenant à SYS alors qu'on peut en ajouter!
          SQL> alter table dual  drop column TEST_COL
          alter table dual  drop column TEST_COL
          *
          ERROR at line 1:
          ORA-12988: cannot drop column from table owned by SYS

Continuons nos tests : on peut modifier le type d'une colonne des tables du dictionnaire de données.
          SQL> alter table DUAL modify DUMMY NUMBER;
          alter table DUAL modify DUMMY NUMBER
                        *
          ERROR at line 1:
          ORA-01439: column to be modified must be empty to change datatype

          SQL> truncate table dual;
          Table truncated.

          SQL> alter table DUAL modify DUMMY NUMBER;
          Table altered.

          SQL> desc dual;
          Name                       Null?    Type
          ----------------------------------------- -------- ----------------------------
          DUMMY                            NUMBER
          TEST_COL                        VARCHAR2(10 CHAR)

Bon, on a assez joué, recréons proprement la table DUAL avec un DROP et un CREATE TABLE via le code DDL récupéré auparavant. Aïe aïe aïe, impossible de la supprimer en 12c... En 11g c'était OK mais Oracle a resserré les boulons en 12. Comme quoi, se connecter comme SYS peut provoquer des dégats :-(
          SQL> drop table dual;
          drop table dual
                     *
          ERROR at line 1:
          ORA-00604: error occurred at recursive SQL level 1
          ORA-01775: looping chain of synonyms

Pas le choix, on va garder la table dans cet état! Vous avez compris maintenant qu'avec SYS on peut faire des bêtises? D'un autre côté, ces modifications ne semblent pas perturber le fonctionnement de DUAL.
          SQL> select sysdate from dual;
          SYSDATE
          ---------
          06-JUL-17


============================================================================================
Supprimer un DBLink ou un job d'un autre utilisateur : KO
============================================================================================

SYS a accès par défaut, via des rôles, à tous les objets créés par les autres utilisateurs. Néanmoins les DBLink sont gérés à part dans le sens où SYS lui même ne peut pas supprimer le DBLink d'un autre user.

Voyons d'abord un exemple avec une table : SYS peut supprimer la table nouvellement créée d'un autre user sans qu'on ait dû lui donner des droits dessus.
          SQL> show user
          USER is "HR"

          SQL> create table T1(id number);
          Table created.

          SQL> connect SYS / as sysdba
          Enter password:
          Connected.

          SQL> drop table HR.T1 purge;
          Table dropped.

Maintenant, le user HR crée un dblink.
          SQL> show user
          USER is "HR"

          SQL> create database link test_link01 connect to HR identified by HR using 'orcl12c';
          Database link created.

Le user SYS en crée un autre et on le supprime juste pour vérifier la syntaxe de la suppression.
          SQL> connect SYS as sysdba
          Enter password:
          Connected.

          SQL> create database link test_link_SYS connect to HR identified by HR using 'orcl12c';
          Database link created.

          SQL> drop database link test_link_SYS;
          Database link dropped.

Et maintenant, étonnamment, SYS ne peut pas supprimer le DBLink du user HR; bien sur on a préfixé le nom du dblink par le nom du user.
          SQL> drop database link HR.TEST_LINK01;
          drop database link HR.TEST_LINK01
                            *
          ERROR at line 1:
          ORA-02024: database link not found

Pourtant il existe bien, on se connecte comme HR et, tiens tiens, même erreur! La syntaxe pour supprimer un DBLink n'accepte pas que son nom soit préfixé par son schéma.
          SQL> connect HR/HR
          Connected.

          SQL> drop database link HR.TEST_LINK01;
          drop database link HR.TEST_LINK01
                            *
          ERROR at line 1:
          ORA-02024: database link not found

          SQL> drop database link TEST_LINK01;
          Database link dropped.

L'explication est que ce n'est pas une restriction liée à SYS mais à tous les users comme le dit la doc Oracle à l'adresse https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_8010.htm : "You cannot drop a database link in another user's schema, and you cannot qualify dblink with the name of a schema, because periods are permitted in names of database links. Therefore, Oracle Database interprets the entire name, such as ralph.linktosales, as the name of a database link in your schema rather than as a database link named linktosales in the schema ralph."
En résumé, comme les dblinks acceptent les . (point) et @ comme caractères spéciaux en plus de $ # et _ Oracle ne peut pas savoir que user01.dblink01 est le dblink de nom dblink01 du user01 mais que c'est, pour le user courant, un dblink de nom user01.dblink01. C'est pourquoi aucun user, même pas SYS, ne peut référencer un dblink d'un autre schéma et donc le supprimer.

Mais bon, SYS étant un user spécial, on aurait pu s'attendre à ce qu'il ait des droits supplémentaires :-)


============================================================================================
Une partie des données du dictionnaire de données est cachée à SYS
============================================================================================

Quand vous êtes connecté comme SYS, vous avez accès à toutes les tables du dictionnaire de données; c'est cool, on se prend pour le roi de la montagne! Et puis un jour on tombe de haut en découvrant que même SYS n'a pas accès, du moins par défaut, à certaines données.

Pour voir la liste des roles d'une base, il suffit de faire un SELECT dans DBA_ROLES me direz vous.
         SQL> set pagesize 200            
         SQL> select role from dba_roles order by role;
         ROLE
         --------------------------------------------------------------------------------
         ADM_PARALLEL_EXECUTE_TASK
         APEX_ADMINISTRATOR_READ_ROLE
         APEX_ADMINISTRATOR_ROLE
         APEX_GRANTS_FOR_NEW_USERS_ROLE
         APPLICATION_TRACE_VIEWER
         AQ_ADMINISTRATOR_ROLE
         AQ_USER_ROLE
         AUDIT_ADMIN
         AUDIT_VIEWER
         AUTHENTICATEDUSER
         CAPTURE_ADMIN
         CDB_DBA
         CONNECT
         CSW_USR_ROLE
         CTXAPP
         DATAPATCH_ROLE
         DATAPUMP_EXP_FULL_DATABASE
         DATAPUMP_IMP_FULL_DATABASE
         DBA
         DBFS_ROLE
         DBJAVASCRIPT
         DBMS_MDX_INTERNAL
         DV_ACCTMGR
         DV_ADMIN
         DV_AUDIT_CLEANUP
         DV_DATAPUMP_NETWORK_LINK
         DV_GOLDENGATE_ADMIN
         DV_GOLDENGATE_REDO_ACCESS
         DV_MONITOR
         DV_OWNER
         DV_PATCH_ADMIN
         DV_POLICY_OWNER
         DV_PUBLIC
         DV_REALM_OWNER
         DV_REALM_RESOURCE
         DV_SECANALYST
         DV_STREAMS_ADMIN
         DV_XSTREAM_ADMIN
         EJBCLIENT
         EM_EXPRESS_ALL
         EM_EXPRESS_BASIC
         EXECUTE_CATALOG_ROLE
         EXP_FULL_DATABASE
         GATHER_SYSTEM_STATISTICS
         GDS_CATALOG_SELECT
         GGSYS_ROLE
         GLOBAL_AQ_USER_ROLE
         GSMADMIN_ROLE
         GSMUSER_ROLE
         GSM_POOLADMIN_ROLE
         HS_ADMIN_EXECUTE_ROLE
         HS_ADMIN_ROLE
         HS_ADMIN_SELECT_ROLE
         IMP_FULL_DATABASE
         JAVADEBUGPRIV
         JAVAIDPRIV
         JAVASYSPRIV
         JAVAUSERPRIV
         JAVA_ADMIN
         JAVA_DEPLOY
         JMXSERVER
         LBAC_DBA
         LOGSTDBY_ADMINISTRATOR
         OEM_ADVISOR
         OEM_MONITOR
         OLAP_DBA
         OLAP_USER
         OLAP_XS_ADMIN
         OPTIMIZER_PROCESSING_RATE
         ORDADMIN
         PDB_DBA
         PROVISIONER
         RDFCTX_ADMIN
         RECOVERY_CATALOG_OWNER
         RECOVERY_CATALOG_OWNER_VPD
         RECOVERY_CATALOG_USER
         RESOURCE
         SCHEDULER_ADMIN
         SELECT_CATALOG_ROLE
         SODA_APP
         SPATIAL_CSW_ADMIN
         SYSUMF_ROLE
         WM_ADMIN_ROLE
         XDBADMIN
         XDB_SET_INVOKER
         XDB_WEBSERVICES
         XDB_WEBSERVICES_OVER_HTTP
         XDB_WEBSERVICES_WITH_PUBLIC
         XFILES_ADMINISTRATOR
         XFILES_USER
         XS_CACHE_ADMIN
         XS_CONNECT
         XS_NAMESPACE_ADMIN
         XS_SESSION_ADMIN
         94 rows selected.

Maintenant, les DBA curieux iront voir le code DDL de DBA_ROLES et là, surprise, deux roles sont cachés par défaut, même à SYS : PUBLIC et _NEXT_USER. Quelle est la raison derrière cela, je ne sais pas mais preuve est faite que même comme SYS, Oracle ne nous affiche pas toutes les informations. Attention, en 12c, il faut être connecté au CDB$ROOT pour voir la définition de DBA_ROLES.
          SQL> set long 1000000       

          SQL> select dbms_metadata.get_ddl('VIEW', 'DBA_ROLES') from dual;
          ERROR:
          ORA-31603: object "DBA_ROLES" of type VIEW not found in schema "SYS"
          ORA-06512: at "SYS.DBMS_METADATA", line 6478
          ORA-06512: at "SYS.DBMS_SYS_ERROR", line 105
          ORA-06512: at "SYS.DBMS_METADATA", line 6465
          ORA-06512: at "SYS.DBMS_METADATA", line 9202
          ORA-06512: at line 1
          no rows selected

          SQL> show con_name
          CON_NAME
          ------------------------------
          ORCL

          SQL> alter session set container = CDB$ROOT;
          Session altered.

          SQL> select dbms_metadata.get_ddl('VIEW', 'DBA_ROLES') from dual;
          DBMS_METADATA.GET_DDL('VIEW','DBA_ROLES')
          --------------------------------------------------------------------------------
          CREATE OR REPLACE FORCE NONEDITIONABLE VIEW "SYS"."DBA_ROLES" ("ROLE", "ROLE_I
          D", "PASSWORD_REQUIRED", "AUTHENTICATION_TYPE", "COMMON", "ORACLE_MAINTAINED", "
          INHERITED", "IMPLICIT") AS
            select name, user#,
                   decode(password, null,
                       decode(spare4, null, 'NO',
                         decode(REGEXP_INSTR(spare4, '[ST]:'), 0, 'NO',
                            'YES')),
                            'EXTERNAL',    'EXTERNAL',
                            'GLOBAL',      'GLOBAL',
                            'YES'),
                   decode(password, null,
                       decode(spare4, null, 'NONE',
                         decode(REGEXP_INSTR(spare4, '[ST]:'), 0, 'NONE',
                            'PASSWORD')),
                            'EXTERNAL',    'EXTERNAL',
                            'GLOBAL',      'GLOBAL',
                            'APPLICATION', 'APPLICATION',
                            'PASSWORD'),
                   decode(bitand(spare1, 4224), 0, 'NO', 'YES'),
                   decode(bitand(spare1, 256), 256, 'Y', 'N'),
                   decode(bitand(spare1, 4224),
                      128, decode(SYS_CONTEXT('USERENV', 'CON_ID'),
                          1, 'NO', 'YES'),
                      4224, decode(SYS_CONTEXT('USERENV', 'IS_APPLICATION_PDB'),
                           'YES', 'YES', 'NO'),
                      'NO'),
                   decode(bitand(spare1, 32768), 32768, 'YES', 'NO')
          from  user$
          where type# = 0 and name not in ('PUBLIC', '_NEXT_USER')