Technical-Specification

From Webhuis wiki
Revision as of 21:28, 24 March 2026 by Martin (talk | contribs) (Created page with "<span id="technical-specification"></span> = Technical Specification = <blockquote>'''Document ID:''' PGCBL-TSD-001 · '''Version:''' 1.0 · '''Status:''' Approved · '''Last updated:''' 2026-03-17 </blockquote> '''← Business Requirements''' | Data Dictionary → ----- <span id="contents"></span> == Contents == # System Architecture #* Three-Tier Model #* #12-inter-...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Technical Specification[edit]

Document ID: PGCBL-TSD-001 · Version: 1.0 · Status: Approved · Last updated: 2026-03-17

Business Requirements | Data Dictionary →



Contents[edit]

  1. System Architecture
  2. Component Inventory
  3. Pseudocode
  4. Database Connection Parameters
  5. SQL Statement Inventory
  6. File I/O Specification
  7. Known Technical Issues



1. System Architecture[edit]

1.1 Three-Tier Model[edit]

┌──────────────────────────────────────────────────────┐
│                    primesmain                        │
│   Orchestrator · session controller · entry point   │
│   Source: primesmain.cbl                             │
└───────────────────────┬──────────────────────────────┘
                        │ CALL "primesgen" USING primes-session
              ┌─────────▼──────────────┐
              │       primesgen        │
              │  Business Logic tier   │
              │  Sieve algorithm or    │
              │  cursor read-loop      │
              │  Source: primesgen.cbl │
              └──────┬─────────────────┘
    CALL "primes"    │           │ CALL "primesui"
    USING primes-dal │           │ USING primes-ui
           ┌─────────▼──┐   ┌───▼──────────────┐
           │   primes   │   │    primesui       │
           │  Data      │   │  Presentation     │
           │  Access    │   │  Print file       │
           │  Layer     │   │  Console log      │
           │  All SQL   │   │  primesui.cbl     │
           │  primes.cbl│   └───────────────────┘
           └──────┬─────┘           │
                  │ EXEC SQL        │ WRITE to
                  │ via GixSQL      │ primes.prt
           ┌──────▼─────────────┐   │
           │   PostgreSQL 11    │   │
           │  schema: primes    │   ▼
           │  table:  primes    │  (file system)
           └────────────────────┘

Design rule: SQL appears only in primes.cbl. File I/O appears only in primesui.cbl. All other programs use the method-dispatch pattern to delegate to these two.

1.2 Inter-Tier Communication Pattern[edit]

Every program-to-program call uses the same protocol:

Step 1  Caller MOVEs a verb string into the control block's methods field
           MOVE "connect" TO dal-methods

Step 2  Caller invokes the subprogram, passing the control block by reference
           CALL "primes" USING primes-dal

Step 3  Callee EVALUATEs the verb and performs the matching paragraph
           EVALUATE TRUE
             WHEN db-connect  → PERFORM s00-connect
             ...

Step 4  Callee sets a result code before EXIT PROGRAM
           MOVE 0 TO dal-result   ← success

Step 5  Caller inspects the result code
           IF dal-method-ok THEN ...
Tier boundary Control block Verbs Result codes
primesmain → primesgen primes-session report · generate 0=ok · 1=nok · 9=eof
primesgen → primes primes-dal connect · cursor · next-prime · next-divider · write · disconnect 0=ok · 1=nok · 99=eof
any → primesui primes-ui start · write · log-message · stop 0=ok · 1=nok



2. Component Inventory[edit]

Programs[edit]

Program Source file Tier Contains SQL Opens files
primesmain primesmain.cbl Orchestrator No No
primesgen primesgen.cbl Business logic No No (FD declared but unused)
primes primes.cbl Data access Yes — via GixSQL No
primesui primesui.cbl Presentation No Yes — primes.prt

Copybooks[edit]

Copybook Root record Used by Purpose
primes-session.cpy primes-session primesmain · primesgen Session-tier control block
primes-dal.cpy primes-dal primesgen · primes DAL-tier control block
primes-ui.cpy primes-ui all four UI-tier control block
primes-table.cpy primes-table primes SQL host variables — character format
primes_table.cpy primes_table primes SQL host variables — COMP-3 format ⚠ duplicate
SQLCA.cpy SQLCA primes GixSQL SQL Communications Area

Full field definitions: Data Dictionary → Control Blocks



3. Pseudocode[edit]

3.1 primesmain[edit]

PROGRAM primesmain
  ACCEPT commandline-args FROM COMMAND-LINE      ← PIC X(32)

  MOVE commandline-args TO methods               ← load session control block
  MOVE "primesmain"     TO program-name

  CALL primesui("start")                         ← open primes.prt
  IF ui-method-result ≠ 0 THEN
    DISPLAY "Emergency: UI failed" ON console
    STOP RUN                                     ← hard abort, no cleanup

  LOG "UI initialisation succeeded."
  LOG commandline-args

  EVALUATE commandline-args
    WHEN "report"
      LOG "Primes report generation starts."
      MOVE "report"    TO methods
      CALL primesgen USING primes-session        ← report path

    WHEN "generate"
      LOG "Primes generation starts."
      MOVE "generate"  TO methods
      ── CALL primesgen commented out ──         ← ⚠ Defect T1

    WHEN OTHER
      LOG "Bad parameter, program initialisation failed."
      CALL primesui("stop")
      STOP RUN
  END-EVALUATE

  LOG "Primes run complete, program stops."
  CALL primesui("stop")                          ← flush + close primes.prt
  STOP RUN
END PROGRAM

3.2 primesgen — Generate Path[edit]

PROCEDURE r91-start-primes-generation
  CALL primes("connect")
  IF dal-method-ok THEN
    test-divider    = 2                          ← first divisor
    old-ident       = 1
    test-number     = 3                          ← first candidate (odd)
    test-number-sqr = SQRT(3)                    ← COMPUTE test-number ** 0.5
    LOG "Database initialisation succeeded."
  ELSE
    LOG "Database initialisation failed."
    session-result = 1
    RETURN                                       ← falls through to r99-close-primes

MAIN LOOP — PERFORM r80-test-number UNTIL test-number = 999999999

  PROCEDURE r80-test-number
    DIVIDE test-number BY test-divider
           GIVING test-quot REMAINDER test-rest

    EVALUATE TRUE
      WHEN test-rest = 0                         ← divisible → composite
        PERFORM r82-next-test-number

      WHEN test-divider > test-number-sqr        ← no factor ≤ √N → prime
        PERFORM r85-write-prime
        PERFORM r82-next-test-number

      WHEN OTHER                                 ← keep trying
        PERFORM r89-get-next-divider

  PROCEDURE r82-next-test-number
    ADD 2 TO test-number                         ← skip even numbers
    COMPUTE test-number-sqr = test-number ** 0.5
    MOVE 1 TO old-ident
    PERFORM r89-get-next-divider                 ← reload first divisor

  PROCEDURE r85-write-prime
    MOVE "write" TO ui-methods
    CALL primes   USING primes-dal               ← INSERT INTO primes (prime)
    CALL primesui USING primes-ui                ← accumulate in print buffer

  PROCEDURE r89-get-next-divider
    MOVE "get" TO gen-methods                    ← verb for the local primes group
    CALL primes USING primes                     ← SELECT prime WHERE ident = old-ident+1
                                                 ← sets test-divider

END LOOP
CALL primes("disconnect")
EXIT PROGRAM

3.3 primesgen — Report Path[edit]

PROCEDURE r90-start-primes-report
  CALL primes("connect")
  IF NOT dal-method-ok THEN
    LOG "Database initialisation failed."
    session-result = 1
    GOTO r99-close-primes

  CALL primes("cursor")                          ← START TRANSACTION; OPEN primescursor
  IF NOT dal-method-ok THEN
    LOG "Cursor initialisation failed."
    session-result = 1
    GOTO r99-close-primes

  PERFORM r94-fetch                              ← position cursor on first row
  IF dal-method-ok THEN
    LOG "Fetch first row ok."
    MOVE 0 TO dal-result
  ELSE
    LOG "Fetch first row nok."
    MOVE 1 TO dal-result

REPORT LOOP — PERFORM r86-report-primes UNTIL session-method-eof

  PROCEDURE r86-report-primes
    MOVE "write"     TO ui-methods
    MOVE primes-data TO u-primes                 ← primes-sequence + prime-number → u-sequence + u-number
    CALL primesui USING primes-ui                ← write to 6-column print buffer
    PERFORM r94-fetch                            ← advance cursor

  PROCEDURE r94-fetch
    MOVE "next-prime" TO dal-methods
    CALL primes USING primes-dal                 ← FETCH primescursor INTO :primes-row
    IF NOT dal-method-ok THEN
      LOG "Fetch failed."
      session-result = 1                         ← ⚠ sets nok (1), not eof (9) — loop may not terminate
                                                 ← See Defect T7 in defect register

END LOOP
CALL primes("disconnect")
EXIT PROGRAM

3.4 primes (DAL)[edit]

PROGRAM primes  USING primes-dal

  EVALUATE TRUE on dal-methods
    WHEN db-connect      → PERFORM s00-connect
    WHEN db-cursor       → PERFORM s01-cursor
    WHEN next-prime      → PERFORM r80-get-next-prime  (→ s02-fetch)
    WHEN next-divider    → PERFORM r81-get-next-divider
    WHEN write-prime     → PERFORM r83-write-prime
    WHEN db-disconnect   → PERFORM s99-disconnect
    WHEN OTHER           → MOVE 1 TO dal-result
  END-EVALUATE
  EXIT PROGRAM

── s00-connect ──────────────────────────────────────────────────────
  EXEC SQL
    CONNECT TO :DATASRC AS primes USER :DBUSR USING :DBPWD
  END-EXEC
  IF SQLCODE = 0 THEN dal-result = 0
  ELSE LOG error; dal-result = 1

── s01-cursor ───────────────────────────────────────────────────────
  EXEC SQL AT primes START TRANSACTION END-EXEC
  IF SQLCODE = 0 THEN LOG "Start transaction ok."
  ELSE dal-result = 1

  IF dal-method-ok THEN
    EXEC SQL OPEN primescursor END-EXEC
    IF SQLCODE = 0 THEN LOG "Start primescursor ok."
    ELSE dal-result = 1

── s02-fetch (called by r80-get-next-prime) ─────────────────────────
  EXEC SQL FETCH primescursor INTO :primes-row END-EXEC
  IF SQLCODE = 0 THEN
    primes-sequence = r-ident
    prime-number    = r-prime
    dal-result = 0
  ELSE LOG error; dal-result = 1

── r81-get-next-divider ─────────────────────────────────────────────
  ADD 1 TO old-ident GIVING new-ident
  EXEC SQL AT primes
    SELECT prime INTO :test-divider
    FROM primes WHERE ident = :new-ident
  END-EXEC
  IF SQLCODE ≠ 0 THEN DISPLAY SQLCODE; DISPLAY "select new-divider nok"
  MOVE new-ident TO old-ident

── r83-write-prime ──────────────────────────────────────────────────
  EXEC SQL AT primes
    INSERT INTO primes (prime) VALUES (:prime)
  END-EXEC
  IF SQLCODE ≠ 0 THEN DISPLAY SQLCODE; DISPLAY "insert nok: " prime-number
  ── COMMIT is commented out ──                  ← ⚠ Defect T3

── s99-disconnect ───────────────────────────────────────────────────
  EXEC SQL CONNECT RESET primes END-EXEC         ← ⚠ Defect T2: cbsql.out shows "primesdb"
  IF SQLCODE = 0 THEN dal-result = 0
  ELSE dal-result = 1
  DISPLAY "s99 disconnect from database"
  DISPLAY SQLCODE

3.5 primesui[edit]

PROGRAM primesui  USING primes-ui

  EVALUATE TRUE on ui-methods
    WHEN start-ui    → PERFORM r90-start-primesui
    WHEN write-ui    → PERFORM r92-write-primesui
    WHEN message-ui  → PERFORM r98-message-ui
    WHEN stop-ui     → PERFORM r99-stop-primesui
    WHEN OTHER       → MOVE 1 TO ui-method-result
  END-EVALUATE
  EXIT PROGRAM

── r90-start-primesui ───────────────────────────────────────────────
  OPEN OUTPUT fprinter  (primes.prt)
  IF primes-prt-status = "00" THEN
    SET primes-idx TO 1
    MOVE 0 TO ui-method-result
    LOG "Open printer Ok"
  ELSE
    MOVE 1 TO ui-method-result
    DISPLAY primes-prt-status ON console

── r92-write-primesui ───────────────────────────────────────────────
  t-ident(primes-idx) = u-sequence               ← load into current cell
  t-prime(primes-idx) = u-number
  SET primes-idx UP BY 1                         ← advance index

  IF new-page THEN PERFORM r93-new-page          ← heading + column header

  IF primes-idx = 7 THEN                         ← 6 entries filled
    WRITE file-buffer FROM primes-table          ← 132-char data line
    SET primes-idx TO 1

  IF linage-counter = 53 THEN                    ← 3 lines from page end
    PERFORM r94-eop                              ← footing + page increment

── r93-new-page ─────────────────────────────────────────────────────
  WRITE primes-heading   (="primes overview")
  WRITE table-header     (="Sequence  Prime  " × 6)
  MOVE ZERO TO print-new-page                    ← clear flag

── r94-eop ──────────────────────────────────────────────────────────
  WRITE blank line
  WRITE primes-footing   (right-aligned "page: ZZZZ9")
  ADD 1 TO page-number
  MOVE 1 TO print-new-page                       ← trigger heading on next write

── r98-message-ui ───────────────────────────────────────────────────
  DISPLAY process-message UPON scherm            ← program-name + paragraph + message

── r99-stop-primesui ────────────────────────────────────────────────
  MOVE 0 TO u-sequence
  MOVE 0 TO u-number
  PERFORM r92-write-primesui UNTIL new-page      ← flush partial line with zeros
  LOG "close printer"
  CLOSE fprinter
  MOVE primes-prt-status TO ui-method-result

4. Database Connection Parameters[edit]

Parameter Value
Driver pgsql (GixSQL native PostgreSQL driver)
Host localhost
Port 5432
Database name primes
Schema primes (set via default_schema=primes in connection string)
Connection alias primes (used in all EXEC SQL AT primes clauses)
User primes_user
Password pr1mes_user ⚠ hard-coded — see Defect T5
Full connection string pgsql://localhost:5432/primes&default_schema=primes



5. SQL Statement Inventory[edit]

ID Statement Paragraph Path
S1 CONNECT TO :DATASRC AS primes USER :DBUSR USING :DBPWD s00-connect Both
S2 START TRANSACTION s01-cursor Report only
S3 DECLARE primescursor CURSOR FOR SELECT * FROM primes Compile-time Report only
S4 OPEN primescursor s01-cursor Report only
S5 FETCH primescursor INTO :primes-row s02-fetch Report only
S6 SELECT prime INTO :test-divider FROM primes WHERE ident = :new-ident r81-get-next-divider Generate only
S7 INSERT INTO primes (prime) VALUES (:prime) r83-write-prime Generate only
S8 CONNECT RESET primes s99-disconnect Both

Host variable mappings:

SQL host variable COBOL field PICTURE Source
:DATASRC DATASRC PIC X(64) WS — primes.cbl
:DBUSR DBUSR PIC X(64) WS — primes.cbl
:DBPWD DBPWD PIC X(64) WS — primes.cbl
:primes-row primes-row group r-ident + r-prime COMP-3 WS — primes.cbl
:test-divider test-divider PIC 9(9) WS — primes.cbl local primes group
:new-ident new-ident PIC 9(9) WS — primes.cbl local primes group
:prime prime-number PIC 9(9) Linkage — primes-dal.primes-data



6. File I/O Specification[edit]

Print file primes.prt[edit]

Property Value
Logical name fprinter
Physical name primes.prt (relative to working directory)
Organisation Line-sequential
Record length 132 characters
Linage 56 lines per page
Footing area Lines 55–56 (last 2 of linage)
Bottom margin 2 lines
Top margin 0 (not specified)
Open mode OUTPUT (write-only; created fresh each run)
File-status field primes-prt-status PIC X(2)
EOP trigger linage-counter = 53 (3 lines before page end)

Record types[edit]

Record Content Width
Page heading "primes overview" left-justified 118 + 14 padding = 132
Column header "Sequence Prime " × 6 132
Data line 6 × (Z(9) seq + X(2) sp + Z(9) prime + X(2) sp) 132
Blank separator Spaces 132
Page footing 118 spaces + "page: " + Z(3)9 132



7. Known Technical Issues[edit]

ID Severity Description Impact
T1 🔴 High Generate loop (PERFORM r80-test-number) is commented out in primesmain.cbl line 51 generate mode does not execute the sieve
T2 🔴 High primes_cbsql.out shows disconnect targeting alias primesdb; runtime code uses alias primes Disconnect call will fail with alias-not-found error at runtime
T3 🟡 Medium COMMIT after INSERT is commented out in r83-write-prime Relies on PostgreSQL auto-commit; INSERTs will not commit if an explicit transaction is open
T4 🟡 Medium Prime 2 is not seeded by the algorithm; sieve starts at 3 with old-ident = 1, assuming a row exists at ident = 2 Divider lookup will fail or return wrong value on a fresh empty database
T5 🟠 Medium Database credentials hard-coded in primes.cbl WORKING-STORAGE Credential rotation requires recompile; credentials visible in binary
T6 🔵 Low Two near-duplicate host-variable copybooks: primes-table.cpy (char) and primes_table.cpy (COMP-3, underscore) Ambiguity about which is canonical; risk of one being stale
T7 🟡 Medium On fetch failure, session-result is set to 1 (nok), not 9 (eof); the report loop condition session-method-eof (value 9) is never triggered by normal cursor exhaustion Report loop may not terminate cleanly at end of data



Business Requirements | Data Dictionary →