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

Oracle et le stockage des dates
Vérification des colonnes mises à jour ou bien utilisées dans
les traitements.
Vérifier le format par défaut de la date
Format de la date, utilisation du paramètre RR.
Code 1 – colonnes suspectes dans la
base !
Code 2 – recherche du contenu des
paramètres NLS
Code 3 – recherche de la plage de
dates dans des colonnes de type DATE
Code 4 – recherche de la plage de
dates dans des colonnes de type DATE
Code 5 – recherche d’une chaîne de
caractères dans les procédures cataloguées
Code 6 –généralisation de la
recherche
Sources complémentaires sur le WEB
Une application doit satisfaire les
critères suivants pour vérifier les exigences pour l'année 2000 (Y2K) :
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.
Vous pouvez garantir la conformité
Y2K de votre système d’information uniquement si tous les sous-systèmes
suivants le sont :
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.
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:
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.
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 !
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:
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.)
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 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):
To_char, to_date, YY, MM, DD, instr
To_char, to_date, YY, MM, DD, instr
To_char, to_date, YY, MM, DD, instr
To_char, to_date, substr
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.)
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.
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’
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’.
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.
#
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
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.
#
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;
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;
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
Dans cet exemple, nous
cherchons la chaîne ‘19’ dans le code
SELECT DISTINCT name
FROM
USER_SOURCE
WHERE INSTR (text, ’19’)
> 0;
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)
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;
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.
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.
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
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.
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.
Bien
qu’Oracle soit conforme 2000, vous pouvez l’utiliser d’une manière non
conforme ! Attention !
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