Ceci est un document pondu en 1999 chez Plat par Radu. Théoriquement les droits appartiennent aujourd’hui à Computer Associates.

 

 

 


  

 

 

 

 

 

Radu Caulea, Platinum Technology

 

 

 

 

 

 

 

 

 

 


 

 

Conformité Y2K. 4

Définition. 4

Les années bissextiles. 4

Oracle est certifié Y2000. 4

Oracle et le stockage des dates. 5

Vérification des colonnes mises à jour ou bien utilisées dans les traitements. 5

Vérifier le format par défaut de la date. 5

Format de la date, utilisation du paramètre RR. 5

Domaines. 6

Dates critiques, scenarii 7

Sources à vérifier. 7

PL/SQL. 7

FORMS. 7

REPORTS. 8

PRO*C. 8

Exercices de programmation. 8

Exemple 1. 8

Exemple 2. 8

Exemple 3. 8

Exemple 4. 8

Code. 8

Code 1 – colonnes suspectes dans la base ! 9

Code 2 – recherche du contenu des paramètres NLS. 9

Code 3 – recherche de la plage de dates dans des colonnes de type DATE. 10

Code 4 – recherche de la plage de dates dans des colonnes de type DATE. 10

Code 5 – recherche d’une chaîne de caractères dans les procédures cataloguées 10

Code 6 –généralisation de la recherche. 10

Bugs, problèmes connus. 12

Exports cumulatifs 12

V$ avec date en varchar2. 12

Lister les produits. 12

Problèmes matériels. 12

Questions/Réponses. 13

Le mot de la fin ! 13

Notes. 14

Sources complémentaires sur le WEB. 14

 


Conformité Y2K

 

Définition

 

Une application doit satisfaire les critères suivants pour vérifier les exigences pour l'année 2000 (Y2K) :

 

  • Traiter l'information de date avant, pendant, et après le 1er janvier 2000 sans erreur. Ceci sous entend :

L’entrée des données

La sortie des données

Le stockage des données

Le calcul sur des dates ou portions de dates.

 

  • Fournir les mêmes services avec les mêmes résultats pour les mêmes entrées de la manière stipulée dans la documentation avant, pendant et après le 1er janvier.
  • Répondre d’une manière non ambiguë à la saisie de l’année sur deux caractères.
  • Gérer l’année bissextile 2000.

 

Vous pouvez garantir la conformité Y2K de votre système d’information uniquement si tous les sous-systèmes suivants le sont :

 

  • Le hardware
  • Les systèmes d’exploitation (Clients, Serveurs), les bases de données, les serveurs des bases de données
  • Les applicatifs Clients

 

Les années bissextiles

 

Soyez préparés à tester les années bissextiles. L’année 2000 est bissextile, tandis que 1900 ne l’est pas. A moins que vous n’utilisiez "RR" comme masque de format, Oracle va interpréter 29-FEB-00 comme 1900, et non 2000, or 29 Feb 1900 est une date invalide.

 

Oracle est certifié Y2000

 

Le serveur Oracle est compatible Y2K. Oracle a mené une série de tests pour valider des scenarii visant le contrôle de l’impact de la fin du siècle. Ces scenarii incluent des tests de réplication, recovery (point in time), transactions distribuées, tests réseau, etc. Tous ces tests comportent des vérifications des actions qui traversent la fin du siècle.

 

Ces tests n’éliminent pas le besoin de tester les applications clientes. Dans un premier temps, ces applicatifs devront entre testés sur le serveur lui-même, pour garantir la validité des tests. Ces tests devront avoir lieu même si le logiciel client est garanti conforme Y2K. Ceci du fait qu’il n’existe pas aujourd’hui un algorithme universel pour valider cette conformité.

 

Oracle et le stockage des dates

 

Oracle stocke toutes les informations pertinentes de la date: du siècle à la seconde. C’est pareil pour les utilitaires Oracle : import, export, recovery.

 

Le problème Y2K survient du coté clients qui peuvent ‘supposer’ que toutes les dates sont en format 19’DD’ (par exemple). Dans ce cas, l’applicatif envoie une date ‘incomplète’ au serveur et celui-ci peut bien interpréter d’une manière différente de celle du programmeur ces dates incomplètes. De ce fait, revoyez le code et testez-le !

 

 

Vérification des colonnes mises à jour ou bien utilisées dans les traitements.

 

Egalement, soyez prévenus du fait que votre application peut stocker des dates dans des champs numériques ou alphanumériques. 

 

Oracle suggère que dans le cas d’utilisation des champs non-date pour stocker des dates ces champs soient modifiés. Si cela n’est pas possible, des traitements supplémentaires devront être prévus pour manipuler différemment le contenu de ces champs. Vous pouvez sous certaines contraintes employer des procédures de conversion qui emploient le paramètre ‘RR’ par exemple.

 

Une autre solution est de modifier le format de stockage des dates a l’intérieur de ces champs : 'SYYYY/MM/DD HH24:MI:SS', format qui a l’avantage d’être indépendant de la langue de base (mois en numérique) et d’être naturellement trié !

 

Vérifier le format par défaut de la date

 

Les vues suivantes vous permettent de vérifier les paramètres concernés:

  • V$NLS_DATABASE_PARAMETERS - montre les paramètres initialisés dans init.ora ou bien ceux qui sont là par défaut!
  • NLS_SESSION_PARAMETERS – montre les paramètres modifiés avec une commande ALTER SESSION

 

Les formats décrit le format de date employé lors de l’utilisation de fonctions de type TO_CHAR ou bien TO_DATE pour une des deux actions suivantes :

·         Formatage d’un champ date envoyé par Oracle

·         Formatage d’une date saisie qui sera stockée par Oracle

Dans tous ces cas, le format employé ne modifie pas la représentation interne d’une date pour Oracle !

 

Format de la date, utilisation du paramètre RR.

 

Fixez NLS_DATE = RR-MM-DD dans votre fichier INIT.ORA. (Ou bien une autre combinaison avec RR au lieu de YY). Ceci assure une interprétation cohérente du siècle différent en fonction du siècle courant.  Cohérente à partir de 1950 jusqu’en 2049 (Attention aux saisies de dates de naissance < 1950 ou bien de dates d’effet > 2049!)

 

00-49 sera traduit en 2000 - 2049, 50-99 devient 1950 – 1999, indépendamment du siècle de saisie.

 

Premier test à effectuer: SELECT MONTHS_BETWEEN('01-MAR-99','01-MAR-00') FROM DUAL;

Si vous n’obtenez le résultat escompté, c’est que le format par défaut de la base Oracle n’est pas fiable pour Y2K.

 

Par défaut, Oracle utilise "DD-MON-YY" comme masque de format, si aucune autre indication ne lui est donnée. Vous pouvez en déduire les conséquences des ordres suivants:

 

... WHERE DATE_FIELD > '01-JUL-97'

SELECT MONTHS_BETWEEN('01-MAR-99','01-MAR-00') FROM DUAL;

INSERT INTO orders VALUES (orders_seq.nextval, 100, `10-DEC-99', `02-JAN-00', 2, 1800.00);

 

Oracle Forms V3.0 et antérieurs utilisent "DD-MON-YY" comme format par défaut lors des saisies.

 

Pour modifier le format, utilisez soit

INIT.ORA : NLS_DATE_FORMAT = ‘DD-MON-RR’ ou bien

ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-RR'

 

Cette modification est à faire uniquement si tous les clients garantissent qu’ils n’utilisent pas des dates antérieures à 1950 et ultérieures à 2049.

 

Domaines

 

Le problème Y2K est en fait une question de définition de domaine. Si un cahier des charges est complet, il devrait avoir défini pour chaque colonne participant à la base un domaine relationnel. L’absence d’un domaine de dates mène à l’éventuel stockage de dates incohérentes.

 

Il serait possible de mettre des restrictions de type CHECK pour les données de type DATE.

Par exemple, lors de la saisie, une date de naissance doit être antérieure à la date de saisie, une date d’échéance doit être ultérieure à la date de saisie.

 

Ces restrictions devraient être utilisées à bon escient et généralement indépendantes ou peu dépendantes de la date de saisie (ceci pour garantir la possibilité de réitération d’un traitement qui pourrait être interdit du jour au lendemain (exemple SYSDATE + 1))

 

Si vous avez basé vos CHECK sur des dates absolues, soyez avertis de modifications de syntaxe entre Oracle 7 et 8.

 

La syntaxe suivante est acceptée par ORACLE VERSION 7:

 

create table EMPLOYE

(date_naissance DATE check(date_naissance>'01-JAN-10'));

 

Elle ne l’est pas en ORACLE VERSION 8:

 

ERROR at line 2:

ORA-02436: date or system variable wrongly specified in CHECK constraint

 

Cela devra être écrit en ORACLE VERSION 8 :

 

create table EMPLOYE

(date_naissance DATE check(date_naissance>TO_DATE('01-JAN-1900','DD-MON-YYYY')));

 

Si vous avez des CHECK sur dates avec deux digits, gare à l’IMPORT vers ORACLE VERSION 8 ! Récréez vos tables avant !

 

Dates critiques, scenarii

 

Plusieurs dates critiques pour les tests devraient être prises en considération et testées dans des simulations de type avant, pendant et après:

  • 28/02/1900 (problème d’année bissextile à tort)
  • 31/12/1997, 1/1/1998, 31/12/1998, 1/1/1999, 9/9/1999 (ces dates ont une signification spéciale liée à des ressources spécifiques pour les systèmes d’exploitation);
  • 31/12/1999 (le basculement du siècle);
  • 10/1/2000 (la première date sur neuf digits dans le siècle suivant);
  • 10/10/2000 (la première date sur dix digits dans le siècle suivant);
  • 28/2/2000, 29/2/2000, 1/3/2000 (analyse de l’année bissextile);
  • 1/1/2049, 1/1/2050, 1/1/2051 (vérification de la tranche de 50 ans utilisée notamment par ‘RR’);

 

Des tests devraient être menés pour permettre des simulations de types suivants.

Système arrêté avant la date critique et démarré après.

Système démarré pendant le changement de la date fatidique.

Revenir en arrière (reprises, etc.)

 

Sources à vérifier

 

Une fois les données et leurs domaines analysées, vous pouvez vous pencher sur l’analyse de leurs manipulations. Ceci doit être effectué

  • dans le code existant dans le noyau du serveur (packages, procédures et fonctions stockées)
  • dans le code client (celui qui risque le plus d’être incompatible Y2K) (Attention, le code client peut résider sur la machine serveur !)

Dans cette optique aussi, l’imagination est la seule limite dans la recherche. Chaque logiciel client a ses spécificités de codage, spécificités qui devraient être exploitées au maximum. Voici quelques exemples de vérifications (balayage du texte):

 

PL/SQL

To_char, to_date, YY, MM, DD, instr

FORMS

To_char, to_date, YY, MM, DD, instr

 

REPORTS

To_char, to_date, YY, MM, DD, instr

 

PRO*C

To_char, to_date, substr

 

Exercices de programmation

 

Exemple 1

 

Votre applicatif peut avoir défini un champ ANNEE en NUMBER(2) ou bien CHAR(2).

Lors de l’utilisation des années des deux siècles, ceci mènera à des résultats inattendus

Action : Modifier le champ pour qu’il contienne 4 digits et vérifiez l’emploi de ce champ (19 par défaut, etc.)

 

Exemple 2

 

Votre applicatif peut avoir défini un champ ANNEE en NUMBER(4) ou bien CHAR(4), mais le code pourrait bien manipuler incorrectement ces données ou bien y écrire des années sur deux digits.

Lors de l’utilisation des dates avant 1900, ceci mènera à des résultats inattendus

Action : Vérifier l’inexistence dans votre base des dates < 1900.

 

Exemple 3

 

Examinez vos applicatifs pour déterminer si’ils traitent des dates antérieures à 1950 ou postérieures à 2049 ET qui stockent l’année sur deux digits. Si les deux conditions sont satisfaites, vous ne devrez pas utiliser le format ‘RR’ pour l’année.

Lors de l’utilisation des dates avant 1900, ceci mènera à des résultats inattendus

Action : Modifiez le format ‘YY’ en ‘YYYY

 

Exemple 4

 

L’exemple suivant montre l’interaction entre NLS_DATE_FORMAT et le format ‘RR’.

 

SELECT TO_CHAR(TO_DATE(LAST_DAY(`01-FEB-00'),'DD-MON-RR'), 'MM/DD/RRRR')

  FROM DUAL;

 

Le résultat sera 02/28/2000, ce qui suit la logique d’utilisation de ‘RR’, mais le résultat est faux, du fait que LAST_DAY utilise le NLS_DATE_FORMAT qui par défaut est ‘YY‘!

Action : Modifiez le NLS_DATE_FORMAT a ‘RR’.

 

 

 

Code

 

 

Code 1 – colonnes suspectes dans la base !

 

Le script suivant cherche des noms de colonnes candidates pour stockage des dates mais qui ne sont pas en format date. L’imagination uniquement peut limiter la liste des noms cherchés !

 

 

 

  Name : y2k_col_susp.sql

  Requête qui analyse les colonnes suspectes

  dans une base ORACLE. La suspicion réside

  dans le doute de la déclaration des colonnes

  qui définissent des dates en format numérique

  ou bien texte. Radu Caulea, Platinum Technology

#

        COLUMN table_name  format a25

        COLUMN column_name format a25

        COLUMN owner       format a18

        COLUMN data_type   format a9

        set echo on

        SET pagesize 50000

        break on owner on table_name

        spool y2k_col_susp.lis

        SELECT owner, table_name, column_name, data_type

          FROM all_tab_columns

         WHERE (column_name like '%DATE%'

            or column_name  like '%TIME%'

            or column_name  like '%ANN%'

            or column_name  like '%MOIS%'

            or column_name  like '%TEMPS%'

            or column_name  like '%TEMPS%'

            or column_name  like '%MON%'

            or column_name  like '%YR%'

            or column_name  like '%YEAR%'

            or column_name  like '%DAY%'

            or column_name  like '%DEBUT%'

            or column_name  like 'EXPIR%')

           and data_type != 'DATE'

           and owner != 'SYS' and owner != 'SYSTEM'

         ORDER BY owner, table_name, column_id;

        spool off

 

      

Code 2 – recherche du contenu des paramètres NLS

 

Le script suivant cherche le contenu des paramètres NLS dans l’instance.

 

Doc

  Divers tests de présentation de la date dans le noyau ORACLE

  Bien évidement, le format choisi de la date doit être

  Conforme a ce que l'on veut:

  - compatibilité avec les versions antérieures

  - tolérance mais rigueur concernant les saisies

  - interface facile avec l'existant: ODBC, OCI, etc.

  Radu Caulea, Platinum Technology

#

        COLUMN name  format a25

        COLUMN value format a15

        COLUMN owner       format a18

        COLUMN data_type   format a9

        set echo on

        SET pagesize 50000

 

select name, value, isdefault from v$parameter where name like '%nls%';

select sysdate from dual;

 

Code 3 – recherche de la plage de dates dans des colonnes de type DATE

 

Le script suivant cherche la plage de dates pour UNE TABLE lambda.

Ce script prépare le script suivant pour toutes les tables !

 

Select MIN(Column_Name), MAX(Column_Name)
  from TABLE;

 

 

Code 4 – recherche de la plage de dates dans des colonnes de type DATE

 

 

alter session set nls_date_format='YYYY/MM/DD';

set verify off pagesize 0 feedback off linesize 100

column X format A60 word_wrap

spool date_query.sql

 

select ' select '''||Owner||''' ownr,

        '''||Table_Name||''' tabl,

        '''||Column_Name||''' colmn,

        max('||Column_Name||'),

        min('||Column_Name||')  from '

        ||Owner||'.'||Table_Name||';' X

   from DBA_TAB_COLUMNS

  where Data_Type = 'DATE'

    and Owner not in ('SYS','SYSTEM')

    and Table_Name not in (select View_Name from DBA_VIEWS)

  order by Owner,Table_Name,Column_Name;

 

spool off

spool date_query.lst

@date_query.sql

 

 

 

Code 5 – recherche d’une chaîne de caractères dans les procédures cataloguées

 

Dans cet exemple, nous cherchons la chaîne ‘19’ dans le code

 

SELECT DISTINCT name

  FROM USER_SOURCE

 WHERE INSTR (text, ’19’) > 0;

 

Code 6 –généralisation de la recherche

 

Dans ce code, nous préparons une procédure cataloguée qui recherchera diverses chaînes de caractères, en fonction des paramètres passés.

 

CREATE OR REPLACE PACKAGE valstd

IS

   PROCEDURE progavec (str IN VARCHAR2);

   PROCEDURE pw_rae;

END valstd;

/

CREATE OR REPLACE PACKAGE BODY valstd

IS

   CURSOR objavec_cur (str IN VARCHAR2)

   IS

      SELECT DISTINCT name

        FROM USER_SOURCE

       WHERE UPPER (text) LIKE '%' || UPPER (str) || '%';

       

   PROCEDURE progavec (str IN VARCHAR2)

   IS

   BEGIN

      FOR prog_rec IN objavec_cur (str)

      LOOP

         DBMS_OUTPUT.PUT_LINE (prog_rec.name);

      END LOOP;

   END;

 

   PROCEDURE pw_rae

   IS

      prog_rec objavec_cur%ROWTYPE;

   BEGIN

      progavec ('19');

      progavec ('YY');

      progavec ('MM');

      progavec ('MON');

      progavec ('TO_CHAR');

      progavec ('TO_DATE');

--    etc.

   END;

 


Bugs, problèmes connus

Exports cumulatifs

 

Bug # 778615  les exports cumulatifs ne seront pas correctement importés si un export cumulatif est effectué avant 1 Jan 2000 et le suivant est effectué après.

 

La solution consiste dans un export full le 01/01/2000.

 

Ceci concerne TOUTES les versions 7.

 

V$ avec date en varchar2

 

Bug # 817753  2 des vues  V$ utilisent des champs varchar2 pour contenir des dates

Ceci ne cause pas des problèmes fonctionnels ou opérationnels, mais des scripts utilisateur s‘y reposant peuvent en provoquer.

La solution consiste dans la réécriture des scripts (Notamment les DBAs sont concernés)

 

Des fonctions supplémentaires peuvent être utilisées :

Dans l’exemple suivant, on fait appel au paramètre RR, valable jusqu’en 2049.

 

select to_date( first_time , 'mm/dd/rr hh24:mi:ss' ) from v$loghist ;

 

L’autre vue est V$LOG_HISTORY.

 

Ceci concerne TOUTES les versions 7.

 

Lister les produits

 

Une des manières pour connaître les produits installés est d’utiliser Orainst en choisissant de désinstaller les produits (mais ne PAS les désinstaller).

 

Sur quelques plates-formes (comme Solaris ou Digital Unix) utiliser $ORACLE_HOME/orainst/inspdver

 

Problèmes matériels

 

Effectuez vos tests de préférence sur un mini-LAN indépendant du réseau d’entreprise (architecture minimale : Un serveur, quelques stations, un dérouleur de bande). Faites surtout attention lors des simulations et basculements aux adresses TCP/IP.


Questions/Réponses

 

Q. Comment Oracle réagira-t-il si la date système est modifiée et si l’on doit faire un recovery ?

 

R. Oracle ne tient pas compte de l’heure lors du recovery (sauf pour point-in-time recovery). De ce fait, pas d’inquiétude à avoir. Ce problème peut apparaître régulièrement lors des changements d’heure par exemple, d’où un hiatus dans le temps !

 

Q. Quelles sont les limites du temps pour les OS ?

 

R.   Les tests de compatibilité Oracle sur UNIX ne devraient pas passer au-delà de 2038, limite pour UNIX.

OPEN VMS ne devraient pas poser de problèmes au-delà de la date fatidique Oracle, qui elle est 4712.

Le mot de la fin !

 

Bien qu’Oracle soit conforme 2000, vous pouvez l’utiliser d’une manière non conforme ! Attention !

 


Notes

 

Lire les délimiteurs dans ce texte de la manière suivante :

texte’ comme  simple_quotte texte simple_quotte

« texte » comme double_quotte texte double_quotte

 

2000 est une année bissextile. Pourquoi ?

Une année est bissextile si elle est divisible par 4.

Une année n’est pas bissextile si elle est divisible par 100.

Une année est bissextile si elle est divisible par 400.

      Les tests sont à faire dans cet ordre !

 

Concernant le paramètre NLS_DATE_FORMAT, soyez vigilants et renseignez-le dans la base de registre NT sur les postes serveur et client ! (Oracle Corporate Support Problem Repository Soln# 2065837.6.), variable UNIX, ou bien INIT.ORA

 

 

Sources complémentaires sur le WEB

Ben Lis, blis@nojc.com

Kevin Loney, http://www.kevinloney.com

Oracle Corporation, http://www.oracle.com

Platinum Technology, http://www.platinum.com

 

Le dernier document Oracle concernant la compatibilité des produits est disponible au http://www.oracle.com/year2000/2000/2000.htm

 

Concernant les algorithmes de test, voir http://www.platinum.com/products/year2k/testing.htm, ou

http://www.platinum.com/products/year2k/y2k.htm