Introduction
Le type de données (datatype) VARCHAR, à ne pas confondre avec VARCHAR2, excite depuis 1992 la curiosité de bien des DBA. Ce datatype est apparu avec Oracle 7 et, dès le début, Oracle a dit de ne pas l'utiliser car il était réservé pour un usage futur. En 2018, soit 26 ans après, Oracle nous dit toujours de ne pas l'utiliser :-) que c'est long le futur...

Et comme je suis quelqu'un de très curieux, j'ai eu envie de voir cela de plus près!



 
Points d'attention
Aucun...



Base de tests
N'importe quelle base Oracle.




Exemples
============================================================================================
Datatypes Oracle officiels et officieux
============================================================================================

Dans la doc officielle d'Oracle https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Data-Types.html#GUID-DF7E10FC-A461-4325-A295-3FD4D150809E, il est marqué "
VARCHAR Data Type
Do not use the VARCHAR data type. Use the VARCHAR2 data type instead. Although the VARCHAR data type is currently synonymous with VARCHAR2, the VARCHAR data type is scheduled to be redefined as a separate data type used for variable-length character strings compared with different comparison semantics."

A noter deux points : contrairement à ce qui est dit, VARCHAR n'est pas vraiment un synonyme de VARCHAR2 mais un sous-type (voir plus bas); en outre, il devrait être utilisé pour des tests de comparaison sémantique différents (de ceux utilisés pour VARCHAR2 ?). Intéressant mais je reste sur ma faim.

Toujours dans la doc officielle d'Oracle, https://docs.oracle.com/database/121/SQLRF/sql_elements001.htm#SQLRF30020, sont répertoriés 23 datatypes.
Ils ne sont cependant pas tous présents, il manque notamment les types VARCHAR, SMALLINT, DECIMAL. En outre, dans la vue DBA_TYPES on a une autre liste, de 58 datatypes, en filtrant sur OWNER IS NULL et PREDIFINED = 'YES'.
               BFILE
               BINARY_DOUBLE
               BINARY_FLOAT
               BLOB
               CHAR
               CLOB
               DATE
               FLOAT
               INTERVAL DAY
               INTERVAL YEAR
               LONG
               LONG RAW
               NCHAR
               NCLOB
               NUMBER
               NVARCHAR2
               RAW
               ROWID
               TIMESTAMP
               TIMESTAMP WITH LOCAL TIME ZONE
               TIMESTAMP WITH TIME ZONE
               UROWID
               VARCHAR2
     
Finalement, pour avoir la liste ultime de ces types de données, il faut ouvrir le fichier stdspec.sql du répertoire $ORACLE_HOME/rdbms/admin.
Et là, stupeur et tremblement, on voit que VARCHAR est un sous-type (subtype) de VARCHAR2, tout comme CHAR d'ailleurs; il hérite donc de ses caractéristiques par un processus classique d'héritage. Difficile de dire que les deux sont différents dans ce cas là mais impossible aussi de dire qu'ils sont synonymes puisque cela reviendrait à dire que CHAR et VARCHAR2 sont synonymes.
     Unix$ more /opt/oracle/srv/12.1.0/rdbms/admin/stdspec.sql
     @@?/rdbms/admin/sqlsessstart.sql
     create or replace
     package STANDARD AUTHID CURRENT_USER is              -- careful on this line; SED edit occurs!
     /********** Types and subtypes, do not reorder **********/
     type VARCHAR2 is NEW CHAR_BASE;
     subtype VARCHAR is VARCHAR2;
     subtype STRING is VARCHAR2;
     subtype LONG is VARCHAR2(32760);
     subtype RAW is VARCHAR2;
     subtype "LONG RAW" is RAW(32760);
     subtype ROWID is VARCHAR2(256);
     subtype CHAR is VARCHAR2;
     subtype CHARACTER is CHAR;
     ...
               

============================================================================================
Peut-on créer une colonne de type VARCHAR?
============================================================================================
Est-il possible de créer une colonne de type VARCHAR? Hé bien non, Oracle la transforme en VARCHAR2!
     SQL> create table TEST01 (ID VARCHAR(30));
     Table created.

     SQL> desc TEST01
     Name                       Null?    Type
     --------------------------------------
     ID                                 VARCHAR2(30)

     SQL> select data_type from dba_tab_cols where owner = 'SYS' and table_name = 'TEST01';
     DATA_TYPE
     ------------------------
     VARCHAR2


Modifier directement le dictionnaire de données
Alors voyons voir ce qu'il est possible de faire au niveau des tables du dictionnaire de données. Tout d'abord j'essaye de récupérer l'id du datatype VARCHAR puisque celui-ci est absent de la doc Oracle.
     SQL> create table TEST_TYPES (NUM NUMBER, DAT_E DATE, VARCHA_R2 VARCHAR2(10), CHA_R CHAR(11), TIMESTAM_P TIMESTAMP);
     Table created.
     
On voit, via la table col$, les id des datatypes.    
     SQL> select object_id from dba_objects where object_name = 'TEST_TYPES';
      OBJECT_ID
     ----------
          79579
         
     SQL> select name, type# from col$ where obj# = 79579 order by name;
     NAME           TYPE#
     -----------------------
     CHA_R           96
     DAT_E           12
     NUM              2
     TIMESTAM_P     180
     VARCHA_R2        1
     
Pour récupérer l'id de VARCHAR, je vais faire quelque chose qu'il ne faut JAMAIS, au grand JAMAIS, faire en prod ou chez un client, je vais modifier à la main le dictionnaire de données d'Oracle :-)  Je crée une boucle pour modifier le type d'une colonne et je vois ensuite dans DBA_TAB_COLS le nom de ce type.
BINGO, l'id du  type VARCHAR est 9.
     declare
     DATATYPE_TABLE VARCHAR2(50) ;
     begin
          for i in 1..200
     loop
          update col$ set type# = i where obj# = 79579 and name = 'VARCHA_R2';
          select data_type INTO DATATYPE_TABLE from dba_tab_cols where owner = 'SYS' and table_name = 'TEST_TYPES' and column_name = 'VARCHA_R2';
          dbms_output.put_line(to_char(i) || ': ' || DATATYPE_TABLE );
     end loop;
     end;
     /
     
     1: VARCHAR2
     2: NUMBER
     3: UNDEFINED
     4: UNDEFINED
     5: UNDEFINED
     6: UNDEFINED
     7: UNDEFINED
     8: LONG
     9: VARCHAR
     ...

Je vais maintenant modifier le datatype d'une colonne avec l'id 9 pour voir si Oracle la considère maintenant comme une colonne de type VARCHAR.    
     SQL> update col$ set type# = 9 where obj# = 79579 and name = 'VARCHA_R2';
     1 row updated.
    
     SQL> commit;
     Commit complete.

Hé bien non, le desc renvoit VARCHAR2...    
     SQL> desc test_types;
     Name         Null?    Type
     ---------------------------------
     NUM                  NUMBER
     DAT_E                DATE
     VARCHA_R2            VARCHAR2(10)
     CHA_R                CHAR(11)
     TIMESTAM_P           TIMESTAMP(6)
     
Ohoh, minute, c'est visiblement la commande DESC qui renvoit une mauvaise info! Dans DBA_TAB_COLS, on a bien VARCHAR :-)   
De plus en plus passionnant! 
     SQL> select data_type from dba_tab_cols where owner = 'SYS' and table_name = 'TEST_TYPES' and column_name = 'VARCHA_R2';
     DATA_TYPE
     ------------------------------------------
     VARCHAR

Aïe, impossible de manipuler une colonne de type VARCHAR    
Bon, maintenant que j'ai modifié le type d'une colonne, est-il possible de manipuler la table?
Visiblement non, j'ai dû énerver Oracle  :-(
     SQL> insert into test_types(VARCHA_R2) values('A');
     insert into test_types(VARCHA_R2) values('A')
                                              *
     ERROR at line 1:
     ORA-00932: inconsistent datatypes: expected VARCHAR got CHAR
    
     SQL> drop table test_types purge;
     Table dropped.
     
On va essayer de contourner le problème : créer une table, y insérer des données et changer le type de la colonne en VARCHAR.    
     SQL> create table TEST_TYPES (COL_V2 VARCHAR2(10));
     Table created.
     
     SQL> insert into test_types values('A');
     1 row created.
     
     SQL> commit;
     Commit complete.
     
     SQL> select object_id from dba_objects where object_name = 'TEST_TYPES';
      OBJECT_ID
     ----------
          79580
     
     SQL> update col$ set type# = 9 where obj# = 79580 and name = 'COL_V2';
     1 row updated.
     
     SQL> commit;
     Commit complete.
    
     SQL> select data_type from dba_tab_cols where owner = 'SYS' and table_name = 'TEST_TYPES' and column_name = 'COL_V2';
     DATA_TYPE
     -------------
     VARCHAR

L'UPDATE du datatype est OK mais il est impossible de faire un SELECT sur cette table dorénavant.
Bon, j'abandonne, il est inutile de vouloir contourner les règles des programmes Oracle mais au moins j'aurais essayé.
     SQL> select * from test_types;
     select * from test_types
            *
     ERROR at line 1:
     ORA-00932: inconsistent datatypes: expected CHAR got VARCHAR


============================================================================================
Des colonnes VARCHAR dans le dictionnaire de données?
============================================================================================
Tables avec VARCHAR
On vient de voir que Oracle nous complique la vie pour créer une colonne de type VARCHAR. Mais lui, il gère ce dataype actuellement ou c'est vraiment pour un avenir plus ou moins lointain? Voyons si dans ma base 12c il y a des colonnes de type VARCHAR dans le dictionnaire de données (pour éviter d'être pollué par mes tests).
Ah ben non, aucune! Le contraire m'eut étonné.
     SQL> select DATA_TYPE, count(*) from dba_tab_cols where owner = 'SYS' and data_type not like '%$%' group by data_type order by 1
     DATA_TYPE                   COUNT(*)
     ---------------------------------------- ----------
     ALERT_TYPE                      3
     ANYDATA                      60
     BINARY_DOUBLE                     41
     BINARY_FLOAT                      3
     BLOB                         78
     CHAR                        991
     CLOB                        786
     DATE                           2784
     DBMS_DBFS_CONTENT_PROPERTIES_T              3
     DS_VARRAY_4_CLOB                  1
     FLOAT                          1
     GRANT_PATH                     11
     HSBLKNAMLST                      6
     HSBLKVALARY                      4
     INTERVAL DAY(0) TO SECOND(0)             12
     INTERVAL DAY(3) TO SECOND(0)             72
     INTERVAL DAY(3) TO SECOND(2)             15
     INTERVAL DAY(5) TO SECOND(1)             20
     INTERVAL DAY(9) TO SECOND(6)             12
     INTERVAL DAY(9) TO SECOND(9)             12
     KOTAD                          1
     KOTADX                          1
     KOTMD                          1
     KOTTB                          1
     KOTTBX                          1
     KOTTD                          1
     LONG                        246
     LONG RAW                      7
     NCHAR                          3
     NCLOB                          3
     NUMBER                          53745
     NVARCHAR2                     83
     PACKAGE_ARRAY                      1
     RAW                           2511
     ROLE_ARRAY                      2
     ROLE_ID_LIST                      2
     ROWID                         58
     SCHEDULER_FILEWATCHER_REQ_LIST              1
     SCHEDULER_FILEWATCHER_RESULT              3
     TIMESTAMP(0)                      6
     TIMESTAMP(0) WITH TIME ZONE              9
     TIMESTAMP(1) WITH TIME ZONE              2
     TIMESTAMP(3)                    177
     TIMESTAMP(3) WITH TIME ZONE            121
     TIMESTAMP(6)                    792
     TIMESTAMP(6) WITH LOCAL TIME ZONE          6
     TIMESTAMP(6) WITH TIME ZONE            508
     TIMESTAMP(9)                     39
     TIMESTAMP(9) WITH TIME ZONE            111
     UNDEFINED                      4
     UROWID                          1
     VARCHAR2                      39450
     XMLTYPE                      72

     53 rows selected.

Tables gérant VARCHAR    
Mais, au fait, est-ce que DBA_TAB_COLS gère les colonnes de type VARCHAR? Voyons sa définition.
Pour cela, allons dans le CDB$ROOT pour avoir la définition des tables et vues du schéma SYS via la fonction DBMS_METADATA.GET_DDL.
     SQL> alter session set container = CDB$ROOT;
     Session altered.
     
     SQL> show con_name
     CON_NAME
     ------------------------------
     CDB$ROOT
     
     SQL> select dbms_metadata.get_ddl('VIEW', 'DBA_TAB_COLS') from dual;
     DBMS_METADATA.GET_DDL('VIEW','DBA_TAB_COLS')
     --------------------------------------------------------------------------------
       CREATE OR REPLACE FORCE NONEDITIONABLE VIEW "SYS"."DBA_TAB_COLS" ("OWNER", "TA
     BLE_NAME", "COLUMN_NAME", "DATA_TYPE", "DATA_TYPE_MOD", "DATA_TYPE_OWNER", "DATA
     _LENGTH", "DATA_PRECISION", "DATA_SCALE", "NULLABLE", "COLUMN_ID", "DEFAULT_LENG
     TH", "DATA_DEFAULT", "NUM_DISTINCT", "LOW_VALUE", "HIGH_VALUE", "DENSITY", "NUM_
     NULLS", "NUM_BUCKETS", "LAST_ANALYZED", "SAMPLE_SIZE", "CHARACTER_SET_NAME", "CH
     AR_COL_DECL_LENGTH", "GLOBAL_STATS", "USER_STATS", "AVG_COL_LEN", "CHAR_LENGTH",
      "CHAR_USED", "V80_FMT_IMAGE", "DATA_UPGRADED", "HIDDEN_COLUMN", "VIRTUAL_COLUMN
     ", "SEGMENT_COLUMN_ID", "INTERNAL_COLUMN_ID", "HISTOGRAM", "QUALIFIED_COL_NAME",
      "USER_GENERATED", "DEFAULT_ON_NULL", "IDENTITY_COLUMN", "SENSITIVE_COLUMN", "EV
     ALUATION_EDITION", "UNUSABLE_BEFORE", "UNUSABLE_BEGINNING", "COLLATION", "COLLAT
     ED_COLUMN_ID") AS
       select
          OWNER, TABLE_NAME,
          COLUMN_NAME, DATA_TYPE, DATA_TYPE_MOD, DATA_TYPE_OWNER,
          DATA_LENGTH, DATA_PRECISION, DATA_SCALE, NULLABLE, COLUMN_ID,
          DEFAULT_LENGTH, DATA_DEFAULT, NUM_DISTINCT, LOW_VALUE, HIGH_VALUE,
          DENSITY, NUM_NULLS, NUM_BUCKETS, LAST_ANALYZED, SAMPLE_SIZE,
          CHARACTER_SET_NAME, CHAR_COL_DECL_LENGTH,
          GLOBAL_STATS,
          USER_STATS, AVG_COL_LEN, CHAR_LENGTH, CHAR_USED,
          V80_FMT_IMAGE, DATA_UPGRADED, HIDDEN_COLUMN, VIRTUAL_COLUMN,
          SEGMENT_COLUMN_ID, INTERNAL_COLUMN_ID, HISTOGRAM, QUALIFIED_COL_NAME,
          USER_GENERATED, DEFAULT_ON_NULL, IDENTITY_COLUMN, SENSITIVE_COLUMN,
          EVALUATION_EDITION, UNUSABLE_BEFORE, UNUSABLE_BEGINNING,
          COLLATION, COLLATED_COLUMN_ID
     from dba_tab_cols_v$
     
DBA_TAB_COLS s'appuyant sur DBA_TAB_COL_V$, voyons sa définition.
Ahah, VARCHAR y est présent :-)  donc ce n'est pas entièrement réservé pour un usage futur.
     SQL> select dbms_metadata.get_ddl('VIEW', 'DBA_TAB_COLS_V$') from dual;
     DBMS_METADATA.GET_DDL('VIEW','DBA_TAB_COLS_V$')
     --------------------------------------------------------------------------------
       CREATE OR REPLACE FORCE NONEDITIONABLE VIEW "SYS"."DBA_TAB_COLS_V$" ("OWNER",
     "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", "DATA_TYPE_MOD", "DATA_TYPE_OWNER", "D
     ATA_LENGTH", "DATA_PRECISION", "DATA_SCALE", "NULLABLE", "COLUMN_ID", "DEFAULT_L
     ENGTH", "DATA_DEFAULT", "NUM_DISTINCT", "LOW_VALUE", "HIGH_VALUE", "DENSITY", "N
     UM_NULLS", "NUM_BUCKETS", "LAST_ANALYZED", "SAMPLE_SIZE", "CHARACTER_SET_NAME",
     "CHAR_COL_DECL_LENGTH", "GLOBAL_STATS", "USER_STATS", "NOTES", "AVG_COL_LEN", "C
     HAR_LENGTH", "CHAR_USED", "V80_FMT_IMAGE", "DATA_UPGRADED", "HIDDEN_COLUMN", "VI
     RTUAL_COLUMN", "SEGMENT_COLUMN_ID", "INTERNAL_COLUMN_ID", "HISTOGRAM", "QUALIFIE
     D_COL_NAME", "USER_GENERATED", "DEFAULT_ON_NULL", "IDENTITY_COLUMN", "SENSITIVE_
     COLUMN", "EVALUATION_EDITION", "UNUSABLE_BEFORE", "UNUSABLE_BEGINNING", "COLLATI
     ON", "COLLATED_COLUMN_ID") AS
       select u.name, o.name,
            c.name,
            decode(c.type#, 1, decode(c.charsetform, 2, 'NVARCHAR2', 'VARCHAR2'),
                    2, decode(c.scale, null,
                      decode(c.precision#, null, 'NUMBER', 'FLOAT'),
                      'NUMBER'),
                    8, 'LONG',
                    9, decode(c.charsetform, 2, 'NCHAR VARYING', 'VARCHAR'),
                    12, 'DATE',
                    23, 'RAW', 24, 'LONG RAW',
                    58, nvl2(ac.synobj#, (select o.name from obj$ o
                     where o.obj#=ac.synobj#), ot.name),
                    69, 'ROWID',
                    96, decode(c.charsetform, 2, 'NCHAR', 'CHAR'),
                    100, 'BINARY_FLOAT',
                    101, 'BINARY_DOUBLE',
                    105, 'MLSLABEL',
                    106, 'MLSLABEL',
                    111, nvl2(ac.synobj#, (select o.name from obj$ o
                      where o.obj#=ac.synobj#), ot.name),
                    112, decode(c.charsetform, 2, 'NCLOB', 'CLOB'),
                    113, 'BLOB', 114, 'BFILE', 115, 'CFILE',
                    121, nvl2(ac.synobj#, (select o.name from obj$ o
                      where o.obj#=ac.synobj#), ot.name),
                    122, nvl2(ac.synobj#, (select o.name from obj$ o
                      where o.obj#=ac.synobj#), ot.name),
                    123, nvl2(ac.synobj#, (select o.name from obj$ o
                      where o.obj#=ac.synobj#), ot.name),
                    178, 'TIME(' ||c.scale|| ')',
                    179, 'TIME(' ||c.scale|| ')' || ' WITH TIME ZONE',
                    180, 'TIMESTAMP(' ||c.scale|| ')',
                    181, 'TIMESTAMP(' ||c.scale|| ')' || ' WITH TIME ZONE',
                    231, 'TIMESTAMP(' ||c.scale|| ')' || ' WITH LOCAL TIME ZO
     NE',
                    182, 'INTERVAL YEAR(' ||c.precision#||') TO MONTH',
                    183, 'INTERVAL DAY(' ||c.precision#||') TO SECOND(' ||
                      c.scale || ')',
                    208, 'UROWID',
                    'UNDEFINED'),
            decode(c.type#, 111, 'REF'),
            nvl2(ac.synobj#, (select u.name from "_BASE_USER" u, obj$ o
                  where o.owner#=u.user# and o.obj#=ac.synobj#),
             ut.name),
            c.length, c.precision#, c.scale,
            decode(sign(c.null$),-1,'D', 0, 'Y', 'N'),
            decode(c.col#, 0, to_number(null), c.col#), c.deflength,
            c.default$, h.distcnt,
            case when SYS_OP_DV_CHECK(o.name, o.owner#) = 1
             then h.lowval
             else null
            end,
            case when SYS_OP_DV_CHECK(o.name, o.owner#) = 1
             then h.hival
             else null
            end,
            h.density, h.null_cnt,
            case when nvl(h.distcnt,0) = 0 then h.distcnt
             -- no histogram
             when h.row_cnt = 0 then 1
             -- hybrid
             when exists(select 1 from sys.histgrm$ hg
                 where c.obj# = hg.obj# and c.intcol# = hg.intcol#
                   and hg.ep_repeat_count > 0 and rownum < 2) then h.row_
     cnt
             -- top-freq
             when bitand(h.spare2, 64) > 0
               then h.row_cnt
             -- freq
             when (bitand(h.spare2, 32) > 0 or h.bucket_cnt > 2049 or
               (h.bucket_cnt >= h.distcnt and h.density*h.bucket_cnt < 1))
             then h.row_cnt
             -- height
             else h.bucket_cnt
            end,
            h.timestamp#, h.sample_size,
            decode(c.charsetform, 1, 'CHAR_CS',
                      2, 'NCHAR_CS',
                      3, NLS_CHARSET_NAME(c.charsetid),
                      4, 'ARG:'||c.charsetid),
            decode(c.charsetid, 0, to_number(NULL),
                    nls_charset_decl_len(c.length, c.charsetid)),
            decode(bitand(h.spare2, 2), 2, 'YES', 'NO'),
            decode(bitand(h.spare2, 1), 1, 'YES', 'NO'),
            decode(bitand(h.spare2, 8), 8, 'INCREMENTAL ', '') ||
          decode(bitand(h.spare2, 128), 128, 'HIST_FOR_INCREM_STATS ', '') ||
          decode(bitand(h.spare2, 256), 256, 'HISTOGRAM_ONLY ', '') ||
          decode(bitand(h.spare2, 512), 512, 'STATS_ON_LOAD ', '') ||
          decode(bitand(h.spare2, 2048), 2048, 'HYBRID_GLOBAL_NDV', ''),
            h.avgcln,
            c.spare3,
            decode(c.type#, 1, decode(bitand(c.property, 8388608), 0, 'B', 'C'),
                   96, decode(bitand(c.property, 8388608), 0, 'B', 'C'),
                   null),
            decode(bitand(ac.flags, 128), 128, 'YES', 'NO'),
            decode(o.status, 1, decode(bitand(ac.flags, 256), 256, 'NO', 'YES'),
                 decode(bitand(ac.flags, 2), 2, 'NO',
                        decode(bitand(ac.flags, 4), 4, 'NO',
                           decode(bitand(ac.flags, 8), 8, 'NO',
                              'N/A')))),
            decode(c.property, 0, 'NO', decode(bitand(c.property, 32), 32, 'YES',
                           'NO')),
            decode(c.property, 0, 'NO', decode(bitand(c.property, 8), 8, 'YES',
                           'NO')),
            decode(c.segcol#, 0, to_number(null), c.segcol#), c.intcol#,
            -- warning! If you update stats related info, make sure to also update
            -- GTT session private stats in cdoptim.sql
            case when nvl(h.row_cnt,0) = 0 then 'NONE'
             when exists(select 1 from sys.histgrm$ hg
                 where c.obj# = hg.obj# and c.intcol# = hg.intcol#
                   and hg.ep_repeat_count > 0 and rownum < 2) then 'HYBRI
     D'
             when bitand(h.spare2, 64) > 0
               then 'TOP-FREQUENCY'
             when (bitand(h.spare2, 32) > 0 or h.bucket_cnt > 2049 or
               (h.bucket_cnt >= h.distcnt and h.density*h.bucket_cnt < 1))
             then 'FREQUENCY'
             else 'HEIGHT BALANCED'
            end,
            decode(bitand(c.property, 1024), 1024,
               (select decode(bitand(cl.property, 1), 1, rc.name, cl.name)
                from sys.col$ cl, attrcol$ rc where cl.intcol# = c.intcol#-1
                and cl.obj# = c.obj# and c.obj# = rc.obj#(+) and
                cl.intcol# = rc.intcol#(+)),
               decode(bitand(c.property, 1), 0, c.name,
                  (select tc.name from sys.attrcol$ tc
                   where c.obj# = tc.obj# and c.intcol# = tc.intcol#))),
            decode(bitand(c.property, 17179869184), 17179869184, 'YES',
               decode(bitand(c.property, 32), 32, 'NO', 'YES')),
            decode(bitand(c.property, 68719476736), 68719476736, 'YES', 'NO'),
            decode(bitand(c.property, 137438953472 + 274877906944),
                  137438953472, 'YES', 274877906944, 'YES', 'NO'),
            decode(c.property, 0, 'NO', decode(bitand(c.property, 8796093022208),
                           8796093022208, 'YES', 'NO')),
     
            case when c.evaledition# is null then null
          else (select name from obj$ where obj# = c.evaledition#) end,
            case when c.unusablebefore# is null then null
          else (select name from obj$ where obj# = c.unusablebefore#) end,
            case when c.unusablebeginning# is null then null
          else (select name from obj$ where obj# = c.unusablebeginning#) end,
          case when (c.type# in (1,8,9,96,112))
            then nls_collation_name(nvl(c.collid, 16382))
            else null end,
          c.collintcol#
     from sys.col$ c, sys."_CURRENT_EDITION_OBJ" o, sys."_HIST_HEAD_DEC" h, sys.user$
      u,
          sys.coltype$ ac, sys.obj$ ot, sys."_BASE_USER" ut, sys.tab$ t
     where o.obj# = c.obj#
       and o.owner# = u.user#
       and o.obj# = t.obj#(+)
       and c.obj# = h.obj#(+) and c.intcol# = h.intcol#(+)
       and c.obj# = ac.obj#(+) and c.intcol# = ac.intcol#(+)
       and ac.toid = ot.oid$(+)
       and ot.type#(+) = 13
       and ot.owner# = ut.user#(+)
       and (o.type# in (3, 4)                     /* cluster, view */
     
            or
            (o.type# = 2    /* tables, excluding iot - overflow and nested tables */
     
         and
         not exists (select null
                   from sys.tab$ t
                  where t.obj# = o.obj#
                    and (bitand(t.property, 512) = 512 or
                     bitand(t.property, 8192) = 8192 or
                     bitand(t.property, power(2,65)) = power(2,65)))))

VARCHAR dans les scripts Oracle    
Pourtant VARCHAR est fréquemment utilisé dans les scripts Oracle mais ce sont souvent des paramètres de fonctions donc du PL/SQL...
Identifions dans le répertoire des scripts Oracle les fichiers ayant des lignes contenant VARCHAR et non pas VARCHAR2.
     [oracle@vbgeneric admin]$ cd $ORACLE_HOME/rdbms/admin/
     [oracle@vbgeneric admin]$ grep -i varchar * | grep -vi varchar2 > ../Liste_VCHAR01.txt

Prenons au hasard cataqjms.sql.
     [oracle@vbgeneric admin]$ vi cataqjms.sq
     create type aq$_jms_header
     oid '00000000000000000000000000021022'
     as object
     (
       replyto     sys.aq$_agent,
       type        varchar(100),
       userid      varchar(100),
       appid       varchar(100),
       groupid     varchar(100),
       groupseq    int,
       properties  aq$_jms_userproparray,

     MEMBER PROCEDURE lookup_property_name (new_property_name IN VARCHAR ),
     ...

Plus curieux, on peut trouver dans ces scripts la table sys.registry$error avec un CREATE TABLE comportant trois colonnes VARCHAR au lieu de VARCHAR2 :-) Dans le fichier txt obtenu, le script affiché est catupstr.sql.
     [oracle@vbgeneric admin]$ grep -i varchar * | grep -vi varchar2 | grep -i CREATE > ../Liste_VCHAR_CREATE.txt
     [oracle@vbgeneric admin]$ vi catupstr.sql
     Rem
     Rem Create error logging table
     Rem
     CREATE TABLE sys.registry$error(username   VARCHAR(256),
                                     timestamp  TIMESTAMP,
                                     script     VARCHAR(1024),
                                     identifier VARCHAR(256),
                                     message    CLOB,
                                     statement  CLOB);
     
     DELETE FROM sys.registry$error;
     commit;
     
Comme vu précédement, DESC remplace VARCHAR par VARCHAR2.
     SQL> desc registry$error
      Name                       Null?    Type
      ----------------------------------------- -------- ----------------------------
      USERNAME                        VARCHAR2(256)
      TIMESTAMP                        TIMESTAMP(6)
      SCRIPT                         VARCHAR2(1024)
      IDENTIFIER                        VARCHAR2(256)
      MESSAGE                        CLOB
      STATEMENT                        CLOB
     
Mais, plus curieux, DBA_TAB_COLS liste aussi du VARCHAR2...
     SQL> select column_name, data_type from dba_tab_cols where owner = 'SYS' and lower(table_name) = 'registry$error' order by 1;
     COLUMN_NAME               DATA_TYPE
     ------------------------------ ------------------------------
     IDENTIFIER               VARCHAR2
     MESSAGE                CLOB
     SCRIPT                   VARCHAR2
     STATEMENT               CLOB
     TIMESTAMP               TIMESTAMP(6)
     USERNAME               VARCHAR2
     
     6 rows selected.
    
Peut-être que le fichier catupstr.sql n'est pas appelé lors du CREATE DATABASE car la définition de SYS.REGISTRY$ERROR est différente de celle du fichier, avec seulement des colonnes VARCHAR2. Ou bien il y a des ALTER TABLE après mais je ne les ai pas trouvés.
     SQL> select dbms_metadata.get_ddl('TABLE', 'REGISTRY$ERROR') from dual;
     DBMS_METADATA.GET_DDL('TABLE','REGISTRY$ERROR')
     --------------------------------------------------------------------------------
       CREATE TABLE "SYS"."REGISTRY$ERROR" SHARING=METADATA
        (    "USERNAME" VARCHAR2(256),
         "TIMESTAMP" TIMESTAMP (6),
         "SCRIPT" VARCHAR2(1024),
         "IDENTIFIER" VARCHAR2(256),
         "MESSAGE" CLOB,
         "STATEMENT" CLOB
        ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
      NOCOMPRESS LOGGING
       STORAGE(INITIAL 65536 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"
      LOB ("MESSAGE") STORE AS BASICFILE (
       TABLESPACE "SYSTEM" ENABLE STORAGE IN ROW CHUNK 8192 RETENTION
       NOCACHE LOGGING
       STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
       PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
       BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT))
      LOB ("STATEMENT") STORE AS BASICFILE (
       TABLESPACE "SYSTEM" ENABLE STORAGE IN ROW CHUNK 8192 RETENTION
       NOCACHE LOGGING
       STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
       PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
       BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT))
     
Et bootstrap$ alors?
Dernier dernier dernier test : forcer la création d'une table via la table bootstrap$. A nouveau, échec et ma base ne démarre même plus...

       SQL> insert into bootstrap$ values(500, 80000, 'CREATE TABLE ZZTEST01 (ID VARCHAR(30)')
       1 row created.

       SQL> commit;
       Commit complete.

       SQL> startup force;
       ORA-00704: bootstrap process failure
       ORA-00600: internal error code, arguments: [16704], [501], [], [], [], [], [], [], [], [], [], []



Conclusion? VARCHAR est un datatype actuellement inexploitable sous Oracle :-)
      

[EDIT 12/05/2019]
Une piste, pour créer une colonne de type VARCHAR, est d'utiliser la procédure décrite ici pour changer le propriétaire d'une table, chose que Oracle ne permet pas par défaut : http://dbaoraclesql.canalblog.com/archives/2019/05/03/37306802.html
A savoir, faire une trace 10046, exécuter un ordre ALTER TABLE *** MODIFY colonne_number VARCHAR2 et voir dans le fichier trace la liste des INSERTs et UPDATEs dans le dictionnaire de données pour un changement de type de colonne. Il suffit ensuite de répéter, à la main, les mêmes opérations mais en remplaçant le type VARCHAR2 par le type VARCHAR :-)