InterSystems IRIS

Silent Corruption und Undetected Mutation in InterSystems IRIS

Ein Access Failure ist der harmloseste der drei Metadatenfehler: Der Treiber kann den Wert nicht lesen, er wirft eine Exception, und der Fehler ist sofort sichtbar. Der Übersichtsartikel Metadaten-Inkonsistenzen in InterSystems IRIS erkennen und beheben behandelt diesen Fall und die beiden folgenden im Überblick.

In diesem Artikel geht es um die anderen beiden. Keiner von beiden erzeugt eine Fehlermeldung, keiner eine Warnung, einen Log-Eintrag oder einen sichtbaren Hinweis. Eine Zeile lässt sich von jedem Client fehlerfrei lesen und widerspricht trotzdem den Metadaten, die derselbe Client zuvor übermittelt bekommen hat. Ich nenne die beiden Varianten Silent Corruption und Undetected Mutation.

Beide stecken in der Datenbank DATATYPE_SAMPLE, Sie können also jeden Schritt selbst nachvollziehen:

Silent Corruption

Die Tabelle Employee enthält einen gezielt manipulierten Datensatz, der das Verhalten zeigt: die Zeile mit ID = 110. Weder auf den ersten noch auf den zweiten Blick ist an ihr etwas auffällig. Weder der Datenbanktreiber noch das Abfragewerkzeug meldet beim Lesen dieser Zeile ein Problem.

Die Tabelle Employee in SQL DATA LENS mit markierter Zeile ID 110. Die Zelle Name enthält eine sich selbst vermessende Zeichenkette, 10XxXxXxXx20XxXxXxXx und so weiter bis 60 Zeichen, rot markiert.

Erst bei genauem Hinsehen wird klar, dass der Wert in der markierten Zelle nicht zu den Metadaten passt, die der Treiber für diese Spalte übermittelt hat. Die Spalte Name ist als VARCHAR(50) definiert. Der Wert ist 60 Zeichen lang.

Der Reiter Columns für SQLUser.Employee in SQL DATA LENS. Die Spalte Name ist rot markiert und als VARCHAR(50) definiert.

Der Demowert ist so aufgebaut, dass er sich ohne Hilfsmittel prüfen lässt: Er zählt sich in Zehnerblöcken selbst ab und läuft über die Marke 50 hinaus bis 60XxXxXxXx. In einer echten Datenbank wäre der Überhang von einem gewöhnlichen Namen nicht zu unterscheiden.

Warum das ein Problem ist

Es gibt Fälle, in denen dieses Verhalten überhaupt keinen Schaden anrichtet, weil der Treiber die Inkonsistenz nachsichtig behandelt und der Wert ohnehin nur angezeigt wird. Probleme entstehen dort, wo ein nachgelagertes System sich auf die gelieferten Metadaten verlässt. Baut die Weiterverarbeitung auf diesen Definitionen auf, treten Fehler auf, sobald der tatsächliche Inhalt die vereinbarte Schnittstelle verletzt.

ETL-Werkzeuge sind das typische Beispiel. Sie erzeugen Zieltabellen aus den Quell-Metadaten oder leiten Transformationen daraus ab, und ein 60 Zeichen langer Wert, der in einer aus VARCHAR(50) dimensionierten Spalte ankommt, wird abgewiesen oder abgeschnitten. Der Fehler zeigt sich im Zielsystem, weit entfernt von der Zeile, die ihn verursacht hat.

So finden Sie ihn

Die folgende Abfrage ermittelt Datensätze, deren Inhalt von den definierten Metadaten abweicht:

SELECT
 Name,
 CASE WHEN LENGTH(Name) > 50 THEN 1 ELSE 0 END AS Name_LENGTH_CHECK
,SSN,
 CASE WHEN LENGTH(SSN) > 50 THEN 1 ELSE 0 END AS SSN_LENGTH_CHECK
FROM SQLUser.Employee
WHERE
      LENGTH(Name) > 50
OR    LENGTH(SSN) > 50

Sie liefert ausschließlich die fehlerhaften Zeilen. In jeder Zeile ist die betroffene Zelle mit einer 1 gekennzeichnet, wenn der Wert die in den Metadaten definierte Länge überschreitet.

Ergebnisgitter mit einer Zeile. Name_LENGTH_CHECK ist 1 und rot markiert, SSN_LENGTH_CHECK ist 0.

Undetected Mutation

Der zweite Fehler ist subtiler. DATATYPE_SAMPLE enthält einen Datensatz, der eigens dafür verändert wurde: die Zeile mit ID = 120. Auch hier meldet weder der Treiber noch das Abfragewerkzeug beim Lesen ein Problem.

Die Tabelle Employee in SQL DATA LENS. In der Zeile ID 120 zeigt die Zelle Age den Wert 0, rot markiert.

Diesmal scheint der Wert sogar zu den Metadaten zu passen. Die Spalte Age ist als INTEGER definiert, und die Zelle liefert eine ganze Zahl, in diesem Beispiel 0.

Dieser Wert steht so nicht in der Datenbank. Ein direkter Blick auf das zugrunde liegende Global zeigt den tatsächlichen Inhalt: Durch Manipulation wurde eine Zeichenkette in das Feld geschrieben.

Global Browser mit dem Knoten ^poCN.D1Ex.1(20). Der Listenwert beginnt mit 120, gefolgt von der Zeichenkette NoINT, rot markiert; das Panel zum ausgewählten Knoten führt Position 2 als NoINT.

Der Global Browser zerlegt den Knoten ^poCN.D1Ex.1(20) in seine $LISTBUILD-Positionen. Position 2, die als Age projiziert wird, enthält die Zeichenkette "NoINT". Der Treiber kann daraus keine ganze Zahl machen und liefert stattdessen 0. Das Ergebnis ist in sich stimmig und vollständig falsch.

Das ist der Fehlermodus, auf den es im Reporting und bei Migrationen ankommt. Ein Access Failure stoppt den Lauf. Eine Undetected Mutation lässt ihn zu Ende laufen und eine falsche Zahl darin stehen, und eine erzwungene 0 in einer Alters-, Gehalts- oder Mengenspalte wird ohne Fehlermeldung summiert, gemittelt und in Diagramme übernommen.

So finden Sie sie

SELECT
 CAST(Age AS VARCHAR(255)) AS Age,
 ISNUMERIC(CAST(Age AS VARCHAR(255))) AS Age_ISNUMERIC
FROM SQLUser.Employee
WHERE
    ISNUMERIC(CAST(Age AS VARCHAR(255))) = 0

Entscheidend ist die vorgezogene Umwandlung nach VARCHAR: Sie umgeht genau die Typkonvertierung, die vorher die 0 erzeugt hat, und liefert die gespeicherte Repräsentation. Die Abfrage gibt nur die Zeilen mit Metadaten-Inkonsistenz zurück und kennzeichnet die problematische Zelle mit einer 0, wenn der Treiber den Wert nicht als numerisch interpretieren kann.

Ergebnisgitter mit der Spalte Age und dem Wert NoINT sowie Age_ISNUMERIC mit dem Wert 0, beschriftet als der echte Wert und NICHT numerisch.

Die Spalte Age zeigt nun NoINT — den Wert, der wirklich gespeichert war — und Age_ISNUMERIC markiert ihn mit 0.

Fazit

Beide Szenarien zeigen, wie scheinbar wohlgeformte Daten feine Inkonsistenzen verbergen können, besonders in Altsystemen, die an den üblichen Schutzmechanismen vorbeischreiben. Ein Access Failure fällt sofort auf. Silent Corruption und Undetected Mutation bleiben meist unbemerkt und verursachen nachgelagert ernsthafte Probleme, vor allem in Systemen, die auf strikte Metadatentreue angewiesen sind.

Mit der Datenbank DATATYPE_SAMPLE und den beiden Abfragen oben lassen sich solche Fälle von Hand aufspüren. Diese Prüfungen von Hand zu schreiben ist allerdings mühsam und fehleranfällig: Jede Spalte braucht ihr eigenes Prädikat, und die Prädikate müssen bei jeder Änderung der Klassendefinition nachgezogen werden.

SQL DATA LENS erzeugt sie stattdessen. Seit Version 3.22 bietet das SQL-Scripting-Menü SELECT with length check und SELECT with numeric check an; beide bauen die obigen Statements aus den aktuellen Metadaten einer Tabelle, einer View oder einer Stored Procedure. Der SQL-Editor führt sie aus, im Table Viewer rufen Sie sie auf, und der Data Inspector zeigt bei einem Befund, wie ein strukturierter Wert tatsächlich kodiert ist.

Wenn Sie das Werkzeug noch nicht installiert haben, beginnen Sie auf der Download-Seite. Zum dritten Fehlermodus, dem, der tatsächlich eine Exception wirft, siehe Metadaten-Inkonsistenzen in InterSystems IRIS erkennen und beheben.


Dieser Artikel erschien zuerst in der InterSystems Developer Community als Testing Metadata Inconsistencies in InterSystems IRIS Using the DATATYPE_SAMPLE Database (Part II) — Silent Corruption. SQL DATA LENS ist außerdem auf InterSystems Open Exchange gelistet.

← Alle Artikel

Explore your IRIS data from SQL down to globals

Download, unzip, connect. Your first namespace is on screen in about three minutes.

Windows 10, 11 and Windows Server (64-bit) · ~132 MB · version 4.02 · full 30-day Pro trial included