Jako, że w MySQL nie dzieje się najlepiej postanowiliśmy zmigrować jeden z naszych projektów na Postgresa. Bazuje on na Symfony 1.1, co oznacza starego Propela 1.2.
Samo przestawienie połączenia nie stwarzało większych problemów, wystarczyło w databases.yml i propel.ini przerobić mysql na pgsql:
all:
propel:
class: sfPropelDatabase
param:
persistent: true
phptype: pgsql
…
propel.database = pgsql
propel.database.createUrl = pgsql://zdzislaw@localhost/
propel.database.url = pgsql://zdzislaw@localhost/piwo
Oczywiście o przebudowaniu modelu, utworzeniu bazy i jej struktury nie ma co wspominać :)
Brak SERIAL
Niestety, propelowy generator skyptu SQL tworzącego schemat bazy nie uraczył nas typem SERIAL przy identyfikatorach, jednakże w samej aplikacji nie stwarza to problemów, ponieważ sekwencje i tak są wykorzystywne. Trzeba po prostu uważać podczas zabawy w CLI Postgresa.
Dane binarne pobierane „ręcznie”
Drobny problem pojawił się, w miejscach, gdzie pobieraliśmy dane binarne (BLOB/BYTEA) własnym zapytaniem, omijając nieco wbudowany we framework Active Record. Dane takie trzeba było dodatkowo „od-eskejpować” funkcją stripcslashes.
AKTUALIZACJA:
Po aktualizacji projektu do Symfony 1.2 (chociaż tutaj właściwie chodzi o aktualizację Propela do wersji 1.3) okazało się, że żadne stripcslashes nie będzie potrzebne, ponieważ dane binarne (blob) są pobierane jako… stream. Innymi słowy, przy zapytaniach tworzonych samodzielnie, do akcji musiała wkroczyć funkcja stream_get_contents.
GROUP BY
Najwięcej problemów sprawiło grupowanie, ponieważ Postgres ostro trzyma się standardów i wymusza podanie wszystkich kolumn, które są używane, w klauzuli GROUP BY. MySQL natomiast „po cichu” sam sobie je dołączał. Różnicę w zachowaniu prezentuje poniższy (nie mający większego sensu) przykład:
psql=# select sum(id), id from users;
ERROR: column "users.id" must appear in the GROUP BY clause or be used in an aggregate function
mysql> select sum(id), id from users;
+---------+----+
| sum(id) | id |
+---------+----+
| 45 | 1 |
+---------+----+
CONCAT
Łącznie ciągów znaków odbywa się całkiem inaczej w MySQL i PgSQL. W tym pierwszym wykonuje się to za pomocą funkcji CONCAT(), natomiast w drugim wykorzystuje się operator ||.
FORMAT
W naszym kodzie używaliśmy MySQL-owego FORMAT(), aby ograniczyć liczbę cyfr po przecinku, którego w Postgresie nie ma. Można by tutaj użyć funkcji ROUND(), obecnej i tu i tu, jednak zdecydowaliśmy się przenieść rozwiązanie tego problemu do warstwy języka programowania.
LIKE
LIKE w Postgresie, w przeciwieństwie do MySQL, rozróżnia wielkość znaków. Jednak naprawa tej przypadłości sprowadza się jedynie od zamiany LIKE na ILIKE.
?
Na koniec coś, czego do końca nie udało nam się zrozumieć. Zaraz po przestawieniu konfiguracji na pgsql, strona przestała odpowiadać (a dokładniej odpowiadała gdy połączenie z bazą przekroczyło czas oczekiwania). Niemniej jednak Postgres sam w sobie działał, jak również możliwe było połączenie z „czystego” PHP. Jedynie aplikacja Symfony dziwnie się zachowywała. W logach pojawiało się następujące stwierdzenie:
Dec 4 11:20:22 myhost httpd: [wrapped: Could not connect [Native Error: pg_pconnect() [function.pg-pconnect]: Unable to connect to PostgreSQL server: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request.] [User Info: host=localhost port=80 dbname='piwo' user='zdzislaw'] [User Info: Array]]
Taka sama sytuacja powtórzyła się na dwóch różnych maszynach (jednak na tym samym systemie operacyjnym). Niezrozumiałe jest to, że w czasie różnych zabaw z konfiguracją wszystko wracało do normy, jednak nie bardzo da się znaleźć konkretną przyczynę. Innymi słowy nie potrafimy zreprodukować tej sytuacji.
Krótko podsumowując — migracja rozwiniętego projektu w Symfony nie jest bardzo trudna, chociaż zawsze mogłaby być mniej problematyczna, gdyby unikać rozwiązań specyficznych dla danego systemu baz danych. Ale czy warto?