R-04-07.doc

(264 KB) Pobierz
PLP - Rozdział 4: Interfejsy PostgreSQL

Rozdział 4. Interfejsy PostgreSQL

Po zapoznaniu się z podstawowym sposobem interaktywnego dostępu do bazy PostgreSQL z interpretera psql, który korzysta z języka SQL, możemy zająć się sprawą dostępu do bazy danych z kodu programu. Odbywa się to bardzo podobnie i wszystkie znane polecenia używane dotychczas w wierszu poleceń działają w kodzie niemal natychmiast.

Dostęp do PostgreSQL z kodu programu

Do baz PostgreSQL można uzyskać dostęp z wielu języków programowania. Autorzy znają jedynie takie:

q       C

q       C++

q       Java

q       Perl

q       Python

q       PHP

q       Tcl

Prawdopodobnie istnieją jeszcze inne języki obsługujące PostgreSQL, ale o nich na razie nic nie wiemy.

Istnieje także sterownik ODBC, który umożliwia dostęp z wielu innych systemów, włącznie z klientami MS Windows, które mogą korzystać ze źródeł danych ODBC, takimi jak na przykład Access.

Głównym językiem używanym w przykładach w naszej książce jest język C i z tego właśnie języka chcemy mieć dostęp do naszej bazy danych PostgreSQL. Istnieją dwie metody uzyskiwania dostępu do PostgreSQL z kodu programu.

q       Pierwszą jest utrzymane w tradycyjnym stylu korzystanie z biblioteki o nazwie libpq. W celu uzyskania dostępu do bazy trzeba wywoływać funkcje biblioteczne z kodu programu.

q       Druga metoda polega na osadzaniu poleceń SQL w kodzie języka C i ich przetwarzaniu przez preprocesor przed ostateczną kompilacją. Według terminologii PostgreSQL nazywa się to ecpg. Jest to podejście bardzo podobne do użycia preprocesora języka C przetwarzającego polecenia #include i #define przed przekazaniem kodu do głównego kompilatora. Zagadnienie to z pewnością jest znane użytkownikom niektórych komercyjnych produktów, takich jak PRO*C firmy Oracle i ESQLC firmy Informix, ponieważ każdy z nich spełnia w większym lub mniejszym stopniu standard ANSI opisujący osadzanie poleceń SQL.

W tym rozdziale pokażemy praktyczne zastosowanie obydwu metod, co ułatwi dokonanie wyboru metody najwłaściwszej dla potrzeb użytkownika lub najwygodniejszej do pracy.

Biblioteka libpq

Ogólnie rzecz biorąc, funkcje występujące w bibliotece libpq można pogrupować na trzy następujące kategorie:

q       Funkcje do zarządzanie połączeniami.

q       Funkcje służące do uruchamiania poleceń SQL.

q       Funkcje zwracające wyniki zapytań.

Omówimy te grupy po kolei. W bibliotece libpq przez lata zgromadziły się pewne przestarzałe funkcje, które są utrzymywane tylko dla zachowania zgodności ze starymi wersjami. Nie będziemy się tu nimi zajmować i pokażemy tylko te, które powinny być używane w nowszych programach. Jeśli przy przeglądaniu jakiegoś starszego kodu libpq spostrzeżemy nieznane wywołania funkcji bibliotecznych, to zawsze możemy zapoznać się z nimi w dokumentacji dostępnej na stronie internetowej PostgreSQL pod adresem: http://www.postgresql.org.

Aby skorzystać z którejś funkcji libpq, należy:

q       Dołączyć plik nagłówkowy libpq-fe.h.

q       Dopisać katalog pgsql do ścieżki zawierającej biblioteki dołączane podczas kompilacji.

q       Skonsolidować program z biblioteką pq.

Końcówka „fe” w nazwie libpq-fe oznacza interfejs (od słów front-end). Aby skompilować plik używający libpq, należy użyć polecenia:

 

$ gcc -o program -I/usr/include/pgsql program.c -lpg

Oczywiście, szczegółowe parametry zależą od położenia katalogów instalacyjnych w danym systemie. Jeśli znajdują się one w innym miejscu, to trzeba będzie inaczej określić położenie katalogu zawierającego pliki dołączane i wskazać alternatywny katalog biblioteki za pomocą opcji -L/usr/local/pgsql/lib.

Funkcje do obsługi połączeń z bazą danych

Zaleca się połączenia z bazą danych PostgreSQL za pomocą polecenia PQconnectdb. Czasem należy użyć opcji -i, gdy ma być uruchomiony demon postmaster nasłuchujący na gniazdach TCP/IP i domeny UNIX.

 

PGconn *PQconnectdb(const char *conninfo);

Napis conninfo definiujący połączenie może zawierać sekwencję parametrów i wartości oddzielonych spacjami. Jeżeli w samej wartości ma znaleźć się spacja, to należy ją ująć w apostrofy. Parametry, którym nie nadaje się wartości w sposób jawny, uzyskują domyślnie wartości NULL. Również funkcje biblioteczne uzyskują wartości domyślne lub wartości zdefiniowane przez zmienne środowiskowe. Można definiować następujące parametry połączenia:

 

host

Nazwa komputera, z którym będzie zestawiane połączenie. Domyślnie jest to komputer lokalny.

port

Numer portu, na którym będzie utrzymywane połączenie. Domyślnie jest to standardowy port używany przez PostgreSQL o numerze 5432.

dbname

Nazwa bazy danych, z którą chcemy się połączyć. Domyślnie jest to taka sama nazwa jak nazwa zalogowanego użytkownika systemu Linux.

user

Nazwa użytkownika bazy danych. Domyślnie jest to nazwa używana przy logowaniu.

password

Hasło dostępu do bazy.

options

Wymagane opcje śledzenia.

tty

Plik lub terminal używany jako wyjście komunikatów o błędach wytwarzanych przez program.

Za każdym parametrem następuje znak równości, a następnie wartość tego parametru. Do połączenia się np. z bazą template1 na komputerze gw1 należy użyć następującego polecenia:

 

conn = PQconnectdb("host=gw1 dbname=template1");

Wskaźnik o wartości NULL jest zwracany tylko wtedy, gdy biblioteka nie zdoła przydzielić obiektu, z którym ma nastąpić połączenie. Nawet jeśli otrzymamy wskaźnik nie mający wartości NULL, to nadal trzeba sprawdzać, czy połączenie nastąpiło — musimy w tym celu wywoływać funkcję PQstatus.

 

ConnStatusType PQstatus(PGconn *conn);

Funkcja ta zwraca jedną z dwóch wartości: albo CONNECTION_OK, albo CONNECTION_BAD. Znaczenie ukryte jest w ich nazwach. Po udanym nawiązaniu połączenia z bazą pozostaje ono w takim stanie, chyba że występują problemy z siecią lub oddalona baza danych zostanie zamknięta.

Jeśli występują problemy z połączeniem, to tekst komunikatu o błędzie można uzyskać poprzez wywołanie funkcji:

 

char *PQerrorMessage(PGconn *conn);

Funkcja ta zwraca wskaźnik do ustalonego obszaru pamięci, a więc dany tekst komunikatu może być tekstem generowanym przy późniejszych wywołaniach funkcji z biblioteki libpq. Jeśli trzeba zamknąć połączenie z powodu zakończenia pracy programu lub awarii, należy czynić to za pomocą funkcji:

 

void PQfinish(PGconn *conn);

Funkcja ta musi być zawsze wywoływana, nawet gdy połączenie się nie udało. Jest to potrzebne, ponieważ powoduje ona nie tylko zamknięcie połączenia z bazą, ale także zwolnienie obszaru pamięci i innych zasobów związanych z połączeniem. Niewłaściwie zamknięte połączenie może spowodować, że program będzie wymagał nadmiernego zwiększenia zasobów systemowych.

Po zamknięciu połączenia wskaźnik obiektu połączeniowego nie oznacza niczego sensownego i nie może być przekazywany jako parametr do jakichkolwiek funkcji. Dobrym zwyczajem programisty powinno być nadanie mu wartości NULL tuż po wywołaniu funkcji PQfinish.

Znamy już kilka funkcji i możemy napisać pierwszy program służący do połączenia się z serwerem PostgreSQL. Nie będzie on wprawdzie zbyt użyteczny, ponieważ służy tylko do testowania połączenia, ale dzięki niemu uczynimy pierwszy krok. Musimy pamiętać o zmianie nazwy serwera i użytkownika na nazwy używane lokalnie, oraz o utworzeniu bazy danych o nazwie takiej jak nazwa użytkownika (tworzenie bazy opisaliśmy w poprzednim rozdziale).

 

#include <stdlib.h>

#include <stdio.h>

#include <libpq-fe.h>

 

int main()

{

 

   PGconn *conn;

   const char *connection_str = "host=localhost dbname=template1";

 

   conn = PQconnectedb(connection_str);

   if (PQstatus(conn) == CONNECTION_BAD) {

      fprintf(stderr, "Connection to %s failed, %s, connection_str,

PQerrorMessage(conn));

   } else {

      printf("Connected OK\n");

   }

   PQfinish(conn);

   return EXIT_SUCCESS;

}

Program ten bardzo łatwo można przeanalizować: najpierw tworzony jest napis używany jako parametr połączenia z bazą template1 na serwerze localhost, potem następuje próba połączenia, wyświetlenie komunikatu (jeżeli wystąpi błąd) i zamknięcie połączenia przed zakończeniem działania programu.

Uruchamianie poleceń SQL

Okazuje się niespodziewanie, że uruchamianie zapytań na serwerze jest bardzo proste. Istnieje tylko jedna funkcja służąca do wywołania polecenia i trzy funkcje wykorzystywane do sprawdzenia wyniku i odczytu informacji o błędach. Uruchomienie polecenia SQL odbywa się następująco:

 

PGresult *PQexec(PGconn *conn, const char *sql_string);

Funkcja ta zwraca wskaźnik o wartości NULL tylko w nadzwyczajnych okolicznościach, więc musi on być przechwytywany, ponieważ w przeciwnym wypadku można otrzymać wyniki na podstawie wskaźnika innej funkcji:

 

ExecStatusType *PQresultStatus(PGresult *result);

Wynik zawiera wyliczenie typu ExecStatusType, które ma jedną z podanych niżej wartości:

 

PGRES_EMPTY_QUERY

Nic nie zostało zrobione.

PGRES_COMMAND_OK

Polecenie zostało wykonane poprawnie, lecz żadne dane nie zostały zwrócone, ponieważ nie było to polecenie SELECT.

PGRES_TUPLES_OK

Polecenie zostało wykonane poprawnie i jakieś dane mogły być zwrócone.

PGRES_COPY_OUT

Trwa operacja kopiowania do pliku zewnętrznego.

PGRES_COPY_IN

Trwa operacja kopiowania z pliku zewnętrznego.

PGRES_BAD_RESPONSE

Zdarzyło się coś nieoczekiwanego.

PGRES_NONFATAL_ERROR

Wystąpił błąd niekrytyczny.

PGRES_FATAL_ERROR

Wystąpił błąd krytyczny.

Zwróćmy szczególną uwagę na definicję PGRES_TUPLES_OK. Otrzymanie takiej odpowiedzi oznacza, że polecenie SELECT zostało wykonane poprawnie, ale jednocześnie nie znaczy to, że jakieś dane zostały zwrócone. W następnym podrozdziale zobaczymy, jak sprawdzić, czy rzeczywiście dane zostały zwrócone. Błędy typu COPY dotyczą ładowania bazy danych lub tworzenia kopii zapasowej tej bazy.

Jeśli chcemy otrzymać tekst komunikatu o błędzie, to używamy funkcji:

 

const char *PQresultErrorMessage(PGresult *result);

Zauważmy, że tekstowy komunikat o błędzie otrzymujemy tu w inny sposób niż przy funkcjach obsługujących połączenia, gdzie stosuje się PQerrorMessage...

Zgłoś jeśli naruszono regulamin