Co je skriptová proměnná

  • Skriptová proměnná je dočasné úložiště hodnot používané během provádění skriptu.
  • Proměnné se zapisují ve tvaru „#A#“, „#B#“, „#C#“ atd.
  • Skriptové proměnné nejsou databázové sloupce – existují pouze po dobu běhu skriptu.
  • Každá proměnná má vždy právě jeden datový typ.

Podporované datové typy proměnných:

  • String – textový řetězec
  • Integer – celé číslo
  • Long – velké celé číslo
  • Double – desetinné číslo
  • Date – datum

Databázová hodnota null

  • Skript používá databázovou hodnotu „null“.
  • Hodnota „null“ znamená, že proměnná nemá definovanou hodnotu.
  • Nově deklarovaná proměnná, které nebyla přiřazena hodnota, má vždy hodnotu „null“.
  • Hodnotu „null“ je možné přiřadit explicitně pomocí proměnné „#null#“.

Deklarace proměnné

Proměnnou je nutné před použitím vždy deklarovat. Deklarací se určuje její datový typ.

Proměnnou lze deklarovat několika způsoby:

  • Pomocí příkazu pro deklaraci proměnné ve skriptu.
  • Načtením hodnoty z databázového dotazu – datový typ proměnné se automaticky převezme z typu databázového sloupce.
  • Pomocí výrazů:
    • String(text)
    • Integer(číslo)
    • Long(číslo)
    • Double(číslo)
    • Date(datum)
  • Přiřazením jiné proměnné nebo databázového ovládacího prvku do proměnné, která ještě nemá datový typ – proměnná převezme typ zdroje.

Důležité chování deklarace:

  • Nová deklarace nastaví hodnotu proměnné na „null“ vždy, i při stejném datovém typu, a zruší vazbu proměnné na databázový dotaz, kterým byla načtena.
  • Proměnnou, podle které právě probíhá cyklus, ani proměnné načtené souběžně s ní nelze deklarovat a nelze podle nich spustit vnořený cyklus – skript skončí chybou. Uvnitř cyklu do nich nelze přiřadit ani jinou proměnnou, výsledek výrazů „String(...)“, „Integer(...)“ a dalších, ručně vytvořené pole hodnot ani výsledek databázového dotazu. Přiřazení jedné hodnoty zapsané do pole hodnoty (konstanty nebo výrazu) nebo hodnoty databázového ovládacího prvku je povolené; hodnota, která je polem hodnot (prvek „MultiListBox“ nebo výraz „GROUP(...)“), skript ukončí chybou.
  • Nedeklarovaná proměnná použitá v podmínce, cyklu nebo výpočtu vyvolá chybu. Dosazená do textu jako „#A#“ chybu nevyvolá a nahradí se prázdným řetězcem.

Jedna hodnota vs. pole hodnot

  • Proměnná načtená z databázového dotazu se automaticky stává polem hodnot.
  • Každý řádek výsledku dotazu odpovídá jednomu prvku pole. Výjimku u prvku „MultiListBox“ popisuje kapitola „Přiřazování hodnot“.
  • Pokud databázový dotaz nevrátí žádný záznam, vznikne pole s nulovým počtem prvků.
  • Proměnná s polem hodnot dosazená do textu zápisem „#A#“ se nahradí všemi prvky pole oddělenými středníkem – takto lze předat například výčet ID do parametru funkce. Datum se vypíše včetně času se sekundami; nulové sekundy se vynechají a v čase 00:00:00 se vypíše jen datum. Desetinné číslo se vypíše s desetinným oddělovačem podle jazyka uživatele (v češtině čárka). Prázdná hodnota – „null“, pole bez prvků i prázdný prvek pole – se u typů Integer, Long a Double vypíše jako 0, u ostatních typů jako prázdný řetězec.

Pole hodnot je možné vytvořit i ručně pomocí serverových funkcí (u funkcí StringArray, LongArray, DoubleArray a DateArray se hodnoty oddělují středníkem nebo tabulátorem):

  • StringArray(hodnota1;hodnota2;...)
  • IntegerArray(počet_prvků) – pole čísel 1 až počet_prvků
  • LongArray(hodnota1;hodnota2;...)
  • DoubleArray(hodnota1;hodnota2;...)
  • DateArray(hodnota1;hodnota2;...)
  • EmailArray(adresa1;adresa2;...) – pole textových hodnot, ve kterém je každý prvek jedna e-mailová adresa ze zadaného seznamu; adresy lze oddělit středníkem i čárkou, prázdné položky se vynechají a adresa zadaná se jménem kontaktu zůstane v prvku pole i se jménem (jméno obsahující čárku nebo středník musí být v uvozovkách, středník se v něm nahradí čárkou)

Přiřazování hodnot

  • Hodnotu proměnné lze přiřadit jiné proměnné nebo databázovému ovládacímu prvku.
  • Přiřazení může být:
    • jednoduché (jedna hodnota),
    • nebo pomocí matematického výrazu (sčítání, odečítání, násobení, dělení).
      • K datu lze přičíst nebo od něj odečíst číslo zapsané v poli hodnoty s jednotkou „d“ (dny), „m“ (měsíce), „y“ (roky) nebo „h“ (hodiny), například „1m“; číslo bez jednotky značí dny. U měsíců, roků a hodin se desetinná část čísla ořízne.
      • Jiný poslední znak než „d“, „m“, „y“ nebo „h“ se za jednotku nepovažuje a celá hodnota se čte jako počet dní. Číslo se z hodnoty čte jako aritmetický výraz, ale na rozdíl od převodu textu na číslo se ignorovaný text za číslem nezapíše do logu „Errors.log“ a hodnota, kterou jako aritmetický výraz nelze přečíst, skript nepřeruší a datum nezmění.
  • U typu String operátor „+“ spojí texty, ostatní operátory skončí chybou. Druhý operand zadaný proměnnou nebo databázovým ovládacím prvkem musí mít stejný datový typ jako první, jinak skript skončí chybou; výjimkou je kombinace typů Integer a Long a přičtení nebo odečtení hodnoty typu Integer k datu, je-li cílem datum.
  • Pokud je proměnná polem hodnot, početní operace se provádějí nad všemi jejími prvky. Je-li polem i druhý operand, počítá se po prvcích jen při stejném počtu prvků; jinak se použije první prvek druhého operandu a prázdné pole výsledek nezmění.
  • Hodnota „null“ se ve výpočtu počítá jako 0, u typu String jako prázdný řetězec. Datum s hodnotou „null“ zůstane po přičtení i odečtení „null“.
  • Typy Integer a Long dělí celočíselně (desetinná část výsledku se ořízne); dělení nulou i výsledek mimo rozsah typu přeruší skript chybou; typ Double dělí desetinně a dělení nulou chybu nevyvolá – výsledkem je nekonečno, u dělení nuly nulou neplatné číslo.
  • Rozdíl dvou dat přiřazený do proměnné nebo ovládacího prvku typu Integer je počet celých dnů mezi kalendářními dny obou dat (čas se nebere v úvahu); je-li některé z dat „null“, výsledkem je „null“. Příkaz „Přiřadit více hodnot z dotazu“ načte hodnotu do proměnné s datovým typem sloupce dotazu, takže do proměnné jím rozdíl dvou dat spočítat nelze; do ovládacího prvku typu Integer ho spočítá.
  • Při přiřazení hodnoty pole do databázového ovládacího prvku se použije pouze první hodnota pole. Výjimkou je prvek „MultiListBox“, do kterého se zapíší všechny prvky pole jako jeho jednotlivé položky.
  • Hodnota prvku „MultiListBox“ načtená do proměnné příkazem „Přiřadit hodnotu z dotazu“ je pole jednotlivých položek ze všech vrácených záznamů, bez duplicit. Příkaz „Přiřadit více hodnot z dotazu“ vrací i u prvku „MultiListBox“ jeden prvek pole na záznam – uloženou hodnotu s položkami oddělenými tabulátorem.
  • Hodnota prvku „MultiListBox“ editačního formuláře přiřazená do proměnné je rovněž pole jeho jednotlivých položek.
  • Pokud pole neobsahuje žádný prvek nebo je hodnota „null“, uloží se do ovládacího prvku databázová hodnota „null“.

Cyklus

  • Cyklus slouží k postupnému zpracování prvků pole hodnot.
  • Počet iterací cyklu odpovídá počtu prvků řídící proměnné.
  • Pokud pole neobsahuje žádné prvky, cyklus se neprovede ani jednou.

Chování proměnných v cyklu:

  • Během jedné iterace se proměnná chová jako jednoprvková.
  • Po skončení cyklu se proměnná opět chová jako pole hodnot.
  • Prvky s hodnotou „null“ jsou v cyklu automaticky přeskočeny.
  • Pokud bylo více proměnných načteno jedním řádkem skriptu (typem řádku „Přiřadit více hodnot z dotazu“), jsou v cyklu procházeny synchronně. Proměnné načtené dvěma řádky se synchronně neprocházejí, ani když používají stejný dotaz. Obsahuje-li některá z nich méně prvků než řídící proměnná, cyklus skončí chybou.
  • Jako řídící proměnná cyklu se doporučuje používat primární klíč „id“.

Porovnávání hodnot

  • Ve skriptu je možné porovnávat hodnoty dvou proměnných.
  • Pokud je některá z proměnných polem hodnot, porovnává běžná podmínka („Jestliže (výraz) ...“) pouze její první hodnotu.
  • Složená podmínka („Jestliže (složený výraz) ...“) porovná proměnnou s více prvky jako jediný text, ve kterém jsou všechny prvky pole oddělené čárkou a mezerou; jednotlivé prvky pole testují jen operátory „obsahuje“, „začíná“ a „končí“. Jako text se ale porovná jen s textem: zadaná hodnota se převádí podle typu proměnné, takže proměnná typu Integer, Long, Double nebo Date s více prvky porovnaná se zadaným číslem nebo datem skončí chybou vyhodnocení podmínky. Chybou skončí i porovnání proměnné s více prvky (libovolného typu) s proměnnou o jednom prvku nebo s databázovým ovládacím prvkem, je-li typu Integer, Long, Double nebo Date. Operátor „rovná se“ s výčtem čísel (například „1;2;3“) u proměnné typu Integer nebo Long chybu nevyvolá, ale splněný není. Proměnnou s polem hodnot je proto ve složené podmínce vhodné používat jen uvnitř cyklu, ve kterém je řídící proměnnou nebo byla načtena z databázového dotazu týmž příkazem jako řídící proměnná – jen tam se chová jako jednoprvková.
  • Ve složené podmínce lze proměnnou nebo databázový ovládací prvek typu Integer nebo Long porovnat s výčtem čísel oddělených středníkem zapsaným do pole hodnoty (například „1;2;3“, nebo „#A#“ s proměnnou obsahující pole hodnot). Operátor „rovná se“ je pak splněný, rovná-li se hodnota některému z čísel, operátor „nerovná se“, nerovná-li se žádnému z nich.
  • Běžná i složená podmínka porovnávají textové hodnoty bez ohledu na velká a malá písmena; u složené podmínky to platí bez ohledu na typ databáze. Operátory „větší“, „větší nebo rovno“, „menší“ a „menší nebo rovno“ běžná podmínka u hodnot typu String nepodporuje a skript skončí chybou; bez chyby se vyhodnotí jen tehdy, je-li některá z porovnávaných hodnot „null“. Složená podmínka tyto operátory u textových hodnot vyhodnotí porovnáním textů.
  • Prvek „MultiListBox“ editačního formuláře porovnává běžná podmínka po jednotlivých položkách: operátory „obsahuje“, „začíná“ a „končí“ a jejich negace procházejí všechny položky, operátory „je definováno“ a „není definováno“ testují jen hodnotu „null“ (prázdný řetězec, který formulář ukládá u prvku bez vybrané položky, je tedy definovaný) a ostatní operátory porovnávají jen první položku. Operátor „rovná se“ s prázdným polem hodnoty splní jen prázdný řetězec, ne hodnota „null“, a operátor „nerovná se“ s prázdným polem hodnoty splní jen vyplněná hodnota. U ostatních operátorů se prvek bez vybrané položky chová jako hodnota „null“, takže například porovnání s proměnnou „#null#“ operátorem „rovná se“ splní i prázdný řetězec.

Operátory „obsahuje“, „začíná“ a „končí“:

  • U pole hodnot testují, zda pole obsahuje konkrétní hodnotu, resp. zda některý z jeho prvků zadanou hodnotou začíná nebo končí. V běžné i složené podmínce se zadaná hodnota převádí podle typu proměnné a proměnná nebo databázový ovládací prvek, se kterým se pole porovnává, musí mít stejný datový typ jako pole (typy Integer a Long se považují za shodné); neplatná hodnota i rozdílný typ ukončí skript chybou.
  • U textového řetězce testují, zda řetězec obsahuje daný podřetězec, resp. zda jím začíná nebo končí.
  • U hodnoty jiného datového typu než String, která není polem hodnot (ovládací prvek, proměnná uvnitř cyklu nebo proměnná s jedinou přiřazenou hodnotou), vyhodnotí složená podmínka tyto operátory jako „rovná se“ a jejich negace jako „nerovná se“. Běžná podmínka u takové hodnoty skončí chybou.

Test na (ne)vyplněnou hodnotu

Prázdná (nevyplněná) hodnota existuje v databázi ve dvou podobách – jako databázová hodnota „null“ a u textových sloupců také jako textový řetězec nulové délky (prázdný string). Samotný operátor „není definováno“ zachytí pouze hodnotu „null“ – prázdný řetězec nezachytí. Podmínka testující (ne)vyplněnost hodnoty proto musí počítat s oběma variantami.

Podmínka „hodnota není vyplněna“ podle datového typu, resp. typu ovládacího prvku:

  • String (TextBox, TextArea, RichTextBox, ComboBox, ListBox, MultiListBox, Radio, CheckBox) – složená podmínka: hodnota rovná se „“ nebo hodnota není definováno. V jazyce SQL: ng_tb = '' OR ng_tb IS NULL.
  • ForeignKey, File, Image – složená podmínka: hodnota rovná se „0“ nebo hodnota není definováno. V jazyce SQL: ng_idfk = 0 OR ng_idfk IS NULL.
  • Integer, Long, Double, Date – stačí operátor „není definováno“. Tyto datové typy nemohou obsahovat prázdný řetězec, nevyplněná hodnota je vždy „null“.

Ve skriptu se složená podmínka zapisuje typem řádku „Jestliže (složený výraz) ...“ se dvěma podmínkami spojenými logickým operátorem „nebo“. Příklad přerušení skriptu v situaci, kdy uživatel nemá vyplněný e-mail – proměnná „#A#“ typu String obsahuje e-mail uživatele načtený databázovým dotazem a řádek typu „14. Jestliže (složený výraz) vyvolat výjimku (přerušení)“ obsahuje dvě podmínky:

  • První podmínka: „#A#“ | operátor „rovná se“ | pole hodnoty záměrně prázdné (porovnává se s prázdným řetězcem) | spojení „nebo“.
  • Druhá podmínka: „#A#“ | operátor „není definováno“.
  • Text výjimky: „Uživatel nemá vyplněný e-mail.“

Běžná podmínka („Jestliže (výraz) ...“) a složená podmínka („Jestliže (složený výraz) ...“) se k hodnotě „null“ chovají rozdílně:

  • Běžná podmínka se vyhodnocuje přímo na serveru a s hodnotou „null“ počítá:
    • Operátor „rovná se“ vyhodnotí dvě hodnoty „null“ jako shodné – test na „null“ lze zapsat porovnáním s proměnnou „#null#“.
    • Operátor „nerovná se“ vyhodnotí hodnotu „null“ proti jakékoliv vyplněné hodnotě i proti prázdnému řetězci jako splněný. Výjimkou je prvek „MultiListBox“ editačního formuláře porovnávaný s prázdným polem hodnoty (viz kapitola „Porovnávání hodnot“).
    • Operátory „větší nebo rovno“ a „menší nebo rovno“ vyhodnotí dvě hodnoty „null“ jako splněné a jedinou hodnotu „null“ jako nesplněné. Operátory „větší“ a „menší“ nejsou s hodnotou „null“ splněné nikdy.
  • Složená podmínka se vyhodnocuje jako SQL podmínka s trojhodnotovou logikou:
    • Hodnota „null“ nesplní operátor „rovná se“ ani „nerovná se“ – bez ohledu na porovnávanou hodnotu.
    • Hodnotu „null“ zachytí operátor „není definováno“ nebo porovnání s proměnnou „#null#“ pomocí operátoru „rovná se“.

Z toho plyne praktický důsledek pro opačný test – „hodnota je vyplněna“ – u datového typu String:

  • Ve složené podmínce stačí jediná podmínka „nerovná se“ s prázdným polem hodnoty – hodnotu „null“ podmínka v SQL logice nepropustí.
  • V běžné podmínce „nerovná se“ s prázdným polem hodnoty hodnotu „null“ propustí (null podmínku splní) – test „je vyplněno“ proto nelze v běžné podmínce zapsat jedinou podmínkou. Výjimkou je prvek „MultiListBox“ editačního formuláře, u kterého „nerovná se“ s prázdným polem hodnoty hodnotu „null“ nepropustí.

Rozdílně se obě podmínky chovají i k datu:

  • Běžná podmínka porovnává data vždy včetně času.
  • Složená podmínka porovná hodnotu databázového ovládacího prvku s datem zadaným v podmínce jako hodnota (i dosazeným zápisem „#...#“) bez času (s časem 00:00) jen podle data – čas uložený v prvku se nebere v úvahu. Je-li vlevo proměnná, nebo vpravo proměnná či jiný ovládací prvek, porovná se včetně času.
  • Datum zapsané do složené podmínky jako proměnná (zápisem „#...#“), které po dosazení není platným datem (typicky prázdná hodnota), se nahradí databázovou hodnotou „null“ a toto porovnání se nesplní. Výjimkou je porovnání proměnné s polem hodnot operátorem „obsahuje“, „začíná“ nebo „končí“, kde neplatné datum ukončí skript chybou.

Stejné pravidlo platí i pro omezující podmínky databázových dotazů. Detailní popis podmínek je uveden v samostatné příručce Návrhář databázových dotazů.

Konverze datových typů

  • Přiřazení proměnné do proměnné s jiným datovým typem skončí chybou; výjimkou je dvojice Integer a Long a rozdíl dvou hodnot typu Date přiřazený do proměnné typu Integer.
  • Konverzi provede zápis proměnné do pole hodnoty, například „#A#“ – hodnota se nejdřív dosadí jako text a teprve pak se převede na datový typ cílové proměnné. Totéž platí pro výrazy „String(#A#)“, „Integer(#A#)“ atd.
  • Převod přes „#A#“ hodnotu „null“ nezachová: prázdná číselná proměnná se dosadí jako 0 (v cíli typu String vznikne text „0“) a prázdná textová proměnná jako prázdný řetězec.
  • Převod textu na číslo vyhodnocuje text jako aritmetický výraz: prázdný text dá 0, úvodní nuly se ignorují (například „05“ se převede na 5), text za číslem se ignoruje a desetinná část se u typu Integer ořízne. Ignorovaný text za číslem (například „1 000“ se převede na 1) skript nepřeruší, ale zapíše se do logu chyb „Errors.log“. Chybou skončí text, který nelze přečíst jako aritmetický výraz – text začínající písmenem (kromě volání matematické funkce, například „abs(-5)“), text obsahující jen mezery, výraz ukončený operátorem (například „12+“) nebo s neuzavřenou závorkou, dělení nulou, při převodu na typ Integer nebo Long číslo mimo rozsah tohoto typu a text, ve kterém za číslem následuje písmeno „e“ nebo „E“ (například „12eur“), protože se čte jako exponent.
  • Prázdný text převedený na datum skončí chybou, protože ho nelze rozpoznat jako platné datum. Vyprázdnit hodnotu proměnné nebo ovládacího prvku jakéhokoli datového typu lze proměnnou „#null#“ zapsanou jako celá hodnota.
  • Příkaz „Nový záznam“ prázdnou hodnotu do sloupce jiného datového typu než String nepřevádí a sloupec nechá s databázovou hodnotou „null“.
  • Převod čísla typu Long na Integer skončí chybou, pokud číslo leží mimo rozsah typu Integer (-2147483648 až 2147483647).

Příklad převodu čísla na text:

  • do proměnné typu String se přiřadí hodnota „#A#“, kde „A“ je proměnná typu Integer

Příklad převodu textu na číslo:

  • do proměnné typu Integer se přiřadí hodnota „#A#“, kde „A“ je proměnná typu String

Typické chyby při práci s proměnnými

  • Proměnná nebyla deklarována před použitím.
  • Autor skriptu očekává jednu hodnotu, ale proměnná je pole hodnot.
  • Hodnota „null“ není ošetřena v následném zpracování.
  • V cyklu je jako řídící proměnná použita proměnná, která obsahuje hodnoty „null“.