14. TŘÍDĚNÍ 14.1. Úvodní informace Jazyk COBOL umožňuje dva způsoby třídění logických vět: a) Třídění v plném slova smyslu, při němž se nepředpokládá, že by logické věty vstupující do třídění byly již předem nějakým způsobem setříděny (příkaz SORT). b) Zatřiďování (též směšování nebo slučování), kdy logické věty vstupují z několika vstupních souborů, přičemž uvnitř každého z nich jsou již setříděné (příkaz MERGE). Chce-li uživatel v programu třídit, musí si v něm deklarovat tzv. třídicí soubor (pozor, třídicí soubor nepatří mezi soubory a nemá s nimi kromě názvu nic společného). Z historických důvodů se deklarace třídicího souboru zapisuje obdobně jako deklarace souboru, má však poněkud jiný význam: a) Pro třídicí soubor je možno v paragrafu FILE-CONTROL uvést klauzuli "SELECT jméno-třídicího-souboru atd." (viz 3.4.). Tato klauzule SELECT sice nesmí být syntakticky rozporná, nicméně všechny informace v ní uvedené se zcela ignorují. Klauzule SELECT pro třídicí soubor (tj. patřící ke klauzuli SD) smí být vynechána. b) Jména všech třídicích souborů musí být různá od sebe navzájem a dále musí být různá ode všech jmen souborů a (jsou-li alespoň jednou použita) též ode všech jmen komunikačních oblastí a ode všech jmen sestav. c) Třídicí soubor se definuje pomocí klauzule SD uvedené ve FILE SECTION a následované popisy logických vět (01) k ní patřících (viz 14.2.). d) Třídicí soubor slouží pouze pro účely třídění; nemá smysl popisovat jej v programu, v němž není žádný příkaz SORT ani MERGE. e) Vlastní třídění nebo zatřiďování se provádí v PROCEDURE DIVISION pomocí příkazů SORT, MERGE, RELEASE a RETURN. Při obou typech třídění musí uživatel zadat následující informace: a) Typ, délku a strukturu logických vět, které se budou třídit - zadává se pomocí klauzule SD a k ní příslušných popisů logických vět (01). b) Způsob, podle něhož mají být logické věty setříděny - zadává se pomocí klauzulí ASCENDING a DESCENDING v příkazu SORT resp. MERGE. c) Způsob vstupu logických vět do třídění - zadává se pomocí klauzule USING nebo INPUT v příkazu SORT resp. pomocí klauzule USING v příkazu MERGE. d) Způsob výstupu logických vět ze třídění - zadává se pomocí klauzule GIVING nebo OUTPUT v příkazu SORT resp. MERGE. e) Způsob předávání logických vět mezi uživatelovou vstupní resp. výstupní rutinou a systémovým třídicím programem - provádí se pomocí příkazů RELEASE resp. RETURN. Poznámka: Používaná terminologie se vztahuje k systémovému třídicímu programu a nikoliv k uživateli: Když cobolský program předává logickou větu systémovému třídicímu programu, mluvíme o vstupu, a když systémový třídicí program předává (vrací) logickou větu zpět cobolskému programu, mluvíme o výstupu. 14.2. Klauzule SD Formát: SD jméno-třídicího-souboru [ RECORDING MODE IS {F | V} ] [ RECORD CONTAINS [celé-č.-1 TO] celé-číslo-2 CHARACTERS ] [ LABEL slovo... ] [ DATA slovo... ]. Pravidla: 1) Klauzule SD se uvádí ve FILE SECTION. Syntakticky má stejný formát jako klauzule FD s těmito odchylkami: a) Místo FD se píše SD. b) Nesmí být uvedeno RECORDING U. c) Nesmí být uvedeny klauzule BLOCK, VALUE OF, LINAGE ani REPORT resp. REPORTS. 2) Za klauzulí SD musí následovat popis jedné nebo několika logických vět (01). Pro jejich zápis platí přesně stejná pravidla jako pro logické věty (01) popsané za klauzulí FD (takže je-li za určitou klauzulí SD popsáno více 01, začínají všechny tyto 01 od téže adresy a tedy se v paměti překrývají). Tyto 01 a jim podřízené položky mohou být uvedeny v kterémkoliv příkazu nebo klauzuli jazyka COBOL, je však přípustné pracovat s nimi pouze během třídění (tj. během činnosti příslušného příkazu SORT nebo MERGE) a nikoliv před začátkem třídění nebo po ukončení třídění; mimo třídění totiž tyto položky nemají přidělen skutečný úsek paměti a proto nesmí být používány. 3) Ve FILE SECTION může být uvedeno i několik klauzulí SD následovaných popisy logických vět (01). Klauzule SD a FD mohou být uvedeny v libovolném vzájemném pořadí. 4) 01 popsaná za SD (jakož i logická věta vstupující do třídění) smí mít nejvýše 32767 bytů při RECORDING F resp. 32765 bytů při RECORDING V. 5) Pro klauzuli RECORDING a klauzuli RECORD platí stejná pravidla jako u klauzule FD (viz 4.4.2. a 4.4.3.). Z nejdůležitějších pravidel uveďme: a) Neuvedení klauzule RECORDING je ekvivalentní s uvedením zápisu RECORDING F. V tomto případě všechny 01 popsané za klauzulí SD (při uvedení klauzule RECORD pouze všechny 01 s pevnou délkou) musí mít stejnou délku. Všechny logické věty předávané třídicímu programu budou mít stejnou délku (rovnou RECSIZE; viz 4.4.3.). b) Zápis RECORDING V musí uživatel použít, chce-li třídit logické věty proměnných délek. Při příkazu SORT resp. MERGE s klauzulí USING jsou logické věty předávány systémovému třídicímu programu automaticky ve své plné původní délce. Při příkazu SORT s klauzulí INPUT PROCEDURE by měl uživatel popsat za SD buďto 01 s proměnnou délkou anebo alespoň dvě 01 s různými pevnými délkami; může ovšem též popsat za SD pouze jedinou 01 s pevnou délkou a určovat pak délku předávaných logických vět pomocí klauzule LENGTH v příkazu RELEASE. Systémovému třídicímu programu jsou předávány logické věty včetně dvoubytového řídicího pole délky předcházejícího každou logickou větu (viz 4.4.2.). 6) Délky logických vět předávaných systémovému třídicímu programu smí dosáhnout (ne však převýšit) maximální délku nejdelší 01 popsané za SD (tzn. u 01 s proměnnou délkou uvažujeme celá-čísla-2 z klauzulí OCCURS) nezávisle na klauzuli RECORD. Na rozdíl od pravidel platících u klauzule FD se tedy klauzule RECORD při RECORDING V nepoužívá pro určení maximální délky předávaných logických vět, nýbrž pouze ke kontrolám. 7) Klauzule LABEL a DATA se považují pouze za poznámky. 8) Klauzule SD spolu s následujícími popisy 01 určuje typ, délku a strukturu logických vět, které se budou třídit. Výjimka nastává v případě, že v SD je uvedeno RECORDING V a zdrojem logických vět vstupujících do třídění je jeden nebo více souborů uvedených v klauzuli USING: pak do třídění vstupují logické věty těchto souborů v plné délce (viz 14.4.) nezávisle na popisech 01 za SD, pokud ovšem tyto 01 jsou schopny obsáhnout nejdelší předávanou logickou větu. Při RECORDING F a také při RECORDING V, je-li zdrojem logických vět vstupní rutina (INPUT PROCEDURE) příkazu SORT, je délka tříděných logických vět určena výhradně klauzulí SD a k ní příslušnými popisy 01 (a případně ještě klauzulí LENGTH v příkazu RELEASE) nezávisle na tvaru logických vět vstupního souboru. 9) Na rozdíl od klauzule FD není klauzule SD spojena s žádným souborem dat na některém vnějším médiu ani s žádným z deklarovaných souborů. 10) Každý příkaz, který realizuje některou akci při třídění (SORT, MERGE, RELEASE, RETURN) se odvolává na určitou klauzuli SD nebo na některou 01 popsanou za SD. Přitom během třídění se musí všechny tyto příkazy vztahovat k téže klauzuli SD. 14.3. Třídicí klíče Způsob, podle něhož má systémový třídicí program setřídit předané logické věty, je zadán pomocí klauzule { ON { ASCENDING | DESCENDING } KEY položka ... } ... uvedené v příkazu SORT resp. MERGE. Položky uvedené v této klauzuli se nazývají třídicí klíče. Pravidla: 1) Každý třídicí klíč musí být částí některé 01 popsané za tou klauzulí SD, k níž se vztahuje toto třídění. 2) Třídicí klíč nesmí mít proměnnou délku, nesmí mít proměnnou adresu (tzn. nesmí ležet ve struktuře za položkou s klauzulí OCCURS DEPENDING) a nesmí mít proměnné indexy. Smí však mít celočíselné indexy a smí mít kvalifikaci. 3) Má-li třídicí klíč jednoznačné jméno mezi všemi položkami patřícími k našemu třídicímu souboru (SD), smí být v klauzuli ASCENDING/DESCENDING uveden bez kvalifikace, i kdyby mimo tento třídicí soubor existovala stejnojmenná položka. Význam: Každý z třídicích klíčů je uveden buďto za slovem ASCENDING - pak se má třídit vzhledem k tomuto klíči vzestupně, nebo za slovem DESCENDING - pak se má třídit vzhledem k tomuto klíči sestupně. Je-li klíčem rozpakovaná, pakovaná, binární, exponenciální krátká nebo exponenciální dlouhá položka anebo položka s USAGE INDEX, srovnávají se při třídění hodnoty tohoto třídicího klíče dle pravidel numerického srovnání (tj. dle numerických hodnot). Je-li klíčem skupinová, alfanumerická, alfanumerická editovaná, exponenciální znaková nebo numerická editovaná položka, srovnávají se při třídění hodnoty tohoto třídicího klíče dle pravidel alfanumerického srovnání (viz 5.4.1.), což u exponenciálních znakových položek a někdy též u numerických editovaných položek způsobí jiné setřídění, než kdyby se srovnávalo dle numerických hodnot. Priorita třídicích klíčů je určena pořadím, v jakém jsou uvedeny v příkazu SORT resp. MERGE. Logické věty tedy budou setříděny dle prvního uvedeného třídicího klíče. Ty skupiny logických vět, které mají stejný první třídicí klíč, budou setříděny dle druhého uvedeného třídicího klíče. Ty skupiny logických vět, které mají stejný první i druhý třídicí klíč, budou setříděny dle třetího uvedeného třídicího klíče atd. U logických vět, které mají všechny uvedené třídicí klíče stejné, není definováno, v jakém pořadí vystoupí ze třídění. Příklad: SD DEJVICE. 01 ULICE. 02 ALICE PIC X(6). 02 VELICE PIC S9(4) COMP-3. 02 SLEPICE PIC X(10). 02 OPICE PIC 9(4). : SORT DEJVICE DESCENDING OPICE ALICE ASCENDING SLEPICE ... Logické věty se setřídí sestupně dle klíče OPICE. Skupiny logických vět se stejným klíčem OPICE se setřídí sestupně dle klíče ALICE. Skupiny logických vět se stejnými klíči OPICE i ALICE se setřídí vzestupně dle klíče SLEPICE. Poznámky: 1) Je-li za klauzulí SD popsáno více 01, pak každý z třídicích klíčů může být popsán v kterékoliv z nich. Třídicí klíč vlastně zadává jen pozici v logické větě, délku a typ toho úseku logické věty, podle něhož se provádí třídění. Takto určený úsek se pak vztahuje na všechny popsané 01 nezávisle na tom, ve které z nich třídicí klíč uvedený v příkazu SORT resp. MERGE, a srovnávají se podle něj všechny logické věty předané do třídění. 2) Při RECORDING V není zakázáno, aby některý z třídicích klíčů byl natolik vzdálen od začátku 01, že částečně nebo zcela nebude obsažen v některých kratších logických větách. Pak je nutné, aby tento třídicí klíč nebyl uveden v příkazu SORT resp. MERGE jako první, a aby u žádné z kratších logických vět neobsahujících celý tento třídicí klíč na srovnání dle tohoto třídicího klíče nedošlo, tj. aby byla vždy zjištěna nerovnost při srovnávání dle některého třídicího klíče s vyšší prioritou. Jinak by se totiž srovnávalo dle úseku ležícího mimo tuto logickou větu, jehož obsah je v nejlepším případě nedefinovaný a v nejhorším případě nepřípustný. Příklad: SD TAJENKA RECORDING V. 01 KAM. 02 CERT PIC 9(5). 02 NEMUZE PIC X(15). 01 TAM. 02 NEKOHO PIC X(40). 02 NASTRCI PIC S9(3) COMP-3. : MERGE TAJENKA ASCENDING CERT NASTRCI ... Je nutné, aby žádná kratší logická věta (typu KAM) se neshodovala s žádnou jinou logickou větou v klíči CERT. Dvě dlouhé logické věty (typu TAM) mohou mít klíč CERT stejný; budou pak srovnávány podle klíče NASTRCI, který je v nich v obou obsažen. 14.8. Realizace příkazů SORT a MERGE Příkazy SORT a MERGE jsou v přeloženém programu realizovány pomocí krátkých posloupností příkazů předávajících řízení do podpůrného podprogramu icbsort resp. icbmerg, jenž provádí vlastní třídění. V cobolském programu smí být uvedeno i více příkazů SORT a MERGE, které se mohou vztahovat k téže klauzuli SD nebo k různým klauzulím SD. Během provádění příkazu SORT nesmí být proveden další příkaz SORT (např. ve vstupní nebo ve výstupní rutině nebo v deklarativní sekci); další příkaz SORT smí být proveden až po ukončení činnosti předešlého příkazu SORT. Podobně během provádění příkazu MERGE nesmí být proveden další příkaz MERGE. Je však přípustné během provádění příkazu SORT provést příkaz MERGE anebo během provádění příkazu MERGE provést příkaz SORT. Příkaz SORT si během načítání logických vět zabírá (pomocí systémové funkce malloc) vnitřní paměť, do níž ukládá vstupující logické věty. Pokud vnitřní paměť nestačí, zapisuje vstupující logické věty do pracovního souboru. Čím více vnitřní paměti má příkaz SORT k dispozici, tím větší objem dat dokáže setřídit a tím je třídění rychlejší; je proto vhodné před začátkem provádění příkazu SORT uvolnit co nejvíce paměti. Na druhé straně odtud vyplývá, že zabral-li již příkaz SORT celou volnou vnitřní paměť, zhavarují případné požadavky uživatele na vnitřní paměť uplatněné ve vstupní nebo ve výstupní rutině (např. CALL 'ICUGETV' apod.); všechny tyto nároky na volnou paměť (ve výjimečném případě i otevírání dalších vstupních resp. výstupních souborů) by měl tedy uživatel raději uplatnit nejpozději na začátku provádění vstupní rutiny anebo již před začátkem provádění příkazu SORT. Celkový objem dat, které mohou být setříděny příkazem SORT, je v praxi omezen pouze volnou kapacitou systémového disku. 14.9. Položky pro třídění definované překladačem Je-li ve zdrojovém programu uvedena alespoň jedna klauzule SD, definuje překladač čtyři binární numerické položky SORT-FILE-SIZE, SORT-CORE-SIZE, SORT-MODE-SIZE a SORT-RETURN s implicitně přijatými popisy 77 SORT-FILE-SIZE PIC S9(8) COMP VALUE 0. 77 SORT-CORE-SIZE PIC S9(8) COMP VALUE 0. 77 SORT-MODE-SIZE PIC S9(5) COMP VALUE 0. 77 SORT-RETURN PIC S9(4) COMP VALUE 0. Uživatel může tyto položky používat ve všech příkazech a klauzulích, kde jsou položky s takovými popisy přípustné. Všechny tyto položky jsou do MX COBOLu zařazena pouze kvůli kompatibilitě. V jiných implementacích jazyka COBOL může pomocí prvních třech z nich uživatel modifikovat činnost příkazu SORT, zatímco v položce SORT-RETURN indikuje příkaz SORT pro uživatele úspěšnost třídění (nula znamená úspěšné třídění, nenula znamená neúspěšné třídění). V MX COBOLu však uživatel činnost příkazu SORT modifikovat nemůže a proto s prvními třemi položkami příkaz SORT vůbec nepracuje. Jakákoliv chyba při třídění způsobí v MX COBOLu vždy okamžité ukončení výpočtu a proto příkaz SORT položku SORT-RETURN nenaplňuje (přesto může uživatel po ukončení provádění příkazu SORT testovat; tato položka zůstává trvale nulová, pokud její hodnotu sám uživatel nezmění). 14.10. Klauzule RERUN Není v MX COBOLu implementována. 14.11. Třídění vět proměnných délek Předpokládejme, že uživatel má jeden nebo několik souborů dat s logickými větami proměnných nebo nedefinovaných délek, a že chce všechny tyto logické věty setřídit a zapsat do nového souboru dat tak, aby původní délka každé logické věty zůstala zachována. K tomu je třeba připomenout následující skutečnosti, jejichž podrobný popis již byl uveden: 1) Je-li v SD uvedeno RECORDING V, přičemž zdrojem logických vět vstupujících do třídění je soubor uvedený v klauzuli USING, předávají se do třídění logické věty tohoto souboru o své původní délce a obsahu bez jakékoliv změny. 2) Je-li v příkazu SORT resp. MERGE uvedena klauzule GIVING, přičemž výstupní soubor uvedený za GIVING má RECORDING V nebo RECORDING U, zapisují se do tohoto souboru setříděné logické věty o přesně stejné délce a stejném obsahu, jak se tyto logické věty získávají od systémového třídicího programu. Při použití klauzulí USING a GIVING se tedy délka i obsah tříděných logických vět zachovávají automaticky. Pokud by však uživatel použil vstupní nebo výstupní rutinu, musel by sám zjišťovat délku přečtené resp. získané logické věty (např. pomocí parametru CBL TALLY), a musel by zajišťovat, aby se odeslala resp. zapsala logická věta v nezměněné délce a obsahu (např. pomocí klauzule LENGTH). Příklad: Máme setřídit dohromady logické věty obsažené v souborech PANNA a HRUBIN. Soubor PANNA obsahuje logické věty pevné délky (RECORDING F), soubor HRUBIN obsahuje logické věty proměnné délky (RECORDING V) o maximální délce 245 bytů. Setříděné logické věty mají být zapsány do souboru NETVOR tak, aby se zachovala původní délka každé logické věty. Ostatní informace jsou zřejmé přímo z programu. IDENTIFICATION DIVISION. PROGRAM-ID. PRUBA. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT PANNA ASSIGN S-PANNA. SELECT HRUBIN ASSIGN S-HRUBIN. SELECT NETVOR ASSIGN S-NETVOR. SELECT POHADKA ASSIGN S-COKOLIV. DATA DIVISION. FILE SECTION. FD PANNA RECORDING F. 01 PIC X. FD HRUBIN RECORDING V. 01 PIC X(245). FD NETVOR RECORDING V. 01 PIC X(245). SD POHADKA RECORDING V. 01. 02 PIC X(16). 02 ZLATY-KLICEK PIC 9(4). 02 PIC X(225). PROCEDURE DIVISION. SORT POHADKA ASCENDING ZLATY-KLICEK USING PANNA HRUBIN GIVING NETVOR. STOP RUN.