php - pgsql
Valaki használta már a php-t postgresql-el?
Van több gondom is vele, a tárolt eljárásoknál a pg_ execute elég fura resultset-et ad. A tárolt eljárás neve van benne, a tényleges eredményt meg megpróbálja string-ként összefűzni... Ha kell küldök kódot is, nem tudom hogy javítható. Egyelőre addig se jutottam el, hogy tárolt eljárással kiolvassam egy tábla tartalmát, aztán azt átadjam php-nek. Mysql-ben ez kb annyi lenne, hogyÍrtam pg függvényekre valami hasonlót, mint pdo. Tudom, hogy van pdo lib pgsql-hez is, de a szolgáltatónál egyelőre csak sima pg függvények vannak fent. Majd megkérdem mennyiért telepítenék. Nem tudom, hogy pdo-val is ugyanúgy rossz lenne e az eredmény, majd később kipróbálom...
Azt hittem a plpgsql-el könnyebb dolgom lesz, mint a mysql-el, de nem igazán találtam semmi használható tutorialt eddig. Legalábbis pont erre a feladatra nem, ellenben minden másra igen. :-) Végülis ugyanez megoldható sima pgsql-es tárolt eljárással is, de jobban tetszene, ha menne plpgsql-ből, mert később bármikor szükség lehet rá.Egyelőre eddig jutottam, de teljesen rossz.Ezt kapom vissza.
Ha a returns-ben átírom az id-ket, és beteszek mondjuk az user_id-hez egy as id-t, akkor meg syntax error-t... Nem túl baráti... Az automatikus kiegészítés sem segít valami sokat, pl a TABLE és RECORD típusokat egyáltalán nem is ismeri, pedig ezek közül kéne valamelyiket használni. Mondjuk a legjobb az lenne, ha automatikusan állítaná be a típust, nem nekem kéne kézzel megadni. A táblák alapján elvileg tudnia kéne...
■ Van több gondom is vele, a tárolt eljárásoknál a pg_ execute elég fura resultset-et ad. A tárolt eljárás neve van benne, a tényleges eredményt meg megpróbálja string-ként összefűzni... Ha kell küldök kódot is, nem tudom hogy javítható. Egyelőre addig se jutottam el, hogy tárolt eljárással kiolvassam egy tábla tartalmát, aztán azt átadjam php-nek. Mysql-ben ez kb annyi lenne, hogy
CREATE PROCEDURE `user_read_all`(
)
BEGIN
SELECT `user_id` AS `id`, `user_name` AS `name`, `user_email` AS `email` FROM `user`
ORDER BY `user_id` DESC;
END;
$stmt = $pdo->query('CALL `user_read_all`()');
$stmt->fetchAll();
Azt hittem a plpgsql-el könnyebb dolgom lesz, mint a mysql-el, de nem igazán találtam semmi használható tutorialt eddig. Legalábbis pont erre a feladatra nem, ellenben minden másra igen. :-) Végülis ugyanez megoldható sima pgsql-es tárolt eljárással is, de jobban tetszene, ha menne plpgsql-ből, mert később bármikor szükség lehet rá.
CREATE OR REPLACE FUNCTION user_read_all()
RETURNS table(user_id INT, user_name VARCHAR, user_email VARCHAR)
AS
$BODY$
BEGIN
return query SELECT
user_id, user_name, user_email
FROM
user;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
array(1) { [0]=> array(1) { ["test"]=> string(4) "(,,)" } }
Ha a returns-ben átírom az id-ket, és beteszek mondjuk az user_id-hez egy as id-t, akkor meg syntax error-t... Nem túl baráti... Az automatikus kiegészítés sem segít valami sokat, pl a TABLE és RECORD típusokat egyáltalán nem is ismeri, pedig ezek közül kéne valamelyiket használni. Mondjuk a legjobb az lenne, ha automatikusan állítaná be a típust, nem nekem kéne kézzel megadni. A táblák alapján elvileg tudnia kéne...
select * from list_users()
Na kipróbálom így, select
select user_read_all()
-t használok, azt olvastam így kell, de ezekszerint ha resultsetet ad vissza, akkor úgy, ahogy te írod. Remélem ez a megközelítés működik olyanoknál is, aminél nem várok eredményt, vagy csak egyetlen értéket várok... Majd azt is kipróbálom. Jelenleg írtam egy proxy-t, ami meghívja a tárolt eljárásokat __call-al, az átadott paramétereket meg szövegként átadja. Egyelőre ez a megközelítés elég jól bevált, alternatívája lehet az orm-es megoldásoknak. A mysql szintén alkalmas ilyesmire, viszont a postgresql fejlettebb, azért most azzal próbálkozom...CREATE FUNCTION test ()
Közben rájöttem, hogy kulcsfontosságú úgy lekérni a mezők adatait, hogy elé tegyem a tábla nevét, különben egyszerűen csak null-t tesz be értéknek, és közben még hibaüzenetet sem kapok.
A fenti kód syntax error-t ír, sima sql-ben viszont valid lenne... :S
A query és a SELECT közé nem
Elvileg nem, legalábbis én
Nem, csak beírtam a keresőbe,
Valószínűleg hibás volt, bár
Execute
setof
Ez most jött át. Szerintem a setof-ot keresed.
Köszi, megnézem. Ezekről a
CREATE FUNCTION test ()
A másik, hogy le szeretném vágni az oszlopnevekről a user_ prefix-et.
Na közben rájöttem magamtól:
Ami nekem igazából kéne az a SETOF RECORD, mert php-ben úgyis string-ként kapok meg mindent. Az a kínom, hogy nem működik:
Sajnos a SETOF RECORD és a
Végül itt kötöttem ki:
Function vs view
Szóval ha előre definiált queryre szeretnél választ visszaadni, akkor view (ez performanciában is jobb). Ha komolyabb logikát szeretnél, akkor tárolt. De az már típusos. Ez előrevetíti azt is, hogy ha módosítasz egy tábla mezőjének típusán, akkor ahol azt használod, ott ezt át kell vezetni. Én ezt nem érzem problémának, ez minden típusos programozási nyelvben így van. Márpedig az sql típusos.
Jó tegyük fel, hogy ilyesmi a
- vannak felhasználók
- vannak szerepkörök amikben felhasználók vannak
- vannak jogkörök amik szerepkörökhöz vagy egyedi felhasználókhoz tartozhatnak
Szeretném lekérni egy felhasználó össze jogosultságát és szerepkörét. Szerinted ezt jobb, ha több külön kérésben csinálom, vagy valahogyan egybe teszem függvényekkel?
Nekem egyelőre az jött le, hogy sokkal egyszerűbb külön lekérni mindet, aztán php-ben összefűzni, de kíváncsi vagyok, hogy ilyen téren mire képes a postgresql...
Ja csak a többi típusos nyelvben tolok egy refactoring-ot, aztán mindenhol magától átírja... Az sql-ben muszáj konkrét oszlopra hivatkozni, különben "error prone" lesz a kód. Ha bármikor típust módosítok, kimaradhat 1-2 helyen, aztán utána elszáll, mert nem azonosak a típusok. Unit tesztekkel mondjuk az ilyesmi orvosolható lenne, viszont akkor is tovább tart kézzel átírogatni, mint törölni a függvényeket, aztán létrehozni újra az egyes oszlopok típusára hivatkozva. A munka is gyorsabb így, mert nem kell állandóan megnézni, hogy melyik oszlopnak mi a típusa. Nem vonom kétségbe, hogy vannak előnyei a típusosságnak, de ahogy a mellékelt ábra mutatja, hátrányai is, legalábbis sql terén.
Az a baj vele, hogy nem szeretnék egy deka sql-t sem látni php-ben. Jelenleg az a koncepcióm, hogy írtam egy proxy-t, amin a függvény nevek ugyanazok, mint amik az adatbázisban is vannak, aztán azokat hívogatja a paraméterekkel... Ami visszajön, arra tolok egy json_encode-ot, aztán megy is a kliens-nek, nem nagyon kell így belenyúlnom, szóval nekem eléggé bejön ez a megközelítés... Nagyon jó olyan szempontból, hogy kikerülöm vele a klasszikus relational mapping-es problémákat. Általában az szokott előjönni bonyolultabb kódoknál, hogy van több query láncban, és egymás eredményét használják fel. Ilyenkor egy csomószor oda-vissza kell típuskonvertálni, ami nagyon nem jó. Körülbelül hasonló sebesség elérhető szerintem tárolt eljárásokkal, viszont cserébe sokkal tisztább lesz a kód...
Szeretném lekérni egy
Szerintem ez megy egy aggregált komplexebb queryvel is. Hogy melyik a gyorsabb, azt most nem merném megtippelni :) Ha jól van megírva, akkor szerintem a query gyorsabb leesz, mintha függvénnyel mókolnál. Mindenesetre a szerepkörei, meg a jogai az tuti 2 különböző result, 2 különböző query/függvény stb.
Igen, ez tény. Erre nem tudok jobbat, de érdekel, ha valakinek van jó megoldása, ötlete rá. És igen, ezt én is úgy érzem, hogy itt csak a teszt segít. De ez amúgy se kikerülhető "jobb helyeken" :) Ha nem függvényed van, hanem kliensben (php pl) futtatsz queryt, de a query mögött megváltozik a tábla struktúrája, akkor azt teszt nélkül nem kapod el. És a tárolt is egyfajta kliens az sql fölött.
Sajnos a pg nem validálja a tároltak tartalmát, csak formailag. Oracle pl besír, ha ilyesmi előfordul.
Ezt azért nem érzem akkora problémának, mert ha a db hívások nincsenek lefedve integrációs tesztekkel, akkor ettől függetlenül is érhet meglepetés. Ami mondjuk probléma, hogy így a tároltra nem nagyon mérsz branch coverage-et pl. De ez már kicsit más tészta :)
Ez érdekes, ezen majd még meditálok :) Én erre olyat csináltam, hogy az egyes lekérdezéseket fileban tároltam, és nem a queryt tettem be a kód közepére, hanem egy new SQLFile(...)-t. Syntax highlightolható, formázható stb. Php-ban az is megoldható, hogy naming convention alapján keresi ki a filet metódushívás alapján, és a paramétereket egyszerűen bedobálja a querynek. Így még tárolt se kell. Cserébe a típus módosításos probléma itt is fennáll :)
De amúgy ha jól érzem, akkor ezt a koncepciódat php oldalon az nem borítja sehol, hogy a pg típust vár függvénynél visszatérési értékként.
Ja, jól érzed... :-) Nekem
Ha egy ilyet tárolt eljárásba teszek, akkor meg lehet oldani, hogy amikor php-ban fetch-elem, akkor valami ilyesmit kapjak, és ne stringbe összefűzött dolgokat? (json-ban írom, úgy tömörebb)
JSON
Ha 9.2-es pg van alattad, akkor határozottan, abban van json típus :)
Amúgy szerintem saját típussal csinálhatsz hasonlót.
Az a gáz, hogy 8.4 van. Saját
szerk:
Van egy json modul, amit esetleg lehetne telepíteni 8.4-re, de árban nem éri meg, és ránézésre nem támogat komplexebb kompozit típusokat. Az egész pgsql-ben elég nehézkesen lett megoldva a típusosság. Bizonyos esetekben van automatikus konverzió: SETOF RECORD <-> TABLE, INT -> TABLE.ROW.COLUMN stb... Bizonyos esetekben meg nincs. Szóval egyáltalán nem egyértelmű, hogy valaminek éppen mi a típusa, vagy hogy két eltérő típus között automatikus konverzió van e vagy sem, stb... Hiányzik egy csomó felületi függvény is, ez mondjuk talán inkább a php-s csatoló hibája, de jó lenne, ha tömböket automatikusan konvertálna, lenne asszociatív array a saját típusok helyett, stb... Jelenleg szerintem még a 9.2-es verzióval is csak nehézkesen lehetne megoldani a problémát. Én személy szerint a kompozit típusok helyett inkább maradok a több kérés küldésénél, és a php-s összefűzésnél bonyolultabb adat formára, mert ott mindez maradéktalanul megoldható.
http://stackoverflow.com/questions/11940720/returning-a-nested-composite-type-from-a-pl-pgsql-function
Itt megcsinálják gyakorlatilag ugyanazt, de mivel nincs asszociatív típus, ezért sima tömböket ad csak vissza, és utólag még azt is fel kell dolgozni. Ez így kb használhatatlan, ha valaki automatikus átalakítást akar...