Oracle Forms koda optimizācija un lietotāja-datora interfeisa uzlabošana


Latvijas Universitāte
Fizikas un matemātikas fakultāte
Datorikas nodaļa










Oracle Forms koda optimizācija un
lietotāja-datora interfeisa uzlabošana




Maģistra darbs













Autors :                         Ivo Ālmanis
st. apl. Nr. DatZ M 96007

Darba vadītājs :      Dr. dat. Andrejs Auziņš






Rīga, 1999


Anotācija

Šajā darbā ir aprakstīta Oracle Forms 4.5 koda optimizācija un lietotāja-datora interfeisa uzlabošana. Darbs sastāv no 2 daļām. Pirmajā no tām liela uzmanība tiek pievērsta tieši rīka izejas koda un objektu atribūtu vērtību optimizācijai, kam ir liela nozīme, ja šai vidē veidotās sistēmas strādā ar lieliem datu apjomiem un ir nepieciešama ātra darbu veikšana un reakcija uz datu kļūdām. Darbā minētie optimizācijas risinājumi paskaidroti ar piemēriem no reālām sistēmām. Otrā daļā tiek aplūkots kā veidot vienotu, vienkāršu un intuitīvi saprotamu lietotāja-datora interfeisu, strādājot ar Oracle Forms 4.5, produktu, kura vājākā vieta, salīdzinot ar citām 4 paaudzes valodām (4GL), ir tieši lietotāja-datora interfeiss. Darba beigās doti programmu kodu piemēri visiem darbā minētajiem problēmu risinājumiem.











Abstract

This Master Thesis is devoted to the optimisation of Oracle Forms 4.5 code and user interface improvement. The Thesis consists of two parts. The first part deals with optimisation of tool’s source code and object attribute values. Both issues are very important because Oracle Forms 4.5 environment systems are managing large volumes of data. Therefore, fast operations and prompt reaction to data errors is essential. The proposed solutions of optimisation are described using real examples of live systems. The second part of the Thesis deals with creating of unified, simple and intuitively understandable user interface for Oracle Forms 4.5. If compare with other 4th generation languages (4GL), the user interface is the main weakness of Oracle Forms 4.5.  In the final part of the Thesis the author provides with the program code examples for all solutions described in this paper.


Аннотация

В данной работе дается описание оптимизации кода Oracle Forms 4.5 и усовершенствования интерфейса пользователя. Работа состоит из двух частей. В первой части большое внимание уделено вопросам оптимизации выходного кода инструментальных программных средств и значений атрибутов объектов. Эти параметры имеют важное значение, если системы, созданные в данной среде, работают с большими объемами данных, где требуется быстродействие и немедленная реакция на ошибочные данные. Решения оптимизации пояснены примерами из реальных систем. Во второй части рассмотрено формирование единого, несложного и интуитивно понятного интерфейса пользователя для работы с Oracle Forms 4.5, где наиболее слабым местом по сравнению с другими языками 4-го поколения (4GL), является интерфейс пользователя. В конце работы приведены примеры программных кодов с решениями вышеупомянутых проблем.





























Autoreferāts

Darba autors strādā SIA Tieto Konts Financial Systems nu jau vairāk par četriem gadiem. Pēdējos trīs ar pusi gadus autors piedalījies daudzu sistēmu, kas balstītas uz Oracle RDBMS, izstrādē, strādājot gan kā programmētājs, gan kā sistēmu analītiķis. Pašlaik autors strādā par produktu grupas vadītāju un galvenokārt nodarbojas ar sistēmu izstrādi un analīzi, taču ļoti bieži arī ievieš izmaiņas pirms gadiem rakstītajās programmās. Bieži vien šīs izmaiņas ir saistītas tieši ar programmas koda optimizāciju.
Maģistra darba pirmajā nodaļā aprakstīta Oracle Forms 4.5 koda optimizācija. Galvenais akcents darbā nav likts tieši uz PL/SQL koda optimizāciju formās, bet gan uz formas objektu atribūtu vērtību optimizāciju kā arī uz konkrētu uzdevumu optimizāciju, pamatojot tos ar piemēriem no reālām sistēmām. Tā kā materiāli par Oracle Forms 4.5 koda optimizāciju prakstiski nav atrodami, darbā dotie risinājumi ir Oracle dokumentācijas apkopojums un autora darba pieredzes rezultāts.
       Vadot sistēmu izstrādi, pie kuras strādā vismaz 3-4 cilvēki, bieži vien nākas saskarties ar problēmu, ka katram izstrādātājam ir sava gaumes un stila izjūta, veidojot formas. Tas parasti noved pie problēmas, ka sistēma izskatās ļoti raiba. Bez tam lietotājiem nav pārliecības, ka tā izstrādāta vienā organizācijā, jo tie nespēj intuitīvi strādāt ar sistēmu, kurā gandrīz katra forma izskatās savādāk. Šīs problēmas neitralizēšanai, autors kā sistēmas izstrādes vadītājs, apkopoja visu pieejamo informāciju par vienota interfeisa izstrādi Oracle Forms 4.5, kas sīkāk aprakstīta darba otrajā nodaļā. Bez tam autors darbā min arī savus risinājumus dažām lietotāja-datora interfeisa problēmām.
Izstrādājot darbu, autors balstījies uz personīgo pieredzi patreizējā darba vietā kā arī uz dažādām publikācijām un grāmatām.




Saturs
Ievads....................................................................................................................................................................... 7
1.        Programmas koda optimizācija............................................................................................. 9
1.1. Formas objektu un to atribūtu vērtību optimizācija...................................................................... 11
1.1.1. Formas objekti un to atribūti, kas iespaido ātrdarbību........................................................ 11
1.1.2. Trigeru pareizs pielietojums un izvairīšanās no atkārtotiem izsaukumiem....................... 15
1.1.3. Ne-tabulas lauku vērtību aktualizēšana................................................................................... 18
1.2. Operāciju ar datnēm optimizēšana................................................................................................... 20
1.2.1. Datņu ielasīšana............................................................................................................................ 21
1.2.2. Datņu veidošana............................................................................................................................ 27
1.2.3. Pakotnes DBMS_PIPE pielietojums.......................................................................................... 33
1.3. Datu ievadformu optimizācija (pieslēgums datu bāzes serverim, izmantojot modemu)....... 35
1.3.1. Datu atlasīšana pēc maskas un piesaistīto tabulu raksti...................................................... 36
1.3.2. Fetched Records atribūts formas blokiem................................................................................ 37
1.3.3. Auto Refresh atribūts LOV objektiem........................................................................................ 39
1.3.4. Ne-tabulas lauku vērtību aktualizēšana................................................................................... 40
1.3.5. Update Changed Columns atribūts formas blokiem............................................................... 41
1.3.6. Datnes ielasīšana.......................................................................................................................... 42
2. Lietotāja-datora interfeisa uzlabošana.......................................................................... 45
2.1. Grafiskā lietotāja-datora interfeisa pamatprincipi......................................................................... 45
2.2. Šablonformu izmantošana formu ģenerācijai................................................................................ 45
2.3. Preferences kā ģeneratora parametri................................................................................................ 50
2.4. Padomi interfeisa uzlabošanai........................................................................................................... 53
2.4.1. Rīku josla........................................................................................................................................ 53
2.4.2. Rīku padomi (Tooltips) - spiedpogu nozīmju aprakstīšana................................................... 54
2.4.3. Standartizvēlnes............................................................................................................................ 54
2.4.4. Ievadlauku krāsu nozīme.............................................................................................................. 56
2.4.5. Logu virsraksti............................................................................................................................... 56
2.4.6. Resursu pārbaude pirms lietojumprogrammas palaišanas................................................... 57
2.4.7. Par - ātra informācija par jūsu lietojumprogrammu.............................................................. 58
2.4.8. Paroles maiņa................................................................................................................................ 59
2.4.9. Progresa rādītājs........................................................................................................................... 60
2.4.10. Lietojumprogrammu palaišana................................................................................................ 60
2.4.11. MS Windows palīdzības logi.................................................................................................... 61
2.4.12. Nodaļlapas (Tabbed pages) - jauns interfeisa standarts.................................................... 62
2.4.13. Palīdzības teksta (Hint) krāsa................................................................................................... 63
Nobeigums.......................................................................................................................................................... 64
Literatūra........................................................................................................................................................ 65
Pielikums............................................................................................................................................................ 66
Programmu teksti......................................................................................................................................... 66
Formu koda optimizācija........................................................................................................................ 66
Lietotāja interfeisa uzlabošana............................................................................................................. 77








      Ievads


       Salīdzinot ar neseno pagātni, tagad ir tendence veidot lielas sistēmas, kur datu apjoms sasniedz simtus un pat tūkstošus megabaitus. Uz personāliem datoriem bāzētās datu bāzu vadības sistēmās, kā Fox Pro, Access un citās, palielinoties datu apjomiem, krasi samazinās darbības ātrums. Drīz tiek sasniegta robeža, kad palielināt apjomu vairs nav iespējams. Bez tam nav iespējama vienlaicīga datu lietošana vairākiem lietotājiem, t.i. vienlaicīgi vairāki lietotāji nevar ievadīt datus, tajā pašā laikā nodrošinot šo datu unikalitāti. Nolasot datus parasti visus resursus aizņem viens lietotājs, pārējiem tikmēr ir jāgaida. Šādu ierobežojumu dēļ, ar laiku sistēmas nav funkcionēt spējīgas. Tās jāveido no jauna un tāpēc ir vajadzīgas DBVS, kurām nav šādu ierobežojumu. Lielās datu bāzu vadības sistēmās (Oracle, DB2 un citas) visas šīs problēmas ir novērstas, lielāku uzmanību pievēršot arī datu aizsardzībai  un drošumam. Oracle piedāvātā tehnoloģija sistēmu izstrādei spēj nodrošināt vieglāku un ātrāku sistēmu izstrādi, izmantojot grafiskos līdzekļus un ģeneratorus, kas aizvieto monotonu programmu rakstīšanu.
Tādēļ aizvien vairāk lielu datu bāzu vadības sistēmu izstrādātāji sāk izstrādāt savas sistēmas tieši Oracle, DB2 un citās vidēs, kas spēj nodrošināt labu produktu izstrādi un kas ir orientētas tieši uz lielām datu bāzēm.
       Iztrādājot lielas sistēmas, kas piemēram balstītas uz Oracle piedāvāto tehnoloģiju, izstrādātāji bieži vien balstās uz to, ka jaunā tehnoloģija ir daudz spēcīgāka un spēj strādāt ar lieliem datu apjomiem, tādējādi piemirstot par rakstāmā produkta izejas koda optimizāciju. Strādājot ar tādiem pašiem datu apjomiem, kādi bija Fox Pro vidē sistēma, neapšaubāmi strādā ātrāk, veicot nepieciešamos datu pieprasījums un labojumus pietiekoši ātri, taču papielinoties datu apjomiem izstrādātās sistēmas tāpat sāk lēni strādāt, kas bieži vien notiek iztrādātāju vainas dēļ, jo tie nav veikuši nekādus izstrādātās sistēmas optimizācijas pasākumus.
       Darba pirmajā nodaļā autors piedāvā savu skatījumu tieši uz Oracle Forms 4.5 optimizāciju, kas sevī ietver gan formas objektu un to atribūtu, gan arī pašas formas izejas teksta optimizāciju. Darbā tiek aplūkoti autora nu jau vairāk kā trīs gadu ilgas darba pieredzes ar Oracle Forms 4.5 rezultāti, jo vismaz pašlaik autora rīcībā nav nevienas grāmatas vai cita informācijas avota kā, piemēram, www lapas, kas sniegtu izsmeļošu informāciju kā optimizēt Oracle Forms 4.5 rakstīto izejas tekstu. Nedaudz informācijas šai sakarā ir atrodama Oracle Forms 4.5 grāmatās (arī on-line Help), bet tā attiecas tikai uz formas objektu atribūtu vērtībām. Darbā bez teorijas apskata tiek aplūkoti arī reālu uzdevumu iespējamā optimizācija, pamatojot to ar reāliem piemēriem no autora rakstītām sistēmām. Ļoti konkrēti tiek apskatītas datņu ielasīšanas un veidošanas optimizācija kā arī darbs ar sistēmu attālinātā režīmā, t.i. ja pieslēgums datu bāzei tiek organizēts, izmantojot modemu.
       Taču bieži vien ar labu sistēmas funkcionalitāti un ātru darbību vien ir par maz. Lietotājs galvenokārt īpašu uzmanību pievērš sistēmas interfeisam, cik viegli ir ar to strādāt un cik intuitīvi viņš var strādāt. Tas parasti tiek aizmirsts, izstrādājot lielas sistēmas, kā rezultātā lietotāji nav apmierināti un vienmēr uzskata, ka vecā sistēmas, kas piemēram bija veidota uz FoxPro bāzes, bija krietni labāka, kaut arī šad tad pazuda dati, sistēma uz lieliem datu apjomiem strādāja lēni, šad tad jāgaida uz kādu, kamēr tas pabeigs savu darbību ar datiem, lai tiem vispār varētu tikt klāt.
       Bez tam, ja tirgū ir pieejami vairāki vienādas kvalitātes produkti produkti, klients vienmēr izvēlēsies to, kas ir vieglāk saprotams, apgūstams un ar kuru strādājot var gūt lielāku darba efektivitāti. Citiem vārdiem sakot, klients izvēlēsies to produktu, kam būs labāks lietotāja-datora interfeiss.
       Taču, lai izveidotu labu lietotāja-datora interfeisu, vienmēr rodas zināmas problēmas. Palielinoties projektu apjomiem, parasti tos vairs nerisina viens cilvēks kā tas ir FoxPro un citu mazu DBVS gadījumā, bet gan 2, 3 un pat vairāk cilvēku. Tā kā katram cilvēkam ir sava gaumes un stila izjūta, katrs programmētājs veido savu lietotāja-datora interfeisu, tādu, kādu tas uztver par vairāk tīkamu. Bet lietotājs vēlas, lai projekta ietvaros visas datu ievadformas un citi datu logi būtu vienota stila. To parasti panāk, izstrādātājiem vienojoties par kopēju lietotāja-datora interfeisu. Tā kā Oracle CASE rīki atļauj ģenerēt formas no iepriekš aprakstītiem moduļiem, tad izstrādātāji vēlētos, lai visas ģenerētās formas, jau saturētu interfeisa standartu, par kuru izstrādes grupa ir vienojusies. To panāk aprakstot formu šablonus (template), kas tiek izmantoti ģenerācijas procesā kā arī sistēmas, atsevišķu moduļu un atsevišķu tabulu preferences (preference), kas tiek izmantotas ģenerācijas procesā.
       Darba otrajā nodaļā tiek aplūkots kā veidot vienotu lietotāja-datora interfeisu strādājot ar Oracle Forms Designer 4.5, produktu, kura visvājākā vieta, salīdzinot ar citām 4 paaudzes valodām (4GL), ir tieši lietotāja-datora interfeiss. Kā vienu no tā iemesliem varu minēt Oracle produktu pieejamību uz vairākām operētājsistēmu platformām, kā rezultātā visi Oracle produkti jebkurā operētājsistēmā izskatās vienādi. Tas panākts ieviešot savus standartus. Tas protams  pārāk daudz neattiecas uz grafisko izpildījumu, bet gan terminoloģiju. Lietotājs nespēj strādāt intuitīvi, kā ar jebkuru citu jaunu produktu, jo tiek lietots daudz jaunu terminu. Lietotājs parasti pirmajā brīdī ir samulsis.
Otrās nodaļas beigās tiek apkopoti vairāki raksti žurnālos un Internetā par tēmu kā labāk veidot savu lietojumprogrammu (application) lietotāja-datora interfeisu, strādājot ar Oracle formām MS Windows vidē.
Angliskie nosaukumi ir tulkoti izmantojot LZA terminoloģijas komisijas informātikas apakškomitejas apstiprinātos angļu terminu latviskojumus. Maz pazīstamiem un nezināmiem terminiem, kuriem iepriekšminētajā vārdnīcā nebija dots tulkojums, ir doti darba autora tulkojumi, iekavās dodot orģinālnosaukumu angliski.




1.    Programmas koda optimizācija


Programmas koda optimizācijas mērķis ir panākt, lai programmas kods izpildītos pēc iespējas ātrāk. To var panāk vairākos veidos. Viens no veidiem, ko bieži pielietoja 3 paaudzes valodās ir programmas kodā jau iekļaut kodu, kas rakstīts asamblera valodā vai pat mašīnkodā. Taču ne visās programmēšanas valodās tas ir iespējams un tāpēc ir jāķeras klāt pie kodu optimizācijas pamatprincipiem, kas nosaka kā rakstīt programmas kodu, lai tas izpildītos ātrāk. Šie pamatprincipi nav stingri kodēšanas likumi, kas būtu jādara, veicot kodēšanu, bet gan elementāras koda optimizācijas idejas, kuras savā kodā var ietvert jebkurš iesācējs [8].
Kā piemērs var tikt minēts If nosacījuma izmantošana, kas iespējama jebkurā programēšanas valodā. Uzmanība šajā gadījumā jāpievērš loģisko operāciju izvietojumam. Kā zināms and nosacījumā abām pusēm jābūt patiesām. Pamatā visas programmēšanas valodās, gadījumā ja nosacījuma pirmā puse ir nepatiesa, otrā puse netiek pārbaudīta jo tam vairs nav nekādas nozīmes. Tātad optimizētā programmas kodā nosacījuma pirmā pusē būs nosacījums, kas izpildās ātrāk un atkarībā no kura vērtības jau ir zināms vai nepieciešams pābaudīt nosacījuma otru pusi. Tāpēc kā pirmā puse būtu jāliek nosacījums, kas visbiežāk atgriež nepatiesu vērtību. Kā zināms, operācijas ar skaitļiem izpildās ātrāk nekā ar string mainīgajiem, tāpēc saliktajos nosacījumos, kur tiek izmantoti abu tipu mainīgie, kā pirmā daļa būtu jāliek skaitļu salīdzinājums. Tā negatīvas atbildes gadījumā nosacījuma otra puse netiek izpildīta, ietaupot dažas procesora komandas. Savukārt or nosacījumiem, vismaz vienai nosacījuma pusei jābūt patiesai, kas nozīmē, ka izdevīgāk kā nosacījuma pirmo daļu likt to, kas biežāk atgriež patiesu vērtību.
Savukārt if…elsif…else…endif gadījumā jāņem vērā nosacījumu kārtība. Kā pirmos vēlams likt tos, kas izpildās biežāk, tādējādi datoram nav jāveic liekas salīdzināšanas operācijas.
       Ļoti bieži novērotā programētāju kļūda ir – nosacījumu ciklos tiek pārbaudītas mainīgo vērtības, kas nemainās šī cikla laikā, tādējādi katrā ciklā veicot liekas operācijas. Piemēram:
string1 = "a string"
       string2 = argument_to_function
       for i = 1 to 100
       begin
             ...
             if (string1 equals string2) and …..
                     Do Something
             ...
       end

     Kā jau redzams mainīgo salīdzināšana katrā cikla solī ir vienkārši lieka. Tā vietā labāk būtu lietot šādu programmas kodu:
     string1 = "a string"
     string2 = argument_to_function
     are_equal = string1 equals string2
     for i = 1 to 100
     begin
             ...
             if (are_equal) and ……
                     Do Something
             ...
     end

    Šajā gadījumā nosacījuma rezultāta pirmā puse jau zināma un nav jārēķina katrā cikla solī. Tas attiecināms uz visiem konstantiem aprēķiniem – jebkurai koda daļai, kas atgriež konstantu rezultātu, jābūt aprēķinātai jau pirms cikla.
       Tas pats attiecināms arī uz programmas kodu, kur cikls iekļauj sevī citu ciklu. Ja ārējais cikls izpildās 10 reizes un iekšējais katrā arējā cikla solī arī 10 reizes, tas nozīmē, ka ieksējais cikls pavisam izpildās jau 100 reizes. Tātad galējais skaits ir šo ciklu skaita reizinājums un lieki piebilst cik ātri tas pieaug, palielinot vienu no cikla garumiem. Ļoti svarīgs fakts ir, ka optimizācija iekšējā cikla kodā var strauji palielināt koda izpildes ātrumu. Šeit jāņem vērā kaut vai pirms tam minētā salīdzinājuma operācijas pareiza izveidošana.
       Vēl viena ļoti svarīga lieta, kas jāievēro veicot programmu optimizāciju, ir jāzin vai procedūras izsaukšana cikla ķermenī ir izdevīgāka par procedūras koda iekļaušanu pašā ciklā. Protams no pārskatāmības viedokļa kods ir vieglāk lasāms, ja n-rindu vietā ir tikai viens procedūras izsaukums, taču jāatceras, ka katram procedūras izsaukumam procesoram jādara sekojošais [8]:
1)      Jāsaglabā esošais stāvoklis;
2)      Jāizveido jauna darba vide, t.i. lokālo mainīgo inicializācija u.t.t.;
3)      Jāizpilda funkcija;
4)      Jāatgriežas izejas stāvoklī;
5)      Jāturpina no vietas, kur tika izsaukts.
Ja soļa 3 izpilde neaizņem vairāk par 2/3 laika, tad nav nekādas vajadzības veidot šo funkciju -  tās kods jāraksta pa tiešo tekstā. Dauzi kompilatori tomēr atļauj rakstīt šādas funkcijas atsevišķi, kas kompilētajā koda gabalā jau ir iekļautas bez funkcijas izsaukuma pa tiešo paša tekstā.
Tas viss ir tikai daļa no pamatprincipiem, kas jāievēro, rakstot optimizētu programmas kodu. Šajā darbā netiks aprakstīta šāda Oracle Forms 4.5 koda optimizācija, bet gan jau daudz plašākā mērogā un tieši konkrētāk Oracle Forms 4.5 videi.
Tā kā Oracle Forms 4.5 ir objektorientēta vide, koda optimizācija varētu nozīmēt ne tikai koda optimizāciju, bet arī formas objektu un/vai to atribūtu vērtību maiņu, kas varētu dod labākus rezultātus formas izpildē. Bez tam ar ļoti daudzām formām tiek veiktas ne tikai vienkāršas datu ievadīšanas un labošanas operācijas, bet arī daudzi citi uzdevumi, t.i. tiek izsauktas dažādas programvienības gan no bibliotēkām, gan servera pakotnēm. Bez tam var tikt veikta arī kāda vienkārša datu manipulācija, kas nav redzama lietotājam. Šajā gadījumā koda optimizācija ir kā vienkāršāk uzrakstīt formas izejas kodu, lai tas izpildītos pēc iespējas ātrāk un arī retāk, jo kā vēlāk darbā tiks aplūkots, programmētāji ļoti bieži uzraksta kodu kas strādā korekti un ātri, taču izpildās pārāk bieži, t.i. tiek pielietoti nepareizie trigeri (trigger) vai tie izvietoti pārāk augstu objektu hiarhijas kokā, kā rezultātā tiek izpildīti daudz biežāk nekā nepieciešams.
Šajā darbā galvenokārt tiks apskatītas formas objektu atribūtu vērtību nozīme formas ātrdarbībā. Tiks aplūkoti arī daži piemēri kā uzlabot tieši izejas kodu, lai tas izpildītos ātrāk. Par to sīkāk nākamājās darba nodaļās.


1.1. Formas objektu un to atribūtu vērtību optimizācija


Vispirms darbā teorētiski tiks aplūkoti visi tie formas objekti un/vai to atribūti, kas zināmā mērā varētu iespaidot formu ātrdarbību, kā arī tiks pamatots kāpēc. Ar formas ātrdarbību šeit nav domāts tikai koda izpildes ātrums, bet arī dažādu atribūtu vērtības, lai novērstu lieku kodu izpildi, kuru dēļ lietotājiem, teiksim, jāveic liekas darbības kā atkārtota tausiņu nospiešana u.c. Pēc tam nākošajās nodaļās ar piemēriem tiks pierādīts, cik liela ir šo objektu un/vai atribūtu ietekme uz formas ātrdarbību.

1.1.1. Formas objekti un to atribūti, kas iespaido ātrdarbību

      
Vispirms aplūkosim pašas formas atribūtus. Eksistē tikai viens formas atribūts, kas iespaido tās ātrdarbību, un tas ir: CURSOR MODE PROPERTY, kas definē formu kursoru (cursor) stāvokli starp tranzakcijām. Šis atribūts ir ļoti noderīgs strādājot tieši ar ne-Oracle datu bāzi. Atribūtam ir 2 vērtības [6]:
·               OPEN_AT_COMMIT – nosaka, ka kursoriem jāpaliek atvērtiem starp tranzakcijām;
·               CLOSE_AT_COMMIT – nosaka, ka kursors ir jāaizver tūlīt pēc COMMIT operācijas.
Kursoru aizvēršana tulīt pēc COMMIT operācijas un to atkārtota atvēršana var ļoti samazināt formas ātrdarbību pie šādām operācijām:
·               Veicot COMMIT operāciju;
·               citu SQL pieprasījumu izpildīšanā uz tiem pašiem ierakstiem;
·               datu pieprasījumu (SELECT…) izpildīšanā.

Oracle Forms 4.5 ātrdarbība samazinās tādēļ, ka katru reizi ir jāatver jauns kursors un tajā esošā komanda atkal ir jāizanalizē.
Tālāk aplūkosim formas objektus un to atribūtus, kuru vērtības varētu iespaidot ātrdarbību. Vispirms viens no primārajiem formas objektiem – bloks. Formās var būt gan datu tabulas bloki, gan kontroles bloki, t.i. bloki, kas neatsaucas uz kādu konkrētu datu bāzes tabulu. Tie parasti tiek izmantoti dažādu kontroles mainīgo glabāšanai, taču tie nekādi nevar iespaidot ātrdarbību. Ir virkne bāzes tabulu bloku (bloks, kam piesaistīta konkrēta bāzes datu tabula) atribūtu, kas iespaido formu ātrdarbību. Tie ir:

a)                                WHERE Clause – standarta SQL pieprasījuma maskas nosacījums bloka bāzes tabulai. Šis maskas nosacījums automātiski tiek pievienots SQL pieprasījumam un tiek izpildīts vienmēr, kad lietotājs pieprasa datus par šim blokam piesaistīto tabulu. Rakstot šo nosacījumu jāņem vērā, ka maskas nosacījums jāraksta tā, lai tas pēc iespējas efektīvāk izmantotu tabulas indeksus, jo pretējā gadījumā tas ļoti krasi samazina formas ātrdarbību. Šī atribūta vērtības optimizācija patiesībā ir izpildāmā SQL pieprasījuma ātrdarbības optimizācija. Gadījumos, ja maskas nosacījums neizmanto nevienu tabulas indeksu un veic pilnu tabulas caurskatīšanu – datu atlasīšana formā var ieilgt līdz pat vairākām minūtēm, kas izmantojot indeksus var būt dažas sekundes daļas;

b)                               ORDER BY Clause – tāpat kā maskas nosacījums arī kārtošanas nosacījums ir standarta SQL pieprasījuma daļa, kas automātiski tiek pievienota SQL pieprasījumam, veicot datu atlasīšanu. Teorētiski kārtošana pēc laukiem, kas ietilpst indeksā noteik ātrāk nekā pēc tiem, kas tajos nav. Tāpat kā maskas gadījumā – rakstot kārtošanas nosacījumu, jāņem vērā, ka optimāla ātrdarbība tiks panākta, ja izpildāmais SQL pieprasījums būs pietiekami labi optimizēts;

c)                                OPTIMIZER HINT – tāpat kā divi augstāk minētie arī šis atribūts raksturo padomu (hint) RDBMS optimizatoram, izpildot SQL pieprasījumus. Pareizi lietojot šo atribūtu iespējams krasi palielināt formu ātrdarbību darbā ar lielām datu tabulām. Piebilde: šis atribūts var tikts lietots tikai strādājot ar Oracle7 datu bāzi. Šo atribūtu var izmantot, lai panāktu ātrāku atbildes laiku uz pieprasījumiem, piemēram, norādot, ka pieprasījumam vispirms jāatgriež tikai pirmās rindas ( /*+ FIRST_ROWS */); Sīkāk par šo un augstāk minēto atribūtu vērtībām var uzzināt Oracle7 grāmatās, nodaļās “Tuning SQL statements” un “The Optimizer”;

d)                               RECORDS BUFERED – atribūts, kas nosaka cik ierakstu no tabulas tiks buferēti klienta darba vietas atmiņā izpildot SQL pieprasījumu. Pēc noklusēšanas šī vērtība ir vienāda ar formā rādāmo bloka ierakstu skaitu plus konstante 3. Tā arī ir minimālā vērtība. Maksimālā vērtība tiek noteikta Oracle Forms 4.5 izpildes laikā, jo tas atkarīgs no pieejamās atmiņas apjoma uz klienta darba vietas. Šī atribūta papielināšana var paātrināt formu ātrdarbību, jo gadījumā, ja lietotājam jāaplūko tabula ar ļoti daudziem ierakstiem, tad mēģinot aplūkot nākošos tie tiks parādīti uzreiz, jo tie jau būs formas atmiņā. Pretējā gadījumā tie tiek savākti no datora virtuālās atmiņas. Uz ātrām darba stacijām ar ātriem diskiem tā nav problēma, jo tas notiek sekundes simtdaļās un ātrāk, bet ja darba stacijas disku ātrums ir lēns tas var radīt nelielu aizkavēšanos parādot ierakstus. Oracle formas buferētos rakstus glabā pagaidu failos uz diska. Tas nozīmē, ka pirms šī atribūta uzstādīšanas ir jārēķinās ar datora resursiem, ko aptuveni varētu aizņemt šie dati, jo rakstu var būt daudz, bet ar mazu apjomu (raksta lauku skaits un to izmēri), vai arī maz rakstu, bet kuru apjoms ir liels (satur laukus ar long datu tipu vai grafiskiem attēliem);

e)                                RECORDS FETCHED – atribūts, kas nosaka ierakstu skaitu, ko vienā reizē no datu bāzes pieprasa Oracle formas. Vislielākā ātrdarbība protams ir gadījumā, ja formām ir jāatlasa viens ieraksts vienā reizē. Lielāks šo ierakstu skaits samazina vispārējo laiku, kas nepieciešams ierakstu atlasīšanai, veicot mazāku skaitu datu pierasījumu izsaukumu. Šī atribūta vērtība jāliek atkarībā no blokā rādāmo ierakstu skaita, vislabāk vienāda ar rādāmo ierakstu skaitu. Strādājot sistēmās, kur pieslēgums datu bāzes serverim organizēts, izmantojot modemu, šī atribūta ieteicamā vērtība būtu vismaz 2-3 reizes lielāka, nekā rādāmo ierakstu skaits. Sīkāk par to tiks aplūkots kādā no nākamajām darba nodaļām;

f)                                UPDATE CHANGED COLUMNS – atribūts, kas nosaka vai izpildot datu modifikācijas komandu (UPDATE table_name SET…) tās parametros tiks iekļauti visas datu tabulas lauki vai tikai mainīto lauku. Pēc noklusēšanas šī atribūta vērtība ir False, kas nozīmē, ka izpildot UPDATE komandu tajā tiks uzrādīti visi datu tabulas lauki, kas dod iespēju Oracle Forms 4.5, lietot to pašu SQL teikumu vairākas reizes neveicot tā atkārtotu analizēšanu (re-parse). Uzstādot šā parametra vērtību uz True, var strauji samazināties Oracle Forms 4.5 ātrdarbība, jo katru reizi izpildāmā komanda vispirms ir jāizanalizē. Pamatā šī atribūta vērtība jāuzstāda uz True tikai gadījumos, ja lietotājs reti mainīs datus, kas prasa laiku to nosūtīšanai pa tīklu, piemēram, long tipa mainīgos vai grafiskos attēlus. To var izmantot arī gadījumos, lai samazinātu datortīkla noslodzi, ja zināms, ka lietotājs mainīs tikai vienu vai divus ierakstus, kā arī, lai izvairītos no lielu datu tabulu lauku vairākkārtējas pārsūtīšanas datortīklā. Gadījumos, ja maināmā tabulā ir tabulas trigeris, kas fiksē tikai mainīto lauku datus, šī atribūta vērtību arī ieteicams uzstādīt uz True, jo citādi datu modifikācijas komanda mainīs arī laukus, kuru vērtības patiesībā nav mainījušās, kas radīs liekas darbības tabulas trigerī;

Kā nākošos formas objektus aplūkosim vērtību sarakstus (LOV – List Of Values) un ierakstu grupas (Record group), kas tiek izmantotas, lai atlasītu ierakstus vērtību sarakstiem. Tāpat kā blokiem arī šiem objektiem ir virkne atribūtu, kuru vērtības var izmainīt formas ātrdarbību. Vērtību saraksta atribūti ir:

a)                                AUTO REFRESH – atribūts, kas nosaka vai pieprasot vērtību saraksta vērtības ieraksti no datu bāzes jāatjauno katru reizi vēršoties pie vērtību saraksta vai tikai pirmo reizi. Pēc noklusēšanas šī atribūta vērtības ir True, kas nozīmē ka vērtību saraksta saturs tiek atjaunots katru reizi, jo pēc katras vērtību izvēles Oracle Forms 4.5 piesaistītās ierakstu grupas datus dzēš no krātuves (cache). Ja šai sarakstā ir maz rakstu – tas notiek ātri, taču ja šo rakstu ir daudz un lietotājs veic masveida datu ievadi, tad šāda datu atjaunošana prasa zināmu laika patēriņu. Tas pats attiecināms uz gadījumiem, ja vērtību saraksti piedāvā izvēlēties kāda klasifikatora vērtības, kas mainās ļoti reti. Tad atjaunošanas darbība vienkārši ir lieka;

b)                               LONG LIST – atribūts, kas nosaka vai pirms vērtību saraksta parādīšanas, formas lietotājam pieprasīs ievadīt maskas nosacījumu atlasāmajiem datiem. Šis atribūts bieži effektīvi izmantojams gadījumos, kad vērtību saraksts ir ļoti liels. Tādējādi tiek samazināts atgriezto ierakstu skaita kā arī atvieglota lietotāja izvēle. Bez tam skaita ziņā mazāk ierakstu atlasīšana tiek veikta ātrāk nekā visas tabulas datu pilna atlasīšana. Maska tiek piesaistīta vērtību saraksta pirmajai kolonnai. Gadījumos, ja vērtību saraksts tiek izmantots arī ieraksta korektuma noteikšanai (validation), maskas nosacījuma dialogs netiek rādīts, tā vietā par masku tiek izmantoti lietotāja jau ievadītie dati attiecīgajā teksta laukā. Ļoti effektīvi šādos gadījumos ir izveidot tabulas indeksu pēc vērtību saraksta pirmās kolonnas lauka. Tā rezultātā datu atlasīšana, izmantojot indeksu, tiek veikta daudz ātrāk;

c)                               AUTO DISPLAY – atribūts, kura vērtība nosaka vai Oracle formas automātiski parādīs teksta laukam piesaistīto vērtību sarakstu ikreiz, kad lietotājs novieto kursoru šai laukā. Ja attiecīgais vērtību saraksts ir ļoti liels, tā vērtību parādīšana un datu atlasīšana kavē datu ievadi, nevajadzīgi traucējot lietotāju;

d)                              AUTO CONFIRM – atribūts, kas raksturo Oracle forms uzvedību gadījumos, ja lietotājam ievadot vērtību datu laukā, tam piesaistītajā vērtību sarakstā (pēc maskas) ir tikai viena vērtība. Vērtība True nosaka, ka vērtību saraksts netiek rādīts un esošā vērtība tiek uzskatīta par pareizu, citādi lietotājam tiek piedāvāta izvēle 1 no 1, vai iespēja atteikties. Ja lietotājs veic masveida datu ievadu, tad šāda lieka vērtību saraksta parakstīšana vienkārši kavē lietotāja darbu, liekot atkārtoti nospiest Enter taustiņu;

e)                               AUTO SKIP – atribūts, kas nosaka, ka pēc vērtības izvēles no vērtību saraksta kursors tiek pārvietots uz nākamo formas ievadlauku. Tas atvieglo lietotāja darbu, atbrīvojot no liekas taustiņu spiešanas, t.i. apstiprinot lauka ievadi;

Vienīgais Oracle Forms 4.5 ievadlauka atribūts, kas būtu pieminams šajā nodaļā un kas atvieglo lietotāja darbu, atbrīvojot to no liekas taustiņu spiešanas ir AUTO SKIP – atribūts, kas nosaka, ka ievadot lauka vērtību, ja tiek sasniegts maksimālais lauka garums, kursors automātiski pārvietojas uz nākamo formas ievadlauku.
Nākamais Oracle Forms 4.5 objekta atribūts, kas var iespaidot formas ātrdarbību ir formas trigeru izpildīšanās kārtība jeb EXECUTION STYLE. Šis atribūts nosaka kādā kārtībā jāizpildās formas trigeriem, ja formās eksistē tāds pats trigeris ar tādu pat vārdu augstākā objektu hierarhijas līmenī. Šim trigera atribūtam ir trīs vērtības – Override, Before un After. Override nozīmē, kas šis trigeris izpildīsies jebkura cita trigera vietā, kas atrodas augstākā objektu hierarhijas līmenī (Augstākā objektu hierarhijas līmenī esošais trigeris neizpildās). Šo vērtību lieto gadījumos, kad kādam ievadlauka līmeņa trigerim jāizpilda kaut kas, ko nepieciešams veikt tikai atrodoties šajā laukā, bet pārējos gadījumos jāizpilda tas izejas kods, kas aprakstīts formas līmenī. Before un After attiecīgi nozīmē, kas esošais trigera kods tiks izpildīts vai nu pirms vai pēc augstākā hierarhijas līmenī esošā trigera koda izpildes. Ja trigeris ar tādu vārdu eksistē gan formas, gan bloka, gan ievadlauka līmenī, tad uzstādot šī trigeru atribūta vērtību uz Before vai After, visbiežāk pieļautā kļūda ir – izpildās abi trigeri un bieži vien abos trigeru kodu tekstos tiek veiktas vienas un tās pašas darbības, kas nozīmē ka šis koda gabals prakstiski tiek izpildīts 2 vai pat 3 reizes. Biežāk lietotās komandas šādos gadījumos ir sistēmas parametru vai formas objektu atribūtu vērtību nolasīšanas funkcijas, kas tiek izsauktas atkārtoti abos trigeru tekstos.
Vēlāk tiks aplūkoti arī citi līdzīgi gadījumi, kā piemēram, vienā līmenī tiek izmantoti dažādi trigeri, kas dara kaut ko līdzīgu (vai arī pie dažiem nosacījumiem izpildās abi trigeri) kā arī, piemēram, ja trigeris atrodas pārāk zemu objektu hierarhijas kokā, kas rada pārāk biežu un lieku šī  koda izpildi.

1.1.2. Trigeru pareizs pielietojums un izvairīšanās no atkārtotiem izsaukumiem


Kā jau minējām iepriekš, rakstot trigeru kodus formās ir jāuzmanās no situācijām, kad kāds trigeris var tikt izsaukts pārāk bieži vai šad tad arī nevietā. Tas var radīt pārāk lēnu formas darbību vai arī sliktākajā gadījumā neparedzētus datu labojumus datu tabulās. Lai izprastu, kur visbiežāk tiek pieļautas kļūdas un kā no tām izvairīties ir pareizi jāsaprot trigeru izpildes kārtība formās, arī atkarībā no to hiarhiskā izvietojuma formā. Tālāk tiek aprakstīti formas bloka līmeņa trigeri, kas tiek izmantoti visbiežāk [3] [6]. Tie ir:
a)                                              WHEN-NEW-BLOCK-INSTANCE – trigeris, kas izpildās, kad lietotājs pārvietojas no viena formas bloka uz otru, neatkarīgi no bloka lauka uz kuru pārvietojas. Izpildās tūlīt pēc tam, kad formas ir gatavas jaunam datu ievadam blokā. Parasti tiek izmantots gadījumos, kad nepieciešams veikt kādu darbību, ja lietotājs formās pārvietojas uz citu bloku, piemēram, aizliegt/atļaut kādas spiedpogas u.c. Ja trigeris ir formas līmenī, tas izpildās jebkurā gadījumā, kad nomainās bloks. Ja tas ir bloka līmenī, tad tikai kad lietotājs pārvieto kursoru uz šo kādu no šī bloka elementiem;

b)                                              WHEN-NEW-RECORD-INSTANCE – trigeris, kas izpildās tūlīt pēc kursora pārvietošanas no viena ieraksta (record) uz otru, kad formas ir gatavas datu ievadam attiecīgajā ierakstā. Parasti tiek izmantots gadījumos, kad, piemēram,  jāveic kādas manupulācijas ar citiem formas objektiem, atkarībā no kāda ieraksta lauka vērtības. Ja trigeris ir formas līmenī, tad tas izpildās jebkurā gadījumā, kad lietotājs pārvietojas no kāda ieraksta uz citu, t.i. arī gadījumos, ja pāreja notiek no viena bloka kāda ieraksta uz cita bloka kādu ierakstu. Ja trigeris ir bloka līmenī, tas izpildās vienmēr, kad notiek pārvietošanās no bloka viena ieraksta uz citu;

c)                                              WHEN-NEW-ITEM-INSTANCE – trigeris, kas izpildās tūlīt pēc kursora pārvietošanas uz kādu no formas ievadlaukiem, tūlīt pēc tam kad formas jau gatavas datu ievadam. Parasti, piemēram, tiek lietotas lai izpildītu formas ierobežotās funkcijas (restricted built-ins). Ja trigeris ir formas līmenī, tas izpildās vienmēr, kad notiek pārvietošanās no viena ievadlauka uz citu. Ja tas ir bloka līmenī, tas izpildās tad, kad notiek pārvietošanās no viena ievadlauka uz citu tajā pašā blokā. Ja tas ir konkrēti jau kāda ievadlauka trigeris, tad tas izpildās tikai gadījumā ja kursors tiek pārvietots uz šo konkrēto ievadlauku;

d)                                             WHEN-CREATE-RECORD – trigeris, kas izpildās vienmēr, kad formās tiek izveidots jauns ieraksts. Parasti tiek izmantots gadījumos, piemēram, kad jāveic kādas darbības, teiksim noklusēto vērtību piešķiršana (funkcija no citu lauku vērtībām, kas aprēķināmas tikai izpildes laikā, un nav nosakāmas izstrādes laikā) jaunajam ierakstam. Ja trigeris ir formas līmenī, tas izpildās vienmēr, kad formās tiek izveidots jauns ieraksts. Ja tas atrodas bloka līmenī, tad vienmēr kad jauns ieraksts tiek izveidots attiecīgajā blokā;

e)                                              WHEN-VALIDATE-RECORD – trigeris, kas izpildās ieraksta validācijas procesā, kā pēdējais posms. Parasti tiek pielietots gadījumos, lai papildinātu formas noklusēto validācijas procesu. Piezīme, lietojot šo trigeri ir, ka formas atļauj šī trigera kodā manīt arī esošā ieraksta lauku vērtības atkārtoti neizsaucot šo trigeri, jo citādi tas var novest pie bezgalīgā cikla. Tāpēc izstrādātājiem jāuzmanās, lai šādi datu tabulās netiktu ierakstītas nekorektas vērtības, jo formas, trigera izpildes pozitīvā gadījumā, atzīmē ierakstu kā korektu. Ja trigeris ir formas līmenī, tas izpildās, ja kaut vienā formas blokā tiek veikta ieraksta validācija. Ja tas atrodas blokā līmenī, tad tikai, ja validācija notiek bloka ierakstiem;

f)                                               WHEN-VALIDATE-ITEM – trigeris, kas līdzīgs WHEN-VALIDATE-RECORD trigerim, tikai izpildās veicot katra ievadlauka validāciju. Izpildes kārtība tāda pati kā iepriekšējam trigerim, papildus šo trigeri var izvietot arī paša ievadlauka līmenī;

g)                                              PRE-BLOCK – trigeris, kas izpildās navigācijas procesa laikā pārvietojoties no viena bloka uz otru (ienākot jaunajā blokā). Trigeris izpildās vēl pirms WHEN-NEW-BLOCK-INSTANCE trigera. Parasti izmanto, lai kontrolētu pieejas tiesības blokam un piešķirtu mainīgo vērtības. Trigeris neizpildās, ja Oracle Forms 4.5 validācijas vienība ir formas līmenis. Izpildes kārtība atkarībā no atrašanās objektu kokā tāpat kā iepriekšminētajiem trigeriem;

h)                                              PRE-TEXT-ITEM – trigeris, kas izpildās navigācijas procesa laikā pārvietojoties no viena objekta uz citu, pie kam objektam uz kuru pārvietojas jābūt teksta ievadlaukam. Parasti izmanto, lai aprēķinātu lauka vērtību atkarībā no citu iepriekšējo ieraksta lauku vērtības vai arī piefiksētu esošo vērtību turpmākai lietošanai. Izpildes kārtība atkarībā no atrašanās objektu kokā tāpat kā iepriekšminētajiem trigeriem;

i)                                                POST-BLOCK – trigeris, kas atšķirībā no PRE-BLOCK trigera arī izpildās navigācijas laikā, taču atstājot kādu no formas blokiem. Parasti izmanto, lai pārbaudītu vai lietotājam tiesības atstāt bloku, balstoties uz kādu nosacījumu. Izpildes kārtība atkarībā no atrašanās objektu kokā tāpat kā iepriekšminētajiem trigeriem;

j)                                                POST-TEXT-ITEM – tāpat kā POST-BLOCK trigeris izpildās navigācijas procesa laikā atstājot kādu no teksta ievadlaukiem. Izpildes kārtība atkarībā no atrašanās objektu kokā tāpat kā iepriekšminētajiem trigeriem;

Gandrīz visiem augstāk minētiem trigeriem, kas sākas ar WHEN-… (izņemot WHEN-RECORD-CREATED, WHEN-VALIDATE-….) kopīgā (labākā) īpašība ir tā, ka tajos var izpildīt formas ierobežotās funkcijas (restricted built-ins), kas nav atļautas citos trigeros. Tas atļauj šajos trigeros veikt vairāk darbību, kā citos. Visbiežāk minētie jautājumi programmētājiem, kas sāk strādāt ar Oracle Forms 4.5 ir: ar ko pamatā atšķiras augstāk minētie trigeri un kā zināt kādus trigerus un kad lietot? Atbildot uz šiem jautājiemiem gribas minēt vienkāršu sakarību. Visi trigeri, kas sākas ar WHEN-… izpildās, kad jau beidzies navigācijas process, kursors nostājies uz jaunā ievadlauka un formas gatavas datu ievadam/labojumiem. Šajos trigeros (ar dažiem izņēmumiem) atļautas formas ierobežotās funkcijas (restricted built-ins), kas nav atļautas citos trigeros. Visi trigeri, kas sākas ar PRE-… izpildās navigācijas procesa laikā pirms kursora novietošanās uz attiecīgā objektā, bet pirms POST-.. trigeriem, kas izpildās “atstājot” kādu no formas objektiem. Tā kā šie trigeri izpildās navigācijas procesa laikā, t.i. pirms formas gatavas jaunam datu ievadam, šajos trigeros nav atļautas formas ierobežotās funkcijas. Taču arī šo ierobežojumu iespējams apiet, šajos trigeros izveidojot taimerus (timer), kas izpildās tūlīt pēc to izveidošanas, kuros savukārt jau var izpildīt visas formas ierobežotās funkcijas. Šāds “apvedceļš” ir ļoti viegli realizējams [9].
Bet atgriežoties pie optimizācijas problēmām, biežāk pieļautās optimizācijas kļūdas, ko pieļauj izstrādātāji, lietojot šos trigerus ir to nepareiza novietošana formas hierarhiskajā objektu kokā. Tie tiek novietoti pārāk augstu vai arī tiek pielietoti trigeri, kas izpildās biežāk nekā nepieciešams. Piemēram, pieņemsim, ka formās ir 3 datu ievades bloki, kas ar relācijās saitēm pakārtoti viens otram. Atkarībā no katra bloka konkrētā ieraksta vērtības ir jāatļauj/jāaizliedz kāda konkrēta ievadlauka pieejamība (enabled/disabled), kas atkarīga tikai no konkrēta bloka konkrētā ieraksta. Bez tā vēl arī no citās datu tabulās esošām vērtībām pēc konkrētas formulas jāizrēķina un jāparāda kāda vērtība. Visvienkāršāk to protams izdarīt (kas arī bieži tiek praktizēts) ir formas līmenī izveidojot WHEN-NEW-RECORD-INSTANCE trigerī, kurā tiek izpildītas šīs aizliegšanas/atļaušanas darbības un izrēķinātas attiecīgā lauka vērtības no zināmajām trīs bloku attiecīgo ierakstu vērtībām. Tas viss ir viegli pārskatāms un ērti lietojams, taču izpildes ātrums krietni samazinās, jo pārvietojoties par katru ierakstu pašā zemākajā blokā, trigera kodā tiks izpildītas liekas darbības, kas attiecas uz diviem augstāk esošajiem blokiem. Tas pats attiecas arī uz pārvietošanos vidējā blokā. Šeit gan jāpiebilst, ka šajā gadījumā trigeris izpildās pat lieku reizi. Pirmā reize būs izvēloties rakstu vidējā blokā, pēc tam pakārtotājā. Forma automātiski parādīs piekārtotos rakstus trešājā blokā, kur atkal būs jāizvēlas vajadzīgais raksts. To darot pašā “augstākajā” blokā, trigeris jau izpildās lieki 2x uz katru ierakstu. Kā jau zināms, šāda lieka koda izpilde samazina formas ātrdarbību, it sevišķi, ja trigeros tiek veikts daudz aprēķinu un datu pieprasījumu no citām datu tabulām.
Savukārt minot piemēru par nepareiza trigera izvēli, kā rezultātā tā kods tiek izpildīts pārāk bieži (trigeris novietots hierarhiskajā līmenī pareizi), der minēt šādu piemēru. Jaunajam ierakstam ir jāpapildina dažas lauku vērtības ar vērtībām no citu datu tabulu laukiem. Tam tiek izmantots WHEN-NEW-RECORD-INSTANCE trigeris, WHEN-RECORD-CREATED trigera vietā, katrā tā izsaukumā tiek pārbaudīts vai jaunā ieraksta atribūts nav New. Lieki piebilst, ka kods tiks izpildīts katru reizi pārvietojoties no viena ieraksta uz otru un ja lietotājs jaunus ierakstus pievieno ļoti reti, kods izpildās prakstiski nevajadzīgi (Parasti jau tā izpilde beidzas tūlīt pēc ieraksta statusa pārbaudes, bet tomēr lieki tiek izsaukts trigeris). Izstrādātāji parasti pieļauj šādas kļūdas gadījumos, kad pilnībā nepārzin visus Oracle Forms 4.5 trigerus un lieto tikai tos kurus pārzin, pielāgojot tos nepieciešamajām situācijām.
Pakāpjoties nedaudz “augstāk” objektu hierarhijas kokā ir vērts pieminēt arī dažus formas līmeņa trigerus, kuri dažkārt tiek nepareizi pielietoti. Tie ir:
a)                                PRE-FORM – trigeris, kas izpildās formas ielādes laikā. Parasti tiek pielietots, lai nolasītu unikālās vērtības no sekvencēm, pārbaudītu pieejas tiesības formai un inicializētu globālos mainīgos. Kļūdas gadījumā (Raise Form_trigger_failure) forma tiek aizvērta neizpildot nevienu citu trigeri [3];

b)                               WHEN-NEW-FORM-INSTANCE – trigeris, kas izpildās tūlīt pēc formas ielādes, kad forma gatava datu ievadam (Pārējie WHEN-NEW-… trigeri jau izpildījušies). Trigeris neizpildās, ja kontrole atgriežas no izsauktās formas tajā, kas to izsauca. Kļūdas gadījumā darbu beidz tikai trigeris.

Kļūda, kas tiek pieļauta šajā gadījumā ir, ka PRE-FORM trigerī nevar izpildīt formas ierobežotās funkcijas, kas varbūt nepieciešamas atverot formu un veicot pieejas tiesību kontroli un mainīgo inicializēšanu. Tāpēc izstrādātāji šo izpildāmo kodu pārnes uz WHEN-NEW-FORM-INSTANCE trigeri, kur tas var veiksmīgi izpildīties. Taču pieļautā kļūda (arī optimizācijas) ir – ja kļūdas gadījumā ir jāaizver forma, PRE-FORM trigerī tas izpildās neizsaucot nevienu citu trigeri. Savukārt otrajā gadījumā, lai aizvērtu formu ir jāizpilda Exit_Form komanda, ka izpilda vēl virkni trigeru, ieskaitot POST-FORM, kas var saturēt arī citas datu manipulācijas komandas. Tadējādi izpildās lieks izejas kods, kas var arī nevēlami mainīt datu bāzes datus. Izeja no šādas situācijas ir šāda - viss nepieciešamais tiek izpildīts PRE-FORM trigerī un WHEN-NEW-FORM-INSTANCE trigerī tiek izpildītas tikai formas ierobežotās funkcijas, ko nevar izpildīt PRE-FORM trigerī. Tas viegli realizējams PRE-FORM trigerī, izmainot kāda mainīgā vērtību, kas nozīmē, ka WHEN-NEW-FORM-INSTANCE trigerī jāizpilda formas ierobežotās funkcijas. Bez tam var lietot arī jau minēto risinājumu, izmantojot taimerus (timer).

1.1.3. Ne-tabulas lauku vērtību aktualizēšana


Ļoti bieži formās datu tabulu blokos ir nepieciešams ievietot laukus, kas patiesībā nepieder tabulai, be gan tikai rāda kāda tabulas lauka koda atšifrējumu no citas tabulas. Parasti to izmanto, lai parādītu klasifikatoru kodu nozīmi. Šādi ne-tabulas lauki tiek iekļauti bloka definīcijā. Pēc tam tiek rakstīts PL/SQL kods šo vērtību aktualizēšanai. Tam parasti izmanto 2 trigerus: POST-QUERY, ko izmanto vērtības aktualizēšanai nolasot ierakstus no datu tabulas un WHEN-VALIDATE-ITEM, ko izmanto gadījumos, ja tiek mainīta klasifikatora vērtība. Visvienkāršākais risinājums šādas klasifikatora koda nozīmes atlasīšanai ir standarta SQL datu pieprasījums formā [6]:
     SELECT name
     INTO :block.code_name
     FROM CODE_TABLE1
     WHERE code = :block.code;

Tā kā šad tad klasifikatoru vērtības var būt arī tukšas papildus tiek apstrādāti tādi gadījumi (exceptions) kā NO_DATA_FOUND un OTHERS, attiecīgi ierakstot tekstu, ka koda vērtība tukša vai nezināma. WHEN-VALIDATE-ITEM trigeris izpildās tikai ievadot jaunu ierakstu vai arī labojot esoša ieraksta vērtības. Tas izpildās tik reizes cik tiek veiktas šādas operācijas. Savukārt POST-QUERY trigeris izpildās tik reizes cik bāzes tabulas ieraksti tiek atlasīti no datu bāzes. Uz katru ierakstu vienu reizi, katru reizi izpildot vienu un to pašu SQL datu pieprasījumu, no vienas un tās pašas tabulas. SQL pieprasījumā mainās tikai maskas nosacījums, kas nosaka kurš ieraksts jāatgriež. Atkārtoti pieprasot datus no vienas un tās pašas tabulas tie būs servera operatīvajā atmiņā (cache) un datu pieprasījums izpildīsies ļoti ātri. Bet skaidri redzams ka šāda darbība ir vienkārši lieka, jo bieži ir daudz ierakstu, kam šī klasifikatoru vērtības sakrīt. Bez tam visi datu pieprasījumi un atbildes tiek pārsūtītas pa tīklu, radot lieku noslodzi datortīklā. Jāņem vērā arī fakts, ka parasti vienā blokā šādu lauku, kuru vērtības ir klasifikatoru kodi ir ne tikai viens, bet gan vairāki. Tātad uz katru ierakstu, kas tiek atlasīts no datu bāzes, tiek papildus veikti vēl n datu pieprasījumi, lai parādītu attiecīgo klasifikatoru kodu vērtības. Ja POST-QUERY trigerī tiek mainītas bloka lauka vērtības Oracle formas attiecīgo ierakstu atzīmē kā labotu (changed), kā rezultātā vēl papildus tiek izpildīts WHEN-VALIDATE-ITEM trigeris. To protams var appiet uzstādot ieraksta atribūtu uz atlastīts (quered) programmātiski, taču tā atkal ir lieka PL/SQL koda izpilde. Optimizācijas risinājums šai problēmai būtu, ja visie šie dati tiktu atlasīti tikai vienreiz kādā virtuālajā masīvā vai kādā citā formas objektā un nepieciešamības gadījumā formas vērstos pie šī objekta nevis veiktu datu pieprasījumu no datu tabulas.
Kā viens no labākajiem risinājumiem šai problēmai, autora skatījumā, ir izmantot Oracle Forms 4.5 objektu list item. Tā aktualizēšanai ir jāizveido ierakstu grupa, kas datu nolasīšanai no datu servera - datu pieprasījumu izpilda tikai vienu reizi, startējot formu. Šis formas objektam ir divas vērtības: pirmā, kas tiek ierakstīta datu tabulā un otra, kas tiek parādīta lietotājam. Lai lietotājs tāpat kā augstāk minētajā gadījumā zinātu, gan laukā ievadītā klasifikatora kodu, gan tā informatīvo vērtību, ieraksta grupa tiek veidota sekojoši:
     SELECT code, code||’-‘||code_name
     FROM CODE_TABLE1;
Tādējādi lietotājs redz abas vērtības, bet datu tabulas laukā ierakstās tikai atbilstošais kods. Taču ja lietotājam paredzētā datu ievadforma domāta masveida datu ievadam, šāds risinājums varētu būt arī pārāk neērts, jo šādi lietotāji parasti strādā zinot šo lauku klasifikatoru kodu vērtības no galvas, un 2 vai 3 ciparu koda ievade no klaviatūras var tikt veikta daudz ātrāk nekā šāda klasifikatora izvēli no list item. Bez tam šim Oracle Forms 4.5 objektam nav iespējas nostāties uz attiecīgā raksta, ievadot raksta pirmās vērtības, kā tas ir iespējams citiem MS Windows vidē esošiem šādiem pašiem objektiem. Tas strādā tikai uz pirmā simbola vērtību. Cerams, ka šī mazā kļūda tiks novērsta jaunajā produkta versijā Oracle Forms 5.0.
Arī šādos gadījumos, autora skatījumā, labāk ir rīkoties šādi – blokā tiek izveidoti 2 objekti. Viens datu ievadlauks klasifikatora kodam, kura vērtības tiek kontrolētas izmantojot vērtību sarakstu (LOV) un klasifikatora informatīvais lauks, objektu kura tips ir jau zināmais list item un kura atribūts List style vienāds ar Poplist vai T-list atkarībā no izstrādātāja gaumes. List item objekta atribūts Mirror Item tiek uzstādīts vienāds ar ievadlauka objektu vārdu. Abus objektu (LOV un list item) vērtību aktualizēšanai tiek izmantotas divas (2) ierakstu grupas, kas atlasa vienus un tos pašus datus. Problēma ir tikai faktā, ka vērtību sarakstam parasti datus atlasa formā code, code_name, bet ierakstu grupai, kas aktualizē list item, tie vajadzīgi citā kārtībā – code_name, code. Protams šeit var diskutēt, kas strādā ātrāk – n-tie datu pieprasījumi pēc vienas rindas no datu tabulas, izmantojot indeksu, vai arī viens (vai 2, ja tiek izmantots otrais variants ar 2 laukiem) visas datu tabulas ierakstu pieprasījums. Ja tabula, kuru apskatām ir ļoti maz ierakstu, bet klasifikatoru tabula ļoti liela apjoma – varbūt arī lielāks ieguvums būs no šī risinājuma (POST-QUERY trigera izmantošana), taču parasti lielās sistēmās ir otrādi – ir ļoti daudz mazu klasifikatoru tabulu, kuru informācija ir daudzās un lielās datu tabulās. Šādā gadījumā viens datu pieprasījums pēc visas tabulas datiem izpildīsies daudz ātrāk nekā n-tie pēc viena ieraksta. Kā tiks aplūkots vēlākā darba gaitā, tas ir ļoti izdevīgi, ja lietotājs pie datu bāzes ir pieslēdzies izmantojot modemu, kur pārāk liela datu plūsma tikai samazina formas ātrdarbību.
Protams pastāv arī iespēja definēt virtuālās tabulas (view), kas atgriež jau atšifrētas klasifikatoru kodu vērtības, tādējādi viss tiek atrisināts jau servera pusē. Taču ja tas nav iespējams, tad neatliek nekas cits kā veidot vērtību atlasīšanu caur trigeriem. (Problēmas parasti ir ja kādas tabulas divi vai vairāki lauki atsaucas uz vienu un to pašu klasifikatoru, vai arī jāveic datu pieprasījums no vairākām tabulām, kur katrā jāveic atkal pieprasījums no vienas un tās pašas klasifikatoru tabulas. Šādi datu pieprasījumi kā rezultātu atgriež šo tabulu rakstu reizinājumu)

1.2. Operāciju ar datnēm optimizēšana


Ļoti daudzas pakešu apstrādes sistēmas (šeit runa nav par ON-LINE sistēmām, kas savstarpēji sazinās, izmantojot kādu tīkla protokolu) veic “sazināšanos” savā starpā, pārsūtot ASCII datnes ar nepieciešamo informāciju, kas no vienas sistēmas tiek eksportētas un otrā importētas. Vienkāršāk izsakoties, notiek datu apmaiņa ar datnēm, abām sistēmām zinot šo datņu formātus. Pie lieliem datu apjomiem vai pie nosacījuma ka šīs operācijas jāveic vairākkārt dienā sistēmas ātrdarbība šo operāciju laikā ir ļoti nozīmīga.
Šajā darbā netiks aplūkotas situācijas, kad datņu ielasīšanu varētu veikt, izmantojot ORACLE SQL*Loader, kurai sagatavotas datnes konkrētā formātā. Tas izskaidrojams ar to, ka šajā vidē ļoti sarežģīti ir veikt datu veselumu kontroli, aplūkojot kontrolvērtības, kas aprakstītas datnes nobeiguma rakstos vai citur. Ļoti bieži šādas datnes tiek saņemtas jau zināmā formātā, kas nav atkarīgs no mūsu izvēles (teiksim ielasot citu sistēmu datus, kas tiek sagatavoti viņu esošā formātā), kas nozīmētu, ka šī datu datne pirms ielasīšanas būtu jāpārveido citā formātā, lai to varētu ielasīt ar ORACLE SQL*Loader. Protams pastāv arī situācija datus ielasīt pagaidu tabulās un tad veikt datu veselumu pārbaudi, bet šādus gadījumus šoreiz neaplūkosim, jo tie prakstiski nedod nekādus labākus rezultātus, jo laiks, kas patērēts datu ierakstīšanai pagaidu tabulās un atlasīšanai no tām pēc tam, var tikt izmantots datu ielasīšanai pa tiešo, nerakstot tās pagaidu tabulās. Parasti arī lietotājiem ir prasība, ka, jau datnes ielasīšanas laikā, tie vēlas redzēt, ka datne ir ielasīta veiksmīgi vai datnē ir kāda kļūda.

1.2.1. Datņu ielasīšana


Parasti rakstot ASCII datņu ielasīšanu Oracle bāzēs pirmais, ko veic programmētāji, izmantojot pakotnes TEXT_IO palīdzību, ir - tiek ielasīti datnes dati, turpat formas programmu vienībās (programm units) tiek pārbaudīts tās datu veselums, kā arī izpildītas nepieciešamās datu ievadīšanas vai labošanas (INSERT un UPDATE) operācijas datu bāzē. Pie ļoti maziem datu apjomiem šādu operāciju ātrdarbība ir ļoti laba un lietotāji parasti par to nesūdzas, taču gadījumos, ja datnes izmēri strauji pieaug, t.i. datnes apjoms ir 5000 un vairāk rindiņas, tās ielasīšana jau prasa zināmu pacietību no lietotāju puses. Pamatā sistēmas “bremzēšana” notiek uz ļoti biežo datu bāzes operāciju INSERT un UPDATE izpildīšanas rēķina, jo visas šīs operācijas, izmantojot Oracle SQL*Net protokolu, tiek padotas Oracle serverim izpildei. Tad tiek sagaidīta operācijas rezultāta atbilde. Gadījumos, kad klienta darba vietas dators ir mazjaudīgs, kā arī pie lielām datortīkla noslodzēm, šo operāciju izpildes laiks krasi samazinās.
Pirms veicam kādu analīzi, lai noskaidrotu, ko var uzlabot lai datņu ielasīšana tiktu veikta ātrāk, ir jānoskaidro cik liels laika patēriņs tiek veikts uz katru mums nepieciešamo operāciju:
1)      Failu operācijas (atvēršana, nolasīšana, aizvēršana);
2)      Datu kontrole (datu veseluma pārbaude);
3)      Datu ievads datu bāzē (INSERT un UPDATE operācijas);
4)      Pārpalikums (f-ju izsaukumi, darba gaitas parādīšana un informācijas sinhronizācija).

Tātad vispirms tiek izveidota forma, kas veiks mums nepieciešamo datu ielasīšanu, sadalīšanu pa laukiem un ievadīšanu datu bāzē (INSERT INTO…). Rakstot šo darbu šādiem testiem tika izmantota autora vadībā izveidotās sistēmas VISA Clearing Interface, datņu ielasīšanas forma, kas veic VISA CTF (VISA Center Transactions File) datņu ielasīšanu sistēmā pirmā versija. Tajā visas datu kontroles un datu ievadfunkcijas tika realizētas formas programvienībās vai bibliotekās (program units vai Program units from Libraries).
1.1. attēlā ir aplūkojams mēģinājumu rezultāts, kuru laikā tika veikts sekojošais: ielasītas 2 VISA CTF datu datnes  – viena ar 3 300 rindiņām, otra ar 56 300 rindiņām. Tika veikti 5 mēģinājumi pie dažādām klienta darba vietas un datu bāzes servera noslodzēm. Pirmie 3 mēģinājumi veikti, darba dienas vidū, kad paralēli tiek eskpluatēts arī datu bāzes serveris. Otrajā un trešājā mēģinājumā uz klienta darba vietas vēl papildus tiek veiktas citas darbības – strādāts ar citām Windows programmām /MS Word, MS Excel, Oracle Forms Designer/, kā arī vēl spēlēta mūzika izmantojot MP3 datņu izpildprogrammu WinAmp, kas kā zināms ļoti daudz patērē datora procesora laiku. /Normālas darba stacijas noslodzes simulēšana/. Ceturtais un piektais mēģinājums tiek veikti vēlu vakaros, kad praktiski nav nekādas noslodzes uz datu bāzes servera, kā arī uz klienta darba vietas tiek darbināta tikai šī programma.






1.1. attēls. Datņu ielasīšana no formām.

Kā redzams attēlā, datu ievadīšanai bāzē (INSERT… operācija) tiek patērēts aptuveni sekojošs laiks: 5m17s – 10m15s (13,3% – 14% no kopējā laika), kas, kā redzams attēlā, ļoti atkarīgs no klienta darba vietas noslodzes. Jo tā lielāka, jo šīs operācijas izpilde vairāk palēninās. Tas pats attiecināms arī uz datu kontroles un datu sadalīšanas operācijām (vienkārša datu virknes sadalīšana pa laukiem /SubStr, Lpad un citas operācijas/ un aizpildīšanu pēc konkrētiem algoritmiem /+, - , *  u.c. operācijas/ ), kurām tiek patērēts no 15m15s līdz 27m40s (aptuveni 40% no kopējā laika).
Tā kā visas datu ievades operācijas (INSERT INTO…) un unikālo identifikātoru nolasīšanas operācijas (SELECT SEQ.nextval …) tik un tā tiek izpildītas uz servera, iespējams, ka tiek lieki patērēts laiks šo operāciju nodošanai izpildei serverim (izmantojot SQL*Net protokolu). Viena no idejām, kas varētu dod ātrākus rezultātus, iespējāms būtu šīs operācijas izpilde uz servera, t.i. servera pakotnēs.
 Vienīgā iespēja, kā samazināt virkņu operācijām patērēto laiku, laikam būtu to izpilde uz jaudīgākas mašīnas, kas šīs operācijas spētu veikt ātrāk. Iespēja, kas mums pastāv ir šo operāciju pārnešana uz servera pakotnēm un to izpildīšana tur. Pakotnei tiek nodoti tikai nepieciešamie parametri. Datu bāžu serveri parasti ir ļoti jaudīgi datori, kas spēj veikt daudzreiz vairāk operāciju sekundē. Šādu operāciju pārnešana dod varbūt ne acīmredzami ātrāku izpildi uz ātrākiem klienta darba vietas datoriem, bet gadījumā, ja klienta darba vietas dators ir 486 tipa dators ir diezgan ievērojama.  Virknes sadalīšana pa laukiem jau pašā servera pakotnē ir izdevīgāka arī ar to, ka funkcijas izsaukumos tagad tiek nodots tikai viens parametrs – virkne, nevis visu datu ievades operācijai nepieciešamos lauku dati, kas atvieglo formas programmas koda rakstīšanu.
Visbeidzot tas reducējas uz to, ka uz klienta darba vietas datora jeb konkrētāk Oracle formas, varētu izpildīt tikai dažas operācijas, kuras nav iespējams izpildīt uz servera - datu nolasīšanu no datnes, servera pakotņu funkciju vai procedūru izsaukšanu un rezultātu parādīšanu lietotājam.
Tātad nākošajos mēģinājumos tiek izmantota jau agrāk minētās formas VISA CTF datņu ielasīšanai otrā versija, kurā forma tikai nolasa datus no datnes un nodod tos serverim, gaidot tā atbildi par veiksmīgu vai neveiksmīgu datu ievades operācijas izpildi. Ciklā, kamēr vien datnē eksistē dati, tiek veiktas sekojošas darbības:

While TEXT_IO.Get_Line(f, line) LOOP
     ………….
IF NOT VISA_READ_CTF.Write_data(line, errtxt) then
     Message(‘Error writing data’||errtxt);
END IF;
………..
END LOOP;


Servera pakotnes funkcijā Write_Data tiek veikta virknes sadalīšana pa laukiem, datu veseluma kontrole un datu ievades operācijas izpilde. Kļūdas gadījumā kļūda tiek atgriezta mainīgajā errtxt.
1.2. attēls. Datņu ielasīšana no formām, ja visas operācijas ar datiem
tiek veiktas servera pakotnēs.
Pirmajā variantā /1.2. attēlā apzīmēti ar (F)/, Oracle formas programvienībās tiek veiktas visas operācijas, t.i. datnes lasīšana, datu kontrole un datu ievades operācijas. Otrajā variantā /attēlā apzīmēti ar (S)/, Oracle formas veic tikai datnes datu nolasīšanu un servera pakotnes funkcijas izsaukšanu.
Arī šajā gadījumā tāpat kā iepriekš tiek veikti 5 mēģinājumi - pirmie 3 tiek veikti, darba dienas vidū, kad paralēli tiek eskpluatēts arī datu bāzes serveris. Otrā un trešā mēģinājuma laikā uz klienta darba vietas vēl papildus tiek veiktas citas darbības – strādāts ar citām Windows programmām. Ceturtajā un piektajā mēģinājumā šis uzdevums ir vienīgais, kas noslogo gan datu bāzes serveri, gan klienta darba vietas datoru.
Aplūkojot INSERT operācijas izpildes laiku, datu kontroles laiku kā arī visas datnes ielasīšanas operācijas koplaiku, jau redzama atšķirība izpildes ātrumā, kopsummā no 1,5 līdz pat 2 reizēm. Kur veidojas šī atšķirība ?
Kā redzams attēlā abos gadījumos datņu operācijām patērētais laiks prakstiski neatšķiras, kas arī ir loģiski, jo abos gadījumos to veic Oracle formas un viss atkarīgs tikai no klienta darba vietas noslodzes – palielinoties klienta darba vietas noslodzei laiks palielinās un samazinoties - samazinās. Tātad abos gadījumos patērētais laiks datņu operācijām ir 1m50s – 4m10s, kas atkarīgs no klientu darba vietas noslodzes. Noslodzes maiņas uz datu bāzes servera nekādi neiespaido datņu ielasīšanas operācijas, kas tiek izpildītas uz klienta darba vietas datora.
Aplūkojot sīkāk pārējo operāciju izpildes laikus, konstatējam, ka datu ievades operācijai (INSERT INTO..), to izpildot servera pakotnē vidēji tiek patērēts 1m50s - 2m05s (3,9% – 7,8% no kopējā laika), savukārt šo pašu operāciju izpildei formas programmvienībās (program units vai Program units from Libraries) tika patērēts 5m17s – 10m15s (13,3% – 14% no kopējā laika). Acīmredzams, ka laika starpība šo operāciju izpildei formas programmvienībās un servera pakotnēs ir 2,5-5x, kas pie vienkāršu datņu ielasīšanas, kur pamatā tiktu veiktas tikai datu ielasīšanas, dotu ātrāku operāciju izpildi. Pie kam jebkurā gadījumā, ja palielinās klienta darba vietas noslodze, tad kopējais izpildes laiks, ja operācija tiek izpildīta formās palielinās, bet ja uz servera - nemainās. Bet ja noslodze tiek palielināta uz servera, tad abos gadījumos, neatkarīgi kur tiek izsaukta datu ievades operācija, tās izpildes laiks palielinās, jo beigās tik un tā operācija tiek izpildīta uz servera.
Nākošais mūs interesējošais rādītājs ir datu veseluma kontrole un pārbaude pirms datu ievades operācijas veikšanas, kas šo konkrēto mēģinājumu gadījumā sevī ietver datnes rindas sadalīšanu pa laukiem (SubStr, Decode, Translate un citas funkcijas), datu pārbaudi uz NULL vērtībām laukiem, kam šādas vērtības nav pieļaujamas. Dažu lauku vērtības tiek aprēķinātas no zināmām citu lauku vērtībām (sevī var ietvert arī datu atlasīšanas operācijas no citām tabulām). Aplūkojot 1.2 attēlu varam konstatēt, ka datu kontrolei servera pakotnē vidēji tiek patērēts no 4m30s līdz 4m40s (10% – 17% no kopējā laika), savukārt šo pašu operāciju izpildei formas programvienībās tiek patērēts no 15m15s līdz 27m40s (aptuveni 40% no kopējā laika). Laika starpība šo operāciju izpildei formas programvienībās un servera pakotnēs ir 3-6x, kas protams ļoti atkarīgs no veiktajām operācijām, taču tendence ir skaidri saskatāma, ka operācijas ar virknes tipa (string) mainīgajiem, dažādu mainīgo vērtību kalkulācija uz klienta darba vietas izpildās lēnāk, kaut vai tāda iemesla dēļ, ka klienta darba vietas datoru procesori ir ar mazāku jaudu. Noslodzes maiņas gan uz klienta darba vietas, gan uz datu bāzes servera šajā gadījumā ir neatkarīgas. Tas nozīmē, ja izpildām operācijas Oracle formās, tad uz servera palielināta noslodze neiespaido mūsu rezultātus un viss par ko jārūpējas ir lai klienta darba vieta būtu noslogota pēc iespējas mazāk un otrādi, ja operācijas tiek izpildītas servera pakotnēs.
Tātad secinājums, kas tiek iegūts pēc šiem mēģinājumiem ir  - jebkuras operācijas ar datiem datu bāzē, ja tās jāveic lielos apjomos daudz ātrāk izpildās, ja tās tiek izpildītas uz servera, t.i. servera pakotnēs. Tas pats attiecināms arī uz virknes sadalīšanu, izmantojot tādas operācijas kā SubStr, Decode, Translate u.c.
Taču neskatoties uz iegūtajiem labākajiem rezultātiem tik un tā datu ielasīšanas ātrums šķiet ļoti lēns – vidēji 0.04-0.05 sekundes uz vienu datnes rindu (0.07-0.08, ja ielasīšana un datu ievades operācijas notika tikai formas programvienībās). Summējot mums visu zināmo kritisko operāciju laikus - faila nolasīšana + datu kontrole + datu ievads mēs iegūstam vidēji 20-30% no koplaika. Zinot arī, ka operācijas rezultātu pierakstam sistēmas žurnāla tabulās un parādīšanai uz ekrāna tiek vidēji patērēts 10-15% resursu, mums pāri paliek ap 55-70% no koplaika, kas atkarīgs no sistēmas noslodzes. Vairāk kā puse no laika resursiem kaut kur tiek patērēta, taču ne mums vajadzīgajās operācijās. Kur tiek patērēts šis laiks? Kārtīgi izpētot uzrakstīto formas kodu un atceroties pašā sākumā minēto par koda optimizāciju ciklu ķermenī, iegūstam sekojošo – zinot ka ielasam datnes, kuru apjoms pārsniedz 59 600 rindas un pie katras rindas tiek izsaukta servera pakotnes funkcija, kas veic datu ievadoperāciju, forma veic 59 600 servera pakotņu izsaukumus, katru reizi kā parametru nododot vienu rindu. Ja datortīkls, kurā darbojas sistēma ir noslogots, samazinās funkcijas izsaukšanas un atbildes laiks. Pirmā ideja, kas šādā situācijā nāk prātā ir – serverim ir jānodod uzreiz vairākas rindas, teiksim 5-10, tādējādi samazinot šo izsaukumu skaitu attiecīgi 5-10 reizes. 5960 funkcijas izsaukumu 59 600 vietā, nododot serverim tikpat daudz informācijas (tās pašas 59 600 rindas ar informāciju), varētu dod mazliet labākus rezultātus. Taču izmēģinot, iegūtie rezultāti patiešām pārsteidz, kas norāda tikai uz to, ka patiešām daudz laika tiek tērēts tieši veicot servera pakotņu funkciju un procedūru izsaukumus no formām.
Tātad atkal tika veiti 5 mēģinājumi pie dažādām formu un servera noslodzēm. 1.3. attēlā ir parādīti šo mēģinājumu rezultāti.























1.3. attēls. Datnes ielasīšana no formām, ja servera pakotņu
izsaukums tiek samazināts 10 reizes.

Kā jau redzams 1.3. attēlā šāda realizācija, izsaucot servera pakotnes funkciju, kurai tiek nodotas uzreiz 10 rindas, dod apmēram 2x reizes ātrāku realizāciju, kas panākts samazinot laiku, kas tiek patērēts procedūru izsaukumiem, jo datnes operācijām, datu ievadam datu bāzē un datu kontrolei patērētais laiks nav mainījies. Datu ielasīšanas ātrums tagad ir vidēji 0.01-0.02 sekundes uz vienu datnes rindiņu. Kas notiktu, ja servera pakotnes funkcijai tiktu padotas 20, 30 vai pat 50 rindas uzreiz? Ātrdarbība palielinātos taču ne vairs tik ļoti, jo pie notiekta rindu skaita tiktu sasniegta iespēju robeža. Bez tam jāatceras, ka uz servera ir jārealizē papildus programmas kods kas apstrādā visas padotās rindas, kam kļūdas gadījumā n-tajā rindā ir jāaptur turpmākā apstrāde. Veicot šos mēģinājumus, tas tika realizēts ļoti vienkārši, bet gari:
IF str1 IS NOT NULL then
      rez := WRITE_DATA(str1, err_txt_tmp);
      err_text := err_txt_tmp;
      IF rez and str2 IS NOT NULL then
              ……………………
              ……………………
Return rez;
          END IF;
       ELSE
         Return TRUE;
      END IF;
  END;
Funkcijas izsaukums formā praktiski paliek nemainīgs, jo izmainās tikai tas, ka uzreiz jānolasa 10 rindas un tās jānodod servera procedūrai, kas atgriež vai nu pozitīvu rezultātu ar visiem brīdinājuma ziņojumiem vai arī sliktākā gadījumā kļūdas paziņojuma tekstu.
Lai lietotājs varētu sekot datnes ielasīšanas procesam, t.i. datnes ielasīšana turpinās un pašlaik vēl nekādu kļūdu nav bijis, ir jāveic kaut kāda informācijas parādīšana lietotājam. MS Windows lietotājiem ļoti pieņemams un viegli uztverams ir progresa rādītājs. (Par tā realizāciju un citiem sīkumiem tiks aprakstīts darba nākošajā nodaļā par lietotāja-datora interfeisa uzlabošanu). Atceroties iepriekš minēto par servera pakotņu funkciju izsaukšanu gandrīz 60 000 reizes varam saprast, ka gadījumā, ja pēc katras rindas tiek mēģināts parādīt paveikto un vēl aprēķināts cik laika nepieciešams līdz procesa beigām - lieki tiek tērēts laiks. Tika veikts papildus mazs mēģinājums veicot šo pašu datņu ielasīšanu, informāciju sinhronizējot tikai pēc katrām 500 rindām /1.3.attēlā redzamie mēģinājumi tika izpildīti sinronizējot informāciju ik pēc 10 rindām/. Rezultāts – datnes tiek ielasītas ātrāk, pamatā tiek samazināts kopējais procesa izpildes laiks. Tātad Oracle Forms 4.5 procedūra informācijas sinhronizēšanai formās Syncronize patērē zināmu laiku. Konkrētu laiku nav iespējams uzrādīt, jo tas ļoti atkarīgs no darba vietas noslodzes. Tās patērētais laiks vienā izpildes reizē var būt ļoti mazs, taču kopsummā tas veido sekundes un minūtes. Tapēc pirms izvēlēties pareizo sinhronizācijas periodu ir jāapsver cik reāli bieži tas nepieciešams, lai lietotājs saprastu, ka process turpinās, kā arī lai tas nebūtu pārāk bieži, tādējādi lieki tērējot sistēmas laika resursus.

1.2.2. Datņu veidošana


Kā jau tika minēts iepriekšējā apakšnodaļā, pirmais programmas kods, ko uzraksta izstrādātāji arī šajā gadījumā ir formas programmvienībās tiek izveidoti kursori (cursor), kas atlasa nepieciešamos datus un pēc tam, izmantojot pakotnes TEXT_IO palīdzību tie tiek pārrakstīti datnēs. Tāpat šajās programmvienībās tiek izpildītas nepieciešamās datu manipulācijas operācijas (INSERT un UPDATE). Šāda uzdevuma realizācija ir ļoti viegli un ātri uzrakstāma un pie ļoti maziem datu apjomiem ātrdarbība vienmēr apmierina klienta prasības. Taču strauji palielinoties datu apjomiem, kā arī gadījumos, ja tiek izmantoti saliktie datu pieprasījumi no vairākām datu tabulām (join izmantošana) vai lieli maskas nosacījumi (where…), šādu kursoru atvēršanas laiks strauji palielinās. Pamatā sistēmas “bremzēšana” notiek, veicot atlasīto datu, t.i. kursora rezultātu, pārsūtīšanu no servera uz formām, izmantojot Oracle SQL*Net protokolu. Gadījumos, kad klienta darba vietas dators ir mazjaudīgs, kā arī pie lielām datortīkla noslodzēm šīs operācijas izpildes laiks samazinās vēl straujāk.
Tāpat kā iepriekš, veicot datņu ielasīšanu, vispirms tiek veikta analīze - cik liels ir laika patēriņš uz katru mums nepieciešamo operāciju. Tādējādi tiek noskaidrots, ko iespējams uzlabot, lai datņu veidošanas operācijas būtu ātrākas. Mūs interesējošie faktori ir:
1)      Datu atlasīšana (datu atlasīšanas operācijas – SELECT …);
2)      Nepieciešamās informācijas labošana datu bāzē (INSERT… & UPDATE….);
3)      Datņu operācijas (atvēršana, ierakstīšana, aizvēršana);
4)      Pārpalikums (f-ju izsaukumi, darba gaitas parādīšana un informācijas sinhronizācija).
Vispirms tiek izveidota forma, kas veic mums nepieciešamo datu atlasīšanu, izvadrindas saformēšanu un ierakstīšanu failā. Rakstot šo darbu, šādiem mērķiem tika izmantota, autora vadībā izveidotās sistēmas VISA Clearing Interface forma, kas veic VISA CTF datņu veidošanu sistēmā  pirmais variants. Tajā datu atlasīšanas, datu kontroles un datņu veidošanas funkcijas tika realizētas formas programvienībās vai bibliotēkās (program units vai Program units from Libraries).
Zemāk, 1.4. attēlā ir aplūkojams veikto 5 mēģinājumu rezultāts. Katrā no tiem tika izveidotas 2-as VISA CTF datnes  – viena ar 3200 rindiņām, otra - 53 800 rindiņām.

Jau iepriekš jāmin, ka šajā darbā netiek apskatīta Oracle servera datu pieprasījumu (SELECT….) optimizācija, kam bez šaubām arī šajā gadījumā ir liela nozīme. Tā kā  mans mēģinājumu mērķis ir tieši Oracle Forms 4.5 koda optimizācija,  tika pieņemts, ka izmantoti datu pieprasījumi ir maksimāli optimizēti.
1.4. attēls. Datnes veidošana no formām.

Kā redzams 1.4. attēlā, datu atlasīšanai no datu bāzes (SELECT…) tiek patērēts laiks no 10m30s līdz 23m50s (aptuveni 30% no kopējā laika), kas, ļoti atkarīgs no klienta darba vietas datora noslodzes. Jo lielāka noslodze, jo vairāk laika tiek patērēts šai operācijas izpildei, kaut gan procentuāli patērētais laiks paliek tas pats – apmēram 30%. Tas pats attiecināms arī uz datu maiņas operācijām datu bāzē (INSERT… & UPDATE…), kurām tiek patērēts no 3m5s līdz 6m30s (aptuveni 9% no kopējā laika).
Kā jau tika minēts pie datnes ielasīšanas, arī šeit visas datu manipulācijas operācijas (SELECT, INSERT & UPDATE….) tik un tā tiek izpildītas uz servera. Tas nozīmē, ka lieki tiek patērēts laiks šo operāciju nodošanai serverim izpildei. Kā jau zināms no datnes ielasīšanas mēģinājumiem, labākus rezultātus iespējams iegūt izpildot šīs operācijas uz servera, konkrētāk - servera pakotnēs.
Virkņu operācijām patērēto laiku tāpat iespējams samazināt tās izpildot uz jaudīgāka datora, kas šīs operācijas spētu veikt ātrāk. Tātad tāpat kā datnes ielasīšanas gadījumā šīs operācijas tiks “pārnestas” uz servera pakotnēm, jo to izpildīšana tur dod vislabākos rezultātus. Šajā gadījumā, tas nozīmē, ka servera pakotnes funkcija atgriež nevis tikai atlasītos sistēmas datus no datu tabulām, bet gan jau saformētu virkni, kuru atliek tikai izvadīt datnē. Optimizējot datnes veidošanu, pirmais mērķis, tāpat kā veicot datnes ielasīšanu, ir visas operācijas, kas izpildās lēni un palielinoties klienta darba vietas datora noslodzei vēl lēnāk, izpildīt citur. Tas nozīmē uz klienta darba vietas datora Oracle formās tiek izpildītas tikai datnes operācijas un servera pakotņu funkciju vai procedūru izsaukšanu un rezultātu parādīšana lietotājam.
Atceroties secinājumu, kas tika iegūts pie datnes ielasīšanas, arī šajā gadījumā uzdevuma optimizācija ir - operācijas kas tik un tā tiek izpildītas datu bāzes serverī, ir obligāti jāizpilda datu bāzes servera pakotnēs, jo tādējādi to izpildi nekavē, teiksim, klienta darba vietas noslodze.
Nākošajos mēģinājumos tika izmantota, jau agrāk minētās formas VISA CTF datnes veidošanai nākamais variants, kurā forma tikai saņem rindu no servera pakotnes funkcijas un ievada to datnē. Šādas funkcionalitātes realizēšana salīdzinājumā ar datnes ielasīšanu ir daudz sarežģītāka, jo jākontrolē izveidoto kursoru stāvoklis (atvērts, aizvērts, vai vēl ir rakstu). Vispirms pakotnē ir jāatver visi nepieciešamie datu kursori, kuros tiks atlasīti dati. Pēc tam ciklā, kamēr vien eksistē dati kursoros, tie jāatgriež formai, kas tos savukārt ievada datnē. Realizācijas kods varētu izskatīties apmēram šāds:
IF NOT VISA_WRITE_CTF.Open_Cursors(errtxt) then
     Message(‘Error opening data cursors!’);
END IF;
While VISA_WRITE_CTF.Get_Data(line, errtxt) LOOP
     ………….
TEXT_IO.Put_Line(f, line) then
………..
END LOOP;
IF errtxt IS NOT NULL then
     Message(‘Error reading data -’||errtxt);
END IF;
IF NOT VISA_WRITE_CTF.Close_Cursors(errtxt) then
     Message(‘Error closing data cursors!’);
END IF;




1.5.attēls. Datnes veidošana no formām, ja datu atlasīšanas operācijas
tiek veiktas servera pakotnēs.

Pirmajā variantā /1.5. attēlā apzīmēti ar (F)/, Oracle formas programvienībās tiek veiktas visas operācijas, t.i. datu rakstīšana datnē, datu atlasīšana un citas datu labošanas operāciju izpilde, bet otrajā /attēlā apzīmēti ar (S)/, Oracle formas veic tikai rakstīšanu datnē un servera pakotnes funkcijas izsaukšanu. Attiecīgā servera pakotnes funkcija katrā izsaukumā atgriež pa vienai rindai, kas ierakstāma datnē.
Šie mēģinājumi tāpat kā visi iepriekšējie veikti pie dažādām gan klienta darba vietas, gan servera noslodzēm.
 Aplūkojot datnes veidošanu, kad visas programvienības atrodas formās un datnes veidošanu, izmantojot funkcijas servera pakotnē, redzama atšķirība izpildes ātrumā no 2 līdz pat 2,5 reizēm. Kuru operāciju uzlabojums veido šo atšķirību ?
Kā jau redzams 1.5. attēlā abos gadījumos datnes operācijām patērētais laiks prakstiski neatšķiras (ar minimālām izmaiņām, kuras raksturo klienta darba vietas noslodze attiecīgā mēģinājuma laikā). Tas ir loģiski, jo abos gadījumos tās tiek veiktas formās uz klienta darba stacijas. Abos gadījumos patērētais laiks datnes operācijām ir no 1m40s līdz 4m15s, kas ļoti līdzīgs laikam, kas tika patērēts ielasot datnes datus ar tādu pašu apjomu.
Tāpat kā pie datnes ielasīšanas arī šoreiz tiek aplūkots katras operācijas izpildes laiks, lai konstatētu, kuras operācijas “pārnešana” uz servera pakotnēm devusi vislielāko ieguldījumu datnes veidošanas optimizācijā. Datu atlasīšanas operācijai (INSERT…), to izpildot servera pakotnē, vidēji tiek patērēts no 1m59s līdz 2m32s (6,2% – 12% no kopējā laika), savukārt šīs pašas operācijas izpilde formas programvienībās (program units vai Program units from Libraries) tiek patērēts 10m27s – 23m50s (aptuveni 30% no kopējā laika). Acīmredzams, ka laika starpība šo operāciju izpildei formas programvienībās un servera pakotnēs ir 10x, pie kam abos gadījumos tiek izmantotas tās pašas datu atlasīšanas komandas. Tāpat izmantoti tiek tie paši datu tabulas indeksi un palīdzības teksti (hints) SQL teikumos. Ja palielinās klienta darba vietas noslodze, tad kopējais izpildes laiks arī palielinās. Savukārt, ja datu atlasīšana izpildās servera pakotnēs, tad izpildes laiks nepieaug tik krasi. Ja savukārt noslodze tiek palielināta uz servera, tad abos gadījumos, neatkarīgi no tā kur tiek izsaukta datu atlasīšanas komanda, tās izpildes laiks palielinās, jo tā tik un tā tiek izpildīta uz datu  bāzes servera.
Nākamais apskates objekts ir datu labošanas komandu (INSERT & UPDATE) salīdzinājums. Aplūkojot 1.5. atēlu redzams, ka datu izmaiņām no servera pakotnēm tiek patērēts no 35s līdz 40s (2% – 4% no kopējā laika), savukārt šo pašu operāciju izpildei formas programvienībās tiek patērēts no 3m5s līdz 7m6s (9% – 10% no kopējā laika). Laika starpība šo operāciju izpildei formas programvienībās un servera pakotnēs ir 6-13x, kas protams ļoti atkarīgs no veiktajām operācijām, dažos gadījumos tas varētu būt tikai 2-3x, citos varbūt pat 15x. Kā jau zināms no iepriekš gūtiem rezultātiem, veicot datnes ielasīšanu, šādu operāciju izpilde servera pakotnēs dod labākus rezultātus jebkurā gadījumā.
Tāpat kā veicot datnes ielasīšanu arī datnes veidošanas gadījumā, neskatoties uz iegūtajiem labākajiem rezultātiem datnes veidošanas ātrums tāpat šķiet ļoti lēns – vidēji 0.02-0.04 sekundes uz vienu datnes rindu atkarībā no datu servera un klienta darba vietas noslodzes (0.04-0.08, ja datu atlasīšana datnes veidošanai tika veikta tikai formas programvienībās). Atceroties iegūtos secinājumus, zinām, ka jāsamazina servera pakotnes funkciju izsaukumu skaits, lai samazinātu izpildes laiku. Tādējādi serverim tiek pieprasīts atgriezt uzreiz vairākas rindas, teiksim 10. Tas nozīmē, ka šo izsaukumu skaits tiek samazināts attiecīgi 10 reizes.
Tāpat atkal tika veikti 5 mēģinājumi pie dažādām klienta darba vietas un datu bāzes servera noslodzēm. 1.6. attēlā ir parādīts šo mēģinājumu rezultāts.






















1.6.attēls. Datnes veidošana no formām, ja servera pakotņu funkciju
izsaukums tiek samazināts 10 reizes.

Kā jau bija gaidāms, šāda realizācija, kad tiek izsauktas servera pakotnes funkcija, kas atgriež uzreiz 10 rindas ar datiem dod apmēram 2x reizes ātrāku realizāciju, kas panākts samazinot laiku, kas tiek patērēts procedūru izsaukumiem, jo datnes operācijām, datu labojumiem datu bāzē un datu formēšanai patērētais laiks prakstiski nav mainījies. Datu pārrakstīšanas datnē ātrums tagad vidēji 0.01-0.02 sekundes uz vienu datnes rindu. Iespējams, ka ja servera pakotnes funkcija atgrieztu uzreiz 20 vai pat 50 rindas uzreiz ātrdarbība palielinātos vēl mazliet, taču ne tik ļoti krasi. Bez tam jāatceras, ka uz servera papildus ir jārealizē programmas kods kas apkopo visas rindas izejas parametros, kā arī jāatgriež visi kļūdu un brīdinājumu ziņojumi, ja tādi bijuši.
Kā jau tika minēts pie datnes ielasīšanas, lai lietotājs varētu sekot datnes veidošanas procesam ir jāveic kaut kāda informācijas parādīšana lietotājam. Tāpat arī šajā gadījumā der atcerēties, ka informācijas sinhronizācija pēc katras rindas ir lieka un tikai patērē laiku. Optimālais variants ir, ja informācija tiek sinhronizēta vismaz 1 reizi sekundē. Ar to ir pietiekoši, lai lietotājs saprastu, ka process turpinās. Šajā gadījumā, kad vinai rindai tiek patērēts apmēram 0.01 sekunde – ir pilnīgi pietiekoši, ja informācija tiek sinhronizēta ik pēc 100 rindām.



1.2.3. Pakotnes DBMS_PIPE pielietojums


Strādājot kādu laiku pie vienas problēmas risināšanas, vai kā mūsu gadījumā, konkrēti, pie datnes ielasīšanas optimizācijas, ļoti bieži tiek sasniegti it kā ļoti labi rezultāti un teorētiski pierādīts, ka tas ir maksimālais, ko iespējams iegūt. Taču parasti jāatceras ka šis ir pats labākais rezultāts, izmantojot šo tehnoloģiju vai šo algoritmu vai šos līdzekļus. Arī šoreiz tā tas izrādījās tikai īsu laiku līdz autora rīcībā nonāca ideja, izmantot pavisam citus līdzekļus datu nosūtīšanai no servera līdz formām, jo kā jau tika minēts iepriekš, pašu datu atlasīšana, rakstīšana failā un citas operācijas kopumā aizņem tikai ne vairāk kā 50% no izmantotajiem laika resursiem. Atlikušie 50% “pazūd” kaut kur formas “iekšienē” un servera procedūru izsaukumos. Tātad jaunākā ideja, ja tā to drīkst dēvēt, ir citas Oracle servera pakotnes izmantošana, kas ļauj daudz straujāk atlasītos datus nosūtīt formām.
DBMS_PIPE – tā ir Oracle servera pakotne, kas ļauj nosūtīt ziņojumus starp divām sesijām. Tā ir līdzīga UNIX vidē pazīstamai komandai pipe. Izmantojot funkciju send_message var tikt nosūtīts ziņojums, bet izmantojot funkciju receive_message -saņemt. Savukārt, lietojot funkcijas pack_message un unpack_message, ziņojumi var tikt ievietoti vai izņemti attiecīgi no statiskā bufera. Pakotnes kanāli (pipe) var strādāt privātā modē, kas nozīmē, ka tikai sesijas, kas izveidotas ar vienu un to pašu lietotāja identifikatoru (user-id) var rakstīt un lasīt noteiktajā kanālā (pipe). Kanāli var tikt atvērti arī publiskai lietošanai, kas ļauj visiem sistēmas lietotājiem, kam ir tiesības uz servera pakotni DBMS_PIPE, to izmantot. Tas tiek norādīts veidojot šo pakotnes kanālu (pipe), kas tiek identificēts ar viennozīmīgu vārdu pipename. Pati labākā šo pakotņu kanālu īpašība ir ka tie strādā neatkarīgi no tranzakcijām, t.i. COMMIT un ROLLBACK operācijas neiespaido datus, kas atrodas pakotnes kanālos. Bez tam ar šiem kanāliem var strādāt asinhronā modē, tas ir rakstīšanas un lasīšanas kārtība pakotnes kanālā nav definēta. To var darīt kad vien ir dati, ko rakstīt. Tāpat vairāki lietotāji vienlaicīgi var rakstīt vienai un tai pašā kanālā un vienlaicīgi arī no tā nolasīt informāciju [11].
Risinājums konkrētajai datnes veidošanas (arī ielasīšanas) problēmai varētu būt, ka neatkarīgs servera process nepārtraukti pakotnes kanālā raksta atlasītos datus no kursoriem, bet savukārt no klienta darba stacijas Oracle formās cits neatkarīgs process veic šo datu savākšanu un ievadīšanu datnē. Tā kā šie abi procesi notiek neatkarīgi, t.i. servera pakotne negaida izsaukumu no formas, lai nolasītu nākamo rakstu no kursora (fetch next records), bet lasa tos nepārtraukti, kā arī klienta process negaida uz servera pakotnes funkciju, kamēr tā atgriezīs rakstu, bet gan nepārtraukti tos nolasa no pakotnes kanāla (pipe), failu izveidošana notiek daudz ātrāk, jo ne viens ne otrs process negaida uz otru.
Šīs pakotnes ātrdarbības testiem tika izmantota SIA Tieto Konts sistēmas Issuing autorizācijas datnes (Q file) veidošanas forma, kas lieto augstāk minēto DBMS_PIPE pakotni.









1.7.attēls. Datnes veidošana no formām, lietojot DBMS_PIPE pakotni.

Patiesībā esošais risinājums ir izveidots ar daļēju darbības sinhronizāciju, izmantojot divus kanālus. Servera process veido 32 kilobaitu lielu informācijas apjomu, kas 8 reizes pa 4 kilobaitiem (puse no kanāla maksimālā apjoma) tiek iesūtīts kanālā. Laikā kamēr tiek pārsūtīts pēdējais no 8 gabaliem un tas arī nolasīts, servera process jau veido nākamos 32 kilobaitus nosūtāmās informācijas. Šai daļējai sinhronizācijai starp formām un servera pakotni arī tiek izmantots otrais kanāls. Formas nosūta informāciju, ka jaunā pakete nolasīta, bet servera process nosūta informāciju, ka kanālā ir ievietots jauns datu sūtījums. Šis uzdevums pagaidām vēl nav realizēts tā lai abi procesi varētu strādāt pilnīgi neatkarīgi, t.i. servera pakotne tikai sūta izveidoto informāciju kanālā, bet formas tikai nolasa informāciju no tā. Tas izskaidrojams ar to, ka vēl līdz galam nav izpētītas visas DBMS_PIPE pakotnes funkcijas kā arī vēl nav skaidra pakotnes darbība, ja kanālā nepārtraukti tiks sūtīta informācija. Bez tam nav skaidrs vai šāda realizācija 100% nenoslogos servera procesorus, jo nepārtraukti tiks veikta datu rakstīšana kanālā. Pašlaik vēl nav izpētīts arī kā šādos gadījumos iespējams atšķirt rakstīšanas kļūdu no fakta, ka pakotnes kanāls reāli jau ir pārpildīts un tajā vairs nav iespējams rakstīt. Šis ir viens no uzdevumiem, ko autors vēlas izpētīt tuvākajā nākotnē.
Atgriežoties pie mēģinājumu rezultātiem, tāpat kā visos iepriekšējos gadījumos tika veikti 5 mēģinājumi, pie dažādām servera un klienta darba vietas noslodzēm. Izveidotā datne satur 221 000 ierakstu un aizņem aptuveni 33 megabaitus informācijas. Salīdzinājumā ar VISA CTF datnēm, kas tika veidotas iepriekšējos mēģinājumos, to apjoms bija apmēram 60 000 ierakstu, kas aizņēma aptuveni 13 megabaitus. Šīs datnes veidošana, kas ir 2-3 reizes lielāka, pat sliktākajā gadījumā tika patērēts tik pat daudz laika cik iepriekšējās datnes (VISA CTF) veidošanai labākajā gadījumā. Lieki piebilst, ka jaunais datnes veidošanas risinājums ir daudz efektīvāks un kā tā maksimums, jau varētu tuvoties tīkla darbības un servera ātrumam, kas nepieciešams datnes datu pārsūtīšanai pa tīklu un ierakstīšanai datnē. Vidēji patērētais laiks, veidojot šo datni, ir no 1.66 līdz 2.36 sekundēm uz 1000 datnes rindām jeb 0.0016-0.0024 sekundes uz vienu datnes rindu.
Kā jau tikai minēts šis risinājums datnes veidošanai ir pagaidām izstrādes procesā, tāpēc arī attēlā nav minēti konkrēti laiki, kas patērēti tādām operācijām kā datu atlasīšana, labošana un ierakstīšana datnē. Autors cer tuvākājā laikā sīkāk iepazīties ar DBMS_PIPE pakotnes darbību un ja iespējams pilnveidot šo uzdevumu līdz pilnīgi neatkarīgai procesu darbībai, ja tas iespējams, kas jau tika minēta kā daļēja nepilnība šim risinājumam.


1.3. Datu ievadformu optimizācija (pieslēgums datu bāzes serverim, izmantojot modemu)


Risinot Oracle Forms 4.5 koda optimizācijas problēmu, manuprāt, viens no veidiem kā reāli apzināties to formas koda daļu, kas rada vislielāko datortīkla noslodzi, iespējams, izpētot formu darbību vidē, kad Oracle Forms 4.5 kā klients ar serveri sazinās, izmantojot modemu. Tādos gadījumos iespējams viegli vērot tīkla noslodzes grafiku, vienkārši izpētot modema nosūtītos un saņemtos datus.
Ja strādājošās sistēmās arī pastāv šāds risinājums, tad tas parasti tiek pielietots situācijās centrs-filiāle, kad “centrā” jeb organizācijas centrālajā ofisā atrodas Oracle datu bāzes serveris, bet filālēs, kas var atrasties pat 100 un vairāk kilometru attālumā serveriem, pieslēdzas, izmantojot modemu, pa telekomunikāciju kanāliem. Šādos gadījumos pieslēguma ātrums atkarīgs no modemiem. Parasti tas ir vai nu 14 400, 19 200 vai 33 000  bit/s. Tas ir ļoti maz, ja salīdzina ar datortīkliem, kur ātrums parasti sasniedz 10 Mbit/s vai pat 100Mbit/s. Bez tam jāņem vērā arī fakts, ka daudzviet arī tepat Latvijā pat, ja ir ļoti ātri modemi, sliktās telekomunikāciju līnijas neļauj izveidot ātrus savienojumus. Brīžiem pieslēguma ātrums varbūt tikai 19 200 vai pat 14 400 bps. Ja izstrādātās formas nav testētas šādiem darba apstākļiem un tās, piemēram, veic lielus datu pieprasījumus, darbs šādā vidē var būt ļoti lēns un neefektīvs. Šajā nodaļā tiks apskatīti jau 1.1. nodaļā minētie formas objekti un to atribūti un kā tie iespaido formu ātrdarbību un kā to iespējams novērst.














Text Box: 10.10.1.200
Pentium 90MHz (2proc.)
64 Mb RAM
Win NT
Oracle Server 7.3.3
Text Box: 10.10.1.201
Pentium II 266Mhz
96 Mb RAM
Win NT
Oracle Forms 4.5






563                                      562
                               
ZYXEL 1496E        ZYXEL 1496E
19 200 bps                      19 200 bps
 
                                                         

1.8. attēls. Mēģinājumos izmantotais servera un klienta darba vietas savienojums.

Autora piezīme: Tālāk darba aprakstā uzrādītie datu plūsmas apjomi uzrādīti pirms modema programmatūras datu kompresijas, t.i., ja uzrādīts, ka nosūtīts 100 000 baitu, tas nozīme, ka reāli savienojuma fiziskā līmenī nosūtīts tikai 20 000 – 30 000 baitu. 70 – 80% ir vidējā kompresijas pakāpe, strādājot ar Oracle Forms 4.5. Strādājot datortīklā šāda datu kompresācija nenotiek, tādējādi skaidri var redzēt, cik liela ir datu plūsma datortīklā. Ļoti iespaidīgi skaitļi būs redzami nodaļas beigās, apskatot datnes ielasīšanu.
Šajā nodaļā tiks aplūkoti, autora uztverē, visbiežāk lietoto formas objektu un atribūtu, kā arī dažādu operāciju iespējamā darbības uzlabošana, pamatojot to ar piemēriem. Visos attēlos darbā attēlota datu plūsma – ienākošā un izejošā, ka arī kopējā. Strādājot šādās vidēs, kad savienojums tiek organizēts, izmantojot modemu, samazinot datu plūsmas apjomu, mēs attiecīgi paātrinam formas darbību, jo lietotājam nav jāgaida, kamēr dati tiks saņemti vai nosūtīti dati. Bez tam jāņem vērā, ka 100 Kb saņemšana uzreiz saņemot kā vienu lielu datu veselumu notiek ātrāk, nekā 10 reizes pa 10Kb, tādējādi veicot 9 liekus datu pieprasījumus. Šī ideja tiek izmantota, optimizējot datu pieprasījumus no datu bāzes servera.
Jāatceras, ka katra konkrētā atribūta vērtības maiņa dod ļoti maz. Reizēm tā ir samazināta datu plūsma, tādējādi palielinot atbildes ātrumu uz kādu pieprasījumu, reizēm vienkārši palielināts atbildes ātrums uz kādu darbību. Katrs šāds uzlabojums formu ātrdarbībā dod 2-4 sekundes ātrāku darbību uz katru veicamo operāciju. Taču visu šo darbību uzlabojums kopumā, dod daudz ietaupīta laika, kas parasti tiek reāli novērtēta no lietotāja puses.

1.3.1. Datu atlasīšana pēc maskas un piesaistīto tabulu raksti


Viens no racionālākajiem veidiem kā paātrināt darbu, ja pieslēgums pie datu bāzes servera izveidots izmantojot modemu, ir vienkārši samazināt datu plūsmu, kas tiek pārsūtīta pa modemu. Visvienkāršākais veids kā to samazināt, ir piedāvāt lietotājam ievadīt nepieciešamo datu masku, tādējādi izveidojot atlasāmo datu masku, kas nosaka kādi raksti tiks rādīti lietotājam. Lietotājam jau pirmajā pieprasījuma rezultātos būs viņam nepieciešamie dati. Tas neprasīs no lietotājiem aplūkot daudz rakstus, lai atrastu nepieciešamo. Maskas lietošana pazemina Oracle servera atbildi uz pieprasījumu, it sevišķi, ja maskas nosacījumos ir lauki, kas nav iekļauti nevienā no indeksiem, taču salīdzinājumā ar laiku, kas patērēts datu pārsūtīšanai ar modemu, to var pielīdzināt tuvu nullei. Izveidot maskas nosacījumu ir ļoti vienkārši, ir jāievēro tikai SQL pieprasījumu sintakse. Pēc tam šo maskas nosacījumu, izmantojot formas funkciju Set_Block_Property, uzstāda blokam un izpilda datu pieprasījumu. Tas izskatās apmēram šādi [4]:
     Set_Block_Property(‘Block_name’, DEFAULT_WHERE,
                                           mask);
     Go_Block(‘Block_name’);
     Execute_Query;

Ļoti daudzās datu ievades formās vienlaicīgi kopā ar galvenās tabulas rakstiem tiek rādīti arī tai pakārtoto tabulu raksti (Master-Detail tables), kas tiek parādīti automātiski. Tas nozīmē, lietotājam pārvietojoties pa galvenās tabulas rakstiem automātiski tiek rādīti pakārtotās vai pakārtoto tabulu raksti. Ja pieslēgums serverim ir organizēts, izmantojot modemu, tas nozīmē, ka katra pārvietošanās pa galvenās tabulas rakstiem veic jaunu datu pieprasījumu no datu bāzes un sagaida atbildi. Reāli katra šāda pārvietošanās lietotājam “maksā” kā minimums 1-2 sekundes. Strādājot datortīklā to prakstiski nejūt, jo tas notiek dažās sekundes daļās. Izvairīties no šādiem liekiem datu pieprasījumiem var komentējot galvenās formas trigerī ON-POPULATE-DETAILS Oracle forms automātiski ģenerēto izejas teksta rindu     Query_Master_Details(rel_id, block_name), kas parāda pakārtotās tabulas rakstus. Bez tam formā vēl izveido vienu spiedpogu, kuras nospiešanas gadījumā izpilda sekojošu tekstu:
Go_Block(‘Block_name’);
     Execute_Query;

Tas ir tas pats izejas teksts, kas tiek izpildīts jau augstāk minētajā rindā, kas tika komentēta. Tagad pakārtoto tabulu dati tiek rādīti tikai, kad tie nepieciešami lietotājam un arī pārvietošanās pa galvenās tabulas rakstiem izpildās krietni ātrāk.
Tā kā šādas datu ievadformas var tikt izmantotas, gan strādājot datortīklā, gan veicot datu ievadi attālināti, izmantojot modema pieslēgumu serverim, vislabāk šīs darbības, pakārtoto rakstu rādīšanai vai nerādīšanai, papildināt tā, lai tas strādātu atkarībā no kāda sistēmas parametra. Tādējādi gan vieni, gan otri lietotāji varētu maksimāli efektīvi strādāt.

1.3.2. Fetched Records atribūts formas blokiem


Iesākumā tiks aplūkota datu ievadforma, kurā jau paredzēta rādāmo datu atlasīšana pēc datu maskas, tādējādi samazinot no servera pieprasāmo datu apjomu. Taču kā jau tika minēts 1.1. nodaļā formas atribūts Records Fetched iespaido formas ātrdarbību, norādot cik rakstus forma saņems no datu bāzes servera uzreiz. Pēc noklusēšanas šī atribūta vērtība vienāda ar blokā rādāmo ierakstu skaitu, taču tā var būt arī lielāka. Records Fetched atribūts kā zināms nosaka, cik ierakstus forma atlasīs uzreiz vienā pieprasījumā. Jo vairāk ierakstu, jo vairāk datu tiks atlasīti. Taču ja esošie datu pieprasījumi bieži vien atgriež daudz ierakstu, ir izdevīgāk uzreiz atlasīt vairāk ierakstu, kas dod lietotājam iespēju viegli tos pārskatīt, jo pretējā gadījumā katru reizi, kad lietotājs gribēs redzēt nākamos ierakstus, kas vēl nav redzami formā, tiks atkal izpildīts datu pieprasījums nākamajiem ierakstiem un lietotājs gaidīs servera atbildi.



Nākamajā attēlā aplūkojami mēģinājumu rezultāti, aplūkojot sistēmas SIS Tieto Konts ISSUING karšu kontu meklēšanas formu. Pirmajā kolonnu grupā redzams datu apjoms, kas tiek nosūtīts un saņemts, ja formā pieprasa tikai 10 rakstus (tik cik vienlaicīgi var redzēt), bet otrajā, ja pieprasa 100 rakstus (10 reizes pa 10). Acīmredzami, ka pieprasot 10 ierakstus datu plūsma ir mazāka, taču jāņem vērā, ka gadījumā ja lietotājs sāks aplūkot nākamos ierakstus, tie tik un tā tiks pieprasīti no datu bāzes servera, kas nozīmēs izejošās datu plūsmas palielināšanos un lietotāja gaidīšanu uz atbildi (2 kolonna). Tas palielina arī kopējo datu plūsmu automātiski, jo ir jāpieprasa jauni dati. Lielākais datu apjoms, manuprāt, tiek nosūtīts pirmajā reizē, kad tiek atvērts un pārbaudīts datu kursors, jo nākamie datu pieprasījumi kopā nedod 10-kārtīgu apjomu. Nākamās komandas satur noteikti tikai komandu - atlasīt nākamos desmit rakstus (fetchs next 10). Izejošo datu plūsma paliek nemainīga pieprasot arī uzreiz 100 rakstus un arī saņemto datu apjoms ir aptuveni tāds pats kā pieprasot 10x10 ierakstus (3 kolonna).

1.9. attēls. Datu apmaiņas apjomi, mainoties pieprasāmo rindu skaitam.

Lai izvairītos no liekiem datu pieprasījumiem ir reāli jāizprot lietotāja vajadzības un aptuvenais darba stils, lai noteiktu cik ierakstus parādīt uzreiz un cik ierakstus atlasīt uzreiz. Kā zināms parasti lietotājs meklējot kādus datus pārskata daudzus ierakstus, tas nozīmē ka vienā reizē vajadzētu atlasīt 2-4 vairāk ierakstu, nekā lietotājs redz uzreiz, tādējādi ietaupot lietotāja laiku un datu plūsmu, kas tiks nosūtīta un saņemta pa modemu. Atlasāmajiem ierakstiem nevajadzētu būt arī bezgalīgi daudz, jo tad lietotājs ilgi gaidīs kamēr dati tiks saņemti, bet izmantos viņš varbūt tikai pirmos ierakstus. Ļoti nozīmīgi datu meklēšanas formās lietotājam piedāvāt izvēlēties datu sakārtojumu kādā saņemt datus, jo tas var samazināt atlasāmo ierakstu skaitu – lietotājs ātrāk atrod viņam nepieciešamos datus. Tas protams samazina servera atbildes laiku, bet salīdzinājumā ar patērēto, saņemot liekus rakstus, ir pielīdzināms nullei.

1.3.3. Auto Refresh atribūts LOV objektiem





Kā jau tika minēts 1.1. apakšnodaļā liela nozīme izstrādājot formas ir kādus izvēlēties datu ievades objektus un kādas uzstādīt šo objektu atribūtu vērtības. Manuprāt galvenokārt šeit jāpiemin datu sarakstu (List of Values) un sarakstu (List Item) objekti. Kā zināms List item objektu vērtības tiek aktualizētas tikai startējot formu, bet vērtību saraksta (LOV) vērtības atkarībā no atribūta Auto Refresh vērtības var tikt aktualizētas katru reizi izsaucot šo objektu (formu noklusētā vērtība) vai tikai vienu reizi. Ja tā ir bieži lietojama datu ievades forma un nepieciešamie datu klasifikatori, kas tiek izmantoti datu ievadam, mainās tikai vienu reizi nedēļā vai vēl retāk nav ieteicams šo objektu atribūtu Auto Refresh uzstādīt kā True, bet gan False. Tas nozīmē vērtību saraksta vērtības tiek nolasītas tikai vienu reizi – startējot formas. Nākamajā 1.10. attēlā redzama, cik liela ir datu plūsma aktualizējot vērtību sarakstus, ja tie tiek izsaukti 10 reizes. t.i. tika veikta 10 ierakstu ievade datu ievades formā kurā ir 2 lauki ar piesaistītiem vērtību sarakstiem. Pirmajā kolonnā redzama datu plūsma, ja vērtību saraksta vērtības tiek aktualizētas katru reizi, otrajā, ja tikai pirmo. Šie vērtību saraksti atgriež valūtu un valstu kodu tabulu datus attiecīgi.
1.10. attēls. Datu plūsma formās ar vērtību sarakstu objektiem, atkarībā no to Auto Refresh  atribūta vērtības.

Kā jau redzams attēlā,  veicot šo 10 ierakstu ievadi, ja Auto Refresh atribūta vērtība ir True, datu plūsma ir vismaz 7 reizes lielāka. Jāatzīmē ka šājā gadījumā, tas nenozīmē tikai 7 reizes lēnāku darbību, jo lietotājam pēc katra datu pieprasījuma ir jāgaida arī servera atbilde. Pirmajā variantā katru reizi lietotājam jāgaida vismaz 2-3 sekundes, kamēr tiks atjaunoti dati, bet otrajā tie jāgaida tikai pirmajā reizē. Pārējos gadījumos vērtību saraksts tiek parādīts uzreiz. Tātad -  ja klasifikatoru dati mainās ļoti reti ir daudz izdevīgāk šī atribūta noklusēto vērtību nomainīt uz pretējo, tādējādi samazinot gan datu plūsmas apjomu, gan arī laiku, kas lietotājam jāpavada, gaidot klasifikatora datus, kas iespējams nemaz nav mainījušies.

1.3.4. Ne-tabulas lauku vērtību aktualizēšana


Kā jau zināms, viena no datu bāžu normālformām prasa, lai dati datu tabulās neatkārtojas. Tas parasti arī tiek ņemts vērā veidojot datu bāzes, ieviešot virkni klasifikatoru, taču, ja jāveic datu parādīšana lietotājam, tie parasti vēlas pilnu informāciju, nevis tikai klasifikatoru kodus. Tādiem nolūkiem visbiežāk formās datu tabulu blokos tiek izveidoti ne-tabulas objekti, kuros, izmantojot POST-QUERY trigeri, kas izpildās katrai no datu tabulas atlasītai rindai, tiek sameklēts attiecīgais ieraksts no tabulas, kas apraksta klasifikatoru (Sīkāk par to jau tika runāts 1.1.3. nodaļā). Kā jau tika minēts, rakstot klasifikatoru koda parādīšanu trigeros, tie izpildās katrai tabulas rindai. Tas nozīmē, ja no tabulas tiks parādīti 100 ieraksti, tad 100 reizes tiks izsaukts datu pieprasījums, kam jāatgriež viena rinda no klasifikatoru tabulas ar klasifikatora koda aprakstu. Strādājot datortīklā tas nav manāms, taču, ja darbs noris attālināti, izmantojot modema pieslēgumu, tad katrs šāds izsaukums kavē datu parādīšanu uz ekrāna. Kā jau tika minēts 1.1.3 nodaļā, ļoti effektīvi ir šādus datu pieprasījumus formās aizstāt ar List Item objektiem, kam dati nolasīti no datu tabulas tikai vienu reizi. Šo datu apjoms varbūt ir lielāks nekā n-tās reizes pieprasot pa vienai rindai, taču jāņem vērā arī laika faktors. Veicot n-tos datu pieprasījums tiek patērēts laiks pārsūtot datu pieprasījumu pa modemu un saņemot atpakaļ rezultātu. Nākamajā 1.11. attēlā ir parādīts, kāds ir datu plūsmas apjoms, kopš formas atvēršanas, ja formā daži datu lauku paskaidrojošie tekti tiek atlasīti no datu tabulas, parādot paskaidrojošo tekstu, kā arī, ja tie ir atlasīti tikai vienreiz un formas veic tikai attiecīgā raksta parādīšanu List Item objektā.




















1.11. attēls. Datu plūsma, ja klasifikatoru paskaidrojums tiek pieprasīts no datu tabulas vai tā parādīšanai tiek izmantots List Item objekts.

Attēlā redzama klientu meklēšanas formas datu plūsma apskatot 50 ierakstus. Pirmajā kolonnu grupā kā redzams datu plūsma ir vismaz 3 reizes lielāka, kas radusies izpildot datu pieprasījumu pēc klasifikatoru paskaidrojošiem tekstiem. (Formā ir 3 lauki – klasifikatori, kuriem tiek atlasītas paskaidrojošās vērtības). Tā izpildās katrai atlasītai rindai tādējādi papildus radot, gan izejošo, gan ienākošo datu plūsmu. Kā redzams attēlā otrās kolonnu grupas, kas attēlo datu plūsmu, ja izmantoti List Item objekti, kopējā datu plūsma pat ir mazāk nekā pirmās izejošo datu plūsma. Arī pati datu atlasīšana otrajā gadījumā ir vismaz reizes 3 ātrāka. Tātad, ja datu apskates forma arī tiek izmantota vidē, kad pieslēgumam serverim tiek izmantots modems, ļoti iesakāms šādus klasifikatoru paskaidrojošo tekstu laukus veidot nevis kā parastu teksta objektus, bet gan kā List Item objektus, kas ļaus lietotājam strādāt ar formu daudz ātrāk un efektīvāk.


1.3.5. Update Changed Columns atribūts formas blokiem


       Formās datu blokiem eksistē tāds atribūts kā Update Changed Columns, kas nozīmē, ka veicot datu kolonnu labošanu, komandas izpildīšanai tiek sūtīti tikai mainītie lauki. Ja blokā ir daži lauki ar lielu datu apjomu, tas nozīmē, ka tiks ietaupīts datu apjoms, kas tiek pārsūtīts. Taču jāatceras, ka šādā gadījumā formām katru reizi jāveido sava unikāla datu labošanas komanda, kura pirms izpildes jaanalizē (reparse). Ja datu tabulas lauki nav gari un netiek izmantoti long tipa mainīgie, kā arī modemu savienojuma ātrums ir pietiekoši ātrs, ieteicams šo parametru uzstādīt kā False, kas nozīmē sūtīt visu kolonnu datus. Savukārt, ja datu lauki ir lieli un modema sakari lēni, šādas datu labojumu komandas tiks ātrāk pārsūtītas, sūtot tikai mainīto kolonnu datus, jo laiks kas tiek patērēts komandas analizēšanai ir krietni mazāks. Nākamajā 1.12. attēlā



tiek parādīts kā izmainās datu plūsma, mainot šī atribūta vērtību.

1.12. attēls. Datu plūsma formā, kad UPDATE komandā ir visi lauki un kad tikai mainītie lauki.

Kā redzams attēlā otrajā gadījumā, kad tiek laboti tikai mainītie datu lauki, izejošā datu plūsma ir prakstiski uz pusi mazāka. Un tas viss tikai labojot 10 ierakstus. Šī starpība būtu vēl lielāka, ja datu tabulā būtu kādi liela izmēra lauki, piemēram long tipa mainīgie. Ja jārunā par operācijas izpildes ātrumu, tad vismaz šajā vidē, kad pielēgumam pie datu bāzes servera, tiek izmantots modems, šī datu labošanas operācija izpildījās otrajā gadījumā ātrāk nekā pirmajā. Tas varētu būt izskaidrojams ar to ka pirmajā gadījuma līdz serverim jāpārsūta lielāks datu apjoms. Savukārt otrajā datu plūsma ir mazāka, bet laiks kas nepieciešams komandas pāranalizēšanai ir vēl mazāks nekā, kas nepieciešams, lai pārsūtītu vēl tik pat datu. Protams, strādājot ātros datortīklos šī atribūta vērtību maiņa var nedot kādu ievērojami rezultātu.

1.3.6. Datnes ielasīšana


Beigās vēl gribētos aplūkot datnes ielasīšanu, izmantojot modema pieslēgumu serverim. Iepriekšējā 1.2. nodaļā jau tika apskatīta datnes ielasīšanas optimizācija. Reālā sistēmas ekspluatācijā tāpat var gadīties, ka lietotājam nepieciešams ielasīt datu bāzes serverī datus no datnes ar zināmu struktūru, kas, piemēram, eksportēta no kādas citas sistēmas. Kā jau atklājām, iepriekšējās nodaļās, visefektīvāk datnes ielasīšanu var veikt, ja visas nepieciešamās darbības, kas nepieciešamas datnes datu ierakstīšanai, tiek veiktas uz Oracle datu bāzes servera un formas nodarbojas  tikai ar datnes nolasīšanu un servera pakotņu funkciju izsaukumiem. Tika arī pierādīts, ka datu manipulāciju operācijas lēnāk izpildās tās veicot formas programmvienībās. Uz neliela piemēra bāzes atkal tiks aplūkota datnes ielasīšana no formām, ja visas darbības notiek formās un ja daļa no tām servera pakotnēs. Mēģinājumam atkal tiek izmantota tā pati VISA CTF datņu ielasīšanas forma, kas tika izmantota iepriekš. Šoreiz tiek ielasīta tikai viena datne ar 3300 rindām. (Jo lielāks datnes apjoms, jo reālāku priekštatu iepējams iegūt par mēģinājuma rezultātu). Strādājot datortīklā šīs datnes ielasīšana uz šī testa datu bāzes servera prasīja aptuveni 5m30s laika (Vidēji 0.1 sekunde uz datnes rakstu, kas ir aptuveni 2x lēnāk nekā mēģinājumos, kas tika veikti iepriekš. Tas izskaidrojams ar lēna datu bāzes servera izmantošanu tieši šiem nolūkiem). Nākamājā 1.13. attēlā redzama šīs pašas datnes ielasīšana, ja pieslēgums datu bāzes serverim ir veidots, izmantojot iepriekšminēto modema pieslēgumu. Pa labi redzama datnes ielasīšana, ja visas darbības tiek veiktas formās, vidū – ja forma veic tikai datnes operācijas un pa kreisi – ja viena izsaukuma laikā servera pakotnei tiek nodotas uzreiz 10 datnes rindas. Patērētais laiks pirmajam variantam ir – 2h46m (!!!), otrajam 1h31m, bet trešajam – 30m. (Gan klienta darba vieta, gan datu bāzes serveris noslogots tikai ar šo uzdevumu) Protams, ka reālajā dzīvē neviens neatļausies tik maza apjoma failu ielasīt, izmantojot šādu attālinātu pieslēgumu, taču šis mēģinājums parāda cik reāli ātri tiek veiktas šādas operācijas modema pieslēguma gadījumā. Pirmajā variantā tas ir – aptuveni viens raksts 3 sekundēs, otrajā – viens raksts 1,7 sekundēs, bet trešajā – 0,6 sekundēs. Ņemot vērā iepriekš minēto par lēna datu bāzes servera izmantošanu, optimistiski varam cerēt, ka pie normāliem darba apstākļeim, tas varētu būt iespējams 2x ātrāk. Taču šie rezultāti nebija mēģinājuma mērķis. Mūs interesēja datu plūsmas apjoms šāda pieslēguma gadījumā. Lai cik tas arī neliktos savādi, šīs nelielās datnes (600 kb) ielasīšanai datu bāzē bija nepieciešams 7,22Mb liela ienākošā un 5,37Mb liela izejošo datu plūsma pirmajā variantā. Mazliet mazāk informācijas bija otrajā, bet vismazāk trešajā variantā, kad tiek izmantota 10 rindu nodošana servera pakotnes funkcijai.
Atliek tikai vienīgi minēt, kas tiek nosūtīts šajos datos, izmantojot SQL*Net protokolu. Vēl viens liels jautājums ir kāpēc ienākošā datu plūsma, skatoties no klienta darba vietas puses, ir lielāka nekā izejošā. Jautājums rodas tāpēc, ka izsaucot pakotnes funkciju tai tiek nodota datu virkne, bet atpakaļ saņemts tikai operācijas rezultāts – patiess vai nepatiess. Kas vēl bez šīs informācijas tiek pārsūtīts noteikti atbildēt var tikai Oracle Forms 4.5 izstrādātāji, bet to uzzināt pagaidām nav bijis iespējams.



















1.13. attēls. Datnes ielasīšana (pieslēgums datu bāzes serverim, izmantojot modemu).

Tātad kā varam nojaust viens no “bremzējošiem” faktoriem ir tieši lielā datu plūsma no klienta darba vietas uz serveri un atpakaļ. Kas tiek pārsūtīts, izmantojot SQL*Net protokolu mēs nezinām, taču cik var noprast no mēģinājumu rezultātiem, pārāk optimizēta, vismaz šādā veida darbībām, formas nav. Redzot attēlā parādītos rezultātus varam skaidri pateikt, ka strādājot arī datortīklā šī lielā datu plūsma ir viens no lielākajiem “bremzējošiem” faktoriem.











2. Lietotāja-datora interfeisa uzlabošana

2.1. Grafiskā lietotāja-datora interfeisa pamatprincipi


Labu grafisko lietotāja-datora interfeisu raksturo faktors, cik viegli lietotājs to apgūst un cik viegli to ir lietot. Runājot par lietošanu, vienmēr būs domstarpības, jo katrs cilvēks ir individualitāte un katram patīk kaut kas cits, kas nepatīk citiem. Labu lietotāja-datora interfeisu definē 3 pamatprincipi [10]:

1)  Vienkāršība (Simplicity) - jo vienkāršāks ir sistēmas interfeiss, jo vieglāk lietotājs var iemācītes lietot sistēmu;

2)  konsekvence, saskaņa (Consistency) - konsekvence raksturo sistēmas izmaiņas, cik viegli lietotājs varēs apgūt sistēmas jaunās komponentes. Lietotājs parasti vēlas, lai sistēmas jaunā komponente darbotos tāpat kā vecā, lai pārāk daudz laika nebūtu japavada apgūstot jaunās sistēmas interfeisa īpatnības;

3)  efektivitāte (Efficiency) - jo mazāk soļu jāveic lietotājam, lai izpildītu kādu operāciju, jo lielāka ir sistēmas efektivitāte šo operāciju izpildei. Lai izveidotu efektīvu lietotāja-datora interfeisu izstrādātājam ir jāzin, kuras ir visbiežāk lietotās operācijas un kā tās tiks kombinētas.

Lietotāja-datora interfeiss neraksturo cik krāšņs un elementu bagāts būs datu ievades logs, bet gan izstrādātāja profesionālismu un radošo potenciālu. Pirmo divu pamatprincipu izveide prasa izstrādes grupai izveidot interfeisa standartus. Bez šādiem standartiem sistēmu interfeisa izstrāde būs haotiska (katra izstrādātāja stilam atbilstoša) un lietotājam grūti apgūstama. Trešā pamatprincipa izveide ir pati grūtākā. Tas ir atkarīgs no sistēmas biznesa modeļa. Tas jāveido sadarbībā ar lietotāju, jo sistēma tiek veidota, lai viņam palīdzētu.
Sīkāk par lietotāja-datora interfeisa uzlabošanu pēc šiem pamatprincipiem aprakstīts nākošajās trīs nodaļās.

2.2. Šablonformu izmantošana formu ģenerācijai


Kā jau tika minēts, lai nodrošinātu vienota lietotāja-datora interfeisa izveidi, atbilstoši izstrādājamā projekta vajadzībām, lietojot Oracle formu ģeneratoru (Oracle Forms Generator), tiek lietotas šablonformas (templates), kurās tiek aprakstīti visi kontroles bloki, rīku joslas, vizuālie objekti, to īpašības. Lai varētu izveidot šādu šablonformu ir jāsaprot, kā savā starpā saistās objekti šablonformā ar objektiem izstrādājamajā formā.
Designer/2000 lieto šablonformas, kurās ir visa nepieciešamā informācija ģenerētai formai - vizuālie atribūti, rīku josla, kontroles bloki un vienības,  kas tiks ievietotas jebkurā ģenerētajā formā. Taču, ievietojot šablonformās daudz izpildāmo bloku, rodas problēmas, jo šie programmu kodi tiek ierakstīti visās sistēmas ģenerētajās formās. Ja kādas izmaiņas tiek izdarītas šablonformās, tad jāveic viens no sekojošiem uzdevumiem:
1)  Jāpārģenerē visas iepriekš ģenerētās formas;
2)  izmaiņas jāveic ar roku katrā noģenerētajā formā.
Lai izvairītos no šadām problēmām, tiek ieteikts pēc iespējas vairāk lietot atsauksmju formas (Reference form) un bibliotēkas (Libraries) šablonformu izstrādē [9]. Ja šablonformās vizuālie atribūti un datu vienības tiek veidotas kā atsauksmes uz citā formā aprakstītiem objektiem, un PL/SQL procedūras, paketes un funkcijas tiek saistītas ar bibliotēkām(tiek apkopotas bibliotēkās), tad ģenerētā forma pārmantos šīs atsauksmes un saistības.  Tas atvieglos sistēmas izstrādi, kad vajadzēs labot vai papildināt šablonformu kodu, jo nebūs jāpārģenerē visas iepriekš veidotās formas.

 























2.1. attēls. Šablonformu, bibliotēku, atsauksmju formu un noģenerēto formu saistība.

Piemēram, ja visa rīku josla (kanva (canvas), kontroles bloks un vienības) ir veidota kā atsauksme uz atsauksmju formu, tad papildus pogas var tikt pieliktas rīku joslai arī vēlāk, pēc formu ģenerācijas, nepārģenerējot šīs formas no jauna. Šīs papildus pogas tikai jāpievieno atsauksmu formai un jāpārraksta PL/SQL kods bibliotēkā, lai jaunā poga strādātu. Tālāk pārkompilējot visas ģenerētās formas, jaunā poga tiek iekļauta ģenerētajā formā.
Atsauksmju formā būtu jāiekļauj sekojoši objekti:
1)  Visu lietoto kanvu informācija;
2)  visi vizuālie atribūti;
3)  visi kontroles bloki;
4)  rīku joslas kanva un bloks (ieskaitot visas pogas, uz kurām atsauksme tiek veidota automātiski).
       Sakarā ar to, ka uz formas līmeņa trigeriem nevar veidot atsauksmes tieši (jo Designer/2000 formu ģenerators pats pārraksta trigerus), visi PL/SQL kodi būtu jāievieto bibliotēkā, kas saistīta ar šablonformu [4]. Tāpēc formas līmeņa trigeriem vajadzētu izsaukt procedūras no bibliotēkas. Bez tam gadījumā, ja jāmaina kāda formas līmeņa trigera kods, to nākas izdarīt tikai vienā vietā - bibliotēkā, kurā aprakstīts trigera kods. Piemēram, ja šablonformā ir WHEN-NEW-FORM-INSTANCE trigeris, tam vajadzētu izskatīties šādi:

   /* WHEN-NEW-FORM-INSTANCE */
   BEGIN
        WHEN_NEW_FORM_INSTANCE;
   END;

Kur WHEN_NEW_FORM_INSTANCE ir procedūra no bibliotēkas. Ja ģenerators pārrakstīs kāda trigera kodu, tad jauno funkciju izsaukums tiks ierakstīts aiz šī koda, nebojājot izstrādātāja rakstīto kodu.
Šeit jāpiemin, ka veidojot atsauksmi uz objektu no citas formas, šo divu formu koordinātu sistēmas nesakrīt Oracle Forms Designer 4.5 neveic automātisku koordi-nātu maiņu. Par to jārūpējas izstrādātājam pašam.
Lai visās formās panāktu vienādu lietotāja-datora interfeisu, visiem tās objektiem jābūt vienādiem, t.i. vienādiem vizuāliem atribūtiem (fonts, fonta izmērs, krāsas, garums, platums u.t.t). Visvieglāk to var panākt veidojot vizuālos atribūtus (Visual attributes) un īpašību klases (Property classes) atsauksmju formā. Vizuālie atribūti ir fonts un tā īpašības (fonta vārds, izmērs, stils, platums, garums), kā arī objekta krāsas (priekšplāns, fons, aizkrāsošanas modelis). Piesaistot visiem vienāda tipa objektiem konkrētu vizuālo atribūtu, ir atvieglota šī tipa objektu vizuālās informācijas maiņa. Tā jādara tikai vienā vietā - tur kur tiek definēts vizuālais atribūts.
Katram objektam formās tiek piesaistīts vai nu noklusētais vizuālais atribūts (default), kas ir atkarīgs no attiecīgās platformas, kurā tiek ekspluatēta forma, vai arī definētais vizuālais atribūts (named). Ja objekta vizuālās īpašības tiek mainītas ar roku, tas iegūst lietotāja vizuālā atribūta (custom) statusu, kas nozīmē, ka lai izmainītu šāda objekta vizuālos atribūtus, tie jāmaina, katram konkrētam objektam, jo tie nav saistīti savā starpā ar kādu no definētiem atribūtiem.
Vizuālā atribūta vārds nosaka objektu, kuram tas tiks pievienots ģenerācijas procesa laikā. Piemēram, ikvienam teksta objektam tiek piešķirts CG$ITEM vizuālā atribūta vārds, ja šis atribūts ir definēts šablonformā. Eksistē liels skaits šādu speciālo vizuālo atribūtu vārdu, kurus aprakstot var viegli veidot ģenerētās formas izskatu. Piemēram, CG$PUSH_BUTTON vizuālais atribūts nosaka jebkuras ģenerētās spiedpogas izskatu, CG$MANDATORY_ITEM - obligātā ievadlauka vizuālos atribūtus utt. Visus šos vizuālo atribūtu vārdus var atrast Oracle palīdzības failā C:\ORAWIN95\DES2_60\HLP\CGEN45.hlp.
Savukārt īpašību klases ir spēcīgs līdzeklis, kas atļauj veidot vienotu lietotāja-datora interfeisu un funkcionalitātes standartus. Īpašību klase ir objekts, kas satur īpašību kopu, kas var tikt veidota pēc izstrādātāja vēlmes, un to vērtībām. Piemēram, var veidot  atsevišķas īpašību klases ievadāmiem neobligātiem ievadlaukiem, ievadāmiem obligātiem ievadlaukiem un informācijas laukiem, spiedpogām, izvēles sarakstiem (LOV) utt.


2.2. attēls. Īpašību klašu un vizuālo atribūtu definēšana šablonformā.

Šādu īpašības klašu skaits nav ierobežots un vienas klases īpašības var tikt piešķirtas dažādu tipu objektiem. Tas, pamatojoties uz iepriekš minēto, dod iespēju mainīt šo objektu definīcijas tikai vienā vietā, tādējādi mainot to visā izstrādājamajā lietojumprogrammā veicot tikai vienu operāciju - formu pārkompilāciju. Visi vizuālie atribūti un īpašību klases, kas aprakstīti šablonformā, tiek iekļauti ģenerētajā formā, neatkarīgi no tā vai eksistē objekts, kas izmanto šo atribūtu vai īpašību klasi, vai nē. Tas dod iespēju jebkurā izstrādes procesa laikā veidot jaunus interfeisa objektus, tos aprakstot ar esošiem vizuāliem atribūtiem vai īpašību klasēm.
Ja darba laikā tiek izveidots jauns vizuālais objekts vai īpašību klase, tā jāpiesaista šablonformai, lai tā tiktu ieģenerēta visās jaunajās formās. Lai šie jaunie atribūti būtu arī jau ģenerētajās formās ir jāveido atsauce uz tiem no katras formas atsevišķi. Taču arī to var automatizēt, veidojot objektu grupas (Object groups), kurās pievieno jaunos vizuālos atribūtus. Tālāk veido atsauces jau uz objektu grupām.
Lai vieglāk būtu apkopot objektus, uz kuriem tiks veidotas atsauksmes, Oracle formās pastāv jēdziens objektu grupas (Object groups). Tas dod iespēju vienkopus apkopot vairāku tipu objektus (logus, blokus, kanvas, vizuālos attibūtus), kas paredzami kā atsauksmju objektu avots.


2.3. attēls. Objektu grupas.

Reāli, veidojot objektu grupas, jauni objekti netiek veidoti, tiek veidota tikai atsauce uz šiem objektiem formas ietvaros. Veidojot objektu grupas jāievēro :
1)  Ievietojot objektu grupā bloku, automātiski tiek ievietoti arī visi tā objekti (vienības, trigeri, relācijas), kaut arī tie objektu grupas kokā netiek rādīti;
2)  programmu vienības (procedūras, funkcijas) nevar tikt iekļautas objektu grupās;
3)  bloku objekti, vieni paši nevar tikt iekļauti objektu grupā, jo tie nevar pastāvēt neatkarīgi bez bloka;
4)  objektu grupas objektiem jābūt definētiem tajā pašā formā, tie nevar būt no citas formas;
5)  objektu grupa nevar saturēt objektu grupu;
6)  dzēšot objektu, tas automātiski tiek dzēsts no objektu grupas;
7)  dzēšot objektu grupu, no formas moduļa netiek dzēsti paši objekti.

       Tālāk aplūkosim kā apvienot programmu kodu, kas nepieciešams vairākās formās. Procedūras un funkcijas, kas tiek lietotas vairākkārt no dažādām formām ieteicams apvienot vienā vietā - bibliotēkās. Savukārt procedūras un funkcijas, kuru izsaukšana neprasa vizuālās informācijas parādīšanu, ietiecams izvietot datu bāzē (Stored procedures), tādējādi samazinot formas izmērus. Lai arī pārējās lietojumprogrammas (application) formās būtu pieejamas šīs procedūras atliek tikai piesaistīt attiecīgo bibliotēku.


2.4. attēls. Piesaistītās bibliotēkas.

       Lai visas vajadzīgās bibliotēkas automātiski tiktu piesaistītas jebkurai ģenerētai formai, šīs bibliotēkas tikai jāpiesaista konkrētai šablonformai, kas tiek izmantota ģenerācijas procesā. Jebkuras izmaiņas, kas tiek veiktas bibliotēkas procedurās vai funkcijās formās ir pieejamas uzreiz pēc to atvēršanas un pārkompilēšanas.
       Ja jāpievieno jauna bibliotēka, tā pirmkārt jāpievieno šablonformai, lai tā tiktu pievienota visām jaunajām formām. Formai drīkst pievienot neierobežotu skaitu bibliotēkas, pie kam tas nepalielina formas izmērus, jo bibliotēkas tiek glabātas atsevišķos *.pll failos, un netiek iekompilētas programmas kodā. Visām jau ģenerētajām formām bibliotēkas jāpiesaista ar roku, jo nav iespējams bibliotēku aprakstīt objektu grupās, kā tika minēts iepriekš. Bez tam pastāv iespēja piesaistīt bibliotēku bibliotēkai, ko varētu izmantot kā risinājumu. Piemēram, kādai no galvenajām bibliotēkām, kas ir visās formās piesaistam klāt jauno bibliotēku, kas pēc formu pārkompilēšanas būs visās formās.
Vislielākās problēmas veidojot šablonformas tomēr ir un paliek dokumentācijas trūkums. Oracle nenodrošina ar labu dokumentāciju (principā tās nav vispār) šablonformu veidošanai, ja neskaita dažus piemērus, kas doti Oracle palīdzībā (Help).

2.3. Preferences kā ģeneratora parametri


Ne visu var aprakstīt šablonformās. Izrādās, ka objektu, kas nav iekļauti kontrolblokos, un citu īpašības un reakcija uz lietotāja darbību, kā arī visi pārējie ģeneratora parametri, tiek aprakstītas ar preferencēm (preference), izmantojot preferenču pārlūkprogramu (preference navigator). Parasti tie ir datu bloki, kas tiek iekļauti formās no moduļa datu diagrammas, logi, ritjosla (scrollbar) un citi objekti.
Preferences ir parametri, kas kontrolē ģenerētās formas izskatu un uzvedību [1]. Preference var būt vai nu obligāta vai neobligāta. Obligātai preferencei vienmēr jābūt uzdotai vērtībai. Katrai preferencei eksistē noklusētā vērtība, kas tiek izmantota gadījumos, ja dotās preferences vērtība nav definēta.
Preferenču pārlūkprogramma ir grafisks rīks, kas atļauj mainīt preferenču vērtības, kuras izmanto ģeneratori ģenerācijas procesā, kas nosaka ģenerētās formas izskatu un uzvedību. Preferences var tikt piesaistītas pie konkrēta objekta (domeins, forma, modulis, lietojumprogrammas sistēma) sistēmā.


2.5. attēls. Preferenču vērtību ievadīšana lietojot preferenču pārlūkprogrammu.

Ģenerācijas procesa laikā ģenerātors pārbauda, kuras preferences, kas iespaido ģenerēto lietojumprogrammu (application), ja vispār kāda ir uzstādīta. Ja vajadzīgā preference nav uzstādīta, ģenerātors lieto noklusēto.
Katra preferences vērtība var būt mantota (iedzimta), vai uzstādīta tikai konkrētam lietojumprogrammas līmenim. Preferenču pārlūkprogramma nosaka šo preferences īpašību, to apzīmējot ar dažādām ikonām preferenču kokā, vai dažādām krāsām kopējā preferenču izvēlnē. Šī iespēja ļauj viegli kontrolēt, piemēram, konkrēta datu bloka vai moduļa uzvedību, vai tas būs tāds pats kā pārējos moduļos vai atsevišķs, konkrēts tikai šim modelim.
Kad tiek ģenerētas formas, attiecīgajam ģeneratoram ir jāzin, kuras preferenču vērtības ir uzstādītas. Ģenerācijas procesa laikā ģenerators pārlūko visu preferenču hierarhiju katrai preferencei, kas nepieciešama ģenerācijas procesā. Meklēšana notiek no zemākā lietojumprogrammas (application) līmeņa virzienā uz augstāko.
1. tabulā doti, pēc autora domām, svarīgāko preferenču (preference) apkopojums, kas nosaka ģenerētās formas izskatu un reakciju uz lietotāja darbību.

1. tabula. Svarīgākie formu ģeneratora parametri.
Kategorija
Parametra nosaukums
Apraksts
Iespējamās vērtības
END USER LEVEL
AUTOHP
Vai parādīt HINT lauka vērtību, kad lietotājs aktivizē ievadlauku
Y, N

DELWRN
Vai brīdināt lietotāju, ka dzēšot rakstu tiek dzēsti arī raksti no citām tabulām (formas ietvaros)
Y, N
LAYOUT-BLOCK
BLKSBP
Bloka scrolbara atrašanās vieta
LEFT, RIGHT

BLKVSB
Vai tiek ģenerēts bloka vertikālais scrolbars
Y, N
LAYOUT-TEXT ITEM
TXTBEV
Teksta vienību slīpums
None, Raised,
Lowered

TXTDDF
Teksta lauku noklusētais datuma formāta tips
Datuma formāts

TXTDHT
Teksta lauku noklusētais augstums
1-9

TXTDNF
Teksta lauku noklusētais  skaitļu formāts
Skaitļu formāts
LAYOUT
WIN???
Visi šie parametri nosaka logu noklusētās īpašības

LIST OF VALUES
LOVBUT
Vai laukam, kam iespējams LOV blakus rādīt LOV pogu
Y, N

LOVVAL
Vai pārbaudīt lauka vērtību LOV’ā
Y, N
TEMPLATE
STFFMB
Šablonformas vārds

GENERATE OPTIONS
VLDTFK
Kad pārbaudīt ārējās atslēgas korektumu
B, C, F, N

VLDTPK
Kad pābaudīt primārās atslēgas  korektumu
B, C. F, N

Vislielākās problēmas, aprakstot preferences, ir to apjoms, izmantotie saīsinājumi un ļoti mazais dokumentācijas apjoms. Lai saprastu katras preferences būtību no tās saīsinājuma, vai arī, lai atrastu kura preference apraksta konkrēto īpašību, vajadzīgs laiks. Visa palīdzības informācija pieejama tikai izmantojot Oracle palīdzību (Online Documentation) [2].

2.4. Padomi interfeisa uzlabošanai 


Oracle Developer/2000 ir attīstījies daudzu gadu laikā, no simbolu bāzētas vides uz grafisko vidi, tomēr vēl joprojām patērējams daudz laika, lai izveidotu Oracle lietojumprogrammu ar labu lietotāja-datora interfeisu.
Kā piemēru aplūkosim izvēlni. Oracle izvēlne pēc noklusēšanas satur: darbība (Action), bloks (Block), lauks (Field) u.t.t., bet MS Windows vidē noklusētā izvēlne ir fails (File), labot (Edit), skats (View). Veidojot lietojumprogrammas Oracle vidē, to galvenā priekšrocība ir tā, ka tās var izpildīt arī citās platformās, tādās kā Macintosh, Motif u.c. Šis varētu būt iemesls kāpēc aizkavējās labu lietotāja-datora applikāciju izstrāde speciāli  MS Windows videi, kurā strādā lielākā daļa datoru.
Lasot vairākus literatūras izdevumus un informācijas lappuses Internetā tika apkopoti un izanalizēti vajadzīgākie un labākie 12 padomi, kā labāk veidot profesionālākas, vieglāk lietojamas un intuitīvi saprotamas Oracle lietojumprogrammas MS Windows videi, tādā veido laužot Oracle standarta lietojumprogrammu iezīmi [7], [9]. Kā rāda pieredze, lietotājiem, kas strādā MS Windows vidē ir ļoti grūti pārslēgties uz Oracle piedāvāto stilu un terminoloģiju.

2.4.1. Rīku josla


Šodien jebkura grafikās vides lietojumprogramma liekas nepilnīga, ja tajā nav rīku joslas. Parasti uz rīku joslas krāsainu spiedpogu veidā tiek attēloti visbiežāk lietoto funkciju izsaukumi. Bieži lietojamās funkcijas tiek attēlotas grafiski vieglākai informācijas uztverei un izpildei.



Visbiežāk lietojamās funkcijas Oracle formās, kuras vajadzētu ievietot rīku joslā ir - saglabāt (Commit or Save), nākošais ieraksts (Next record), iepriekšējais ieraksts (Previous record), attīrīt formu (Clear form), attīrīt rakstu (Clear record), beigt (Exit), meklēt (Enter Query), atlasīt rakstus (Execute Query) un citas atkarībā no uzdevuma.


2.6. attēls. Rīku josla.

 Funkcijas, kuras var apvienot grupās arī rīku joslā vajadzētu attēlot grupās, tādējādi atdalot funkcijas pēc to nozīmes. Piemēram, vienā grupā likt funkcijas nākošais ieraksts (Next record), iepriekšējais ieraksts (Previous record), un otrā izveidot ierakstu (Create record), dzēst ierakstu (Delete record), attīrīt ierakstu (Clear record). Vienas grupas spiedpogas ir jānovieto blakus viena otrai, bet grupas savstarpēji jāatdala ar 6-10 punktu tukšu joslu.
Bez tam daudz lietotāju vēlas rīku joslu atvērt atsevišķā logā, kuru var novietot jebkurā vietā pēc izvēles. Arī to iespējams izveidot, nedaudz mainot programmas kodu, tikai ar vienu piebildi, ka rīku josla būs vai nu atsevišķā logā, vai pamatlogā zem izvēlnes. Lietotājs to nevar pārnest no viena stāvokļa uz otru kā tas iespējams MS Word vidē.

2.4.2. Rīku padomi (Tooltips) - spiedpogu nozīmju aprakstīšana

      



       Rīku padomi (Tooltips) ir palīdzības teksts, kas apraksta spiedpogas nozīmi un parādās, kad pele kādu laiku nekustīgi tiek novietota virs spiedpogas. Kā zināms lielākā daļa MS Windows lietojumprogrammu satur šos rīku padomus. Tas palīdz saprast spiedpogas nozīmi, ja tās ideju nevar uztvert pēc grafiskās interpretācijas.

2.7. attēls. Oracle standarta rīka padoms.




       Oracle noklusētais rīka padoms tāpat kā visi citi interfeisa objekti, atšķiras no MS Windows standarta rīka padoma, skatīt 2.7. attēlu. Tam ir standarta izmērs, un tas vienmēr parādās blakus spiedpogai, tādējādi aizsedzot pārējās. Nedaudz pielabojot esošo programmkodu, vai arī izmantojot no Oracle corp. saņemto hint.dll failu, rīku padomu var pārveidot par MS Windows standartam līdzīgu kā parādīts 2.8. attēlā, kas neaizsedz citas spiedpogas un kuras izmērs ir atkarīgs no teksta garuma.

2.8. attēls. Rīka padoms, kas līdzīgs MS Windows standartam.

 

2.4.3. Standartizvēlnes


       Izvēlne ir viena no galvenajām komponentēm lietojumprogramas interfeisā [5]. Diemžēl noklusētā Oracle Forms 4.5 izvēlne krasi atšķiras no pieņemtās MS Windows standarta izvēlnes. Tajā ietverti tādi termini kā darbība (Action), labot (Edit), bloks (Block), lauks (Field), ieraksts (Record), pieprasījums (Query). Tie ir datu bāzu vadības sistēmu pamatjēdzieni, taču to lietošana izvēlnēs samulsina lietotājus, jo tie ir pieraduši pie izvēlņu standartjēdzieniem - fails (File), labot (Edit) u.t.t. Bez tam diez vai lietotāju interesē programmas skaņošanas režīms (Debug).




2.9. attēls. Oracle standarta izvēlne.

Lai nerastos problēmas ar to lietošanu, vairāki autori neiesaka to lietot. Tā vietā izstrādātājam pašam vajadzētu izveidot izvēlni, kas līdzinātos standarta MS Windows izvēlnei. Tad arī lietotājiem neradīsies  problēmas atrast to ko viņi meklē, jo tie intuitīvi zinās, zem kuras izvēlnes punkta atrodas viņu meklējamā funkcija.
       Vispirms izvēlnei ir jādod iespēja piekļūt visiem sistēmas moduļiem. Var pastāvēt arī citi veidi un ceļi kā izsaukt kādu citu modeli, taču izvēlnei jābūt vispilnīgākajai. Izstrādājot izvēlni kā piemēru var aplūkot jebkuru MS Windows produkta izvēlni. Pirmajiem diviem izvēlnes punktiem no kreisās puses jābūt fails (File) un labot (Edit). Pēdējiem diviem jābūt logi (Windows), kam seko palīdzība (Help). Palīdzības izvēlnes parasti satur šādas standarta iespējas kā palīdzības izsaukšana, informāciju par lietojumprogrammu un citas, skatīt 2.10. attēlu. Tas protams labi noder, kad runa iet par konkrētu datu ievades formu. Bet kā veidot izvēlnes galvenajai formai, kas izsauc citus moduļus, no kuriem tālāk tiek izsauktas datu ievades un redigēšanas formas? Tā laikam ir katra izstrādātāja un pasūtītāja gaumes un norunas lieta.


2.10. attēls. Sistēmas izvēlne, kas līdzīga MS Windows izvēlnei.

       Izvēlnes var tikt veidotas, kā nemainīgas visas lietojumprogrammas darbības gaitā, kā arī tādas, kas mainās atkarībā no konteksta. Iecienītākā pieeja šajā gadījumā ir lietot standarta nemainīgas izvēlnes, ar papildus iespēju aizliegt izvēlnes punktus, kad tie nav vajadzīgi, atkarībā no konteksta. Tādējādi lietotājs vienmēr zinās izvēlnes izkārtojumu, neatkarīgi no konteksta, kas otrajā gadījumā būtu daudz grūtāk, ja izvēlne mainās atkarībā no konteksta.

2.4.4. Ievadlauku krāsu nozīme


       Strādājot ar datu bāžu vadības sistēmām, datu ievades formās ievadāmie raksti parasti satur obligātos laukus (not null, mandatory), laukus, kas var būt arī tukši (optional) un laukus, kas tiek izmantoti tikai informācijas rādīšanai (kur informāciju nedrīkst ievadīt vai mainīt).  Tas palīdz lietotājam vizuāli ātrāk atšķirt informatīvos laukus no laukiem, kuros dati ir jāievada. Daži autori iesaka katram no šiem trim tipiem lietot savu krāsu, taču kā rāda pieredze, pārāk krāsainas datu formas biedē lietotājus, jo tie apjūk šajā krāsu gammā. Bet ir lietas, ko vajadzētu izšķirt vienmēr - laukus datu ievadei un laukus informācijas pasniegšanai. Tāpat kā standarta MS Windows lietojumprogrammās, arī Oracle formās būtu ieteicams informācijas laukus rādīt vienkārši kā tekstu vai kā pelēku ievadlauku, kurā nav iespējama informācijas maiņa.




2.11. attēls. Ievadlauku attēlošana, atkarībā no informācijas.

 Taču neatšķirot obligātos (mandatory) laukus no neobligātiem (optional), lietotājs bieži vien, saglabājot datus, saņem kļūdas paziņojumu, ka laukā obligāti jāievada informācija (“field must be entered !”) vai lauks nevar tikt mainīts (“field is protect to update against !”). Vai šos laukus veidot atšķirīgus vai nē pilnā mērā atkarīgs no izstrādātāja un lietotāja vienošanās.

2.4.5. Logu virsraksti


       Strādājot ar Oracle Forms 4.5, to izpildāmais modulis (Oracle Forms Runtime) kā logu virsrakstu vienmēr lieto tekstu “Developer/2000 Forms Runtime for Windows 95/NT - [module]“.


2.12.attēls. Oracle Forms Runtime noklusētais logu virsraksts.

Jebkura profesionāli izstrādāta lietojumprogramma vienmēr satur savu nosaukumu, kas papildināts ar tekošā moduļa nosaukumu. Pamatlogs, kurā tiek startēta lietojumprogramma, tiek saukts par FORMS_MDI_WINDOW. Šī loga parametri nevar tikt mainīti izstrādes laikā, tāpēc tie jāmaina programmātiski. Galvenās formas WHEN-NEW-FORM-INSTANCE trigerī ir jānomaina šī loga virsraksts lietojot komandu:

   Set_Window_Property(Forms_MDI_Window, Title, “Mana
applikācija”);




2.13. attēls. Lietotāja definēts logu virsraksts.

       Katrai formai sistēmā, tās galvenā moduļa logam ir jāievada tā virsraksts, aprakstot to loga “Title” īpašībā. Tādējādi visas lietojumprogrammas darbības laikā jūsu lietojumprogrammas virsraksts būs  - “Mana lietojumprogramma [modulis]”.
       Ja lietojumprogramma satur vairākus moduļus (formas), tad katra moduļa nosaukums jāpievieno cieši klāt visas lietojumprogrammas nosaukumam, izmantojot to pašu funkciju.
       Šad tad ir ļoti vajadzīgi loga virsrakstā ievietot informāciju par aktīvo rakstu, bloku, piemēram, tāpat kā MS Word attēlo tekošā dokumenta nosaukumu. To, tāpat kā iepriekš tika aprakstīts var mainīt tikai programmātiski lietojumprogrammas darbības laikā.
       Bez loga virsraksta maiņas vēl var mainīt katra loga ikonu, tādējādi arī grafiski raksturojot moduli, kuram pieder konkrētā forma. To var izdarīt jebkuram formas logam, gan formu dizainerī, gan programmātiski formas darbības laikā, izņemot pašu galveno logu - FORMS_MDI_WINDOW. Kāpēc Oracle nav devusi iespēju labot arī šo loga ikonu, nav saprotams, taču paliek cerība, ka tas būs realizēts nākošajā  Oracle Forms 5.0.

2.4.6. Resursu pārbaude pirms lietojumprogrammas palaišanas

      
       Developer/2000 vide savai darbībai prasa ļoti daudz resursu, it sevišķi, ja formā tiek lietots daudz spiedpogu, izvēles sarakstu, izvēles rūtiņas (check box) un citi [3]. Iztērējot visus sistēmas resursus, Windows 3.1 vidē tika izraisīta atmiņas kļūda (GPF - General Protection Fault or “insufficient memory to run this application”). Šāda tipa kļūdas ir raksturīgas arī Windows95/NT vidē. Ja tiek izstrādātas ļoti liela apjoma lietojumprogrammas, tad šāda tipa kļūdas var būt ļoti biežas, it sevišķi, ja lietotāja datoram ir maz resursu.
       Viens no veidiem kā izvairīties no šāda tipa kļūdām, ielasot kārtējo formu, ir resursu pārbaude pirms formas ielādes. Ja tas ir zem minimālās robežas, tad izdod brīdinājuma signālu. Viena no Oracle Forms 4.5 demostrācijām dod piemēru kā noteikt brīvos resursus  MS Windows 3.1 vidē. Lai to pašu veiktu  MS Windows95 vidē, var izmantot to pašu algoritmu, tikai jāpārraksta *.DLL fails, lai varētu nolasīt sistēmas un atmiņas resursus MS Windows95 vidē.
Experimentāli tika pārbaudīts, ka uz datora ar pastāvīgu virtuālās atmiņas apgabalu, gadījumā ja atmiņas resursi ir zem 10% no iespējamā (runa ir tikai par atmiņu - brīvās atmiņas attiecība pret visu atmiņas apjomu), Oracle Forms Runtime 4.5 nestartējas, paziņot par atmiņas trūkumu dažādu bibliotēku ielādei. Tādējādi var uzskatīt, ka kritiskā robeža formas ielādei ir šie 10%.
Kā kritiskā robeža jaunas formas ielādei eksperimentāli tika noteiks - 1% no atmiņas resursiem.
Programmas koda piemēru, lietojumprogrammas atvēršanai ar atmiņas resursu pārbaudi MS Windows95 videi, var aplūkot pielikumā, darba beigās.

2.4.7. Par - ātra informācija par jūsu lietojumprogrammu


Kā viens no MS Windows lietojumprogrammu interfeisa standartiem ir parādīt galveno informāciju par lietojumprogrammu atsevišķā logā (About box).
Šādā logā attēlo vajadzīgo un nepieciešamo informāciju par jūsu lietojumprogrammu. Piemēram, šādā logā var attēlot šādu informāciju par jūsu lietojumprogrammu kā: lietojumprogrammas nosaukums, tekošās versijas numurs, izlaišanas datums, kā arī lietotāja “login” vārds, tekošās formas nosaukums, Oracle datubāzes nosaukumu un pat sistēmas brīvo resursu apjoms. Tas var lieliski palīdzēt lietotājam aprakstīt sistēmas tekošo stāvokli, ziņojot par sistēmas kļūdām.



Kā arī, ja gribas izteikt atzinību projekta komandai, šeit ir īstā vieta kur ievietot viņu vārdus.
2.14. attēls. Par - ātra informācija par jūsu lietojumprogrammu.
Lai izveidotu šādu formu Developer/2000 vidē, atliek tikai izveidot parastu formu, kurā pirms datu parādīšanas no datubāzes vai teksta faila, tiek nolasīta informācija par sistēmas versiju, izstrādes datumu utt. Pārējo informāciju, kā lietotāju, sistēmas resursus un citus, var iegūt no sistēmas mainīgajiem, vai izmanojot ORA_FFI funkcijas kā tika minēts iepriekš.

2.4.8. Paroles maiņa

      
       Laiku pa laikam sistēmas drošības nolūkos lietotājam ir jāmaina sava parole un visdraudzīgākais veids kā to veikt ir veidot savu formu ar labu interfeisu, jo Oracle Forms 4.5 to nepiedāvā kā standarta iespēju. Visparastākais un vienīgais veids kā to lietotājs var veikt ir izpildīt dažas komandas SQL*Plus vidē. Bet, tā kā lielākā daļa lietotāju nav pazīstami ar SQL*Plus (un vispār nezin kādam nolūkam tas paredzēts), ir vajadzīga vienkāršāka iespēja.


2.15. attēls. Paroles maiņa.

       Lai nomainītu lietotāja paroli, ir jāizveido maza forma, kas pārprasa lietotāja veco paroli, lūdz ievadīt jauno paroli un pēc tam to nomaina. Lietotāja vārdu un tekošo paroli var uzzināt izmantojot Get_Application_Property funkciju [3]. Savukārt lai nomainītu lietotāja paroli ir jāizpilda sekojoša komanda:
   Forms_DDL(‘ALTER USER ‘|| :block.name ||’ IDENTIFIED
 BY ‘||  :block.new_password);

       Ja paroles maiņa bijusi veiksmīga, tad tikai atliek aizvērt esošo savienojumu (disconnect) ar Oracle datu bāzi un atkal atjaunot savienojumu (reconnect), izmantojot komandas:
   LOGOUT;
LOGON(:block.user, :block.new_password || ‘@’||
 ConnectString, TRUE);

2.4.9. Progresa rādītājs


Salīdzinoši ar citām DBVS sistēmām, tādām kā MS Fox Pro, MS Access un citām, Oracle strādā salīdzinoši lēnāk vairāku iemeslu dēļ. Pirmkārt jau grafiskā interfeisa vide, kas salīdzinoši ar teksta vidi ir lēnāka. Otrkārt, nodrošinot lielu datu drošumu, tiek zaudēts daudz laika, kaut vai veicot visparastākās ierakstīšanas vai labošanas operācijas datu bāzē. Taču lietotājs parasti vērojot ilgus procesus, kas tiek īsi aprakstīti ar frāzi “Mazliet uzgaidiet…” vai “Working…” ir ne pārāk apmierināts, jo nezin, cik ilgi vēl mazliet būs jāgaida. Tāpēc gadījumos, kad operācijas ar datiem varētu ievilkties ilgāk par 20-30 sekundēm, būtu ieteicams lietot progresa rādītāju, kas parāda cik ātri noris process un cik ilgi tas vēl iespējams turpināsies.


2.16. attēls. Progresa rādītājs.

Oracle Forms to nepiedāvā kā daļu no sava interfeisa, bet to viegli var izveidot kā *.dll failu kādā citā programēšanas vidē (C++, Delphi). Piemēru kā to veikt, var aplūkot pielikumā, darba beigās.


2.4.10. Lietojumprogrammu palaišana


       Viens no parastākajiem veidiem kā startēt Developer/2000 lietojumprogrammu ir izpildīt komandrindu, kas startē Oracle Runforms, kā parametru saņemot izpildāmās formas vārdu:
c:\orawin\bin\f45run.exe c:\mydir\myapp.fmx

       Taču tas izskatītos daudz labāk, ja lietojumprogramma tiktu startēta, piemēram šādi:
   c:\mydir\myapp.exe

       Tādējādi tiks atvieglota sistēmas palaišanas problēma un konfigurēšana. Lielākais vairums liela apjoma lietojumprogrammu, kas startējas zināmu laiku, izmanto pagaidu (Splash) ekrānus, kas tiek rādīti, kamēr ielādējas sistēma, parādot, ka notiek sistēmas ielāde. Tas ir labāk nekā skatīties kā deg diska aktivitātes lampiņa, un domāt vai notiek sistēmas ielāde, vai atmiņas pārnešana uz disku. Tam ir liela nozīme gadījumos, ja sistēma startējas ilgu laiku, kas ilgāks par 4-5 sekundēm, it sevišķi kā tas ir Developer/2000 gadījumā (Oracle Runform ielāde uz Pentium 133MHz datora ar 16Mb atmiņu aizņem 15-25s).  Pagaidu (Splash) ekrāns var tikt iekļauts .exe failā, kas arī startē lietojumprogrammu.  Programmas piemēru var aplūkot pielikumā, darba beigās.





2.17. attēls. Pagaidu ekrāns programmas startēšanas laikā.

       Tādu .exe moduli var izveidot, lietojot daudzus programmēšanas rīkus, kā C, Delphi, Visual Basic.  Startējot programmu no šīs vides, tiek parādīts grafisks attēls, un pēc tam tiek ielādēta Oracle lietojumprogramma, izpildot sekojošu komandu rindu:
c:\orawin\bin\f45run.exe c:\mydir\myapp.fmx

Lai programma varētu izpildīties no jebkuras mašīnas, pirms Oracle lietojumprogrammas startēšanas no sistēmas reģistrija jānolasa Oracle instalācijas katalogs, lai zinātu, kur atrodas formu startēšanas programma f45run.exe. Oracle instalācijas katalogs sistēmas reģistrijā atrodas zem atslēgas -
My Computer\HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\ORACLE_HOME

2.4.11. MS Windows palīdzības logi


       Ja darbam ar lietojumprogrammu nepieciešama labi organizēta palīdzība un visas lietojumprogrammas tiek izstrādātas MS Windows vidē, tad šeit it tikai viens veids kā to panākt - MS Help. MS Help ir lielisks līdzeklis sistēmas palīdzības aprakstīšanai, pie kam lietotājs papildus nav jāapmāca ar to rīkoties, kā tas ir gadījumā ar Oracle Book 2.2 (programma Oracle palīdzības failu lasīšanai), kas bez tam prasa laiku un datora resursus, lai to lietotu. Lai to veiktu, var izmantot jebkuru MS Windows palīdzības tekstu veidotāj-lietojumprogrammu. Tās ir viegli lietojamas, kas ļauj ātri veidot palīdzības failus. Kad palīdzības faili ir gatavi, tos var integrēt Developer/2000 lietojumprogrammu vidē.
       No Oracle vides standarta palīdzību var izsaukt, izmantojot ORA_FFI (Oracle Foreign Function Interface) paketi [3], kas atļauj izsaukt standarta palīdzības funkcijas no Developer/2000 lietojumprogrammu vides. Tādējādi iespējams izveidot kontekst-jūtīgu palīdzību jebkurai Oracle lietojumprogrammai.

2.4.12. Nodaļlapas (Tabbed pages) - jauns interfeisa standarts


       Nodaļu lapu (tabbed pages) interfeiss kļuva ļoti populārs tūlīt pēc MS Windows95 iznākšanas. Nodaļu lapas ir viegli saprotams veids informācijas grupēšanai un pasniegšanai lietojumprogrammā. Šāda veida informācijas attēlošana, ļauj lietotājam viegli apskatīt visu informāciju lietojumprogrammā.
Oracle Forms 4.5-ās nodaļlapas var izveidot lietojot vizuālos pamatelementus VBX (Visual Basic Control) [3] vai arī vienkāršas bildes, kurām pievieno triggerus, lai apstrādātu gadījumus kad lietotājs nopiež vienu vai otru pogu un veiktu pāreju uz citu lapu. Lai šādas lapas izveidotu Oracle Forms 4.5 vidē, ir nepieciešams uzrakstīt programmas kodu, taču kā informē Oracle Corp., nodaļlapas kā interfeisa objekts jau ir iekļautas jaunajā Oracle Forms 6.0 versijā (Developer 6.0).  



2.18. attēls. Nodaļlapas Oracle Forms 4.5.

Bez tam eksistē dažas nianses, ko daži autori iesaka ievērot, veidojot nodaļlapas. Katru nodaļu vajag nosaukt īsi, parasti vienā vārdā un tam ir jābūt saprotamam, kā arī viennozīmīgi jāraksturo zem tā esošās lapas ideja. Bez tam, nav ieteicams veidot vairāk par 7 nodaļām vienlaikus, jo cilvēka vizuālās informācijas uztveres spējas ir ierobežotas.

2.4.13. Palīdzības teksta (Hint) krāsa


       Standarta palīdzības teksti (Hint message), kas tiek parādīti Oracle Forms 4.5 konsoles logā (console window), izpildot Message funkciju, ir ļoti grūti pamanāmi, jo tie tiek rakstīti ar maziem melniem burtiem uz pelēka fona, kā rezultātā lietotāji tos parasti neievēro. Problēmas sākas gadījumos, kad lietotājs ir palaidis garām kādu svarīgu informāciju. Protams pastāv iespēja, izmantot Oracle formu Alert funkciju, kas parāda informatīvu logu un gaida kamēr lietotājs nospiedīs OK pogu. Taču šāds risinājums no lietotāju viedokļa ne vienmēr ir pieņemams, jo tas prasa lieku darbību izpildīšanu, kas ne vienmēr ir vēlama. Viena no iespējām būtu parādīt šo palīdzības tekstu lielākā fontā, taču sakarā ar to ka šis tekstam paredzētais laukums nav maināms, palielinot fontu būs redzama tikai daļa no teksta - vai nu augšējā vai apakšējā. Otrs risinājums, kas arī ir viegli realizējams, ir izmainīt šī teksta krāsu, teiksim uz sarkanu va zilu, kas uzreiz pievērš lietotāja uzmanību.
       Lai izmainītu Oracle Forms 4.5 palīdzības loga teksta krāsu ir jālieto programma Oracle Terminal. Tā atļauj lietotājam mainīt krāsas, fontus un citus atribūtus, izveidojot resursu datni, kurā visa šī informācija tiek glabāta. Konkrēti Oracle Forms 4.5 palīdzības teksta krāsas maiņa veicama, labojot atribūta forms_logical īpašības Status-Message un Status-Hint. Pirmais no tiem nosaka palīdzības līnijas krāsas, kas tiek parādītas ar funkcijas Message palīdzību, bet otrais attiecīgi palīdzības tekstu, kas tiek rādīts nostādot kursoru kādā no ievadlaukiem (lauka informatīvais teksts - hint). Beidzot darbu ar šo programmu, tās dati jāsaglabā kā atsevišķa resursu datne, kas jānorāda kā parametrs startējot sistēmu. Izpildīšanas sintakse ir:
c:\orawin\bin\f45run.exe
         c:\mydir\myapp.fmx term=resource.res:windows



2.19. attēls. Palīdzības teksts sarkanā krāsā.





Nobeigums

      
       Tā kā Oracle formu veidošanas rīks nav pārāk populārs, salīdzinot kaut vai ar Delphi un citiem produktiem, vēl nav pieejams pietiekoši daudz literatūras par dažādiem izstrādes aspektiem, nemaz nerunājot, ka literatūra latviešu valodā par Oracle nav pieejama praktiski vispār. Rakstot šo darbu, tika atklāts daudz vērtīgas informācijas, kas lasot oriģinālās Oracle grāmatas, bija iepriekš palaists garām, tieši apgūstamās informācijas lielā apjoma dēļ. Gūtās iemaņas jau ir palīdzējušas vieglāk un efektīvāk veidot Oracle formas un formu šablonformas, kas ietvertu visu nepieciešamos objektus turpmākai izstrādei. Liels ieguvums bija iegūtā informācija par formu izejas koda optimizāciju. Prasības pēc sistēmas izejas koda optimizācijas radās automātiski, tiklīdz pieauga ekspluatējamās sistēmas datu apjoms un veicamie darbi sāka izpildīties lēnāk tikai lielā datu apjoma dēļ vien. Pirmā reālā problēma bija optimizēt datņu veidošanu, kas sekmīgi tika realizēta, kā tas tika aprakstīts darbā. Organizācijā, kurā es pašlaik strādāju, drīzumā ekspluatācijā tiks palaista sistēma, kurā daudz klientu atradīsies ļoti tālu no datu bāzes servera. Savienojums tiks organizēts, izmantojot modema pieslēgumu. Rakstot šo darbu, tika atklātas daudzas nianses formas objektu atribūtu vērtībās, kas rakstot sistēmas darbam normālā datortīklā netiek ņemtas vērā, kaut vai tāda iemesla dēļ, ka Oracle kompānija tās savā produktā piedāvā kā noklusētās vērtības. Taču startējot sistēmu attālinātā režīmā tās darbība ir krietni lēnāka, nekā pēc formu optimizācijas. Kā jau tika minēts darba gaitā, turpmāk ir vēlēšanas izpētīt vēl dažas Oracle formu un Oracle servera iespējas, kas ļautu dažus uzdevumus risināt vēl ātrāk.
 Ļoti liels ieguvums bija arī 2. nodaļā aprakstītā šablonformu izmantošana formu ģenerācijā. Arī līdz šim tika lietotas šablonformas, taču bez atsaucēm uz objektiem. Tas radīja lielu laika patēriņu sistēmas izstrādes gaitā, kad atklājās, ka vajadzīgs jauns objekts vai jālabo kāda vizuālā atribūta īpašības (visbiežāk krāsas), jo izrādās, ka citos datoros, ar citu izšķirtspēju un krāsu paleti, to nav iespējams redzēt. Nepieciešamo objektu aprakstīšana šablonformā, izmantojot atsauces, to minimizēja līdz minimumam, jo izmaiņas tagad bija jāveic tikai vienā vietā - formā no kuras tiek veidota objektu atsauce. 2.4. nodaļā aprakstītie piemēri novērš dažus Oracle formu lietotāja-datora interfeisa trūkumus. Šeit jāatceras, ka Oracle formas ir produkts, kas tiek lietots uz daudzām platformām, kā rezultātā produktam ir savas lietotāja-datora interfeisa īpatnības, kas MS Windows lietotājam nevienmēr ir pieņemamas. Daži no tiem tika apkopoti no rakstiem žurnālos un internetā, daži manis doti, kas kļuva aktuāli pēc sarunām ar lietotājiem vai vienkārši iedomājoties sevi lietotāja vietā. Vēl līdz galam neizpētīta ir palikusi tikai lietotāju palīdzības logu veidošana, izmantojot MS Help, ko autors cer realizēt tuvākajā laikā.
Kā tika minēts darbā, jaunajā produkta versijā Oracle Forms 6.0 ir paredzami uzlabojumi un papildinājumi lietotāja-datora interfeisa jomā - vairāki jauni interfeisa objekti, kas tagad ir standarta interfeisa objekti MS Windows vidē.



Literatūra


1.      Oracle Designer/2000 A Guide to Developer/2000 Generation, ORACLE 1995
2.      Oracle Designer/2000 Online Documentation
3.      Oracle Developer/2000 Forms 4.5 Reference Manual vol.1/ vol. 2, ORACLE 1994
4.      Oracle Developer/2000 Forms 4.5 Advanced Techniques Manual, ORACLE 1994
5.      Oracle Developer/2000 Forms 4.5 Getting Started Manual, ORACLE 1994
6.      Oracle Forms 4.5 Online Help
7.      Oracle Informant, March 1997, vol.2. #3, “Your Game Face - Tips for Developing a Quality User Interface” p. 8-13, An Informant Communications Group Publication 1997
11.  DBMS_PIPE pakotnes apraksts datu bāzē



Pielikums


Programmu teksti


Formu koda optimizācija


-----------------------------------
--  Datnes ielasīšana formu daļa --
-----------------------------------

BEGIN
  if NOT VISA_SYSTEM.Get_Parameter_Value('DSPL_LINES', s_lines) then
      s_lines := '5';
  end if;
  sync_lines := To_Number(s_lines);

  LOG.pInit;
  MyList.InitRetrieval('SELECTED_FILES',vFileNameForLog );
  p.SingleFilename := MyList.GetListElement;
  IF p.SingleFilename IS NULL then
    RAISE NotFile;
  END IF;
  :BLOCK1.idi:=NULL;
  go_item('block1.sview');
  Set_Item_Property('BLOCK1.ok', ENABLED, Property_False);
  Set_Item_Property('BLOCK1.exit', ENABLED, Property_False);

  START_TIME := DBMS_UTILITY.Get_Time;
  VISA_READ_IN_CTF.Reset_Perf_Time;
  LOG.log_time := 0;

  WHILE p.SingleFilename IS NOT NULL LOOP
      write_sum := True;
      begin
      LOG.ResetVariables(iMonTransactions,Line,iBatch_nr);
      :block1.cur_file := p.SingleFilename;
      begin
            sREAD_TIME := DBMS_UTILITY.Get_Time;
    in_file := TEXT_IO.FOPEN(p.StartDir||
p.SingleFilename, 'r');
            READ_TIME := READ_TIME +
(DBMS_UTILITY.Get_Time - sREAD_TIME);
      exception when OTHERS then
          LOG.MyErrorMsg := CanNotOpenMsg||p.StartDir||
p.SingleFilename;
          RAISE MyError;
      end;
      :block1.line := 0;
     :block1.batch_nr := 0;
      :block1.transaction := 0;
      synchronize;


  IF NOT VISA_READ_IN_CTF.Init(p.SingleFilename,
LOG.MyErrorMsg,nFileID) then
          RAISE MyError;
      END IF;

      SET_APPLICATION_PROPERTY(CURSOR_STYLE, 'busy');
      BEGIN     -- process file
            :BLOCK1.idi:=:BLOCK1.idi||to_char(nFileID)||',';
         LOOP
                sREAD_TIME := DBMS_UTILITY.Get_Time;
                BEGIN
                      TEXT_IO.GET_LINE(in_file, linebuf);
                  EXCEPTION
                      WHEN NO_DATA_found then
                            Raise Faila_beigas;

                  When OTHERS then
LOG.MyErrorMsg := VISA_SYSTEM.Get_Error_Message(50, p.StartDir||
p.SingleFilename, NULL, NULL);
                      RAISE MyError;
            END;
                READ_TIME := READ_TIME +
(DBMS_UTILITY.Get_Time - sREAD_TIME);

            LOG.pCalculateSummaries(linebuf,
iMonTransactions,Line,iBatch_nr);

            ---------------------------------------------
                -- Ivo   20.01.99
                -- Nosakam banku kurai pieder fails
            ---------------------------------------------
                IF Line = 1 then
                      BEGIN
                            SELECT NAME
                            INTO Bank_name
                            FROM VISA_BANKS
                        WHERE bin = SubStr(linebuf, 3,6);
                        Exception WHEN OTHERS then
                            Bank_name := 'Unknown';
                      END;

                  ----------------
      LOG.AddErrMesgInList(VISA_SYSTEM.
Get_Error_Message(98,p.StartDir||
p.SingleFilename, Bank_name, NULL));
            END IF;
                -------------------------------------
                -- TE IR VISA SAALS
                -------------------------------------

IF NOT VISA_READ_IN_CTF.WRITE_DATA(linebuf,
LOG.MyErrorMsg) then
                  RAISE MyError;
                END IF;

            IF LOG.MyErrorMsg IS NOT NULL then
                      :BLOCK1.sview := 2;
                      Show_view('LOG');
                END IF;
            LOG.AddErrMesgInList(LOG.MyErrorMsg,TRUE);
        END LOOP;
      EXCEPTION
          WHEN no_data_found or Faila_beigas THEN
                sREAD_TIME := DBMS_UTILITY.Get_Time;
                      TEXT_IO.FCLOSE(in_file);
                      READ_TIME := READ_TIME +
(DBMS_UTILITY.Get_Time –
sREAD_TIME);
      END;  -- process file

      :block1.line := Line;
     :block1.batch_nr := iBatch_nr;
      :block1.transaction := iMonTransactions;
      synchronize;

      --process End
      IF NOT VISA_READ_IN_CTF.ValidateEnd(LOG.MyErrorMsg)
then
          RAISE MyError;
        ELSE
          IF LOG.MyErrorMsg IS NOT NULL then
                LOG.AddErrMesgInList(LOG.MyErrorMsg,TRUE);
                write_sum := False;
          END IF;
      END IF;

      BEGIN
              sREAD_TIME := DBMS_UTILITY.Get_Time;
message(VISA_SYSTEM.Get_Error_Message(21,
p.SingleFilename,p.Destination, NULL),
NO_ACKNOWLEDGE);
               synchronize;
            Destination := p.Destination ||p.SingleFilename;

              Win_Api_Utility.move_file(p.StartDir||p.SingleFilename, Destination);
            READ_TIME := READ_TIME + (DBMS_UTILITY.Get_Time
- sREAD_TIME);
            message(' ' , NO_ACKNOWLEDGE);
            synchronize;
      exception
        when no_data_found then
            LOG.AddErrMesgInList(VISA_SYSTEM.
Get_Error_Message(9021,Destination,NULL,
NULL));
      END;
    --*********************************
      LOG.AddErrMesgInList(OkMsg);
      IF write_sum then
            LOG.pWriteSummary(Settlement=>FALSE);
      END IF;
      totallines := totallines + line;

    --********* Addind from Plus Bin -> to BIN TMP .. 
          sPLUS_TIME := DBMS_UTILITY.Get_Time;
        AddPlusBin;
          PLUS_TIME := PLUS_TIME + (DBMS_UTILITY.Get_Time
- sPLUS_TIME);

    /**********STOPLIST creation*/
          sSTOP_TIME := DBMS_UTILITY.Get_Time;
        CreateStopList;
          STOP_TIME := STOP_TIME + (DBMS_UTILITY.Get_Time
- sSTOP_TIME);

    /**********VSM file creation*/
          sVSM_TIME := DBMS_UTILITY.Get_Time;
        CreateVSMFile; 
  VSM_TIME := VSM_TIME + (DBMS_UTILITY.Get_Time –
sVSM_TIME);

      -- Ivo 12.08.98 tuksha liinija aiz katra faila
          LOG.AddErrMesgInList(' ');

     EXCEPTION
        when MyError then
           pError;
       when OTHERS then
             LOG.MyErrorMsg := SQLERRM;
             pError; 
END;
   LOG.sLOG_TIME := DBMS_UTILITY.Get_Time;
   :block1.cur_file := NULL;
    :block1.transaction := NULL;
   line := 0;       
   :block1.line :=NULL;
   :block1.batch_nr:=NULL;
   p.SingleFilename := MyList.GetListElement;
   LOG.LOG_TIME := LOG.LOG_TIME + (DBMS_UTILITY.Get_Time –
LOG.sLOG_TIME);

END LOOP;
TOTAL_TIME  := DBMS_UTILITY.Get_Time - (START_TIME +
 PLUS_TIME + STOP_TIME + VSM_TIME);


lTIME       := LOG.LOG_TIME;
                -- Savaadaak kameer shitos drukaas buus
-- jau lielaaks

  IF totallines <> 0 then
      tsecperline  := Round((TOTAL_TIME)/totallines, 0);
    ELSE
      tsecperline  := 0;
  END IF;


  -- PERFORMANCE
  LOG.AddErrMesgInList('--- Performance ---');
  LOG.AddErrMesgInList('Total Time         :
'||VISA_SYSTEM.Perf_Time(TOTAL_TIME, TOTAL_TIME));
  LOG.AddErrMesgInList('    File operations:
'||VISA_SYSTEM.Perf_Time(READ_TIME, TOTAL_TIME));
  LOG.AddErrMesgInList('    Checking data  :
'||VISA_SYSTEM.Perf_Time(VISA_READ_IN_CTF.CHECKTIME,
TOTAL_TIME));
LOG.AddErrMesgInList('    Inserting data :
'||VISA_SYSTEM.Perf_Time(VISA_READ_IN_CTF.INSERTTIME, TOTAL_TIME));
LOG.AddErrMesgInList('    ----------------');
vDummy :='1';
IF totallines <> 0 then
  LOG.AddErrMesgInList('    Time per TCR   :
'||VISA_SYSTEM.Perf_Time(tsecperline,
tsecperline));
END IF;

LOG.pWriteFromList('block1.messages','READ_VISA_CTF',
 nFileID, vFileNameForLog);--
        :BLOCK1.tasknr:=nFileID;
        set_item_property('block1.print_log', enabled,
property_true);

END;

-------------------------------------
--  Datnes ielasīšana servera daļa --
-------------------------------------

FUNCTION WRITE_DATA(str IN VarChar2, err_text OUT
VarChar2) Return BOOLEAN IS
galva   VarChar2(2) := SubStr(str, 1, 2);
MasterTransNotFound EXCEPTION;
PRAGMA EXCEPTION_INIT(MasterTransNotFound, -02291);

BEGIN
        -- PERFORMANCE
        sCHECK_TIME := DBMS_UTILITY.Get_Time;

        /****Kontrole****/
         if nLine=1 then
            if LENGTH(str)=0 then   --File is empty
                      Return(DoError(10, err_text));
            elsif galva != '90' then   
-- File doesn’t begin with Header record
-- ''90''
                Return(DoError(11, err_text));
            end if;
        end if;
 IF galva='92' AND IeprieksejaGalva <>'91' then
      --Pirms beigaam nav kopsavilkuma
            Return(DoError(12, err_text));
       END IF;
       IF galva <> '90' then  
    -- not Header -> calculate TRANSACTIONs
            gTcrSk := gTcrSk + 1;
            fTcrSk := fTcrSk + 1;
        END IF;

        /****IELASIISHANA****/
        IF galva = '90' then
              -- Faila KONTROLE !!!!!!  Ivo 20.01.99
              IF NOT Check_File_Header then
                    Return false;
              END IF;
              InsertHeader_buf;


        ELSIF galva = '01' or galva = '02' or galva = '03' then
              IF SubStr(str, 4, 1) IN('0', '1', '2', '3',
'4', '5', '6', '7', '8') then
                     InsertRETURNED_ITEM08;
                     if SubStr(str, 4, 1) = '0' then
                        gMonTrnSk := gMonTrnSk + 1;
                        fMonTrnSk := fMonTrnSk + 1;
                     end if;
              ELSIF SubStr(str, 4, 1) = '9' then
                     InsertRETURNED_ITEM9;
              ELSE  --error
                     Return(DoError(3, err_text));
              END IF;

        ELSIF galva IN ('05','06','07','15','16','17',
'25','26','27','35','36','37') then
              IF SubStr(str, 4, 1) = '0' then
                     InsertDRAFT0_BUF;
                     gMonTrnSk := gMonTrnSk + 1;
                     fMonTrnSk := fMonTrnSk + 1;
              ELSIF SubStr(str, 4, 1) = '1' then
                     InsertDRAFT1_BUF;
              ELSIF SubStr(str, 4, 1) = '3' then
                     InsertDRAFT3_BUF;
              ELSIF SubStr(str, 4, 1) = '4' then
                     InsertDRAFT4_BUF;
              ELSIF SubStr(str, 4, 1) = '5' then
                     InsertDRAFT5_BUF;
              ELSIF SubStr(str, 4, 1) = '6' then
                     InsertDRAFT6_BUF;
              ELSE  --error
                     Return(DoError(4, err_text));
              END IF;

        ELSIF galva IN ('10','20') then
              InsertFEE_COL_FUNDS_DISB;
              gMonTrnSk := gMonTrnSk + 1;
              fMonTrnSk := fMonTrnSk + 1;

        ELSIF galva = '33' then
              IF SubStr(str, 35, 10) = 'TAPEHEADER' then
                    PLUS_HEAD := TRUE;
                    InsertPLUS_BIN_HEADER;

              ELSIF SubStr(str, 35, 11) = 'TAPETRAILER' then
                    PLUS_TRAIL :=TRUE;
                    InsertPLUS_BIN_TRAILER;

              ELSIF SubStr(str, 35, 6) = 'HEADER' then                                  ROUTE_HEAD := TRUE;
                    Route_Line := nLine;

              ELSIF SubStr(str, 35, 7) = 'TRAILER' then                                        ROUTE_TRAIL :=TRUE;
                    err_text :=
VISA_SYSTEM.Get_Error_Message(42,
to_char(Route_line),to_char(nLine),
NULL);

              ELSIF SubStr(str, 35, 6) = vVSM_VERS||'000' then
                    VSM_HEAD := TRUE;
                    InsertVsmHEADER;
              ELSIF SubStr(str, 35, 6) = vVSM_VERS||'900' then
                    if VSM_HEAD then
                        VSM_TRAIL := TRUE;
                        InsertVsmTRAILER;
                        VSM_HEAD := FALSE;
                        WasInsertedVSM := TRUE;
                    else
                        Return(DoError(30, err_text));
  end if;
              ELSE
                    if PLUS_HEAD then
                        if NOT PLUS_TRAIL then
                            InsertPLUS_BIN_DETAILS;
                            WasInsertedPlusBinDetails := TRUE;
                        else
              Return(DoError(31, err_text));
end if;

                    elsif ROUTE_HEAD then
                        if NOT ROUTE_TRAIL then
                               NULL;
                        else
                            Return(DoError(43, err_text));
                        end if;

                    elsif VSM_HEAD then
                        if SubStr(str, 35, 6) =
 vVSM_VERS||'200' then
                            InsertVsmTran1;
                        elsif SubStr(str, 35, 6) =
vVSM_VERS||'210' then
                            InsertVsmTran2;
                        elsif SubStr(str, 35, 6) =
vVSM_VERS||'220' then
                            InsertVsmTran3;
                        elsif SubStr(str, 35, 6) =
vVSM_VERS||'225' then
InsertVsmTran4;
                        elsif SubStr(str, 35, 6) =
vVSM_VERS||'250' then
                            InsertVsmATM;
                        elsif SubStr(str, 35, 6) =
vVSM_VERS||'260' then
                           InsertVsmMultiCCY;
                        elsif SubStr(str, 35, 6) =
vVSM_VERS||'500' then                   
                            InsertVsmRECM1;
                        elsif SubStr(str, 35, 6) =
vVSM_VERS||'510' then                   
                            InsertVsmRECM2;
                        else
err_text :=
VISA_SYSTEM.Get_Error_Message(32,to_char(nLine),SubStr(str, 35, 6), NULL);
                            RememberError(err_text);
                        end if;
                    else
err_text :=
VISA_SYSTEM.Get_Error_Message(33,to_char(nLine),SubStr(str, 35, 6), NULL);
RememberError(err_text);
                         Return(DoError(33,
err_text,SubStr(str, 35, 6)));
                    end if;
              END If;
        ELSIF galva = '44' then
              IF UPPER(SubStr(str, 36, 1)) IN ('R','A') then
                    InsertCBATCH_ACKNOW_TRN_AR;
              ELSIF UPPER(SubStr(str, 4, 1)) != '0' then
                           InsertCBATCH_ACKNOW_TRN_18;
              ELSE
                    Return(DoError(5, err_text));
              END IF;

        ELSIF galva = '45' then
              InsertGEN_DEL_REPORTS;

        ELSIF galva = '46' then
              IF UPPER(SubStr(str, 60, 2)) IN
('4F','4G','6F','7 ','8A','9A') then
                    InsertMEMB_SETTL_DATA0;
              ELSIF SubStr(str, 60, 2) = '12' then
                    InsertMEMB_SETTL_DATAB;
              ELSIF SubStr(str, 60, 2) = 'C4' then
                    InsertMEMB_SETTL_DATAC;
              ELSIF SubStr(str, 60, 2) = '89' then
                    InsertMEMB_SETTL_DATAI;
              ELSE
                    Return(DoError(6, err_text));
              END IF;

        ELSIF galva = '48' then
              IF SubStr(str, 4, 1) = '0' then
                    IF SubStr(str, 17, 1) = '0' then
                        InsertBASEI_ADV_REC0F0;
                    ELSIF SubStr(str, 17, 1) = '1' then
                        InsertBASEI_ADV_REC0F1;
                    END IF;
              ELSIF SubStr(str, 4, 1) = '1' then
                    InsertBASEI_ADV_REC1;
              ELSIF SubStr(str, 4, 1) = '2' then
                    InsertBASEI_ADV_REC2;
              ELSE
                    Return(DoError(7, err_text));
              END IF;
        ELSIF galva = '50' then
              IF UPPER(SubStr(str, 23, 5)) = 'CTMFI' then
                    NULL;
       ELSIF UPPER(SubStr(str, 23, 5)) <> 'CTMFI' then
                    InsertTEXT_MESSAGES;
                    irteksts:=TRUE;
              ELSE
                    Return(DoError(8, err_text));
              END IF;
        ELSIF galva IN('51','52','53') then
              IF SubStr(str, 4, 1) = '0' then
                    InsertRETREQ_CONFIRM0;
              ELSIF SubStr(str, 4, 1) = '1' then
                    InsertRETREQ_CONFIRM1;
              ELSIF SubStr(str, 4, 1) = '4' then
                    InsertRETREQ_CONFIRM4;
              ELSE
                    Return(DoError(9, err_text));
              END IF;

        ELSIF galva = '55' then
              IF SubStr(str, 4, 1) = '0' then
                    InsertRCRF_UPDATE0;
              ELSIF SubStr(str, 4, 1) IN ('1','2') then
                    InsertRCRF_UPDATE12;
              ELSE
                    Return(DoError(29, err_text));
              END IF;
              WasInsertedSTOPLIST := TRUE;

        ELSIF galva = '56' then
              InsertCCY_RATE_UPDATES;

        ELSIF galva = '91' then    
 --Kopsavilkums, Batch beigas
              if NOT InsertBATCH_FILE_TRAILER_BUF(err_num) then
                 Return(DoError(err_num, err_text));
              end if;
              BatchNr := BatchNr +1;
              gTcrSk :=0;      --Batch level Check
              gMonTrnSk :=0;
              gDestAmount :=0;

        ELSIF galva = '92' then     -- trailer
              if VSM_HEAD then
                 return(DoError(36, err_text));
 end if;
              if NOT InsertBATCH_FILE_TRAILER_BUF(err_num) then
                 Return(DoError(err_num, err_text));
              end if;
              BatchNr := BatchNr - 1;
        ELSE
              err_text :=
VISA_SYSTEM.Get_Error_Message(20,
to_char(nLine),SubStr(str,1,4), NULL);
  END IF; -- galva
    
     nLine := nLine +1;
     IeprieksejaGalva := galva;

      -- Performance
      CHECK_TIME := CHECK_TIME + (DBMS_UTILITY.Get_Time –
sCHECK_TIME);
      return(TRUE);

    EXCEPTION
        WHEN MasterTransNotFound then
            if galva IN('01','02','03','05','06','07',
'15','16','17','25','26','27',
                       '35','36','37','51','52','53') then
               -- Performance
               CHECK_TIME := CHECK_TIME +
 (DBMS_UTILITY.Get_Time - sCHECK_TIME);

               return(DoError(24, err_text));
            else
               -- Performance
               CHECK_TIME := CHECK_TIME +
(DBMS_UTILITY.Get_Time - sCHECK_TIME);

               return(DoError(48, err_text));
   end if;
        WHEN OTHERS then
            -- Performance
            CHECK_TIME := CHECK_TIME +
(DBMS_UTILITY.Get_Time - sCHECK_TIME);

            return(DoError(19, err_text));

END; -- WRITE_DATA



---------------------------------
--  Datu atlasīšana pēc maskas --
---------------------------------

PROCEDURE Set_Mask (pre_form IN BOOLEAN) IS
    bnk   VarChar2(2) := IZD_RESTR_ACC.acc_bank;
    grp   VarChar2(2) := IZD_RESTR_ACC.acc_card_grup;
    id    VarChar2(6) := IZD_RESTR_ACC.user_id;
    -----------------------------------
    mask        VarChar2(1234);
    xclient           IZD_CL_ACCT_SEARCHW_MASK.client%TYPE;
    xf_names    IZD_CL_ACCT_SEARCHW_MASK.f_names%TYPE;
    xsurname    IZD_CL_ACCT_SEARCHW_MASK.surname%TYPE;
    xccy        IZD_CL_ACCT_SEARCHW_MASK.ccy%TYPE;
    xcard_acct  IZD_CL_ACCT_SEARCHW_MASK.card_acct%TYPE;
    xcard_name  IZD_CL_ACCT_SEARCHW_MASK.card_name%TYPE;
BEGIN
    If pre_form then
          -- Savacam vecos datus
          SELECT client, f_names, surname, ccy, card_acct, card_name
          INTO xclient, xf_names, xsurname, xccy, xcard_acct,
xcard_name
          FROM IZD_CL_ACCT_SEARCHW_MASK
          WHERE usrid = id and bank_c = bnk and groupc = grp;
          Set_Block_Property('MASK', DEFAULT_WHERE,
'usrid='''||id||''' and bank_c='''||bnk||''' and
groupc='''||grp||'''');
      ELSE
          xclient           := :MASK.client;
          xf_names          := :MASK.f_names;
          xsurname          := :MASK.surname;
          xccy        := :MASK.ccy;
          xcard_acct        := :MASK.card_acct;
          xcard_name        := :MASK.card_name;
    End IF;

    mask := '';
    If xclient IS NOT NULL then
          mask := 'client like '''||xclient||''' and client=client';
    End if;
    If xf_names IS NOT NULL or xsurname IS NOT NULL then
          If mask IS NOT NULL then
                mask := mask||' and search_name like
UPPER('''||xf_names||'%'||xsurname||'%'')';
            ELSE
                mask := 'search_name like
UPPER('''||xf_names||'%'||xsurname||'%'')';
          End If;
    End if;
    If xccy IS NOT NULL then
          If mask IS NOT NULL then
                mask := mask||' and UPPER(ccy) like
UPPER('''||xccy||''')';
            ELSE
                mask := 'UPPER(ccy) like UPPER('''||xccy||''')';
          End If;
    End if;
    If xcard_acct IS NOT NULL then
          If mask IS NOT NULL then
                mask := mask||' and card_acct like
'''||xcard_acct||''' and card_acct=card_acct';
            ELSE
                mask := 'card_acct like '''||xcard_acct||''' and
card_acct=card_acct';
          End If;
    End if;
    If xcard_name IS NOT NULL then
          If mask IS NOT NULL then
                mask := mask||' and UPPER(card_name) like
UPPER('''||xcard_name||''')';
            ELSE
                mask := 'UPPER(card_name) like
UPPER('''||xcard_name||''')';
          End If;
    End if;

    IF :PARAMETER.next_hop = 'MAKE_ACCNT_DORM' then
          If mask IS NOT NULL then
                mask := mask||' and status <> ''3''';
            ELSE
                mask := 'status <> ''3''';
          End If;
      ELSIF :PARAMETER.next_hop = 'MAKE_DORM_ACTIV' then
          If mask IS NOT NULL then
                mask := mask||' and status = ''3''';
            ELSE
                mask := 'status = ''3''';
          End If;
      ELSIF :PARAMETER.next_hop = 'MAKE_ACCNT_CLOS' then
          If mask IS NOT NULL then
                mask := mask||' and status = ''3''';
            ELSE
                mask := 'status = ''3''';
          End If;
    END IF;

    Set_Block_Property('ACSEARCH', DEFAULT_WHERE,mask);
    If NOT pre_form then
          :CG$CTRL.changed := 'TRUE';
    END IF;
END;








































Lietotāja interfeisa uzlabošana


----------------------------
--  RĪKU JOSLAS DARBĪBAS  --
----------------------------

/ PROCEDURE TOOLBAR_ACTIONS /
-- This procedure implements the toolbar functionality.
-- The logic reads the pressed button name and then calls
-- the appropriate function. If you want to change the
-- toolbar then make sure the if statement below has one
-- entry for each button.
----------------------------------------------
-- Standart from ORACLE FORMS GENERATOR
-- Modified by me, May 1997
----------------------------------------------
PROCEDURE TOOLBAR_ACTIONS IS
    button_name varchar2(61);
    button      varchar2(31);
BEGIN
show_window(get_view_property(get_item_property(
      name_in('SYSTEM.CURSOR_ITEM'), item_canvas), window_name));
      button_name := name_in('SYSTEM.TRIGGER_ITEM');
      button      := substr(button_name, instr(button_name, '.')+1);
      if    (button = 'SAVE') then
 do_key('COMMIT_FORM');
      elsif (button = 'PRINT') then
 do_key('PRINT');
      elsif (button = 'CLEAR_FORM') then
 do_key('CLEAR_FORM');
      elsif (button = 'QUERY_FIND') then
if (name_in('SYSTEM.MODE') != 'ENTER-QUERY') then
do_key('ENTER_QUERY');
              else
do_key('EXECUTE_QUERY');
            end if;
      ELSIF (button = 'INSERT_RECORD') THEN
 do_key('CREATE_RECORD');
      ELSIF (button = 'DELETE_RECORD') THEN
 do_key('DELETE_RECORD');
      ELSIF (button = 'CLEAR_RECORD') THEN
 do_key('CLEAR_RECORD');
      ELSIF (button = 'LIST') THEN
 do_key('LIST_VALUES');
      ELSIF (button = 'EDIT') THEN
             do_key('EDIT_FIELD');
      ELSIF (button = 'HELP') THEN
             do_key('HELP');
      ELSIF (button = 'OPNAME' ) THEN
             -- Operators name who changed this record
             get_operator_name ;
      ELSIF (button = 'SWITCH' ) THEN
             -- Change layout mode from BROWSE to RECORD
 change_layout_mode ;
      ELSIF (button = 'HISTORY' ) THEN
             -- Record’s update history
 Hist.History_Show ;
      ELSIF (button = 'EXIT') THEN
do_key('EXIT_FORM');
      END IF ;
END;

/PROCEDURE Change_Layout_Style/
PROCEDURE change_layout_mode  IS
-- Blocks need always end  '1' and '2'
-- blockname1 and blockname2
l_Block_Name      VARCHAR2(30) := Name_In(':SYSTEM.CURRENT_BLOCK') ;
l_block_name_head VARCHAR2(30) := SUBSTR( RTRIM( l_Block_Name ), 1,
                              LENGTH( RTRIM( l_Block_Name ) ) - 1  );
l_block_name_tail VARCHAR2(1) := SUBSTR( RTRIM( l_Block_Name ),-1,1);
l_go_block_name VARCHAR2(30) ;
l_go_block  BLOCK ;
BEGIN
      -- Change to………
      IF l_block_name_tail = '1' THEN
            l_go_block_name := l_block_name_head || '2' ;
      ELSE
                  l_go_block_name := l_block_name_head || '1' ;
      END IF ;
      -- Block’s ID
      l_go_block := FIND_BLOCK( l_go_block_name ) ;
      IF ID_NULL( l_go_block ) THEN
            -- Block not found -> go to the same block
            l_go_block_name := l_block_name_head  ;
            l_go_block := FIND_BLOCK( l_go_block_name ) ;
      END IF ;

      IF NOT ID_NULL( l_go_block )THEN
BEGIN
                  GO_BLOCK( l_go_block_name ) ;
              EXCEPTION
                  WHEN OTHERS THEN
                        MESSAGE( 'Unable change layout :' ||
    ERROR_TEXT ) ;
                  END ;
      END IF ;
END;


----------------
--  TOOLTIPS  --
----------------
-- Uses: Hint.pll            -- From ORACLE Corp.
--       Shwhnt32.dll

/ PACKAGE HINT.pll /
PACKAGE HINT IS
PROCEDURE ShowButtonHelp( timedelay NUMBER := 500);
PROCEDURE ShowButtonHelpHandler;
PROCEDURE HideButtonHelp;
END HINT;

/ WHEN-TIMER-EXPIRED TRIGGER /
BEGIN
      -- Shows tootip
hint.ShowButtonHelpHandler;
END;

/ WHEN-MOUSE-UP TRIGGER /
/ WHEN-MOUSE-LEAVE TRIGGER /
/ WHEN-MOUSE-DOWN TRIGGER /
/ WHEN-NEW-BLOCK-INSTANCE TRIGGER /
/ WHEN-WINDOW-CLOSED TRIGGER /
/ WHEN-WINDOW-ACTIVATED TRIGGER /
/ WHEN-WINDOW-DEACTIVATED TRIGGER /
BEGIN
      -- Hides tootip
hint.HideButtonHelp;
END;

/ WHEN-MOUSE-ENTER TRIGGER /
BEGIN
      -- Creates timer for tooltip
hint.ShowButtonHelp;
END;


-------------------------------------
--  IEVADLAUKU KRĀSU APRAKSTĪŠANA  --
-------------------------------------

/ WHEN-NEW-FORM TRIGGER /
Set_Field_DSPL_Property(‘BLOCK_NAME’, ‘FIELD_NAME’, Property);
            -- Property : 0 - DISABLED
                          1 - ENABLED, Optional
                          2 - ENABLED, Mandatory



/PROCEDURE Set_Field_DSPL_Property/
PROCEDURE Set_Field_DSPL_Property(  block_name IN CHAR,
field_name IN CHAR,
value IN CHAR) IS
      can_update  VarChar2(10);
BEGIN
      IF value = '0' Then
            -- DISABLED Item
            Set_Item_Property(block_name||'.'||field_name,
      UPDATEABLE, Property_False);
            Set_Item_Property(block_name||'.'||field_name,
VISUAL_ATTRIBUTE, 'DISABLED_ITEM');
            Set_Item_Property(block_name||'.'||field_name,
ENABLED, Property_False);

        ELSIF value = '1' Then
            -- OPTIONAL Item
            Set_Item_Property(block_name||'.'||field_name,
ENABLED, Property_True);
            Set_Item_Property(block_name||'.'||field_name,
NAVIGABLE, Property_True);
            Set_Item_Property(block_name||'.'||field_name,
REQUIRED, Property_False);
            Set_Item_Property(block_name||'.'||field_name,
VISUAL_ATTRIBUTE, 'CG$ITEM');

        ELSIF value = '2' Then
            -- MANDOTARY Item
can_update:=Get_Item_Property(block_name||'.'||
field_name, UPDATEABLE);
            Set_Item_Property(block_name||'.'||field_name,
ENABLED, Property_True);
            Set_Item_Property(block_name||'.'||field_name,
NAVIGABLE, Property_True);
            Set_Item_Property(block_name||'.'||field_name,
VISUAL_ATTRIBUTE, 'CG$ITEM');

            -- REQUIRED var uzstadīt tikai ja UPDATEABLE=true
            Set_Item_Property(block_name||'.'||field_name,
UPDATEABLE, Property_True);
            Set_Item_Property(block_name||'.'||field_name,
REQUIRED, Property_True);
            IF can_update = 'FALSE' then
                  Set_Item_Property(block_name||'.'||
field_name, UPDATEABLE, Property_False);
            END IF;
      END IF;
END;


-----------------------
--  LOGU VIRSRAKSTI  --
-----------------------
/PRE-FORM TRIGGER/
Set_Window_Property(FORMS_MDI_WINDOW, WINDOW_STATE, MAXIMIZE);
Set_Window_Property(FORMS_MDI_WINDOW, TITLE, ‘MY APPLICATION’);

Set_Window_Property(‘WINDOW_NAME’, TITLE, ‘MY MODULE’);


---------------------------------
--  SISTĒMAS RESURSU PĀRBAUDE  --
---------------------------------
-- Uses: MemInfo.pll       -- Interface for MemInfo.dll
         MemInfo.dll       -- Written by Eriks Aleksans

/ MemInfo.pll /
PACKAGE MemInfo IS
      FUNCTION TotalPhysMem RETURN PLS_INTEGER;
      FUNCTION FreePhysMem RETURN PLS_INTEGER;
      FUNCTION TotalVirtualMem RETURN PLS_INTEGER;
      FUNCTION FreeVirtualMem RETURN PLS_INTEGER;
END;

PACKAGE BODY MemInfo IS
---------------------------------------------------------
-- Special THANKS to Eriks Aleksans (Xire) for
-- MEMINFO.DLL /written in Delphi II/
---------------------------------------------------------
      lu ORA_FFI.LIBHANDLETYPE := ORA_FFI.load_Library('',
'MEMINFO.DLL');
      f1 ORA_FFI.FUNCHANDLETYPE :=
ORA_FFI.Register_Function(lu, 'TotalPhysMem',
ORA_FFI.PASCAL_STD);
      f2 ORA_FFI.FUNCHANDLETYPE :=
ORA_FFI.Register_Function(lu, 'FreePhysMem',
ORA_FFI.PASCAL_STD);
      f3 ORA_FFI.FUNCHANDLETYPE :=
ORA_FFI.Register_Function(lu,’TotalVirtualMem',
ORA_FFI.PASCAL_STD);
      f4 ORA_FFI.FUNCHANDLETYPE :=
ORA_FFI.Register_Function(lu, 'FreeVirtualMem',
ORA_FFI.PASCAL_STD);

---------------------------------------------------------
      FUNCTION GetResult(fh IN ORA_FFI.FUNCHANDLETYPE)
RETURN PLS_INTEGER;
      PRAGMA interface(c, GetResult, 11265);
---------------------------------------------------------
      Function TotalPhysMem return PLS_INTEGER IS
      BEGIN
            Return Round(GetResult(f1)/1024);
      END;

      Function FreePhysMem return PLS_INTEGER IS
      BEGIN
            Return Round(GetResult(f2)/1024);
      END;

      Function TotalVirtualMem return PLS_INTEGER IS
      BEGIN
            Return Round(GetResult(f3)/1024);
      END;


      Function FreeVirtualMem return PLS_INTEGER IS
      BEGIN
            Return Round(GetResult(f4)/1024);
      END;
---------------------------------------------------------
BEGIN
  ORA_FFI.Register_Return(f1, ORA_FFI.C_INT);
  ORA_FFI.Register_Return(f2, ORA_FFI.C_INT);
  ORA_FFI.Register_Return(f3, ORA_FFI.C_INT);

  ORA_FFI.Register_Return(f4, ORA_FFI.C_INT);
END;


/ FUNCTION FreeMemResources /
FUNCTION FreeMemResources return PLS_INTEGER IS
BEGIN
      Return Round(((MemInfo.FreePhysMem + MemInfo.FreeVirtualMem) /
(MemInfo.TotalPhysMem + MemInfo.TotalVirtualMem))
* 100);
END;


/ PROCEDURE Call_My_Form with no parameters/
PROCEDURE Call_My_Form (name IN char) IS
      min_mem           NUmber := 1;
      al_id       Alert;
      al_button   Number;
BEGIN
      IF FreeMemResources > min_mem then
            -- OK. Call form
            Call_Form(name, HIDE, NO_REPLACE, NO_QUERY_ONLY);
        ELSE
            al_id := Find_Alert('YES_NO_CHOICE');
            IF Id_Null(al_id) THEN 
                  MSG_ALERT('Error: ALERT ''YES_NO_CHOICE''
not found!', 'E', True);
              ELSE
                  Set_Alert_Property(al_id, alert_message_text,
'WARNING: There are less than ' || To_Char(min_mem) || '% of memory free! Do You want to continue?');
            END IF;
            al_button := Show_Alert( al_id );
            IF al_button = alert_button1 then
                  Call_Form(name, HIDE, NO_REPLACE, NO_QUERY_ONLY);
              ELSE
                  Return;
            END IF;                      
      END IF;
END;


/ PROCEDURE Call_My_Form with parameters /
PROCEDURE Call_My_Form_With_Param (name IN CHAR,
pl_id IN PARAMLIST) IS
      min_mem           NUmber := 1;
      al_id       Alert;
      al_button   Number;
BEGIN
      IF FreeMemResources > min_mem then
            -- OK. Call form
            Call_Form(name, HIDE, NO_REPLACE, NO_QUERY_ONLY, pl_id);
        ELSE
            al_id := Find_Alert('YES_NO_CHOICE');
            IF Id_Null(al_id) THEN 
                  MSG_ALERT('Error: ALERT ''YES_NO_CHOICE''
not found!', 'E', True);
              ELSE
                  Set_Alert_Property(al_id, alert_message_text,
'WARNING: There are less than ' || To_Char(min_mem) || '% of memory free! Do You want to continue?');
            END IF;
            al_button := Show_Alert( al_id );
            IF al_button = alert_button1 then
                  Call_Form(name, HIDE, NO_REPLACE, NO_QUERY_ONLY,
pl_id);
              ELSE
                  Return;
            END IF;                      
      END IF;
END;


-----------------------------------------------------
--  PAR - ĀTRA INFORMĀCIJA PAR LIETOJUMPROGRAMMU --
-----------------------------------------------------

/WHEN-NEW-FORM-INSTANCE TRIGGER/
DECLARE
      vcVer varchar2(40);
BEGIN
      Set_Window_Property('ABOUTWINDOW', TITLE, 'About ‘
||:parameter.system);
      show_window_centered('ABOUTWINDOW');
      IF :parameter.version_number is not null then
            vcVer := ' Version: ‘ ||:parameter.version_number;
      END IF;

      :about.System          := :parameter.System;
      :about.version          := vcVer;
      :about.Copyright        := :parameter.copyright_msg;
      :about.user             := User;
      :about.database         :=
Get_Application_Property(Connect_String);

      IF :about.database IS NULL then
            :about.database   := 'Default';
      END IF;

      IF Get_Application_Property(Calling_Form) IS NOT
   NULL then
            :about.form       :=
Get_Application_Property(Calling_Form);
        ELSE
            :about.form       := 'None';
      END IF;

      :about.mem              := To_Char(FreeMemResources)||                           
' %';
      Go_Item('ABOUT.CLOSE');
END;


---------------------
--  PAROLES MAIŅA  --
---------------------
/WHEN-BUTTON-PRESSED TRIGGER/
-- Uses : OUO package   -- SIMPLE ALERTS SERVICE
          SRV package   -- SIMPLE PACKAGE, that returns
                            ITEMS ID
DECLARE curr_butt VARCHAR2(61) := :SYSTEM.TRIGGER_ITEM;
   i NUMBER;
BEGIN
      IF curr_butt = 'BT.OK_BUTT' THEN
            IF NVL( :BT.PASSWORD , CHR(7) ) <> :BT.PWD THEN
-- old password does not match
                  i := ouo.up_alert( ouo.A_WARNING,
'WARNING',
'Old password does not match!');
                  GO_ITEM( srv.ptr_password );
              ELSIF :BT.NEW_PASSWORD IS NULL THEN
                        i := ouo.up_alert( ouo.A_WARNING,
'WARNING',
'Password cannot be empty!');
                  GO_ITEM( srv.ptr_password );
              ELSIF :BT.NEW_PASSWORD <> NVL( :BT.NEW_VERIFY
  , CHR(7) ) THEN
            -- old password OK, new isn't NULL
                        i := ouo.up_alert( ouo.A_WARNING,
'WARNING',
'New passwords does not match!');
                  GO_ITEM( srv.ptr_password );

              ELSE
                  Change_Password;
            END IF;

        ELSIF curr_butt = 'BT.CANC_BUTT' THEN
            DO_KEY('EXIT_FORM');
      END IF;
END;
/PROCEDURE Change_Password /
-- Uses : OUO package    -- SIMPLE ALERTS SERVICE
SRV package        -- SIMPLE PACKAGE, that returns
                            ITEMS ID

PROCEDURE Change_Password IS
      i NUMBER;
      SQL_Text VARCHAR2(128);
BEGIN
      i := ouo.up_alert( ouo.A_ACCEPT, 'ACCEPT', 'Are you sure you
 wish to change the password?');
      IF i = ALERT_BUTTON1 THEN
            i := ouo.up_alert( ouo.A_ACCEPT,
'ACCEPT','Accept once more : are you sure you wish to change the password?');
            IF i = ALERT_BUTTON1 THEN -- Do IT!
                  i := ouo.up_alert( ouo.A_ACCEPT,
'WARNING', 'Attempt to change password will commit all uncommited changes! Do You want to continue?');
                  IF i = ALERT_BUTTON1 THEN
                        IF :BT.NEW_PASSWORD IS NULL THEN
                              SQL_Text := 'ALTER USER '|| :BT.USR ||
' IDENTIFIED  EXTERNALLY';
                            ELSE
                              SQL_Text := 'ALTER USER '||
:BT.USR ||
' IDENTIFIED BY "'|| :BT.NEW_PASSWORD||'"';
                        END IF; -- :BT.NEW_PASWORD IS NULL
                        FORMS_DDL( SQL_Text );
                        IF FORM_SUCCESS THEN
                              i := ouo.up_alert( ouo.A_INFORM,
'NOTE', 'Your password has been  changed successfuly.');
                              DO_KEY('EXIT_FORM');
                         ELSE
DECLARE et VARCHAR2(200) := 
DBMS_ERROR_TEXT;
t VARCHAR2(200):=  ERROR_TEXT;
BEGIN
i := ouo.up_alert( ‘CFG_ERROR',
'DBMS_ERROR', et);
GO_ITEM( srv.ptr_new_password);
                              END;
                        END IF; -- FORM_SUCCESS
                    ELSE
                        GO_ITEM( srv.ptr_password );
                  END IF;     -- i = ALERT_BUTTON1
               ELSE
                  GO_ITEM( srv.ptr_password );
            END IF; -- i = ALERT_BUTTON1 THEN -- Do IT!~
        ELSE
            GO_ITEM( srv.ptr_password );
      END IF;
END;


/ PACKAGE OUO /
PACKAGE OUO IS          -- Often Used Objects
-- for F45 with STDT_KON referenced objects
A_SYS_ERR ALERT := FIND_ALERT('CFG_SYSTEM_ERROR');
A_ERROR ALERT;  := FIND_ALERT('CFG_ERROR');
A_INFORM ALERT  := FIND_ALERT('CFG_INFORMATION');
A_WARNING ALERT := FIND_ALERT('CFG_WARNING_A');
A_ACCEPT ALERT  := FIND_ALERT('CFG_ACCEPT_A');

-- PROCEDURES AND FUNCTIONS

-- ALERTS SERVICES
FUNCTION Up_ALERT ( a_id ALERT, a_Title VARCHAR2,
  a_Message VARCHAR2) RETURN NUMBER;
FUNCTION Up_ALERT ( a_name VARCHAR2, a_Title VARCHAR2,
  a_Message VARCHAR2)RETURN NUMBER;
-- Error message from code
FUNCTION Treat_Error_Code ( eCode NUMBER ) RETURN VARCHAR2;
END;

/PACKAGE SRV/
PACKAGE srv IS
      -- Returns Items ID for “Change_Password” form’s objects
ptr_password ITEM := FIND_ITEM( 'BT.PASSWORD' ) ;
ptr_new_password ITEM := FIND_ITEM( 'BT.NEW_PASSWORD' ) ;
ptr_new_verify ITEM := FIND_ITEM( 'BT.NEW_VERIFY' ) ;
ptr_ok_butt ITEM := FIND_ITEM( 'BT.OK_BUTT' ) ;
ptr_canc_butt ITEM := FIND_ITEM( 'BT.CANC_BUTT' ) ;
END;


-------------------------
--  PROGRESA RĀDĪTĀJS  --
-------------------------
-- Uses: INDI.pll       -- Interface library for
-- INDI32.dll
        INDI32.dll      -- Writen by Karlis Ogsts in C++

/ INICIALIZĀCIJA /
If INDI.LoadLibrary(err_txt) then
      INDI.Open;
      Msg_Txt:='Preparing interface files ...';
      INDI.SetInfoMessage(msg_txt);
      INDI.SetIndicator( 0 );
   else
      Message(err_txt);
      Return;
End If;

/ TEKOŠĀS VĒRTĪBAS PARĀDĪŠANA /
INDI.SetIndicator( 2 );
/ PROGRESA RĀDĪTĀJA AIZVĒRŠANA /
INDI.CLOSE;
INDI.FreeLibrary;


/ INDI.pll /
package indi is
function LoadLibrary(szErrorMessage in out varchar2)
return boolean;
procedure Open;
procedure SetIndicator(plsComplete pls_integer);
procedure SetInfoMessage(szInfoMessage in out varchar2);
procedure Close;
procedure FreeLibrary;
END;

--------------------------------------------------------
-- LIETOJUMPROGRAMMAS STARTĒŠANA AR SPLASH EKRĀNU un  --
-- RESURSU PĀRBAUDI                                   --
--------------------------------------------------------

/ WHEN-NEW-FORM-INSTANCE TRIGER /
IF USER = 'GHOST' then
      -- kill splash screen
      HOST('Erase c:\issuing.knt', NO_SCREEN);
      -- Reconect;
      LOGOUT ;
      WHILE NOT Connected LOOP
            LOGON_SCREEN;
            o_user := GET_APPLICATION_PROPERTY( USERNAME );                         o_pwd  := GET_APPLICATION_PROPERTY( PASSWORD );
            o_cs  := GET_APPLICATION_PROPERTY(
CONNECT_STRING ) ;
            IF RTRIM( o_user ) IS NOT NULL THEN
                  IF RTRIM( o_cs ) IS NOT NULL THEN
                        LOGON( o_user , o_pwd ||'@'|| o_cs , FALSE);
                    ELSE
                        LOGON( o_user , o_pwd , FALSE );
                  END IF ;
              ELSE
                  --  Atgriezts tukss USER vaards
                  EXIT_FORM;
            END IF ;

            BEGIN
                  test := USER;
                  Connected := True;
               EXCEPTION
                  WHEN OTHERS Then
                        LOGOUT;
                        -- Ļaujam konektētie tikai 3x
                        IF Try = 3 then
                              EXIT_FORM;
                        END IF;
                        Try := Try + 1;
            END;
      END LOOP;
END IF;


/ MY_APPLICATION.EXE written in DELPHI II /
program mpcs;
uses
  Forms,
  Unit1 in 'Unit1.pas' {main};
  {$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(Tmain, main);
  Application.Run;
end.



unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, T3Dt, StdCtrls, nbutton, NoTask, RegFiles;

type
  Tmain = class(TForm)
    Panel1: TPanel;
    Image1: TImage;
    Timer1: TTimer;
    Timer2: TTimer;
    NoTask1: TNoTask;
    Reg: TRegFile;
    Text3D1: TText3D;
    Text3D2: TText3D;
    Text3D3: TText3D;
    Text3D4: TText3D;
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure Timer1Timer(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    f : file;
    tagadvar : boolean;
    procedure OuttaHere;
  public
    { Public declarations }
  end;

var
  main: Tmain;

implementation

{$R *.DFM}


procedure Tmain.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
      -- Avārijas gadijumā vienmēr varam aizvērt splash screen ar F12
      if Key = VK_F12 then Halt;
end;


procedure Tmain.OuttaHere;
begin
    Halt;
end;


procedure Tmain.Timer1Timer(Sender: TObject);
var
  i : integer;
  s : TSearchRec;
begin
    if not tagadvar then Exit;
    // Skatamies uz fiktiivu failu ko, savukārt dzēš ieks
    // FORMS 4.5 kad taa stratējusies.
    // ------------------------------------------------------
    // DEREETU PAARTAISIIT UZ REGISTRI !!!!!!!!!!!!
    if FindFirst('c:\forms45.knt', faArchive, s) <> 0 then begin
       FindClose(s);
       Timer1.Enabled := False;
       OuttaHere;
    end;
    FindClose(s);
end;


procedure Tmain.Timer2Timer(Sender: TObject);
var
  s,
  s1 : string;
  i  : integer;
begin
    s := Reg.ValueDefault['ORACLE_HOME', s];
    -- Palaizam formu, kas pieslēdzas ar fiktiivu useri GHOST
    s := s + '\bin\f45run32.exe TOP_MPCS.fmx USERID=GHOST/G';
    for i := 1 to ParamCount do begin
        s := s + ParamStr(i);
    end;
    Timer2.Enabled := False;
    // Izveidojam fiktiivo failu
    AssignFile(f, 'c:\forms45.knt');
    ReWrite(f, 1);
    CloseFile(f);
    tagadvar := True;
    WinExec(PChar(s), 1);
end;



function FreePhysMem : integer; stdcall external 'meminfo.dll'
 index 1;
function TotalPhysMem : integer; stdcall external 'meminfo.dll'
index 2;
function FreeVirtualMem : integer; stdcall external 'meminfo.dll'
index 3;
function TotalVirtualMem : integer; stdcall external 'meminfo.dll'
index 4;




procedure Tmain.FormCreate(Sender: TObject);
const
    st = '            ';
var
  s : string;
  i : integer;
begin
    s := Reg.ValueDefault['LOCAL', s];
    if s = '' then begin
       // Registrija jaabut LOCAL datubaazei defineetai…
       ShowMessage('    Local connect string not defined
in registry!   ');

       Halt;
    end;
    i := Round( ((FreePhysMem + FreeVirtualMem) /
     (TotalPhysMem + TotalVirtualMem)) * 100);
    // RESURSU Pa’rbaude………
    if i <= 10 then begin
        if Application.MessageBox('Free memory resources less than
10 %. '  +  'Do You want to continue?',
                  'Warning',
                  MB_ICONQUESTION + MB_YESNO) = IDNO
 then Halt;
       end;
    tagadvar := False;
end;
end.





Nav komentāru:

Ierakstīt komentāru