Obecnie większość aplikacji czy to webowych czy desktopowych jako mechanizmy przechowywania danych wykorzystuje relacyjne bazy danych. Baza Oracle jest jednym z najczęściej stosowanych rozwiązań tego typu. Przyczyniła się do tego m.in. zarówno dostępność bezpłatnych wersji z ograniczoną funkcjonalnością, pełne wsparcie dla klientów biznesowych, jak i wydajne mechanizmy dostępu do dużych ilości danych, możliwość przetwarzania rozproszonego. W niniejszych artykule postaram się przedstawić wybrane aspekty dotyczące wykorzystania Oracle we własnych środowiskach testowych jak i metody prowadzenia testów technicznych dotyczących weryfikacji zapisu danych w tej bazie.

1. Struktura instancji Oracle czyli kilka słów o konstrukcji bazy.

To co potocznie nazywamy bazą Oracle referując do udostępnianych przez nią struktur danych to w rzeczywistości bardziej skomplikowany byt dedykowany zapisowi, przetwarzaniu i udostępnianiu danych klientom końcowym.

Sam wybór typu środowiska bazy podczas jej instalacji i tworzenia już implikuje konieczność zastosowania bardziej skomplikowanych procesów niż w wypadku klasycznych baz plikowych i wpływa na komplikację budowy:

  • General Purpose – do zadań ogólnych – użytkownicy wykonują zarówno proste operacje transakcyjne jak skomplikowane zapytania
  • Transaction Processing – do przetwarzania wielu, równolegle wykonywanych transakcji przetwarzających relatywnie proste operacje na małej ilości danych, jak zapis, odczyt, kasowanie danych z tabel
  • Data Warehouse – użytkownicy wykonują wiele skomplikowanych operacji przetwarzających wielkie ilości informacji, polegających głównie na odczycie. Czas dostępu, trafność danych i ich dostępność są kluczowymi zagadnieniami

Chcąc w świadomy sposób zarządzać swoimi środowiskami testowymi z udziałem Oracle należy sobie zdawać sprawę jak funkcjonują bazy danych tego typu. Baza danych w Oracle to tak naprawdę zbiór plików danych tworzących logiczne przestrzenie danych, plików przywracania transakcji Redo logs, zarchiwizowanych plików Redo (Archive logs), pliki śledzenia i ostrzeżeń, pliki archiwów danych, plików parametrów startu oraz plików kontrolnych bazy przechowujących informacje o jej strukturze fizycznej np.: lokalizacjach plików danych i plików przywracania transakcji.

Sama baza danych w tym fizycznym ujęciu nie jest dostępną dla użytkownika końcowego (oprogramowania klienta bazy) ani od strony komunikacyjnej ani od strony dostępu do danych. Tutaj pojawia się pojęcie tzw. instancji bazy Oracle.

Instancja Oracle jest to zarezerwowany obszar pamięci o nazwie System Global Area wraz z procesami tła zapewniającymi obsługę bazy i procesów użytkownika. W ogólności można powiedzieć, że za każdym razem kiedy baza danych Oracle jest uruchamiana następuje alokacja obszaru SGA i uruchomienie procesów obsługi w tle. SGA zawiera dane instancji i jej informacje kontrolne. W wypadku gdy więcej niż jeden użytkownik jest podłączony równocześnie do instancji, struktury danych w tym obszarze będą współdzielone pomiędzy użytkowników. Jest to ważne choćby z tego punktu widzenia, że aplikacje korzystające z baz relacyjnych projektowane są przeważnie tak aby zapewnić wielodostęp do danych i mają konkretne wymagania na liczbę sesji użytkownika i procesów, które baza powinna obsłużyć współbieżnie (w zależności o typu architektury obsługi procesów tzw. Shared oraz Dedicated server). Ogólnie do wersji 11 włącznie można powiedzieć, że pojedyncza instancja bazy Oracle startuje i obsługuje najwyżej jedną bazę danych Oracle – użytkownicy łączą się do instancji bazy a nie do samej bazy fizycznej – to instancja zapewnia dostęp użytkownikom do danych i odpowiada za aspekty tak komunikacyjne jak i przetwarzania danych. Od wersji 12 Oracle umożliwia tworzenie w obrębie jednego fizycznego kontenera bazy wielu tzw. Pluggable Databases z własnymi przestrzeniami danych. Kontekst bazy może być ustawiany z poziomu sesji użytkownika jednak kontener fizyczny jest obsługiwany przez jedną instancję bazy i jej procesy. Dodatkowo w zastosowaniach Oracle RAC możliwe jest rozproszone przetwarzanie danych tej samej bazy fizycznej poprzez klaster instancji Oracle.

klasyczna-instancja-oracle

Powyżej przedstawiono schemat klasycznej instancji Oracle, uwidoczniono w niej:

  • SGA wraz z buforem pamięci podręcznej bazy, buforem logów Redo
  • Procesy użytkownika podłączone w zależności od architektury bazy do procesów Shared Server’a(wiele procesów użytkownika jest obsługiwanych przez mały zbiór współdzielonych procesów serwera) bądź procesu Dedicated Server’a (jeden proces użytkownika jest obsługiwany przez jeden proces serwera). Proces D000 dispatcher’a obsługuje tutaj przydzielanie procesów serwera procesom użytkownika w architekturze Shared Server’a
  • Recoverer Process: RECO – odpowiedzialny za przywracanie transakcji i rozwiązywanie problemów z transakcjami rozproszonymi – obecny tylko w konfiguracji wspierającej transakcje rozproszone
  • Proces PMON – monitorujący stan procesów użytkownika i procesu dispatcher’a – dba o zwalnianie zasobów i czyszczenie bufora pamięci podręcznej bazy w sytuacjach kiedy w/w procesy zakończyły się porażką
  • System Monitor Process: SMON – zapewnia przywracanie transakcji na poziomie startu instancji, czyszczenie tymczasowych segmentów danych, przywracanie transakcji na poziomie włączania nieaktywnych tabel wyłączonych z powodu wystąpienia błędu
  • Database Writer Process: DBW – zapisuje zawartość buforów pamięci podręcznej bazy do plików danych – dba o dostępność wolnych buforów pamięci podręcznej dla procesów użytkownika. Zapisywane są w pierwszej kolejności zmodyfikowane bufory (dirty) nie zawierające często wykorzystywanych danych (cold) co pozwala na szybki dostęp do z’cache’owanych wcześniej istotnych danych
  • Log Writer Process: LGWR – zapisuje bufor logu REDO do plików redo na dysku – dba o to aby zapis występował nadmiarowo do wszystkich plików z grupy redo zawsze kiedy przekroczona jest wartość 1/3 bufora lub gdy wystąpi commit transakcji (zostaną wprowadzone permanentne zmiany danych – operacje insert, delete, update) lub miną 3 sekundy. Blokuje wprowadzenie zapisu do plików danych dopóki zmiany REDO nie zostaną zapisane
  • Checkpoint Process: CKPT – aktualizuje nagłówki wszystkich plików danych o informacje o nowo wybranym checkpoint’cie. Checkpoint rozumiany jest tutaj jako pozycja w Redo logu wskazująca odkąd można rozpoczynać przywracanie bazy – pozycja ta jest wskazywana poprzez najstarszy „brudny” bufor w pamięci podręcznej buforów
  • Archiver Processes : ARC0 – kopiuje Redo logi do wyznaczonej lokalizacji fizycznej kopii zapasowej za każdym razem kiedy niezbędne jest zmiana Redo logu w wyniku zbliżającego się przepełnienia. W przypadku dużego narzutu operacji LGWR tworzy dodatkowy proces ARC aby zapobiec utracie danych Redo logów (do 10)

Wszystkie powyższe procesy posiadają wyznaczony plik śledzenia umożliwiający zapisanie ewentualnych problemów w obsłudze procesu. Dodatkowo baza danych posiada tzw. alert.log zawierający m.in.:

  • błędy wewnętrzne , informacje o uszkodzonych blokach, informacje o deadlockach transakcji (zakleszczeniu się wzajemnie transakcji blokującymi dostęp do danych)
  • wydane polecenia administracyjne
  • błędy odświeżania widoków
  • informacje o działaniu procesu dispatcher’a i shared server’a

Największą wydajność w przetwarzaniu danych osiąga się kiedy cały obszar SGA zmieści się w pamięci operacyjnej serwera i nie ulega on zapisowi w pliku wymiany komputera host’a bazy. Nie zawsze jest to oczywiste ponieważ obszar SGA składa się z kilku struktur o różnej wielkości, które wpływają na łączny rozmiar zużywanej pamięci a ta jest przydzielana dynamicznie. Do wersji 9i Oracle server’a włącznie poniższe parametry należało ustawić ręcznie jako parametry startowe instancji:

  • DB_CACHE_SIZE : rozmiar pamięci podręcznej bazy przechowującej współdzielone przez podłączonych użytkowników kopie często pobieranych danych
  • LOG_BUFFER : liczba bajtów przyznanych buforowi Redo logu
  • SHARED_POOL_SIZE : liczba bajtów pamięci dedykowanej współdzielonymi prywatnym zapytaniom SQL,  procedurom, pakietom, wyzwalaczom i funkcjom PL/SQL oraz strukturom kontrolnym jak blokady (lock)
  • LARGE_POOL_SIZE : wielkość opcjonalnego obszaru pamięci dedykowanemu rozszerzeniu pamięci sesji Shared serwera, alokacji dużej ilości pamięci i odciążenia pamięci zapytań od operacji wejścia/wyjścia, procesów  backup’u i przywracania
  • JAVA_POOL_SIZE : rozmiar pamięci związanej z obiektami Java i pamięcią wykonywalną maszyny wirtualnej Java.

Obecnie od wersji 10G Oracle serwera są one przydzielane dynamicznie poprzez mechanizm automatycznego zarządzania pamięcią, użytkownik z prawami administratora bazy (DBA) może ustawić pożądane wartości SGA_TARGET i SGA_MAX_SIZE opisujące odpowiednio docelową wartość całej SGA oraz limit tej pamięci. W wypadku gdy parametr TARGET zostanie ustawiony powyżej wartości MAX, różnica zostanie uwzględniona zwiększając dostępne maksimum.

Jak widać powyżej instancja Oracle jest skomplikowanym bytem zapewniającym nie tylko zapis, dostęp i przetwarzanie danych ale również obsługę procesów bezpieczeństwa danych umożliwiających późniejsze odzyskanie danych utraconych w wyniku wystąpienia błędów mediów fizycznych, błędnych zapytań, błędów przetwarzania etc.

Wspomnianego wcześniej obszaru pamięci SGA nie należy mylić z tzw. Process Global Area czyli PGA. Obszar ten jest tworzony przez proces serwera i nie może być w żaden sposób współdzielony. Jest on dedykowany temu procesowi i tylko on ma do niego ekskluzywny dostęp. Każdy z procesów serwera posiada w tym wypadku własny obszar PGA – sumę tych wielkości określa się zbiorczo jako pamięć zagregowaną PGA (aggregated PGA memory).

Obszary te są niezbędne do działania instancji Oracle w tzw. wieloprocesowej architekturze Oracle umożliwiającej różnym użytkownikom w tym samym czasie wielodostęp do bazy:

wieloprocesowa-architektura-oracle

Za każdym razem kiedy klient bazy danych w architekturze klient –serwer zestawił połączenie komunikacyjne pomiędzy swoim procesem użytkownika a instancją bazy Oracle dochodzi do utworzenia sesji użytkownika. Sesja trwa ta aż do odłączenia użytkownika od instancji. Użytkownik instancji o danej nazwie może podłączyć się w tym samym czasie do tej samej instancji bazy Oracle i utworzyć wiele współbieżnych sesji. Procesy serwera są tworzone aby obsłużyć żądania procesu użytkownika, jego sesję, analizować i uruchamiać zapytania SQL zgłaszane poprzez aplikacje podłączoną bo bazy, odczytywać dane z plików bazodanowych (o ile nie są one umieszczone już w buforach SGA i gotowe), zwracać rezultaty w formie możliwej do przetworzenia przez aplikację. Jak wspomniano wcześniej każdemu procesowi serwera jest przy tym przydzielany niezależny obszar pamięci PGA. Parametry instancji takie jak maksymalna liczba procesów obsługiwanych równocześnie przez serwer oraz utrzymywanych sesji znacząco wpływają zatem na możliwości przetwarzania danych przez instancję jak i zużycie przez nią pamięci operacyjnej (przy założeniu pełnego wykorzystania parametrów przez żądania obsługi).

2. Środowisko testowe z silnikiem Oracle jako odzwierciedlenie architektury aplikacji.

Środowiska testowe powinny jak najlepiej odpowiadać warunkom w jakich aplikacje mają pracować docelowo oraz odzwierciedlać architektoniczne założenia systemu w stosunku do kategorii wymagań. Przykładowo prowadząc testy logiki systemu aSISt – tranSIS a nie testy obciążeniowe można pokusić się o stworzenie takiej konfiguracji gdzie jedna instancja bazy Oracle obsługuje trzy aplikacji modułowe systemu. Pomoże nam to przetestować komunikację pomiędzy składnikami oprogramowania i prześledzić relacje czasowe w propagacji danych. Zaleca się przy tym aby instancja Oracle była posadowiona na innym komputerze fizycznym niż składniki aplikacyjne bądź na wirtualnej maszynie odzwierciedlającej w przybliżeniu minimalną zakładaną wydajność hosta fizycznego bazy.

instancja-bazy-oracle

W powyższej konfiguracji obrazującej możliwości instancji Oracle aplikacja aSISt tak jak wspominano wcześniej wykorzystuje wielodostęp serwera Oracle aby zapisywać i odczytywać dane z tego samego schematu danych ASIST oraz komunikuje się z serwerem ActiveMQ w celu wymiany wiadomości JMS. Z drugiej strony serwer tranSIS zapisuje i odczytuje własne dane do dedykowanego mu schematu danych oraz wymienia wiadomości z serwerem ActiveMQ, który zapisuje wiadomości zarówno z aSISt jak i tranSIS w swoim schemacie danych. Wszyscy użytkownicy bazodanowi ASIST, TRANSIS i ACTIVEMQ zostali utworzeni tak jak zobrazowano w obrębie tej samej instancji a odwołujące się  do nich aplikacje są klientami bazy danych. Decydując się przykładowo na posadowienie oprogramowania aplikacji aSISt i tranSIS console na pierwszym host’cie, aplikacji AMQ na drugim i aplikacji tranSIS serwera na trzecim możemy łatwo symulować komunikację pomiędzy odseparowanymi modułami. Obserwować obsługę timeout’ów połączeń, symulować błędy komunikacyjne oraz ich obsługę i wycofywanie zerwanych transakcji. Monitorować zakładany zbiór połączeń do bazy oraz ilość aktywnych sesji, ich zamykanie od strony aplikacji przy obsłudze błędów i zakańczaniu pracy klienta.

3. Struktury danych.

Wykorzystując przykładowo Oracle SQL Develper jako klienta bazy możemy w łatwy sposób sprawdzić obsługiwane przez testowaną aplikacje struktury danych. Opcja podglądu tabel umożliwia nam zapoznanie się z budową każdej z tablic, do której odbywa się zapis oraz wyświetlić zapisane już dane:

oracle-sql-develper

Z punku widzenia testera najbardziej istotnymi wydają się zakładki:

  • Columns : opisuje budowę poszczególnych kolumn danych w bazie i typy danych. Umożliwia sprawdzenie czy kolumna akceptuje tzw. null data czyli puste dane
  • Data : wyświetla konkretne wiersze tabeli złożone z poszczególnych kolumn i umożliwia ich sortowanie oraz modyfikację poszczególnych danych za pomocą wbudowanego edytora
  • Constraits : pozwala na zapoznanie się z tzw. więzami integralności nałożonymi na analizowaną tabelę
  • Triggers : listuje wyzwalacze tabeli pływające na automatyczne modyfikację danych w określonych warunkach
  • Dependencies : pozwala zapoznać się z zależnościami tabeli czyli w zbiorczy sposób obejrzeć wszystkie aktywne dla niej procedury, wyzwalacze i widoki na dane – czyli byty zależne od tej tabeli.
  • Indexes : założone na tabeli indeksy przyśpieszające operacje wyszukiwania danych w sposób określony wybranymi kryteriami

Pozostałe typy zakładek odnoszą się do:

  • Grants : praw danych użytkowników bazy przyznanych dla tej tabeli – funkcja bardziej administracyjna
  • Statistics : statystyk tabeli np.: liczebności wierszy, bloków, średniej długości wiersza, liczebności niepowtarzalnych danych etc., które muszą zostać pierwotnie wygenerowane
  • Flashback : poprzednich wersji danych tabeli, zanim wystąpiła na niej manipulacja danymi w danym punkcie czasu (np.: przed przywróceniem tabeli do stanu z dnia X bądź do numeru zmiany systemowej – SCN – odnoszącego się do danej operacji modyfikującej dane)
  • Details : szczegółowych charakterystyk dotyczących zarówno liczebności danych jak i ostatnich zmian struktury tabeli, umożliwia zapoznanie się z budową fizyczną tabeli (liczba zaalokowanych bloków/segmentów etc.) jak i właściwościami opisującymi jej status
  • Partitions : partycjonowania – w przypadku olbrzymich tabel zawiera partycje na jakie została rozbita tabela i ich właściwości – partycjonowanie stosuje się aby zapewnić dużą wydajność przetwarzanych danych w oparciu o kryteria podziału tabeli na drobniejsze przedziały
  • SQL : pełnej listy poleceń tworzących tabelę i związanych z nią bytów, potrzebnych do odtworzenia struktury tabeli

Właściwie w większości aplikacji znaleźć można komponenty udostępniające możliwość wprowadzenia danych wszelakiego rodzaju poprzez tzw. input field’y. Odpowiadają one przeważnie strukturom danych w bazie o wyznaczonym dla nich typie. Wprowadzone wartości dla tych pól są przeważnie weryfikowane zarówno po stronie aplikacji jak i po stronie bazy poprzez tzw. więzy integralności mające na celu zachowanie spójności bazy pod kątem narzuconych kryteriów. Analizując byty takie jak kolumny odpowiadającej input field’owi tabeli, możemy zapoznać się z typami danych wybranymi do zapisu i przechowywania wprowadzanych wartości. Oprócz najczęściej spotykanych testów sprawdzających warunki brzegowe aplikacji odpowiadające wymaganiom biznesowym należy przeprowadzić szereg dodatkowych testów eksploracyjnych weryfikujących wprowadzanie i zapis danych. Do testów takich przykładowo należeć mogą:

test wprowadzania  wartości przekraczających dopuszczalny zakres typu danych:

  • zakładając, że w kolumna zawiera dane typu varchar2 o długości 100 znaków należy wprowadzić ciąg przekraczający tą długość – aplikacja powinna walidować długość wprowadzonego tekstu zanim zostanie on zapisany do bazy. W wypadku braku walidacji po stronie aplikacji i naruszenia więzów integralności transakcja powinna zostać obsłużona w odpowiedni sposób i z’rollback’owana (wycofana).

Mechanizm wycofywania transakcji jest przy tym mechanizmem wspólnym dla wszystkich baz transakcyjnych. Dane istnieją po stronie bazy zarówno w formie zmodyfikowanej jak i niezmodyfikowanej. Dopóki nie dojdzie do zatwierdzenia transakcji poleceniem COMMIT zmodyfikowane dane nie są zapisywane do struktur danych schematu bazy a wspomniany wcześniej CHECKPOINT nie jest tworzony. Polecenie ROLLBACK służy do wycofywania błędnych modyfikacji i nie wprowadzi zmian w bazie po wystąpieniu polecenia COMMIT. Niektóre błędy procesu przetwarzania są z automatu wycofywane przez silnik bazy (np.: ostatnie polecenie prowadzące do naruszenia błędów), innym należy zapewnić obsługę po stronie aplikacji. Generalnie powiedzieć można, że transakcje pozwalają zachować spójność danych w bazie i wymuszają atomowość (niepodzielność) wprowadzanych zmian nawet po wystąpieniu błędu. Stanowią podstawę każdej manipulacji danymi przez zapytanie SQL. Zapewniają także odpowiedni poziom izolacji zmian. Przy przetwarzaniu z wielodostępem gdzie równolegle połączenia tego samego bądź innego użytkownika uzyskują dostęp w tym samym czasie do tych samych danych sprawiają, że chwilowa niespójność danych jest widzialna tylko dla połączenia skojarzonego z transakcją i może zostać wycofana bez wprowadzania błędów.

  • zakładając, że kolumna służy do zapisu danych liczbowych, dziesiętnych o ustalonej skali i precyzji np.: NUMBER lub DECIMAL (18,2) należy wprowadzić liczbę o konstrukcji nieodpowiedniej dla takiej wartości
  • zakładając, że dane zapisywane są w formacie daty, wprowadzić wartości spoza obsługiwanego przez typ zakresu oraz sprawdzić czy nie są konwertowane transparentnie do formatu nieodpowiedniego dla aplikacji
  • zakładając, że kolumna może przechowywać jedynie wartości enumerowane ENUM upewnić się, że aplikacja nie będzie próbowała zapisać danych spoza zakresu wyspecyfikowanych wartości
  • zakładając, że kolumna nie dopuszcza możliwości wprowadzania pustych wartości sprawdzić czy aplikacja nie naruszą więzów typu NOT NULL podczas zapisu
  • zakładając, że dane dla kolumny w formacie VARCHAR2 zawierają znaki specjalne i regionalne upewnić się, że zastosowany sposób kodowania znaków instancji bazy nie wpływa na utratę bądź transparentną konwersję znaków (np.: ‘a’ zamiast ‘ą’).

O ile aplikacja wymaga występowania unikatowych danych w obrębie wyspecyfikowanej kolumny/kolumn tabeli występuje potrzeba założenia więzów zapewniających niepowtarzalność danych. Więzy typu UNIQUE uniemożliwiają zapisanie takich samych danych i pozwalają uniknąć pomyłki w odczycie danych zapisanych poprzednio. Błąd implementacji mechanizmów zapisu aplikacji może polegać zarówno na braku występowania takich więzów jak i na możliwości uruchomienia funkcji naruszającej istniejące więzy unikatowe. Ta sama zasada dotyczy więzów typu NOT NULL.

Najprostszą metodą sprawdzającą czy nie dochodzi do naruszenia więzów typu UNIQUE jest uruchomienie tej samej funkcjonalności, zapisującej ten sam typ danych w tym samym oknie czasowym z wielu różnych klientów bazy (tej samej aplikacji końcowej) i próba zapisu takich samych danych. Dotyczy to zarówno tzw. FAT clients czyli aplikacji desktopowych o wielu funkcjonalnościach jak i aplikacji web’owych gdzie instancją procesu użytkownika bazy jest kolejna instancja przeglądarki sieciowej z uruchomioną w niej instancją aplikacji web’owej. Przeważnie od strony aplikacji stosuje się zabezpieczenia związane z blokowaniem używanych przez inna sesję funkcji czyli tzw. lockowaniem pesymistycznym uniemożliwiającym skorzystanie z funkcji w całym oknie czasowym istnienia blokady.

Wspomniane wcześniej trigger’y czyli wyzwalacze stosuje się w bazach danych do automatycznej aktualizacji danych związanych z nimi kolumn przy wystąpieniu konkretnej akcji. Przykładem mogą być wyzwalacze aktualizujące kolumnę daty o czas utworzenia krotki (czyli unikatowego wiersza tabeli złożonego z poszczególnych rekordów danych z niepowtarzalnym identyfikatorem zapewnianym przez PARENT_KEY tabeli czyli klucz główny – w odróżnieniu od FOREIGN_KEY będącego kluczem obcym stanowiącym relację klucza głównego do powiązanej tabeli danych). Z punktu widzenia testera ważne jest upewnienie się czy formaty danych prowadzanych przez trigger będą zrozumiałe i odpowiednio prezentowane przez aplikację oraz czy kompilują się w bazie po ewentualnych zmianach schematu bądź migracji danych. To samo dotyczy procedur i funkcji uruchamianych na schemacie danych mających na celu przetworzenie danych w określony sposób bądź zwrócenie odpowiednich wyników. Tutaj przykładem mogą być widoki (VIEWS) łączące wyniki z wielu tabel w jeden logiczny, łatwo dostępny byt.

Omawiane wcześniej indeksy służą zapewnieniu możliwie najszybszego wyszukiwania danych i z punktu widzenia testera również wystarcza przeważnie sprawdzenie ich pod kątem udanej kompilacji bądź efektywności działania w przypadku rozbudowy związanych z nimi tabel o nowe kolumny bądź wystąpienia zbyt wysokiego wskaźnika fragmentacji danych (clustering factor).

Osobną kategorię stanowią też sekwencje – zapewniają one sekwencyjne nadawanie kolejnych identyfikatorów tworzonym w obrębie tabeli nowym danym. Ważnym aspektem jest upewnienie się czy podczas migracji danych schematu danych aplikacji nie dochodzi do próby wykorzystania istniejących już zakresów. Prowadzi to do konieczności tzn. przewinięcia sekwencji.

Analizując relacje pomiędzy tabelami przy pomocy odnoszących się do niej zależności oraz istniejących kluczy obcych, zapewniających powiązanie danych pomiędzy tabelami, możemy także sami pokusić się o konstruowanie zapytań zwracających to co powinno było zostać zapisane przez aplikację, bądź powinno zostać odczytane podczas wykorzystania danej funkcji pobierającej dane. O wykorzystaniu języka SQL do weryfikacji danych aplikacji i testach bezpieczeństwa pod kątem tzw. wstrzyknięć kodu SQL czyli SQL injection oraz o przydatnych poleceniach języka SQL i PL/SQL opowiemy w kolejnym odcinku 🙂