Flow-Diagrams
Flow Diagrams
Document ID: PGCBL-FLD-001 · Version: 1.0 · Status: Approved · Last updated: 2026-03-17
Notation: Mermaid
flowchart TDandsequenceDiagram
← Data Dictionary | Primes system Design →
Contents
- Top-Level Application Flow
- primesgen Dispatch Flow
- Prime Generation — Sieve Loop
- Prime Report — Cursor Loop
- DAL (primes.cbl) Method Dispatch
- UI (primesui.cbl) Method Dispatch
- Inter-Program Call Sequence — Generate Run
- Inter-Program Call Sequence — Report Run
1. Top-Level Application Flow
Program: primesmain.cbl
What it shows: How primesmain reads the command-line argument, initialises the UI layer, routes to the correct processing path, and shuts down cleanly.
⚠️ The
generatebranch callsr92-generate-primesbut the PERFORM inside that paragraph that drives the sieve is commented out. See Technical Specification — Defect T1.
flowchart TD
A([START]) --> B[ACCEPT commandline-args\nFROM COMMAND-LINE]
B --> C[MOVE commandline-args TO methods\nMOVE 'primesmain' TO program-name]
C --> D[r90-start-session\nMOVE 'start' TO ui-methods\nCALL primesui USING primes-ui]
D --> E{ui-method-ok?}
E -->|No| F[DISPLAY emergency msg\nUPON scherm\nSTOP RUN]
E -->|Yes| G[LOG 'UI initialisation succeeded.'\nLOG commandline-args]
G --> H{EVALUATE\ncommandline-args}
H -->|'report'| I[LOG 'Primes report generation starts.'\nMOVE 'report' TO methods]
I --> J[r92-generate-primes\nCALL primesgen USING primes-session]
H -->|'generate'| K[LOG 'Primes generation starts.'\nMOVE 'generate' TO methods]
K --> L["⚠️ r92-generate-primes\n[PERFORM commented out in source]"]
H -->|other| M[LOG 'Bad parameter'\nCALL primesui 'stop'\nSTOP RUN]
J --> N[LOG 'Primes run complete, program stops.']
L --> N
N --> O[r99-stop-session\nMOVE 'stop' TO ui-methods\nCALL primesui USING primes-ui]
O --> P([STOP RUN])
Key paragraphs:
| Paragraph | Action |
|---|---|
r90-start-session
|
Opens primes.prt; hard-stops if open fails
|
r92-generate-primes
|
Single CALL to primesgen; passes primes-session by reference
|
r99-stop-session
|
Flushes print buffer and closes primes.prt
|
2. primesgen Dispatch Flow
Program: primesgen.cbl
What it shows: How primesgen reads the methods field in primes-session and routes to either the generation or report path, then always performs cleanup.
flowchart TD
A([ENTRY — primesgen\nUSING primes-session]) --> B{EVALUATE TRUE\non methods}
B -->|report-primes| C[PERFORM r90-start-primes-report]
B -->|generate-primes| D[PERFORM r91-start-primes-generation]
B -->|other| E[LOG 'Bad method, primes process failed.']
C --> F{session-method-ok?}
F -->|Yes| G[PERFORM r86-report-primes\nUNTIL session-method-eof]
F -->|No| Z
D --> H{session-method-ok?}
H -->|Yes| I[PERFORM r80-test-number\nUNTIL test-number = 999999999]
H -->|No| Z
G --> Z
I --> Z
E --> Z
Z[r99-close-primes\nMOVE 'disconnect' TO dal-methods\nCALL primes USING primes-dal] --> END([EXIT PROGRAM])
3. Prime Generation — Sieve Loop
Program: primesgen.cbl (r80-series paragraphs) + primes.cbl (r81, r83)
What it shows: The trial-division sieve — how each candidate is tested, how composites are skipped, and how confirmed primes are persisted.
Algorithm in words: 1. Start at candidate = 3. Load first divisor (prime at ident 1 = prime 2, assumed pre-seeded). 2. Divide candidate by current divisor. 3. If remainder = 0 → composite. Add 2, reset divisor to first prime. 4. If divisor > √candidate → prime confirmed. Write to DB and print buffer. Add 2, reset divisor. 5. Otherwise → try next divisor (fetch next prime from DB by ident).
flowchart TD
A([r91-start-primes-generation]) --> B[CALL primes 'connect']
B --> C{dal-method-ok?}
C -->|No| FAIL([session-result = 1\nEXIT])
C -->|Yes| D[test-divider = 2\nold-ident = 1\ntest-number = 3\ntest-number-sqr = SQRT 3]
D --> LOG1[LOG 'Database initialisation succeeded.']
LOG1 --> LOOP{test-number\n= 999999999?}
LOOP -->|Yes| CLOSE([r99-close-primes\nEXIT PROGRAM])
LOOP -->|No| DIV[r80-test-number\nDIVIDE test-number BY test-divider\nGIVING test-quot REMAINDER test-rest]
DIV --> EVAL{EVALUATE TRUE}
EVAL -->|test-rest = 0\ncomposite| NEXT[r82-next-test-number]
EVAL -->|test-divider > test-number-sqr\nprime confirmed| WRITE[r85-write-prime\nCALL primes 'write'\nINSERT INTO primes prime\nCALL primesui 'write'\nadd to print buffer]
EVAL -->|otherwise\ntry next divisor| GETDIV[r89-get-next-divider\nCALL primes 'next-divider'\nSELECT prime WHERE ident = old-ident+1]
WRITE --> NEXT
GETDIV --> LOOP
NEXT --> NA[ADD 2 TO test-number\nCOMPUTE test-number-sqr = test-number ** 0.5\nMOVE 1 TO old-ident\nr89-get-next-divider\nload first divisor]
NA --> LOOP
Data flow through the sieve:
test-number (candidate) ──→ DIVIDE ──→ test-rest
test-divider (from DB) ──→ DIVIDE ──→ test-quot
test-number-sqr (SQRT) ──→ compare to test-divider
old-ident (DB row pointer) ──→ SELECT prime WHERE ident = old-ident+1 ──→ test-divider
prime-number (confirmed) ──→ INSERT INTO primes (prime) ──→ database
──→ u-number / u-sequence ──→ primesui print buffer
4. Prime Report — Cursor Loop
Program: primesgen.cbl (r86, r90, r94) + primes.cbl (s01, s02)
What it shows: How the report path opens a cursor over the database, fetches rows one at a time, and sends each to the print buffer.
flowchart TD
A([r90-start-primes-report]) --> B[CALL primes 'connect'\ndal-methods = 'connect']
B --> C{dal-method-ok?}
C -->|No| FAIL1([LOG 'Database init failed.'\nsession-result = 1\nGOTO close])
C -->|Yes| D[LOG 'Database initialisation succeeded.'\nCALL primes 'cursor'\ndal-methods = 'cursor']
D --> E[s01-cursor:\nEXEC SQL START TRANSACTION\nEXEC SQL OPEN primescursor]
E --> F{dal-method-ok?}
F -->|No| FAIL2([LOG 'Cursor init failed.'\nsession-result = 1\nGOTO close])
F -->|Yes| G[LOG 'Cursor initialisation succeeded.'\nr94-fetch → CALL primes 'next-prime'\nFETCH primescursor INTO primes-row]
G --> H{dal-method-ok?}
H -->|No| FAIL3([LOG 'Fetch first row nok.'\ndal-result = 1\nGOTO close])
H -->|Yes| I[LOG 'Fetch first row ok.'\ndal-result = 0]
I --> LOOP{session-method-eof?}
LOOP -->|Yes| CLOSE[r99-close-primes\nCALL primes 'disconnect']
CLOSE --> END([EXIT PROGRAM])
LOOP -->|No| WRITE[r86-report-primes\nMOVE primes-data TO u-primes\nCALL primesui 'write']
WRITE --> FETCH[r94-fetch\nCALL primes 'next-prime'\nFETCH primescursor INTO primes-row]
FETCH --> FCHECK{dal-method-ok?}
FCHECK -->|Yes| LOOP
FCHECK -->|No| ERR[LOG 'Fetch failed.'\nsession-result = 1]
ERR --> LOOP
⚠️
session-result = 1(nok) is set on fetch failure, but the loop condition testssession-method-eof(value 9). These values do not match — the loop will continue rather than exit cleanly on cursor exhaustion. See Technical Specification — Defect T7.
5. DAL (primes.cbl) Method Dispatch
Program: primes.cbl
What it shows: The complete method-dispatch EVALUATE inside the DAL and the SQL operations each verb triggers. Each invocation handles exactly one operation.
flowchart TD
A([ENTRY — primes\nUSING primes-dal]) --> B{EVALUATE TRUE\non dal-methods}
B -->|db-connect| C["s00-connect\nEXEC SQL\n CONNECT TO :DATASRC AS primes\n USER :DBUSR USING :DBPWD"]
B -->|db-cursor| D["s01-cursor\nEXEC SQL AT primes START TRANSACTION\nEXEC SQL OPEN primescursor"]
B -->|next-prime| E["r80-get-next-prime → s02-fetch\nEXEC SQL FETCH primescursor\n INTO :primes-row\nprimes-sequence = r-ident\nprime-number = r-prime"]
B -->|next-divider| F["r81-get-next-divider\nnew-ident = old-ident + 1\nEXEC SQL AT primes\n SELECT prime INTO :test-divider\n FROM primes WHERE ident = :new-ident\nold-ident = new-ident"]
B -->|write-prime| G["r83-write-prime\nEXEC SQL AT primes\n INSERT INTO primes (prime)\n VALUES (:prime)\n⚠️ COMMIT commented out"]
B -->|db-disconnect| H["s99-disconnect\nEXEC SQL CONNECT RESET primes\n⚠️ cbsql.out shows 'primesdb'"]
B -->|other| I[dal-result = 1]
C --> SC{SQLCODE = 0?}
SC -->|Yes| SOK[dal-result = 0\nLOG ok]
SC -->|No| SNOK[dal-result = 1\nLOG error]
D --> Z([EXIT PROGRAM])
E --> Z
F --> Z
G --> Z
H --> Z
I --> Z
SOK --> Z
SNOK --> Z
Verb → SQL mapping (summary):
| Verb | SQL | Notes |
|---|---|---|
connect
|
CONNECT TO :DATASRC AS primes …
|
Sets connection alias primes
|
cursor
|
START TRANSACTION + OPEN primescursor
|
Report path only |
next-prime
|
FETCH primescursor INTO :primes-row
|
Report path only |
next-divider
|
SELECT prime WHERE ident = :new-ident
|
Generate path only |
write
|
INSERT INTO primes (prime) VALUES (:prime)
|
Generate path only |
disconnect
|
CONNECT RESET primes
|
Both paths |
6. UI (primesui.cbl) Method Dispatch
Program: primesui.cbl
What it shows: How primesui routes each verb to the correct paragraph, and the detail of the write path — page management, line accumulation, and EOP handling.
flowchart TD
A([ENTRY — primesui\nUSING primes-ui]) --> B{EVALUATE TRUE\non ui-methods}
B -->|start-ui| C[r90-start-primesui\nOPEN OUTPUT fprinter\nprimes.prt]
B -->|write-ui| D[r92-write-primesui]
B -->|message-ui| E[r98-message-ui\nDISPLAY process-message\nUPON scherm]
B -->|stop-ui| F[r99-stop-primesui]
B -->|other| G[ui-method-result = 1]
C --> C1{primes-prt-status\n= '00'?}
C1 -->|Yes| C2[SET primes-idx TO 1\nui-method-result = 0\nLOG 'Open printer Ok']
C1 -->|No| C3[ui-method-result = 1\nDISPLAY status on console]
D --> D1[t-ident at primes-idx = u-sequence\nt-prime at primes-idx = u-number\nSET primes-idx UP BY 1]
D1 --> D2{new-page?}
D2 -->|Yes| D3[r93-new-page\nWRITE primes-heading\nWRITE table-header\nprint-new-page = 0]
D2 -->|No| D4{primes-idx = 7?}
D3 --> D4
D4 -->|Yes| D5[WRITE primes-table line\n132-char data record\nSET primes-idx TO 1]
D4 -->|No| D6{linage-counter = 53?}
D5 --> D6
D6 -->|Yes| D7[r94-eop\nWRITE blank line\nWRITE primes-footing\npage-number += 1\nprint-new-page = 1]
D6 -->|No| Z
F --> F1[MOVE 0 TO u-sequence and u-number\nPERFORM r92-write-primesui\nUNTIL new-page — flush partial line]
F1 --> F2[LOG 'close printer'\nCLOSE fprinter\nui-method-result = primes-prt-status]
C2 --> Z
C3 --> Z
D7 --> Z
E --> Z
F2 --> Z
G --> Z
Z([EXIT PROGRAM])
Page management state machine:
print-new-page = 1 (initial)
│
▼ (on any "write" call)
IF new-page → r93-new-page:
WRITE heading + column header
print-new-page = 0
│
▼ (accumulate 6 entries)
IF primes-idx = 7 → WRITE data line, reset idx to 1
│
▼
IF linage-counter = 53 → r94-eop:
WRITE blank + footing
page-number += 1
print-new-page = 1 ← triggers new heading on next write
7. Inter-Program Call Sequence — Generate Run
What it shows: All CALL interactions between programs during a generate invocation, including the sieve loop, each divisor lookup, each prime insertion, and the shutdown sequence.
sequenceDiagram
participant OS as OS / Shell
participant main as primesmain
participant gen as primesgen
participant dal as primes (DAL)
participant ui as primesui
participant db as PostgreSQL
OS->>main: execute with arg "generate"
main->>ui: CALL "primesui" ui-methods="start"
ui-->>main: ui-method-result=0 / primes.prt opened
main->>ui: CALL "primesui" ui-methods="log-message" "Primes generation starts."
ui->>OS: DISPLAY on console
main->>gen: CALL "primesgen" methods="generate"
gen->>dal: CALL "primes" dal-methods="connect"
dal->>db: EXEC SQL CONNECT TO primes
db-->>dal: SQLCODE=0
dal-->>gen: dal-result=0
gen->>ui: LOG "Database initialisation succeeded."
loop sieve: test-number 3 → 999,999,999
gen->>gen: DIVIDE test-number BY test-divider → test-rest
alt test-rest = 0 (composite)
gen->>gen: r82-next-test-number (test-number += 2, sqrt recalc)
gen->>dal: CALL "primes" dal-methods="next-divider"
dal->>db: SELECT prime WHERE ident = :new-ident
db-->>dal: test-divider value
dal-->>gen: dal-result=0
else test-divider > √test-number (prime confirmed)
gen->>ui: CALL "primesui" ui-methods="write" u-sequence, u-number
ui->>ui: accumulate in 6-column buffer\nwrite line to primes.prt every 6 entries
gen->>dal: CALL "primes" dal-methods="write"
dal->>db: INSERT INTO primes (prime) VALUES (:prime)
db-->>dal: SQLCODE=0
dal-->>gen: dal-result=0
gen->>gen: r82-next-test-number
else otherwise (try next divisor)
gen->>dal: CALL "primes" dal-methods="next-divider"
dal->>db: SELECT prime WHERE ident = :new-ident
db-->>dal: test-divider value
dal-->>gen: dal-result=0
end
end
gen->>dal: CALL "primes" dal-methods="disconnect"
dal->>db: EXEC SQL CONNECT RESET primes
db-->>dal: SQLCODE=0
dal-->>gen: dal-result=0
gen-->>main: session-result=0 / EXIT PROGRAM
main->>ui: CALL "primesui" ui-methods="log-message" "Primes run complete."
main->>ui: CALL "primesui" ui-methods="stop"
ui->>ui: flush partial line\nCLOSE primes.prt
ui-->>main: ui-method-result=0
main->>OS: STOP RUN
8. Inter-Program Call Sequence — Report Run
What it shows: All CALL interactions during a report invocation — UI setup, database connection, transaction and cursor lifecycle, the fetch loop, and shutdown.
sequenceDiagram
participant OS as OS / Shell
participant main as primesmain
participant gen as primesgen
participant dal as primes (DAL)
participant ui as primesui
participant db as PostgreSQL
participant prt as primes.prt
OS->>main: execute with arg "report"
main->>ui: CALL "primesui" ui-methods="start"
ui->>prt: OPEN OUTPUT
prt-->>ui: file-status="00"
ui-->>main: ui-method-result=0
main->>gen: CALL "primesgen" methods="report"
gen->>dal: CALL "primes" dal-methods="connect"
dal->>db: EXEC SQL CONNECT TO primes
db-->>dal: SQLCODE=0
dal-->>gen: dal-result=0
gen->>ui: LOG "Database initialisation succeeded."
gen->>dal: CALL "primes" dal-methods="cursor"
dal->>db: EXEC SQL AT primes START TRANSACTION
dal->>db: EXEC SQL OPEN primescursor
db-->>dal: SQLCODE=0
dal-->>gen: dal-result=0
gen->>ui: LOG "Cursor initialisation succeeded."
gen->>dal: r94-fetch → dal-methods="next-prime"
dal->>db: EXEC SQL FETCH primescursor INTO :primes-row
db-->>dal: first row (ident, prime)
dal-->>gen: primes-sequence, prime-number / dal-result=0
gen->>ui: LOG "Fetch first row ok."
loop for each row until cursor exhausted
gen->>ui: CALL "primesui" ui-methods="write" u-sequence / u-number
ui->>prt: accumulate in 6-col buffer\nwrite 132-char line every 6 entries\nwrite heading+footing at page boundaries
gen->>dal: r94-fetch → dal-methods="next-prime"
dal->>db: EXEC SQL FETCH primescursor
db-->>dal: next row or SQLCODE≠0 (no more rows)
dal-->>gen: dal-result=0 (row) or dal-result=1 (eof/error)
note over gen: ⚠️ session-method-eof (9) never set;\nloop exits on error (1), not clean eof
end
gen->>dal: CALL "primes" dal-methods="disconnect"
dal->>db: EXEC SQL CONNECT RESET primes
db-->>dal: SQLCODE=0
dal-->>gen: dal-result=0
gen-->>main: session-result=0 / EXIT PROGRAM
main->>ui: CALL "primesui" ui-methods="log-message" "Primes run complete."
main->>ui: CALL "primesui" ui-methods="stop"
ui->>ui: pad remaining cells with zeros\nPERFORM r92 UNTIL new-page\nCLOSE fprinter
ui->>prt: CLOSE
prt-->>ui: file-status="00"
ui-->>main: ui-method-result=0
main->>OS: STOP RUN