Gadfly (baza danych)

Giez
Deweloperzy Aarona Roberta Wattersa
Pierwsze wydanie 1994 ; 29 lat temu ( 1994 )
Wersja stabilna
1.0 / 5 stycznia 2005 ; 18 lat temu ( 05.01.2005 )
Napisane w Pyton
System operacyjny Międzyplatformowe
Typ System zarządzania relacyjną bazą danych
Licencja Licencja Pythona
Strona internetowa Gadfly .sourceforge .net

Gadfly to system zarządzania relacyjną bazą danych napisany w języku Python . Gadfly to zbiór modułów Pythona, który zapewnia funkcjonalność relacyjnej bazy danych w całości zaimplementowaną w Pythonie. Obsługuje podzbiór standardowego RDBMS Structured Query Language (SQL) .

Gadfly działa wszędzie tam, gdzie działa Python i obsługuje klienta / serwer na dowolnej platformie obsługującej standardowy interfejs gniazd Pythona . Formaty plików używane przez Gadfly do przechowywania są wieloplatformowe — katalog bazy danych gadfly można przenieść z systemu Windows 95 do systemu Linux za pomocą mechanizmu kopiowania binarnego, a gadfly odczyta i uruchomi bazę danych.

Obsługuje trwałe bazy danych składające się ze zbioru ustrukturyzowanych tabel z indeksami oraz dużego podzbioru SQL do uzyskiwania dostępu i modyfikowania tych tabel. Obsługuje protokół odzyskiwania oparty na logach, który umożliwia odzyskanie zatwierdzonych operacji bazy danych , nawet jeśli baza danych nie została zamknięta [ wymagane wyjaśnienie ] we właściwy sposób (tj. w przypadku awarii procesora lub oprogramowania [ale nie w przypadku awarii dysku]). Obsługuje również TCP/IP Klient/Serwer, w którym zdalni klienci mogą uzyskiwać dostęp do bazy danych Gadfly przez sieć TCP/IP (taką jak Internet) z zastrzeżeniem konfigurowalnych mechanizmów bezpieczeństwa.

Ponieważ Gadfly ściśle zależy od pakietu kw Parsing , jest dystrybuowany jako część pakietu kwParsing, z tymi samymi prawami autorskimi.

Gadfly umożliwia programom Pythona przechowywanie, pobieranie i przeszukiwanie danych tabelarycznych bez konieczności polegania na zewnętrznym silniku bazy danych lub pakiecie. Zapewnia silnik relacyjnej bazy danych w pamięci dla programów w Pythonie, wraz z pojęciem „zatwierdzonej, możliwej do odzyskania transakcji” i „przerwania”. [ potrzebne źródło ]

Stosowanie

Główny moduł „gadfly” stara się wiernie przestrzegać interfejsu API bazy danych Python Grega Steina , zgodnie z omówieniem i certyfikatem Python DB-SIG.

Jednoczesne aktualizacje baz danych nie są obsługiwane. „Bazy danych” są obecnie zaprojektowane do zapisywania/modyfikowania przez jeden proces w izolacji. Wiele procesów może uzyskiwać dostęp [ wymagane wyjaśnienie ] do bazy danych Gadfly, gdy dostępy są rozstrzygane przez proces serwera Gadfly protokołu TCP/IP.

Tworzenie nowej bazy danych

W przeciwieństwie do większości interfejsów Pythona/silnika bazy danych, bazy danych Gadfly muszą być tworzone przy użyciu Pythona. Aby to osiągnąć, programiści używają:

 
   importuj  połączenie  gadfly  =  gadfly  .  bąbel  () 

bez argumentów. Następnie uruchamiają bazę danych przy użyciu metody uruchamiania:

  połączenie  .  uruchomienie  (  "mojabaza danych"  ,  "mójkatalog"  ) 

Tutaj „mydirectory” musi być katalogiem, który istnieje i do którego można zapisywać pliki bazy danych. Startup tworzy niektóre pliki w „mydirectory”. Powoduje to zablokowanie dowolnej istniejącej bazy danych Gadfly o nazwie „mydatabase” w katalogu „mydirectory”. Gadfly nie pozwoli jednak na dwukrotne uruchomienie tego samego połączenia.

Pierwszy „ gadfly importu ” wczytuje i inicjuje dość duże struktury danych używane do analizowania SQL, a zatem może trwać dłużej niż import innych modułów.

W bazie danych użytkownik może tworzyć tabele, wypełniać je i zatwierdzać wynik, gdy jest zadowolony:

  



   
     
    
 kursor  =  połączenie  .  kursor  ()  kursor  .  wykonaj  (  „UTWÓRZ TABELĘ ph (nm VARCHAR, ph VARCHAR)”  )  kursor  .  wykonaj  (  "WSTAW W WARTOŚCI ph(nm, ph) ('arw', '3367')"  )  kursor  .  wykonaj  (  "SELECT * FROM ph"  )  dla  x  w  kursorze  .  fetchall  ():  print  x  # drukuje ('arw', '3367')  połączenie  .  popełnić  () 

Ponowne łączenie z istniejącą bazą danych

Gdy baza danych istnieje, można ją ponownie połączyć z:

 
    importuj  połączenie  gadfly  =  gadfly  .  gadfly  (  "mojabaza danych"  ,  "mójkatalog"  ) 

Spowoduje to odczytanie w tabelach bazy danych z ostatnio zatwierdzonymi wartościami. Zainicjowana baza danych jest następnie przeszukiwana i aktualizowana:

  


   
     
     kursor  =  połączenie  .  kursor  ()  kursor  .  wykonać  (  "UPDATE ph SET nm='aaron' WHERE nm='arw'"  )  kursor  .  wykonaj  (  "SELECT * FROM ph"  )  dla  x  w  kursorze  .  fetchall  ():  print  x  # prints ('aaron', '3367') 

Jeśli użytkownik nie chce zatwierdzić aktualizacji, nie wykonuj zatwierdzenia na obiekcie połączenia (który zapisuje tabele). Aby przywrócić stare wartości z istniejącej bazy danych, używają:

 połączenie  .  przerwać  () 

Aktualizacje są zapisywane tylko po wywołaniu connection.commit(). [Właściwie, jeśli automatyczny punkt kontrolny jest wyłączony, aktualizacje są zapisywane tylko w plikach tabeli w punkcie kontrolnym — patrz dokumentacja mechanizmu odzyskiwania.]

  wydrukować  kursor  .  pp  () 

aby „ładnie wydrukować” wynik dowolnej oceny (która może być Brak dla braku wyboru).

Cechy

W tej wersji wszystkie tabele są wczytywane do pamięci po "połączeniu" z bazą danych, a "dotknięte" tabele są wypisywane w punkcie kontrolnym. Każda tabela jest reprezentowana jako osobny plik w katalogu docelowym, istnieje również plik „definicji danych” (lista deklaracji definicji danych). Podczas aktywnego użytkowania plik dziennika pojawia się również w katalogu aktywnym, a jeśli proces ulegnie awarii, ten plik dziennika jest używany do odzyskania zatwierdzonych operacji.

Instrukcja SELECT

W tym momencie Gadfly obsługuje całkiem sporo semantyki SQL wymaganej w specyfikacji ODBC 2.0. Obsługiwane instrukcje SQL obejmują SELECT:

    
   
     
      
     
    
       WYBIERZ  [  RÓŻNE  |  ALL  ]  wyrażenia  lub  tabele  *  FROM  [  warunek  WHERE  ]  [  GROUP  BY  wyrażenia  grupowe  ]  [  HAVING  warunek  agregacji  ]  [  klauzula  sumy  ]  [  ORDER  BY  kolumny  ]  _  _  _ 

To stwierdzenie jest dość mocne. Brzmi następująco:

  1. Wykonaj wszystkie kombinacje wierszy z tabel (wiersz Z)
  2. Wyeliminuj te kombinacje, które nie spełniają warunku (linia WHERE)
  3. (jeśli występuje GROUP) tworzą grupy zagregowane, które pasują do wyrażeń grupowych
  4. (jeśli MAJĄ obecne) wyeliminuj grupy zagregowane, które nie spełniają warunku zagregowania.
  5. oblicz kolumny do zachowania (linia SELECT).
  6. (jeśli obecna jest klauzula sumy) łączy (sumę, różnicę, przecięcie) wynik z wynikiem innej instrukcji select.
  7. jeśli DISTINCT, wyrzuć zbędne wpisy.
  8. (jeśli występuje ORDER) uporządkuj wynik według kolumn (rosnąco lub malejąco, jak określono, z priorytetem zgodnie z listą).

Rzeczywista implementacja w gadfly jest znacznie lepsza niż intuicyjne czytanie, szczególnie w krokach 1 i 2 (które są łączone poprzez optymalizację transformacji i algorytmy łączenia skrótów).

Warunki mogą obejmować równości i nierówności wyrażeń. Warunki można również łączyć za pomocą AND, OR, NOT. Wyrażenia obejmują nazwy kolumn, stałe i standardowe operacje arytmetyczne na nich.

Obsługiwane zapytania osadzone obejmują wyrażenia podzapytania, expr IN (wybór podrzędny), porównania ilościowe i predykat EXISTS (wybór podrzędny).

Zagregowane testy i obliczenia można zastosować tylko po GRUPOWANIU i przed wybraniem kolumn (kroki 3,4,5). Operacje agregujące obejmują COUNT(*), COUNT(wyrażenie), AVG(wyrażenie), SUMA(wyrażenie), MAX(wyrażenie), MIN(wyrażenie) i niestandardową MEDIAN(wyrażenie). Można je zastosować do wartości DISTINCT (wyrzucając nadmiarowość, jak w przypadku COUNT(DISTINCT pijący). jeśli nie ma funkcji GRUPOWANIE, obliczenia zbiorcze mają zastosowanie do całego wyniku po kroku 2.

O instrukcji SELECT można dowiedzieć się znacznie więcej. Zestaw testów test/test_gadfly.py zawiera liczne przykłady instrukcji SELECT.

Tworzenie tabel i „typy danych”

Utwórz tabele za pomocą instrukcji CREATE TABLE:

        CREATE  TABLE  name  (  nazwa_kolumny  typ danych  [,  nazwa_kolumny  typ danych  ...]) 

Typy danych obecnie „obsługiwane” to integer , float i varchar . Są one ignorowane przez implementację, wszystko, co można haszować i łączyć, może obecnie przejść do dowolnej kolumny (ale to prawdopodobnie się zmieni). Na przykład:

  
 
 
  UTWÓRZ  TABELĘ  bywalców  (  pijący  VARCHAR  ,  bar  VARCHAR  ,  tygodniowo  INTEGER  ) 

Obecnie krotki, kompleksy lub cokolwiek innego można umieścić w kolumnie określonej jako „VARCHAR”.

Inne obsługiwane instrukcje

Gadfly obsługuje również wyszukiwane USUŃ i UPDATE; INSERT VALUES i INSERT subselect; UTWÓRZ/USUŃ INDEKS i USUŃ TABELĘ. Mają one nieformalną składnię:

    
       
         
      
        
  
   DELETE  FROM  tabela  WHERE  warunek  UPDATE  tabela  SET  kol  =  wyrażenie  [,  kol  =  wyrażenie  ...]  WHERE  warunek  INSERT  INTO  tabela  [(  kolumna  [,  kolumna  ...])]  WARTOŚCI  (  wartość  [,  wartość  ...])  WSTAW  DO  table  [(  kolumna  [,  kolumna  ...])]  subselect  CREATE  [  UNIQUE  ]  INDEX  nazwa  ON  table  (  kolumna  [,  kolumna  ...])  DROP  TABLE  table  DROP  INDEX  name 

Wiele instrukcji może być wykonanych w jednym kursorze.execute(S) poprzez oddzielenie instrukcji średnikami w S, na przykład S może mieć wartość ciągu:

  
   INDEKS  USUWANIA  tdindex  ;  DROP  TABLE  tymczasowo lubi 

SQL nie rozróżnia wielkości liter.

Wartości dynamiczne

Wyrażenia obejmują również wyrażenie specjalne „?” (wyrażenie dynamiczne w stylu ODBC) jak w:

  
  
  
   insertstat  =  "WSTAWIĆ DO WARTOŚCI ph(nm,ph) (?,?)"  kursor  .  wykonaj  (  wstawstat  ,  (  'nan'  ,  "0356"  ))  kursor  .  wykonaj  (  wstawstat  ,  (  "rachunek"  ,  "2356"  ))  kursor  .  wykonaj  (  wstawstat  ,  (  'tom'  ,  "4356"  )) 

Wartości dynamiczne umożliwiają kursorowi wielokrotne użycie tego samego przeanalizowanego wyrażenia dla podobnej operacji. Powyżej insertstat jest analizowany i wiązany z bazą danych tylko raz. Korzystanie z atrybutów dynamicznych powinno przyspieszyć dostępy. Zatem powyższe powinno działać znacznie szybciej niż odpowiednik:



 kursor  .  wykonaj  (  „WSTAW DO WARTOŚCI ph(nm,ph) („nan”, „0356”)”  )  kursor  .  wykonaj  (  „WSTAW DO WARTOŚCI ph(nm,ph) („rachunek”, „2356”)”  )  kursor  .  wykonaj  (  "WSTAW DO WARTOŚCI ph(nm,ph)('tom', '4356')"  ) 

Atrybuty dynamiczne mogą pojawiać się w innych instrukcjach zawierających wyrażenia (takie jak SELECT, UPDATE i DELETE).

Dla SELECT, UPDATE i DELETE podstawienia wyrażeń dynamicznych muszą składać się z pojedynczej krotki, jak w:

    
   
  
   
   stat  =  "WYBIERZ * Z ph GDZIE nm=?"  kursor  .  wykonaj  (  stat  ,  (  "nan"  ,))  ...  kursor  .  wykonaj  (  stat  ,  (  "bob"  ,))  ... 

Ponieważ dynamiczne podstawienie eliminuje potrzebę analizowania i wiązania (kosztowne operacje!), powyższe powinno działać szybciej niż jego odpowiednik:

 
 
 
  kursor  .  wykonaj  (  "SELECT * FROM ph WHERE nm='nan'"  )  ...  kursor  .  wykonaj  (  "SELECT * FROM ph WHERE nm='bob'"  )  ... 

Jeśli kilka podobnych zapytań jest powtarzanych wiele razy, każde zapytanie „ciąg szablonu” jest powiązane z unikalnym obiektem kursora, tak że każdy szablon musi być analizowany i powiązany tylko raz. Niektóre stosunkowo złożone zapytania z zestawu testów działają 2 do 3 razy szybciej po przeanalizowaniu i powiązaniu, nawet bez wbudowanego kjbuckets. Z kjbuckets to samo działało od 5 do 10 razy szybciej.

Wiele wstawek wsadowych i wartości dynamicznych

W szczególnym przypadku INSERT VALUES lista krotek zastępczych umożliwia mechanizmowi zapytań wykonywanie operacji wstawiania w zoptymalizowanym trybie wsadowym. Tak więc najszybszym sposobem wykonania trzech podanych wcześniej wstawek jest:

       
  
  data  =  [(  'nan'  ,  "0356"  )),  (  'bill'  ,  "2356"  ),  (  'tom'  ,  "4356"  )]  stat  =  "WSTAWIĆ DO WARTOŚCI ph(nm,ph) (?, ? )"  kursor  .  wykonywać  (  statystyka  ,  dane  ) 

Byłoby jeszcze szybciej, gdyby kursor wcześniej wykonał statystykę z innymi danymi (od tego czasu nie wystąpiłoby żadne parsowanie ani wiązanie).

Introspekcja

Domyślnie baza danych gadfly automatycznie zawiera „introspektywne” tabele, które umożliwiają zapytaniu gadfly „zapytanie o kształt bazy danych” - na przykład w celu wyświetlenia nazw tabel i nazw wierszy w tabelach:

  
 
  

 







 >>>  g  =  gadżet  ()  >>>  g  .  start  (  "test bazy danych"  ,  "test bazy danych"  )  >>>  c  =  g  .  kursor  ()  >>>  c  .  wykonaj  (  "wybierz * z __table_names__"  )  >>>  print  c  .  pp  ()  IS_VIEW | NAZWA_TABELI   =========================  1 | __NAZWY_TABELI__   1 | PODWÓJNY   1 | __DATADEFS__   1 | __KOLUMNY__   1 | __WSKAŹNIKI__   1 | __INDEKSKOLE__  

Tutaj DUAL jest standardową tabelą testową z jednym wierszem/jedną kolumną (z tradycji Oracle), a inne tabele dostarczają informacji o schemacie bazy danych:






 











 



















 





 





 

 >>>  c  .  wykonaj  (  „utwórz tabelę t1 (a varchar, b varchar)”  )  >>>  c  .  wykonaj  (  „utwórz tabelę t2 (b varchar, c varchar)”  )  >>>  c  .  wykonaj  (  „utwórz unikalny indeks t1a na t1(a)”  )  >>>  c  .  wykonaj  (  „utwórz indeks t1b na t1(b)”  )  >>>  c  .  wykonaj  (  "wybierz * z __table_names__"  )  >>>  print  c  .  pp  ()  IS_VIEW | NAZWA_TABELI   =========================  0 | T1   1 | __DATADEFS__   1 | __WSKAŹNIKI__   0 | T2   1 | __NAZWY_TABELI__   1 | __KOLUMNY__   1 | PODWÓJNY   1 | __INDEXCOLS__   >>>  c  .  wykonaj  (  „wybierz * z __kolumn__”  )  >>>  drukuj  c  .  pp  ()  NAZWA_KOLUMNY | NAZWA_TABELI   =============================  A | T1B   | T1   NAZWA | __DATADEFS__   DEFN | __DATADEFS__   INDEX_NAME | __INDICES__   NAZWA_TABELI | __INDICES__   IS_UNIQUE | __INDICES__   NAZWA_TABELI | __TABLE_NAMES__   IS_VIEW | __TABLE_NAMES__   B | T2   C | T2   KOLUMNA 1 | PODWÓJNA   NAZWA_TABELI | __COLUMNS__   NAZWA_KOLUMNY | __KOLUMNY__   NAZWA_INDEKSU | __INDEXCOLS__   NAZWA_KOLUMNY | __INDEXCOLS__   >>>  c  .  wykonaj  (  „wybierz * z __indeksów__”  )  >>>  drukuj  c  .  pp  ()  IS_UNIQUE | NAZWA_TABELI |  INDEX_NAME   ===================================  0 | T1 |  T1B   1 | T1 |  T1A   >>>  c  .  wykonaj  (  „wybierz * z __indexcols__”  )  >>>  drukuj  c  .  pp  ()  NAZWA_KOLUMNY | INDEX_NAME   ========================  B | T1B   A | T1A   >>>  c  .  wykonaj  (  „wybierz * z podwójnego”  )  >>>  drukuj  c  .  pp  ()  KOLUMNA1  ======= 
0

Testy interaktywne

Po instalacji utworzoną bazę danych można interaktywnie przetestować z tego samego katalogu za pomocą interaktywnego interpretera:





   
   
  




 












 Python 2.1.3 (#1, 30 kwietnia 2002, 19:37:40)  [GCC 2.96 20000731 (Red Hat Linux 7.1 2.96-96)] na linux2  Aby uzyskać więcej informacji, wpisz „copyright”, „credits” lub „license”.  >>>  >>>  from  gadfly  import  gadfly  >>>  connection  =  gadfly  (  "test"  ,  "dbtest"  )  >>>  kursor  =  połączenie  .  kursor  ()  >>>  kursor  .  wykonaj  (  „wybierz * z częstych”  )  >>>  kursor  .  opis  (('PIJĄCY', Brak, Brak, Brak, Brak, Brak, Brak), ('PERWEEK', Brak, Brak, Brak, Brak, Brak, Brak), ('BAR', Brak, Brak, Brak,  Brak , Brak, Brak))  >>>  drukuj  kursor  .  pp  ()  PIJĄCY | TYGODNIOWO |  BAR   ============================  Adam | 1 |  lolas   woody | 5 |  pozdro   sam | 5 |  na zdrowie   norma | 3 |  zdrowie   więdną | 2 |   norma  Joesa |   1 | Joe   Lola | 6 |  lolas   norma | 2 |  lolas   woody | 1 |  lolas   pierre | 0 |  franki   >>> 

Architektura

Gramatyka SQL jest opisana w grammar.py, wiązanie konstrukcji gramatycznych z obiektami semantycznymi jest wykonywane w bindings.py, obiekty semantyczne i ich strategie wykonania są zdefiniowane w semantics.py. Semantyka wykorzystuje wiele klasycznej i nieklasycznej logiki ( logiki cylindrycznej ), a także heurystyki optymalizacyjnej, aby zdefiniować stosunkowo wydajną i poprawną implementację SQL.

Najbardziej podstawowe struktury danych implementacji są podane w kjbuckets0.py lub szybszym kjbucketsmodule.c, które implementują te same sygnatury typów danych odpowiednio w Pythonie iw rozszerzeniu C do Pythona.

Moduł database.py to proste opakowanie, które zapewnia systemowi standardowy interfejs DBAPI.

Zestaw testów test/test_gadfly.py próbuje zapewnić test regresji i demonstrację systemu.

Parser SQL wymaga również pakietu generującego parser kwParsing, który składa się z szeregu dodatkowych modułów Pythona.

Narzędzia

Dzięki gfplus bazą danych gadfly można interaktywnie manipulować za pomocą poleceń SQL. Narzędzie działa podobnie do SQL*Plus firmy Oracle .

Konkurencja

Ponieważ brakuje mu prawdziwej kontroli współbieżności i indeksowania opartego na systemie plików, nie nadaje się do bardzo dużych wieloprocesowych systemów opartych na transakcjach .

Dwie aplikacje mogą jednocześnie uzyskiwać dostęp do tej samej bazy danych. Jednak zmiany wprowadzone przez jedną aplikację mogą być widoczne dla drugiej aplikacji dopiero po jej ponownym uruchomieniu. Może to być spowodowane tym, że każda aplikacja ładuje bazę danych w pamięci tylko podczas uruchamiania.

Linki zewnętrzne