Phase 3 (Kern): Laufzeitbibliothek, Bildschirm und Datei-E/A
Setzt den OpenSpec-Change phase-3-runtime-bildschirm um (77/77 Aufgaben). Abdeckung laut Inventar: 195 implementiert, 37 offen, 53 Non-Feature. Vollstaendigkeits-Inventar - docs/inventar.md mit 285 Eintraegen aus den Themenlisten von bas7advr.hlp und qb45advr.hlp, je mit Status und Fundstelle - crates/tb-frontend/tests/inventar.rs haelt die Tabelle in beide Richtungen gegen den Code; der Abdeckungsstand kann nicht veralten Bruchschritt (Puffer, Host, Korpus) - Cell/TextScreen ziehen ratatui-frei nach tb-runtime::screen; tb-ui behaelt Farbabbildung, Widget und den neuen Terminal-Host - Host wechselt vom Zeichenstrom auf Anzeige des Zellenpuffers plus Ereignisse (Taste, Groessenaenderung, Abbruch) - Korpusvergleich auf getrimmten Bildschirm-Snapshot; die acht bestehenden Sollausgaben blieben dabei unveraendert Groessenunabhaengigkeit - 80x25 ist nirgends mehr eine feste Grenze; Groessenaenderungen waehrend der Ausfuehrung werden zugestellt (Inhalt oben links erhalten, Cursor und VIEW PRINT geklemmt) - Korpusnachweis: dasselbe Programm bei 80x25 und 120x40 mit je eigener Sollausgabe, plus ein Programm mit Groessenwechsel mitten im Lauf Bibliothek - Breite Unicode-Zeichen belegen zwei Zellen (Cursor, POS, Randumbruch) - Bildschirm: CLS, COLOR, LOCATE, WIDTH, VIEW PRINT, SCREEN, CSRLIN, POS - Tastatur: INKEY$, INPUT$, Funktionstasten-Makros (KEY n / LIST / ON) - PRINT USING, LPRINT USING, FORMAT$, SetFormatCC - Mathematik mit kompatiblem PRNG (gleiche Saat, gleiche Folge) - Datum und Zeit mit Serienwerten ab 1899 - Finanzmathematik: FV#, PV#, Pmt#, IPmt#, PPmt#, NPer#, Rate#, NPV#, IRR#, MIRR#, SLN#, SYD#, DDB# - Datei-E/A: sequenziell, RANDOM (Recordpuffer und UDT-Variablen), BINARY, FIELD/LSET/RSET, Statusfunktionen, Dateisystem, MK$/CV - System: ENVIRON, FRE, CLEAR, TRON/TROFF, STACK, ERDEV, ERR-Anweisung Altlasten aus Phase 2 - ON ERROR GOTO auf Modulebene ist aus Prozeduren ansprechbar (prozeduruebergreifender Fixup im Codegenerator) - DATA behaelt seinen Rohtext (Gross-/Kleinschreibung, innerer Leerraum) - Die vier TODO-verify-Zellen der Konvertierungsmatrix sind aufgeloest Vom Inventar aufgedeckte Fehler - Zwoelf Non-Features wies der Compiler entgegen der Phase-1-Spec nicht ab (CALLS, SSEG, POINT, VIEW, COM, PEN, STRIG, STICK, die String*-Routinen, LINE und OPEN "COMn:") -- geschlossen - Drei Gruppen fehlten im urspruenglichen Umfang: Finanzmathematik, Record-Konvertierung, Rest der Dateisystemfunktionen - bas7advr.hlp allein ist keine vollstaendige Quelle; das Inventar bildet die Vereinigung mit qb45advr.hlp Neue Changes - phase-3-isam: schliesst Phase 3 ab (Speicherschicht redb) - phase-3-ortszeit: zieht die UTC-Abweichung zurueck Neue Abhaengigkeit: unicode-width. Dokumentiert: sprachreferenz.md und tbvm-design.md sind TODO-frei, docs/bibliothek.md neu, PLAN.md fortgeschrieben. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2
openspec/changes/phase-3-isam/.openspec.yaml
Normal file
2
openspec/changes/phase-3-isam/.openspec.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-09-03
|
||||
209
openspec/changes/phase-3-isam/design.md
Normal file
209
openspec/changes/phase-3-isam/design.md
Normal file
@@ -0,0 +1,209 @@
|
||||
## Context
|
||||
|
||||
Siehe proposal.md — Why. Technisch relevant ist der Zustand nach
|
||||
`phase-3-runtime-bildschirm`:
|
||||
|
||||
- Die Dateitabelle, die Recordpuffer und die UTF-32-Serialisierung fester
|
||||
Textfelder existieren (Capability `datei-eio`) und sind die Grundlage,
|
||||
auf der ISAM die Sätze ablegt.
|
||||
- Die Laufzeitfehler 81–89 sind in `tb_runtime::errors` bereits
|
||||
vorhanden; dieser Change liefert ihre Auslöser.
|
||||
- Vom ISAM-Sprachumfang existiert heute nur die Parser-Klausel
|
||||
`OPEN … FOR ISAM` (`parser.rs`). Die ISAM-Anweisungen haben weder
|
||||
Grammatik noch Signatur — sie enden in „unbekannter Bezeichner".
|
||||
- Das Sprachinventar (`docs/inventar.md`) führt die ISAM-Elemente mit
|
||||
Status `offen` und ist der maßgebliche Umfangsnachweis.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- Der volle dokumentierte ISAM-Sprachumfang läuft, nicht eine Auswahl.
|
||||
- Die Cursor-Semantik des Vorbilds ist exakt abgebildet — sie ist der
|
||||
Teil, den keine Fremdbibliothek liefert.
|
||||
- Speicher, Indizes und Transaktionen kommen aus einer erprobten
|
||||
Bibliothek statt aus Eigenbau.
|
||||
- Phase 3 ist mit diesem Change abgeschlossen.
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- Leistungsoptimierung des Satzzugriffs — ISAM-Programme des Vorbilds
|
||||
arbeiten auf Datenmengen, die jede heutige Speicherschicht mühelos
|
||||
trägt.
|
||||
- Nebenläufiger Zugriff mehrerer Prozesse auf dieselbe Datenbankdatei
|
||||
über die Satzsperren aus `datei-eio` hinaus.
|
||||
- Lesen von Datenbankdateien des Vorbilds.
|
||||
|
||||
## Decisions
|
||||
|
||||
### D1: `redb` als Speicherschicht
|
||||
|
||||
Die Datenbankdatei ist eine `redb`-Datei. Sätze und Indexeinträge liegen
|
||||
darin als Key-Value-Paare; `redb` liefert B-Baum, Transaktionen und
|
||||
Crash-Sicherheit.
|
||||
|
||||
*Warum nicht Eigenbau:* Seitenverwaltung, B-Baum und crash-sichere
|
||||
Transaktionen sind gelöste Probleme mit langen Fehlerkatalogen. Der
|
||||
projektspezifische Teil ist die ISAM-Semantik, nicht der Baum darunter.
|
||||
|
||||
*Warum nicht SQLite:* Zöge eine C-Bibliothek in jedes von `tbc build
|
||||
--exe` erzeugte Binary. Der eigentliche Grund ist aber semantisch: ISAM
|
||||
hat einen *stabilen, benannten Cursor*, der Änderungen überlebt und sich
|
||||
vorwärts wie rückwärts bewegt — ein SQL-Cursor ist ein
|
||||
Ergebnismengen-Iterator. Die Abbildung wäre aufwendiger als der Gewinn.
|
||||
Die für Stufe 2 geplante SQL-Erweiterung bleibt davon unberührt; sie ist
|
||||
eine eigene Sprachebene und kann später ihren eigenen Speicher wählen.
|
||||
|
||||
*Was `redb` nicht liefert und wir bauen:* Sekundärindizes,
|
||||
Savepoints innerhalb einer Transaktion, die Cursor-Semantik.
|
||||
|
||||
### D2: Datenmodell — Sätze und Indizes als getrennte Tabellen
|
||||
|
||||
Je Tabelle eine Satztabelle `satz-id → Satzbytes` und je Index eine
|
||||
Tabelle `Schlüsselbytes → satz-id`. Satz-IDs sind monoton vergebene
|
||||
Zahlen und werden nie wiederverwendet.
|
||||
|
||||
*Warum getrennt:* `SETINDEX` wechselt die Durchlaufordnung zur Laufzeit;
|
||||
mit Indextabellen ist das ein Wechsel der zu lesenden Tabelle, ohne die
|
||||
Sätze anzufassen. `MOVEPREVIOUS` und die `SEEK`-Familie sind dann
|
||||
Bereichsabfragen auf einer geordneten Tabelle.
|
||||
|
||||
*Warum IDs nicht wiederverwendet werden:* Der Cursor merkt sich eine
|
||||
Satz-ID. Würde sie nach `DELETE` neu vergeben, könnte ein Cursor still
|
||||
auf einen fremden Satz zeigen.
|
||||
|
||||
### D3: Schlüsselkodierung muss ordnungserhaltend sein
|
||||
|
||||
Indexschlüssel werden so kodiert, dass die Byte-Reihenfolge der Kodierung
|
||||
der fachlichen Reihenfolge entspricht — Zahlen mit vorzeichenrichtiger
|
||||
Kodierung fester Breite, Texte nach der in D4 festgelegten Ordnung,
|
||||
mehrspaltige Schlüssel als Verkettung mit eindeutigem Trenner.
|
||||
Absteigende Spalten werden durch Invertierung der Bytes abgebildet.
|
||||
|
||||
*Warum das die kritische Stelle ist:* `redb` ordnet nach Bytes. Jede
|
||||
Ordnungsverletzung in der Kodierung äußert sich als falsche
|
||||
Satzreihenfolge — ein Fehler, der erst bei bestimmten Datenwerten
|
||||
sichtbar wird. Ein Eigenschaftstest über zufällige Wertepaare
|
||||
(Kodierungsvergleich = fachlicher Vergleich) gehört deshalb zur
|
||||
Umsetzung.
|
||||
|
||||
*Mehrspaltige Präfixsuche* fällt aus dieser Kodierung ab: Suche mit
|
||||
weniger Werten als Spalten ist eine Bereichsabfrage über das
|
||||
Schlüsselpräfix.
|
||||
|
||||
### D4: Sortierordnung explizit festlegen
|
||||
|
||||
Texte werden nach Unicode-Codepoints geordnet, Groß- und Kleinschreibung
|
||||
unterschieden. Es ist dieselbe Ordnung, die der Vergleichsoperator des
|
||||
Dialekts auf Strings anwendet.
|
||||
|
||||
`TEXTCOMP` gibt es in der Original-Hilfe nicht (Befund aus Aufgabe 1.1,
|
||||
2026-09-03); die Ordnung braucht deshalb keine eigene Vergleichsfunktion,
|
||||
sondern muss nur mit dem Stringvergleich der Sprache übereinstimmen.
|
||||
|
||||
*Warum nicht sprachabhängige Sortierung:* Sie machte die Reihenfolge
|
||||
plattform- und locale-abhängig und damit die Korpustests unreproduzierbar.
|
||||
Das Vorbild ordnete nach Zeichencodes einer festen Codepage; Codepoints
|
||||
sind die direkte Entsprechung unter der bereits getroffenen
|
||||
Unicode-Entscheidung. Die Ordnung wird in docs/sprachreferenz.md
|
||||
festgehalten, weil sie beobachtbar ist.
|
||||
|
||||
### D5: Cursor als Wert, nicht als Bibliotheks-Iterator
|
||||
|
||||
Der Cursor je Dateinummer ist ein eigener Zustand: aktiver Index,
|
||||
zuletzt besuchte Satz-ID und ein Kennzeichen „unpositioniert". Jede
|
||||
Bewegung ist eine frische Bereichsabfrage ab dem gemerkten Schlüssel.
|
||||
|
||||
*Warum keine gehaltenen Iteratoren:* Der ISAM-Cursor überlebt
|
||||
Satzänderungen und Transaktionsgrenzen; ein gehaltener Iterator über eine
|
||||
Transaktion tut das nicht. Ein Cursor als Wert bildet außerdem
|
||||
„unpositioniert" (Fehler 85) direkt ab, statt es aus einem
|
||||
Iteratorzustand ableiten zu müssen.
|
||||
|
||||
*Preis:* Jede Bewegung kostet eine Suche statt eines Schritts. Bei den
|
||||
Datenmengen dieser Programme irrelevant; siehe Non-Goals.
|
||||
|
||||
### D6: Savepoints als Rücknahmeprotokoll
|
||||
|
||||
`BEGINTRANS` öffnet eine Schreibtransaktion. Innerhalb davon führt die
|
||||
Laufzeit ein Protokoll der Änderungen; die Funktion `SAVEPOINT` merkt
|
||||
sich eine Position darin und liefert deren Kennung, `ROLLBACK` mit dieser
|
||||
Kennung spielt das Protokoll bis dorthin rückwärts ab. `ROLLBACK ALL` und
|
||||
`COMMITTRANS` nutzen die Transaktion der Bibliothek direkt.
|
||||
|
||||
*Warum ein eigenes Protokoll:* Verschachtelte Rücknahmepunkte gehören
|
||||
nicht zum Funktionsumfang von `redb`. Das Protokoll ist der kleinste
|
||||
Weg dorthin und bleibt auf den Umfang einer laufenden Transaktion
|
||||
begrenzt.
|
||||
|
||||
### D7: Fehler 89 und `SETMEM` bekommen eine echte Grenze
|
||||
|
||||
`SETMEM` ist eine Funktion: sie ändert die Obergrenze des ISAM-Puffers um
|
||||
den übergebenen Betrag und liefert die danach verfügbare Größe.
|
||||
Überschreiten der Grenze löst Fehler 89 aus. Ohne Grenze wäre der Code nie
|
||||
erreichbar und die Anweisung eine Attrappe.
|
||||
|
||||
*Abweichung:* Die Bedeutung in Bytes entspricht nicht dem
|
||||
DOS-Speichermodell des Vorbilds und wird in docs/sprachreferenz.md
|
||||
dokumentiert.
|
||||
|
||||
### D8: Reihenfolge der Umsetzung
|
||||
|
||||
```
|
||||
1. Frontend: Grammatik + Signaturen -> Elemente werden benannt
|
||||
2. Speicher: Datei, Satztabelle, Schluesselkodierung (+ Eigenschaftstest)
|
||||
3. Indizes: CREATEINDEX/SETINDEX/GETINDEX$/DELETEINDEX
|
||||
4. Cursor: MOVE-Familie, SEEK-Familie, EOF
|
||||
5. Saetze: INSERT/RETRIEVE/UPDATE/DELETE, Eindeutigkeit
|
||||
6. Transaktionen: BEGINTRANS/COMMITTRANS/ROLLBACK[ ALL]/SAVEPOINT
|
||||
7. Rest: SETMEM, DELETETABLE, BOF, Formatversion
|
||||
```
|
||||
|
||||
Schritt 1 zuerst, weil er allein schon den Guiding-Principle-Verstoß
|
||||
behebt: ISAM-Programme werden ab da namentlich abgewiesen statt mit
|
||||
„unbekannter Bezeichner". Schritt 2 vor allem anderen, weil die
|
||||
Schlüsselkodierung jede spätere Ordnung bestimmt.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **Fehlerhafte Schlüsselkodierung fällt erst bei bestimmten Daten auf**
|
||||
→ Eigenschaftstest über zufällige Wertepaare je Spaltentyp:
|
||||
Byte-Vergleich der Kodierung MUSS dem fachlichen Vergleich entsprechen.
|
||||
Läuft vor allem Weiteren.
|
||||
- **Der genaue ISAM-Sprachumfang stammt aus der Original-Hilfe und ist
|
||||
bislang nur aus zweiter Hand belegt** → Das Inventar aus
|
||||
`phase-3-runtime-bildschirm` ist die maßgebliche Liste; findet die
|
||||
Erhebung dort weitere Elemente, gehören sie in diesen Change. Die
|
||||
Aufzählung im Proposal ist ein Mindestumfang, keine Obergrenze.
|
||||
- **Cursorverhalten an den Rändern ist die häufigste Fehlerquelle**
|
||||
(`EOF` nach `MOVENEXT` am Ende, Cursor nach `DELETE`, nach `SETINDEX`,
|
||||
nach `ROLLBACK`) → je ein Korpustest pro Randfall, nicht ein
|
||||
Sammeltest.
|
||||
- **Neue Abhängigkeit in `tb-runtime`, die bisher keine hatte** →
|
||||
bewusst; die Alternative wäre ein eigener transaktionaler B-Baum.
|
||||
Die Abhängigkeit bleibt auf das ISAM-Modul beschränkt.
|
||||
- **Das Rücknahmeprotokoll kann bei langen Transaktionen wachsen** →
|
||||
begrenzt auf die laufende Transaktion; `COMMITTRANS` beendet sie. Falls
|
||||
eine Grenze nötig wird, ist Fehler 89 der dafür vorgesehene Ausgang.
|
||||
- **Eigenes Dateiformat heißt: keine Vorbild-Datenbanken lesbar** →
|
||||
bewusst entschieden, dieselbe Linie wie UTF-32-Records; steht in
|
||||
docs/dateiformate.md und in der Sprachreferenz.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
Rein additiv — es gibt heute keine ISAM-Funktionalität und keine
|
||||
Datenbankdateien im Feld. Die einzige sichtbare Änderung an bestehendem
|
||||
Verhalten: `OPEN … FOR ISAM` löst nicht mehr Laufzeitfehler 73 aus,
|
||||
sondern arbeitet.
|
||||
|
||||
Die Datenbankdatei trägt von der ersten Fassung an eine Formatversion,
|
||||
damit spätere Änderungen abgewiesen statt fehlinterpretiert werden.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Genaue Argumentformen einzelner ISAM-Anweisungen (etwa die Schreibweise
|
||||
der Spaltenliste bei `CREATEINDEX`): bei der Umsetzung aus der
|
||||
Original-Hilfe zu übernehmen. Berührt weder Datenmodell noch
|
||||
Aufgabenschnitt.
|
||||
- Konkreter Vorgabewert der `SETMEM`-Grenze: bei der Umsetzung zu wählen
|
||||
und zu dokumentieren.
|
||||
104
openspec/changes/phase-3-isam/proposal.md
Normal file
104
openspec/changes/phase-3-isam/proposal.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Phase 3 (Abschluss) — ISAM-Datenbankunterstützung
|
||||
|
||||
## Why
|
||||
|
||||
Die Leitplanke „Vollständigkeit ist das Soll" und die Entscheidung vom
|
||||
2026-09-02 legen fest: ISAM wird implementiert, es ist kein Non-Feature.
|
||||
Heute existiert davon nur eine Parser-Klausel — `OPEN … FOR ISAM typname
|
||||
tabellenname AS #n` wird erkannt und auf den „nicht verfügbar"-Marker
|
||||
abgesenkt. Die eigentlichen ISAM-Anweisungen und -Funktionen
|
||||
(`CREATEINDEX`, `SETINDEX`, `INSERT`, `RETRIEVE`, `UPDATE`, `DELETE`, die
|
||||
`MOVE`- und `SEEK`-Familien, die Transaktionsanweisungen) besitzen im
|
||||
Frontend **keine Signatur**. Sie enden damit in „unbekannter Bezeichner"
|
||||
bzw. einem generischen Syntaxfehler — genau der Fall, den der Guiding
|
||||
Principle als Bug definiert: ein dokumentiertes Feature wird still und
|
||||
ohne Namensnennung abgewiesen.
|
||||
|
||||
Die Laufzeitfehler 81–89 des ISAM-Bereichs sind bereits als
|
||||
`tb_runtime::errors` implementiert und warten auf ihre Auslöser.
|
||||
|
||||
Dieser Change schließt Phase 3 ab. Der vorausgehende Change
|
||||
`phase-3-runtime-bildschirm` liefert die Datei-E/A-Grundlage
|
||||
(Dateitabelle, Recordpuffer, UTF-32-Festtextfelder), auf der ISAM
|
||||
aufsetzt, sowie das Inventar, in dem die ISAM-Elemente ihren Status
|
||||
führen.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **ISAM-Elemente erhalten Frontend-Signaturen**: Sämtliche in der
|
||||
Original-Hilfe dokumentierten ISAM-Anweisungen und -Funktionen werden
|
||||
in Grammatik und Signaturprüfung aufgenommen, damit ihre Verwendung
|
||||
namentlich diagnostiziert statt als unbekannter Bezeichner behandelt
|
||||
wird. Den maßgeblichen Umfang bestimmt das Sprachinventar aus
|
||||
`phase-3-runtime-bildschirm`; nach heutigem Stand umfasst er
|
||||
mindestens `CREATEINDEX`, `DELETEINDEX`, `SETINDEX`, `GETINDEX$`,
|
||||
`INSERT`, `RETRIEVE`, `UPDATE`, `DELETE`, `DELETETABLE`, `MOVEFIRST`,
|
||||
`MOVELAST`, `MOVENEXT`, `MOVEPREVIOUS`, `SEEKEQ`, `SEEKGT`, `SEEKGE`,
|
||||
`BEGINTRANS`, `COMMITTRANS`, `ROLLBACK`/`ROLLBACK ALL`, `SAVEPOINT`
|
||||
(Funktion), `SETMEM` (Funktion), `BOF` sowie das ISAM-Verhalten von
|
||||
`EOF`, `DELETE`, `LOF` und `LOC`.
|
||||
- **ISAM-Datenbanken und Tabellen**: `OPEN … FOR ISAM typname
|
||||
tabellenname AS #n` bindet eine Tabelle einer Datenbankdatei an eine
|
||||
Dateinummer; das Satzlayout ergibt sich aus dem benannten
|
||||
benutzerdefinierten Typ. Tabellen entstehen beim ersten Öffnen,
|
||||
`DELETETABLE` entfernt sie.
|
||||
- **Indizes**: benannte Indizes über eine oder mehrere Spalten, eindeutig
|
||||
oder mehrdeutig, mit auf- und absteigender Ordnung; `SETINDEX` wählt
|
||||
den aktiven Index und bestimmt damit die Satzreihenfolge, `GETINDEX$`
|
||||
liefert ihn zurück.
|
||||
- **Satzoperationen und Cursor**: `INSERT`, `RETRIEVE`, `UPDATE`,
|
||||
`DELETE` arbeiten auf dem aktuellen Satz; die `MOVE`-Familie bewegt den
|
||||
Cursor in der Ordnung des aktiven Index, die `SEEK`-Familie positioniert
|
||||
über Schlüsselvergleiche (gleich, größer, größer-gleich). `EOF` und
|
||||
`BOF` melden das Überlaufen des Cursors am Ende bzw. am Anfang.
|
||||
- **Transaktionen**: `BEGINTRANS`, `COMMITTRANS`, `ROLLBACK` und
|
||||
`ROLLBACK ALL` mit Rücknahme aller Änderungen seit Transaktionsbeginn
|
||||
bzw. seit einem Sicherungspunkt; `SAVEPOINT` ist eine **Funktion** und
|
||||
liefert die Kennung des gesetzten Sicherungspunkts.
|
||||
- **Vergleichsreihenfolge**: Die Sortierordnung der Indizes wird unter
|
||||
Unicode festgelegt und dokumentiert.
|
||||
- **ISAM-Fehlersemantik**: Die vorhandenen Fehlercodes 81–89 werden von
|
||||
den entsprechenden Situationen ausgelöst (ungültiger Name, Tabelle
|
||||
nicht gefunden, Index nicht gefunden, ungültige Spalte, kein aktueller
|
||||
Satz, Verstoß gegen einen eindeutigen Index, ungültige Operation auf
|
||||
NULL-Index, inkonsistente Datenbank, zu wenig Puffer).
|
||||
- **Eigenes Datenbankdateiformat**: Die Datenbankdatei ist bewusst nicht
|
||||
binärkompatibel zum Vorbild — dieselbe Linie wie bei den UTF-32-
|
||||
Records. Das Format wird in `docs/dateiformate.md` beschrieben.
|
||||
|
||||
**Non-Goals:** Ein Konvertierungswerkzeug für Datenbankdateien des
|
||||
Vorbilds; die eingebettete SQL-Erweiterung samt `WHILE SELECT`
|
||||
(Stufe 2, Ideenspeicher); Mehrprozess-Zugriff über
|
||||
Betriebssystemgrenzen hinweg jenseits der Satzsperren aus `datei-eio`.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `isam-datenbank`: indizierter Satzzugriff — Datenbank- und
|
||||
Tabellenbindung an Dateinummern, Indexverwaltung, Cursorbewegung und
|
||||
Schlüsselsuche, Satzoperationen, Transaktionen, Vergleichsreihenfolge
|
||||
und die ISAM-Fehlersemantik (Codes 81–89).
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `sprach-frontend`: Die Grammatik und die Signaturprüfung SHALL die
|
||||
ISAM-Anweisungen und -Funktionen umfassen, sodass ihre Verwendung
|
||||
namentlich diagnostiziert wird statt als unbekannter Bezeichner.
|
||||
|
||||
## Impact
|
||||
|
||||
- `crates/tb-frontend`: neue Anweisungsgrammatik und Signaturen für die
|
||||
ISAM-Elemente; die bisherige `Unsupported`-Absenkung von `OPEN … FOR
|
||||
ISAM` entfällt.
|
||||
- `crates/tb-runtime`: neues ISAM-Modul (Speicher, Indizes, Cursor,
|
||||
Transaktionen) auf der Dateitabelle und den Recordpuffern aus
|
||||
`phase-3-runtime-bildschirm`.
|
||||
- `crates/tb-vm`: neue Builtin-Indizes für die ISAM-Anweisungen.
|
||||
- `tests/compat`: neue Korpusprogramme für Indexordnung, Schlüsselsuche,
|
||||
Eindeutigkeitsverletzung, Cursorenden und Transaktionsrücknahme.
|
||||
- `docs/`: `docs/dateiformate.md` um das Datenbankdateiformat erweitert;
|
||||
`docs/bibliothek.md` um die ISAM-Elemente; `docs/inventar.md` wechselt
|
||||
deren Status auf `implementiert`; `docs/sprachreferenz.md` hält die
|
||||
Sortierordnung und die Inkompatibilität des Dateiformats fest.
|
||||
- PLAN.md: Phase 3 gilt mit diesem Change als abgeschlossen.
|
||||
187
openspec/changes/phase-3-isam/specs/isam-datenbank/spec.md
Normal file
187
openspec/changes/phase-3-isam/specs/isam-datenbank/spec.md
Normal file
@@ -0,0 +1,187 @@
|
||||
## Purpose
|
||||
Die ISAM-Unterstützung bietet indizierten Satzzugriff auf Tabellen einer
|
||||
Datenbankdatei: Sätze werden über benannte Indizes geordnet durchlaufen
|
||||
und über Schlüsselvergleiche gesucht, Änderungen laufen in Transaktionen
|
||||
und Verstöße melden die ISAM-Fehlercodes des Vorbilds.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Datenbank- und Tabellenbindung an eine Dateinummer
|
||||
`OPEN datenbank$ FOR ISAM typname tabellenname AS #n` SHALL eine Tabelle
|
||||
einer Datenbankdatei an eine Dateinummer binden. Das Satzlayout SHALL
|
||||
sich aus dem benannten benutzerdefinierten Typ ergeben; dessen Felder
|
||||
sind die Spalten der Tabelle. Existiert die Tabelle noch nicht, SHALL sie
|
||||
mit diesem Layout angelegt werden; existiert sie mit abweichendem Layout,
|
||||
MUST Laufzeitfehler 88 „ISAM - Database inconsistent" auftreten. Ein
|
||||
ungültiger Tabellen- oder Datenbankname MUST Fehler 81 „ISAM - Invalid
|
||||
name" auslösen. `CLOSE` SHALL die Bindung lösen und ausstehende
|
||||
Änderungen festschreiben. `DELETETABLE` SHALL eine Tabelle samt ihren
|
||||
Indizes entfernen; eine nicht vorhandene Tabelle MUST Fehler 82 „ISAM -
|
||||
Table not found" auslösen.
|
||||
|
||||
#### Scenario: Tabelle wird beim ersten Öffnen angelegt
|
||||
- **WHEN** eine Datenbank ohne die Tabelle `Kunden` mit `OPEN "db" FOR ISAM KundeTyp "Kunden" AS #1` geöffnet wird
|
||||
- **THEN** entsteht die Tabelle mit den Feldern des Typs und die Dateinummer ist nutzbar
|
||||
|
||||
#### Scenario: Abweichendes Satzlayout
|
||||
- **WHEN** eine bestehende Tabelle mit einem Typ geöffnet wird, dessen Felder nicht zu ihren Spalten passen
|
||||
- **THEN** tritt Laufzeitfehler 88 auf
|
||||
|
||||
#### Scenario: Entfernte Tabelle
|
||||
- **WHEN** `DELETETABLE` für eine nicht vorhandene Tabelle aufgerufen wird
|
||||
- **THEN** tritt Laufzeitfehler 82 auf
|
||||
|
||||
### Requirement: Indexverwaltung
|
||||
`CREATEINDEX` SHALL einen benannten Index über eine oder mehrere Spalten
|
||||
anlegen, wahlweise eindeutig oder mehrdeutig und je Spalte auf- oder
|
||||
absteigend geordnet. `DELETEINDEX` SHALL einen Index entfernen.
|
||||
`SETINDEX` SHALL den aktiven Index einer Dateinummer setzen und damit die
|
||||
Reihenfolge bestimmen, in der Sätze durchlaufen werden; `GETINDEX$` SHALL
|
||||
den Namen des aktiven Index liefern. Ein unbekannter Indexname MUST
|
||||
Laufzeitfehler 83 „ISAM - Index not found" auslösen, ein unbekannter
|
||||
Spaltenname Fehler 84 „ISAM - Invalid column". Nach `SETINDEX` MUST der
|
||||
Cursor als unpositioniert gelten.
|
||||
|
||||
#### Scenario: Aktiver Index bestimmt die Reihenfolge
|
||||
- **WHEN** ein Index über die Spalte `Name` gesetzt ist und die Sätze mit `MOVEFIRST` und `MOVENEXT` durchlaufen werden
|
||||
- **THEN** erscheinen sie in aufsteigender Reihenfolge der Spalte `Name`
|
||||
|
||||
#### Scenario: Unbekannter Index
|
||||
- **WHEN** `SETINDEX #1, "GibtsNicht"` ausgeführt wird
|
||||
- **THEN** tritt Laufzeitfehler 83 auf
|
||||
|
||||
#### Scenario: Index über unbekannte Spalte
|
||||
- **WHEN** `CREATEINDEX` eine Spalte nennt, die der Satztyp nicht führt
|
||||
- **THEN** tritt Laufzeitfehler 84 auf
|
||||
|
||||
### Requirement: Cursorbewegung in der Ordnung des aktiven Index
|
||||
`MOVEFIRST`, `MOVELAST`, `MOVENEXT` und `MOVEPREVIOUS` SHALL den Cursor
|
||||
in der Ordnung des aktiven Index bewegen. Läuft der Cursor über das Ende
|
||||
hinaus, SHALL `EOF` für diese Dateinummer wahr werden; läuft er über den
|
||||
Anfang hinaus, SHALL `BOF` wahr werden. In beiden Fällen SHALL der Cursor
|
||||
als unpositioniert gelten. Eine Bewegung ohne aktiven Index SHALL der
|
||||
Einfügereihenfolge folgen.
|
||||
|
||||
#### Scenario: Cursor läuft über das Ende hinaus
|
||||
- **WHEN** nach dem letzten Satz `MOVENEXT` ausgeführt wird
|
||||
- **THEN** liefert `EOF` für diese Dateinummer wahr
|
||||
|
||||
#### Scenario: Rückwärts über den Anfang hinaus
|
||||
- **WHEN** auf dem ersten Satz `MOVEPREVIOUS` ausgeführt wird
|
||||
- **THEN** liefert `BOF` für diese Dateinummer wahr
|
||||
|
||||
### Requirement: Schlüsselsuche
|
||||
`SEEKEQ`, `SEEKGT` und `SEEKGE` SHALL den Cursor auf den ersten Satz
|
||||
setzen, dessen Schlüssel im aktiven Index gleich, größer bzw.
|
||||
größer-gleich dem angegebenen Wert ist. Die Zahl der Schlüsselwerte MUST
|
||||
höchstens der Spaltenzahl des aktiven Index entsprechen; ein
|
||||
mehrspaltiger Index SHALL mit einem Präfix der Spalten durchsucht werden
|
||||
können. Findet die Suche keinen Satz, SHALL `EOF` wahr werden und der
|
||||
Cursor unpositioniert bleiben. Eine Suche ohne aktiven Index MUST
|
||||
Laufzeitfehler 83 auslösen.
|
||||
|
||||
#### Scenario: Suche nach größerem Schlüssel
|
||||
- **WHEN** Sätze mit den Schlüsseln 10, 20 und 30 vorliegen und `SEEKGT #1, 20` ausgeführt wird
|
||||
- **THEN** steht der Cursor auf dem Satz mit Schlüssel 30
|
||||
|
||||
#### Scenario: Erfolglose Suche
|
||||
- **WHEN** `SEEKGT #1, 30` bei größtem Schlüssel 30 ausgeführt wird
|
||||
- **THEN** liefert `EOF` wahr
|
||||
|
||||
#### Scenario: Suche über Präfix eines mehrspaltigen Index
|
||||
- **WHEN** der aktive Index über `Nachname` und `Vorname` geht und mit nur einem Wert gesucht wird
|
||||
- **THEN** positioniert die Suche auf dem ersten Satz mit passendem `Nachname`
|
||||
|
||||
### Requirement: Satzoperationen auf dem aktuellen Satz
|
||||
`INSERT` SHALL einen Satz aus einer Variablen des Tabellentyps einfügen,
|
||||
`RETRIEVE` den aktuellen Satz in eine solche Variable lesen, `UPDATE` ihn
|
||||
aus einer solchen Variablen überschreiben und `DELETE` ihn entfernen.
|
||||
`RETRIEVE`, `UPDATE` und `DELETE` ohne positionierten Cursor MUST
|
||||
Laufzeitfehler 85 „ISAM - No current record" auslösen. Ein `INSERT` oder
|
||||
`UPDATE`, das einen als eindeutig angelegten Index verletzen würde, MUST
|
||||
Laufzeitfehler 86 „ISAM - Duplicate value for unique index" auslösen und
|
||||
den Satzbestand unverändert lassen. Nach `DELETE` SHALL der Cursor als
|
||||
unpositioniert gelten. Alle Indizes der Tabelle SHALL nach jeder
|
||||
Satzoperation die neue Ordnung widerspiegeln.
|
||||
|
||||
#### Scenario: Einfügen und Zurücklesen
|
||||
- **WHEN** ein Satz eingefügt, per `SEEKEQ` gesucht und mit `RETRIEVE` gelesen wird
|
||||
- **THEN** stimmen alle Feldwerte mit den eingefügten überein
|
||||
|
||||
#### Scenario: Operation ohne aktuellen Satz
|
||||
- **WHEN** nach `SETINDEX` ohne Positionierung `RETRIEVE #1, k` ausgeführt wird
|
||||
- **THEN** tritt Laufzeitfehler 85 auf
|
||||
|
||||
#### Scenario: Verstoß gegen eindeutigen Index
|
||||
- **WHEN** ein Satz eingefügt wird, dessen Schlüssel in einem eindeutigen Index bereits vorkommt
|
||||
- **THEN** tritt Laufzeitfehler 86 auf und der Satzbestand bleibt unverändert
|
||||
|
||||
#### Scenario: Index folgt der Änderung
|
||||
- **WHEN** die indizierte Spalte eines Satzes per `UPDATE` geändert wird
|
||||
- **THEN** erscheint der Satz beim nächsten Durchlauf an seiner neuen Position in der Indexordnung
|
||||
|
||||
### Requirement: Transaktionen mit Rücknahme
|
||||
`BEGINTRANS` SHALL eine Transaktion eröffnen, `COMMITTRANS` alle
|
||||
Änderungen seit ihrem Beginn festschreiben und `ROLLBACK` sie
|
||||
zurücknehmen. `SAVEPOINT` SHALL als **Funktion** einen Sicherungspunkt
|
||||
setzen und dessen Kennung liefern; `ROLLBACK` mit einer solchen Kennung
|
||||
SHALL auf diesen Punkt zurücksetzen, ohne die Transaktion aufzugeben.
|
||||
`ROLLBACK ALL` SHALL alle Änderungen seit `BEGINTRANS` zurücknehmen und
|
||||
die Transaktion beenden. Nach jeder Rücknahme MUST der Satzbestand
|
||||
einschließlich aller Indizes dem Zustand zum Bezugspunkt entsprechen und
|
||||
der Cursor als unpositioniert gelten.
|
||||
|
||||
#### Scenario: Rücknahme stellt den Bestand wieder her
|
||||
- **WHEN** nach `BEGINTRANS` Sätze eingefügt und gelöscht werden und dann `ROLLBACK` folgt
|
||||
- **THEN** entspricht der Bestand beim erneuten Durchlauf dem Zustand vor `BEGINTRANS`
|
||||
|
||||
#### Scenario: Rücknahme auf einen Sicherungspunkt
|
||||
- **WHEN** innerhalb einer Transaktion `s = SAVEPOINT` ausgewertet, danach geändert und mit `ROLLBACK s` zurückgesetzt wird
|
||||
- **THEN** bleiben die Änderungen vor dem Sicherungspunkt erhalten und die danach sind zurückgenommen
|
||||
|
||||
#### Scenario: ROLLBACK ALL beendet die Transaktion
|
||||
- **WHEN** nach mehreren Sicherungspunkten `ROLLBACK ALL` ausgeführt wird
|
||||
- **THEN** entspricht der Bestand dem Zustand vor `BEGINTRANS` und die Transaktion ist beendet
|
||||
|
||||
### Requirement: Vergleichsreihenfolge für Indizes
|
||||
Textspalten SHALL in Indizes nach einer festgelegten, dokumentierten
|
||||
Sortierordnung geordnet werden. Diese Ordnung MUST dieselbe sein, die der
|
||||
Vergleichsoperator des Dialekts auf Strings anwendet, damit ein Programm
|
||||
die Satzreihenfolge vorhersagen kann. Die gewählte Ordnung MUST in
|
||||
docs/sprachreferenz.md festgehalten sein, einschließlich der Behandlung
|
||||
von Groß- und Kleinschreibung und von Zeichen jenseits von ASCII.
|
||||
|
||||
#### Scenario: Indexordnung entspricht dem Stringvergleich
|
||||
- **WHEN** zwei Texte als Schlüssel indiziert und dieselben Werte mit `<` verglichen werden
|
||||
- **THEN** entspricht ihre Reihenfolge im Index dem Ergebnis des Vergleichs
|
||||
|
||||
### Requirement: Pufferverwaltung mit benanntem Fehler
|
||||
`SETMEM` SHALL als **Funktion** die für ISAM verfügbare Puffergröße um
|
||||
den übergebenen Betrag ändern und die danach verfügbare Größe liefern.
|
||||
Reicht
|
||||
der verfügbare Puffer für eine Operation nicht aus, MUST Laufzeitfehler 89
|
||||
„ISAM - Insufficient ISAM buffers" auftreten statt eines generischen
|
||||
Fehlers oder eines stillen Abbruchs. Weicht die Bedeutung von `SETMEM`
|
||||
mangels DOS-Speichermodell vom Vorbild ab, MUST die Abweichung in
|
||||
docs/sprachreferenz.md dokumentiert sein.
|
||||
|
||||
#### Scenario: Pufferfehler wird benannt
|
||||
- **WHEN** eine Operation den verfügbaren ISAM-Puffer überschreitet
|
||||
- **THEN** tritt Laufzeitfehler 89 auf
|
||||
|
||||
### Requirement: Eigenes Datenbankdateiformat
|
||||
Die Datenbankdatei SHALL ein eigenes, in docs/dateiformate.md
|
||||
beschriebenes Format verwenden und ist bewusst nicht binärkompatibel zu
|
||||
Datenbankdateien des Vorbilds — dieselbe Linie wie bei den
|
||||
UTF-32-Festtextfeldern. Das Format SHALL eine Formatversion tragen; eine
|
||||
unbekannte Version MUST mit einem benannten Fehler abgewiesen werden
|
||||
statt fehlinterpretiert zu werden. Eine strukturell beschädigte Datei
|
||||
MUST Laufzeitfehler 88 auslösen.
|
||||
|
||||
#### Scenario: Unbekannte Formatversion
|
||||
- **WHEN** eine Datenbankdatei mit einer höheren Formatversion geöffnet wird
|
||||
- **THEN** wird sie mit einem benannten Fehler abgewiesen und nicht gelesen
|
||||
|
||||
#### Scenario: Beschädigte Datei
|
||||
- **WHEN** eine strukturell beschädigte Datenbankdatei geöffnet wird
|
||||
- **THEN** tritt Laufzeitfehler 88 auf
|
||||
27
openspec/changes/phase-3-isam/specs/sprach-frontend/spec.md
Normal file
27
openspec/changes/phase-3-isam/specs/sprach-frontend/spec.md
Normal file
@@ -0,0 +1,27 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: ISAM-Anweisungen und -Funktionen in Grammatik und Signaturprüfung
|
||||
Der Parser SHALL die ISAM-Anweisungen und -Funktionen des Vorbilds als
|
||||
eigene Konstrukte erkennen, und die Semantik SHALL für jede eine Signatur
|
||||
führen (Argumentanzahl und -typen). Der maßgebliche Umfang ergibt sich
|
||||
aus dem Sprachinventar; er umfasst mindestens `CREATEINDEX`,
|
||||
`DELETEINDEX`, `SETINDEX`, `GETINDEX$`, `INSERT`, `RETRIEVE`, `UPDATE`,
|
||||
`DELETE`, `DELETETABLE`, `MOVEFIRST`, `MOVELAST`, `MOVENEXT`,
|
||||
`MOVEPREVIOUS`, `SEEKEQ`, `SEEKGT`, `SEEKGE`, `BEGINTRANS`,
|
||||
`COMMITTRANS`, `ROLLBACK`, `ROLLBACK ALL`, `SAVEPOINT`, `SETMEM` und
|
||||
`BOF`. Eine fehlerhafte Verwendung MUST eine Diagnose erzeugen, die
|
||||
das Element namentlich nennt; ein ISAM-Element MUST NOT als unbekannter
|
||||
Bezeichner oder mit einem generischen Syntaxfehler abgewiesen werden
|
||||
(Guiding Principle).
|
||||
|
||||
#### Scenario: ISAM-Anweisung wird als solche erkannt
|
||||
- **WHEN** ein Modul `SETINDEX #1, "NachName"` enthält
|
||||
- **THEN** entsteht keine Diagnose „unbekannter Bezeichner" und die Anweisung wird als ISAM-Anweisung erfasst
|
||||
|
||||
#### Scenario: Falsche Argumentanzahl wird namentlich gemeldet
|
||||
- **WHEN** ein Modul `SEEKGT #1` ohne Schlüsselwert enthält
|
||||
- **THEN** nennt die Diagnose `SEEKGT` und die erwartete Argumentanzahl
|
||||
|
||||
#### Scenario: Typprüfung des Satzarguments
|
||||
- **WHEN** `RETRIEVE #1, x$` mit einem String statt einer Variablen des Tabellentyps geprüft wird
|
||||
- **THEN** wird „Type mismatch" mit Quelltextposition gemeldet
|
||||
78
openspec/changes/phase-3-isam/tasks.md
Normal file
78
openspec/changes/phase-3-isam/tasks.md
Normal file
@@ -0,0 +1,78 @@
|
||||
## 1. Umfang festlegen
|
||||
|
||||
- [ ] 1.1 ISAM-Abschnitt der Original-Hilfe auswerten und alle Anweisungen, Funktionen und Klauseln gegen die ISAM-Einträge in `docs/inventar.md` abgleichen; verifiziert dadurch, dass jedes gefundene Element im Inventar mit Status `offen` steht und im Change notiert ist, falls es über die Aufzählung im Proposal hinausgeht
|
||||
- [ ] 1.2 Argumentformen je Element aus der Original-Hilfe festhalten (insbesondere die Schreibweise der Spaltenliste bei `CREATEINDEX`); verifiziert durch die Notiz im Change, die jede Signatur mit ihrer Quelle nennt
|
||||
|
||||
## 2. Frontend: Grammatik und Signaturen
|
||||
|
||||
- [ ] 2.1 ISAM-Anweisungen in die Parser-Grammatik aufnehmen; verifiziert durch Frontend-Test, dass `SETINDEX #1, "Name"` diagnose-frei parst
|
||||
- [ ] 2.2 Signaturen (Argumentanzahl und -typen) für alle ISAM-Elemente in der Semantik führen; verifiziert durch Frontend-Test, dass `SEEKGT #1` ohne Schlüsselwert eine Diagnose erzeugt, die `SEEKGT` namentlich nennt
|
||||
- [ ] 2.3 Satzargumente gegen den Tabellentyp prüfen; verifiziert durch Frontend-Test, dass `RETRIEVE #1, x$` „Type mismatch" meldet
|
||||
- [ ] 2.4 `Unsupported`-Absenkung von `OPEN … FOR ISAM` entfernen und durch die reguläre Absenkung ersetzen; verifiziert dadurch, dass ein ISAM-Programm nicht mehr mit Laufzeitfehler 73 endet
|
||||
- [ ] 2.5 Prüfen, dass kein ISAM-Element mehr als unbekannter Bezeichner behandelt wird; verifiziert durch Frontend-Test über ein Programm, das jedes Element einmal verwendet, ohne Diagnose „unbekannter Bezeichner"
|
||||
|
||||
## 3. Speicherschicht
|
||||
|
||||
- [ ] 3.1 `redb` als Abhängigkeit aufnehmen, auf das ISAM-Modul in `tb-runtime` beschränkt; verifiziert dadurch, dass `cargo build -p tb-runtime` durchläuft
|
||||
- [ ] 3.2 Datenbankdatei mit Formatversion anlegen und öffnen; verifiziert durch Test, dass eine Datei mit höherer Formatversion mit benanntem Fehler abgewiesen und eine strukturell beschädigte Datei mit Laufzeitfehler 88 abgelehnt wird
|
||||
- [ ] 3.3 Satztabelle `satz-id → Satzbytes` mit monoton vergebenen, nie wiederverwendeten IDs; verifiziert durch Test, dass eine nach `DELETE` neu vergebene ID nicht vorkommt
|
||||
- [ ] 3.4 Satzserialisierung auf den Recordpuffern und der UTF-32-Festtextkodierung aus `datei-eio` aufsetzen; verifiziert durch Roundtrip-Test über alle Feldtypen des Satztyps
|
||||
- [ ] 3.5 Ordnungserhaltende Schlüsselkodierung je Spaltentyp (Zahlen vorzeichenrichtig fester Breite, Text nach Codepoints, mehrspaltig verkettet mit eindeutigem Trenner, absteigend durch Byte-Invertierung); verifiziert durch Eigenschaftstest über zufällige Wertepaare, dass der Byte-Vergleich der Kodierung dem fachlichen Vergleich entspricht
|
||||
- [ ] 3.6 Sortierordnung (Unicode-Codepoints, Groß-/Kleinschreibung unterschieden) in docs/sprachreferenz.md festhalten; verifiziert durch den Abschnittseintrag
|
||||
- [ ] 3.7 Datenbankdateiformat in docs/dateiformate.md beschreiben inklusive Formatversion und bewusster Inkompatibilität zum Vorbild; verifiziert durch den Abschnittseintrag
|
||||
|
||||
## 4. Tabellen
|
||||
|
||||
- [ ] 4.1 `OPEN … FOR ISAM typname tabellenname AS #n` an die Dateitabelle binden, Satzlayout aus dem benannten Typ ableiten; verifiziert durch Korpustest, dass die Dateinummer danach nutzbar ist
|
||||
- [ ] 4.2 Tabelle beim ersten Öffnen anlegen; verifiziert durch Korpustest gegen eine Datenbank ohne diese Tabelle
|
||||
- [ ] 4.3 Layoutabgleich bei bestehender Tabelle mit Fehler 88 bei Abweichung; verifiziert durch Korpustest mit unpassendem Typ
|
||||
- [ ] 4.4 Ungültige Datenbank- und Tabellennamen mit Fehler 81 abweisen; verifiziert durch Korpustest
|
||||
- [ ] 4.5 `CLOSE` löst die Bindung und schreibt ausstehende Änderungen fest; verifiziert durch Korpustest, dass die Sätze nach erneutem Öffnen vorhanden sind
|
||||
- [ ] 4.6 `DELETETABLE` entfernt Tabelle samt Indizes, Fehler 82 bei fehlender Tabelle; verifiziert durch Korpustest für beide Fälle
|
||||
|
||||
## 5. Indizes
|
||||
|
||||
- [ ] 5.1 Indextabellen `Schlüsselbytes → satz-id` je Index anlegen; verifiziert durch Test, dass die Einträge in Schlüsselreihenfolge stehen
|
||||
- [ ] 5.2 `CREATEINDEX` mit einer und mit mehreren Spalten, eindeutig und mehrdeutig, auf- und absteigend; verifiziert durch Korpustest je Variante
|
||||
- [ ] 5.3 `DELETEINDEX`; verifiziert durch Korpustest, dass der Index danach nicht mehr gesetzt werden kann
|
||||
- [ ] 5.4 `SETINDEX` setzt den aktiven Index und den Cursor auf unpositioniert, `GETINDEX$` liefert ihn zurück; verifiziert durch Korpustest
|
||||
- [ ] 5.5 Fehler 83 bei unbekanntem Index und Fehler 84 bei unbekannter Spalte; verifiziert durch Korpustest für beide Fälle
|
||||
|
||||
## 6. Cursor
|
||||
|
||||
- [ ] 6.1 Cursor je Dateinummer als Wert führen (aktiver Index, letzte Satz-ID, Kennzeichen unpositioniert); verifiziert durch Unit-Test, dass der Cursor eine Satzänderung überlebt
|
||||
- [ ] 6.2 `MOVEFIRST`, `MOVELAST`, `MOVENEXT`, `MOVEPREVIOUS` in der Ordnung des aktiven Index; verifiziert durch Korpustest, dass ein Durchlauf die Sätze in Indexreihenfolge liefert
|
||||
- [ ] 6.3 Bewegung ohne aktiven Index folgt der Einfügereihenfolge; verifiziert durch Korpustest
|
||||
- [ ] 6.4 `EOF` am Ende und `BOF` am Anfang, Cursor danach jeweils unpositioniert; verifiziert durch je einen Korpustest für `MOVENEXT` am Ende und `MOVEPREVIOUS` am Anfang
|
||||
- [ ] 6.5 `SEEKEQ`, `SEEKGT`, `SEEKGE` inklusive Präfixsuche über einen mehrspaltigen Index; verifiziert durch Korpustest mit den Schlüsseln 10, 20, 30 und einer Präfixsuche
|
||||
- [ ] 6.6 Erfolglose Suche setzt `EOF` und lässt den Cursor unpositioniert; verifiziert durch Korpustest
|
||||
- [ ] 6.7 Suche ohne aktiven Index löst Fehler 83 aus; verifiziert durch Korpustest
|
||||
|
||||
## 7. Satzoperationen
|
||||
|
||||
- [ ] 7.1 `INSERT` und `RETRIEVE`; verifiziert durch Korpustest, dass ein eingefügter Satz per `SEEKEQ` gefunden und feldgleich gelesen wird
|
||||
- [ ] 7.2 `UPDATE` und `DELETE`, Cursor nach `DELETE` unpositioniert; verifiziert durch Korpustest
|
||||
- [ ] 7.3 Fehler 85 bei `RETRIEVE`/`UPDATE`/`DELETE` ohne positionierten Cursor; verifiziert durch je einen Korpustest
|
||||
- [ ] 7.4 Eindeutigkeitsprüfung mit Fehler 86 und unverändertem Satzbestand; verifiziert durch Korpustest, der nach dem Fehler den Bestand nachzählt
|
||||
- [ ] 7.5 Alle Indizes nach jeder Satzoperation nachführen; verifiziert durch Korpustest, dass ein Satz nach Änderung der indizierten Spalte an neuer Position im Durchlauf erscheint
|
||||
|
||||
## 8. Transaktionen
|
||||
|
||||
- [ ] 8.1 `BEGINTRANS`/`COMMITTRANS` auf einer Schreibtransaktion; verifiziert durch Korpustest, dass die Änderungen nach erneutem Öffnen vorhanden sind
|
||||
- [ ] 8.2 Rücknahmeprotokoll der Änderungen innerhalb einer Transaktion; verifiziert durch Unit-Test, dass jede Satzoperation einen Protokolleintrag erzeugt
|
||||
- [ ] 8.3 `ROLLBACK ALL` stellt Sätze und Indizes wieder her, beendet die Transaktion und setzt den Cursor auf unpositioniert; verifiziert durch Korpustest mit Einfügen, Löschen und anschließendem Durchlauf
|
||||
- [ ] 8.4 `SAVEPOINT` als Funktion (liefert Kennung) und `ROLLBACK kennung`; verifiziert durch Korpustest, dass Änderungen vor dem Punkt erhalten bleiben
|
||||
|
||||
## 9. Übrige Elemente
|
||||
|
||||
- [ ] 9.2 `SETMEM` als Funktion mit echter Puffergrenze und Fehler 89 beim Überschreiten; verifiziert durch Korpustest, der die Grenze niedrig setzt und den Fehler auslöst
|
||||
- [ ] 9.3 Vorgabewert und Bedeutung von `SETMEM` sowie die Abweichung vom DOS-Speichermodell in docs/sprachreferenz.md festhalten; verifiziert durch den Abschnittseintrag
|
||||
- [ ] 9.4 Indexordnung gegen den Stringvergleich des Dialekts prüfen; verifiziert durch Korpustest, dass Indexreihenfolge und `<`-Vergleich übereinstimmen
|
||||
|
||||
## 10. Abschluss
|
||||
|
||||
- [ ] 10.1 ISAM-Einträge in `docs/inventar.md` auf `implementiert` setzen; verifiziert dadurch, dass der Abgleichstest aus `phase-3-runtime-bildschirm` grün bleibt
|
||||
- [ ] 10.2 `docs/bibliothek.md` um die ISAM-Elemente erweitern; verifiziert dadurch, dass jedes umgesetzte Element dort einen Eintrag hat
|
||||
- [ ] 10.3 Korpus-ISAM-Programme in einem temporären Arbeitsverzeichnis ausführen; verifiziert dadurch, dass nach `cargo test` `git status` sauber ist
|
||||
- [ ] 10.4 Vollständige Suite auf allen Zielplattformen ausführen; verifiziert dadurch, dass `cargo test --workspace` grün ist
|
||||
- [ ] 10.5 PLAN.md Phase 3 als abgeschlossen markieren; verifiziert durch den aktualisierten Planabschnitt
|
||||
Reference in New Issue
Block a user