Editing
Technical-Specification
(section)
Jump to navigation
Jump to search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
= Technical Specification = <blockquote>'''Document ID:''' PGCBL-TSD-001 Β· '''Version:''' 1.0 Β· '''Status:''' Approved Β· '''Last updated:''' 2026-03-17 </blockquote> '''β [[Business-Requirements|Business Requirements]]''' | [[Data-Dictionary|Data Dictionary β]] ----- <span id="contents"></span> == Contents == # [[#1-system-architecture|System Architecture]] #* [[#11-three-tier-model|Three-Tier Model]] #* [[#12-inter-tier-communication-pattern|Inter-Tier Communication Pattern]] # [[#2-component-inventory|Component Inventory]] # [[#3-pseudocode|Pseudocode]] #* [[#31-primesmain|primesmain]] #* [[#32-primesgen--generate-path|primesgen β Generate Path]] #* [[#33-primesgen--report-path|primesgen β Report Path]] #* [[#34-primes-dal|primes (DAL)]] #* [[#35-primesui|primesui]] # [[#4-database-connection-parameters|Database Connection Parameters]] # [[#5-sql-statement-inventory|SQL Statement Inventory]] # [[#6-file-io-specification|File I/O Specification]] # [[#7-known-technical-issues|Known Technical Issues]] ----- <span id="system-architecture"></span> == 1. System Architecture == <span id="three-tier-model"></span> === 1.1 Three-Tier Model === <pre>ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β 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) ββββββββββββββββββββββ</pre> '''Design rule:''' SQL appears only in <code>primes.cbl</code>. File I/O appears only in <code>primesui.cbl</code>. All other programs use the method-dispatch pattern to delegate to these two. <span id="inter-tier-communication-pattern"></span> === 1.2 Inter-Tier Communication Pattern === Every program-to-program call uses the same protocol: <pre>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 ...</pre> {| !width="25%"| Tier boundary !width="25%"| Control block !width="25%"| Verbs !width="25%"| Result codes |- | primesmain β primesgen | [[Data-Dictionary#11-primes-session|<code>primes-session</code>]] | <code>report</code> Β· <code>generate</code> | 0=ok Β· 1=nok Β· 9=eof |- | primesgen β primes | [[Data-Dictionary#12-primes-dal|<code>primes-dal</code>]] | <code>connect</code> Β· <code>cursor</code> Β· <code>next-prime</code> Β· <code>next-divider</code> Β· <code>write</code> Β· <code>disconnect</code> | 0=ok Β· 1=nok Β· 99=eof |- | any β primesui | [[Data-Dictionary#13-primes-ui|<code>primes-ui</code>]] | <code>start</code> Β· <code>write</code> Β· <code>log-message</code> Β· <code>stop</code> | 0=ok Β· 1=nok |} ----- <span id="component-inventory"></span> == 2. Component Inventory == <span id="programs"></span> === Programs === {| !width="20%"| Program !width="20%"| Source file !width="20%"| Tier !width="20%"| Contains SQL !width="20%"| Opens files |- | <code>primesmain</code> | <code>primesmain.cbl</code> | Orchestrator | No | No |- | <code>primesgen</code> | <code>primesgen.cbl</code> | Business logic | No | No (FD declared but unused) |- | <code>primes</code> | <code>primes.cbl</code> | Data access | Yes β via GixSQL | No |- | <code>primesui</code> | <code>primesui.cbl</code> | Presentation | No | Yes β <code>primes.prt</code> |} <span id="copybooks"></span> === Copybooks === {| !width="25%"| Copybook !width="25%"| Root record !width="25%"| Used by !width="25%"| Purpose |- | <code>primes-session.cpy</code> | <code>primes-session</code> | primesmain Β· primesgen | Session-tier control block |- | <code>primes-dal.cpy</code> | <code>primes-dal</code> | primesgen Β· primes | DAL-tier control block |- | <code>primes-ui.cpy</code> | <code>primes-ui</code> | all four | UI-tier control block |- | <code>primes-table.cpy</code> | <code>primes-table</code> | primes | SQL host variables β character format |- | <code>primes_table.cpy</code> | <code>primes_table</code> | primes | SQL host variables β COMP-3 format β duplicate |- | <code>SQLCA.cpy</code> | <code>SQLCA</code> | primes | GixSQL SQL Communications Area |} Full field definitions: [[Data-Dictionary#1-control-blocks-copybooks|Data Dictionary β Control Blocks]] ----- <span id="pseudocode"></span> == 3. Pseudocode == <span id="primesmain"></span> === 3.1 primesmain === <pre>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</pre> ----- <span id="primesgen-generate-path"></span> === 3.2 primesgen β Generate Path === <pre>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</pre> ----- <span id="primesgen-report-path"></span> === 3.3 primesgen β Report Path === <pre>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</pre> ----- <span id="primes-dal"></span> === 3.4 primes (DAL) === <pre>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</pre> ----- <span id="primesui"></span> === 3.5 primesui === <pre>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</pre> ----- <span id="database-connection-parameters"></span> == 4. Database Connection Parameters == {| !width="50%"| Parameter !width="50%"| Value |- | Driver | <code>pgsql</code> (GixSQL native PostgreSQL driver) |- | Host | <code>localhost</code> |- | Port | <code>5432</code> |- | Database name | <code>primes</code> |- | Schema | <code>primes</code> (set via <code>default_schema=primes</code> in connection string) |- | Connection alias | <code>primes</code> (used in all <code>EXEC SQL AT primes</code> clauses) |- | User | <code>primes_user</code> |- | Password | <code>pr1mes_user</code> β hard-coded β see [[#7-known-technical-issues|Defect T5]] |- | Full connection string | <code>pgsql://localhost:5432/primes&default_schema=primes</code> |} ----- <span id="sql-statement-inventory"></span> == 5. SQL Statement Inventory == {| !width="25%"| ID !width="25%"| Statement !width="25%"| Paragraph !width="25%"| Path |- | S1 | <code>CONNECT TO :DATASRC AS primes USER :DBUSR USING :DBPWD</code> | <code>s00-connect</code> | Both |- | S2 | <code>START TRANSACTION</code> | <code>s01-cursor</code> | Report only |- | S3 | <code>DECLARE primescursor CURSOR FOR SELECT * FROM primes</code> | Compile-time | Report only |- | S4 | <code>OPEN primescursor</code> | <code>s01-cursor</code> | Report only |- | S5 | <code>FETCH primescursor INTO :primes-row</code> | <code>s02-fetch</code> | Report only |- | S6 | <code>SELECT prime INTO :test-divider FROM primes WHERE ident = :new-ident</code> | <code>r81-get-next-divider</code> | Generate only |- | S7 | <code>INSERT INTO primes (prime) VALUES (:prime)</code> | <code>r83-write-prime</code> | Generate only |- | S8 | <code>CONNECT RESET primes</code> | <code>s99-disconnect</code> | Both |} '''Host variable mappings:''' {| !width="25%"| SQL host variable !width="25%"| COBOL field !width="25%"| PICTURE !width="25%"| Source |- | <code>:DATASRC</code> | <code>DATASRC</code> | <code>PIC X(64)</code> | WS β <code>primes.cbl</code> |- | <code>:DBUSR</code> | <code>DBUSR</code> | <code>PIC X(64)</code> | WS β <code>primes.cbl</code> |- | <code>:DBPWD</code> | <code>DBPWD</code> | <code>PIC X(64)</code> | WS β <code>primes.cbl</code> |- | <code>:primes-row</code> | <code>primes-row</code> group | r-ident + r-prime <code>COMP-3</code> | WS β <code>primes.cbl</code> |- | <code>:test-divider</code> | <code>test-divider</code> | <code>PIC 9(9)</code> | WS β <code>primes.cbl</code> local <code>primes</code> group |- | <code>:new-ident</code> | <code>new-ident</code> | <code>PIC 9(9)</code> | WS β <code>primes.cbl</code> local <code>primes</code> group |- | <code>:prime</code> | <code>prime-number</code> | <code>PIC 9(9)</code> | Linkage β <code>primes-dal.primes-data</code> |} ----- <span id="file-io-specification"></span> == 6. File I/O Specification == <span id="print-file-primes.prt"></span> === Print file <code>primes.prt</code> === {| ! Property ! Value |- | Logical name | <code>fprinter</code> |- | Physical name | <code>primes.prt</code> (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 | <code>OUTPUT</code> (write-only; created fresh each run) |- | File-status field | <code>primes-prt-status</code> <code>PIC X(2)</code> |- | EOP trigger | <code>linage-counter = 53</code> (3 lines before page end) |} <span id="record-types"></span> === Record types === {| !width="33%"| Record !width="33%"| Content !width="33%"| Width |- | Page heading | <code>"primes overview"</code> left-justified | 118 + 14 padding = 132 |- | Column header | <code>"Sequence Prime "</code> Γ 6 | 132 |- | Data line | 6 Γ (<code>Z(9)</code> seq + <code>X(2)</code> sp + <code>Z(9)</code> prime + <code>X(2)</code> sp) | 132 |- | Blank separator | Spaces | 132 |- | Page footing | 118 spaces + <code>"page: "</code> + <code>Z(3)9</code> | 132 |} ----- <span id="known-technical-issues"></span> == 7. Known Technical Issues == {| !width="25%"| ID !width="25%"| Severity !width="25%"| Description !width="25%"| Impact |- | T1 | π΄ High | Generate loop (<code>PERFORM r80-test-number</code>) is commented out in <code>primesmain.cbl</code> line 51 | <code>generate</code> mode does not execute the sieve |- | T2 | π΄ High | <code>primes_cbsql.out</code> shows disconnect targeting alias <code>primesdb</code>; runtime code uses alias <code>primes</code> | Disconnect call will fail with alias-not-found error at runtime |- | T3 | π‘ Medium | COMMIT after INSERT is commented out in <code>r83-write-prime</code> | 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 <code>old-ident = 1</code>, assuming a row exists at <code>ident = 2</code> | Divider lookup will fail or return wrong value on a fresh empty database |- | T5 | π Medium | Database credentials hard-coded in <code>primes.cbl</code> WORKING-STORAGE | Credential rotation requires recompile; credentials visible in binary |- | T6 | π΅ Low | Two near-duplicate host-variable copybooks: <code>primes-table.cpy</code> (char) and <code>primes_table.cpy</code> (COMP-3, underscore) | Ambiguity about which is canonical; risk of one being stale |- | T7 | π‘ Medium | On fetch failure, <code>session-result</code> is set to 1 (nok), not 9 (eof); the report loop condition <code>session-method-eof</code> (value 9) is never triggered by normal cursor exhaustion | Report loop may not terminate cleanly at end of data |} ----- '''β [[Business-Requirements|Business Requirements]]''' | [[Data-Dictionary|Data Dictionary β]]
Summary:
Please note that all contributions to Webhuis wiki are considered to be released under the GNU Free Documentation License 1.3 or later (see
Project:Copyrights
for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Navigation menu
Personal tools
Not logged in
Talk
Contributions
Create account
Log in
Namespaces
Page
Discussion
English
Views
Read
Edit
View history
More
Search
Navigation
Voorpagina
Cobol and PostgreSQL
PostgreSQL
CFEngine
Proxmox
Webhuis Kennisbank
Basale infra
Webhuis bouwstenen
Webhuis configuratie
Webhuis Infra
Webhuis Support
Webhuis Raspberry
Opzet Applicaties
Business Applicaties
Community portal
Current events
Recent changes
Random page
Help
sitesupport
Tools
What links here
Related changes
Special pages
Page information