Door
Onbekende gebruiker
op 09-11-2015 12:48
gewijzigd op 09-11-2015 12:51
2.242 views
Achtergrond; ben vrij nieuw met PG, en heb kort geleden met succes mijn MySQL database naar PG gemigreerd.
Nu moet ik mijn SQL-genererende database class aan het aanpassen. Het haalt van tabellen kolominformatie op. Eerder deed ik dat met driverinformatie via mysqli() en 'SHOW FULL COLUMNS', maar dat werkt in PG anders.
Ik dacht eerst aan iets als:
SELECT * FROM "tabelnaam" LIMIT 0 OFFSET 0
om vervolgens met pg_field_name() en pg_field_type() kolominformatie te achterhalen. Vind ik later een nog makkelijker functie: http://php.net/manual/en/function.pg-meta-data.php
Maar nu wil ik meer metadata selecteren, zoals de default waarde, voor bv. het editen in mijn appje. Als ik die opvraag met:
SELECT
"attname"
"pg_catalog".format_type("a"."atttypid", "a"."atttypmod") AS "atttyp"
"attnotnull"
( SELECT "pg_catalog".pg_get_expr("b"."adbin", "b"."adrelid")
FROM "pg_catalog"."pg_attrdef" AS "b"
WHERE "b"."adrelid" = "a"."attrelid"
AND "b"."adnum" = "a"."attnum"
AND "a"."atthasdef"
) AS "attdefault"
FROM
"pg_catalog"."pg_attribute" AS "a"
WHERE
"a"."attrelid" = '"schemanaam"."tabelnaam"'::regclass
AND "a"."attnum" > 0 -- no system columns
AND NOT "a"."attisdropped" -- no dropped columns
ORDER BY
"a"."attnum"
;
En dit is het punt om even heel goed na te denken over of het wel handig is wat je wilt.
Stel bijvoorbeeld dat de expressie een nextval is voor een van je sequences, wat uiteraard het geval is voor bijvoorbeeld je id's. Dan zal de expressie worden uitgevoerd en de sequence worden verhoogd. Dit wordt ook niet teruggedraaid bij rollback. En dit is nog maar een van de pitfalls.
Dank Ben en Vincent voor jullie reacties. Helemaal gelijk natuurlijk, ik had er niet direct aan gedacht omdat ik aan het testen was met een tabel zonder sequence. Met de mysqli client kon je de default waarde 'gewoon' opvragen met een functie in de clientsoftware, en als ik dat met een andere tabel met een serial doe loop ik inderdaad direct tegen het uitvoeren van nextval() aan. Dus moet ik de expressie in PHP parsen om de default-waarde te herleiden. Niet ingewikkeld maar onhandig, ik wilde juist data-logica zoveel mogelijk binnen de database houden.
Maaruhm, is er dat jullie weten geen andere manier om PG de defaultwaarde te laten geven?
Voor de volledigheid, de code die ik had en die we dus vooral niet moeten gebruiken:
CREATE OR REPLACE FUNCTION schemanaam.eval(expression text) RETURNS text AS $$
declare
result text;
begin
execute 'SELECT ' || expression into result;
return result;
end;
$$ LANGUAGE plpgsql;
in combinatie met:
SELECT
"attname"
"pg_catalog".format_type("a"."atttypid", "a"."atttypmod") AS "atttype"
"attnotnull"
"pg_catalog".pg_get_expr("b"."adbin", "b"."adrelid") AS "atdefault",
CASE WHEN "pg_catalog".pg_get_expr("b"."adbin", "b"."adrelid") IS NOT NULL THEN
schemanaam.eval("pg_catalog".pg_get_expr("b"."adbin", "b"."adrelid"))
END AS "atdefval"
FROM
"pg_catalog"."pg_attribute" AS "a"
LEFT JOIN "pg_catalog"."pg_attrdef" AS "b" ON (
"b"."adrelid" = "a"."attrelid"
AND "b"."adnum" = "a"."attnum"
AND "a"."atthasdef"
)
WHERE
"a"."attrelid" = '"schemanaam"."tabelnaam"'::regclass
AND "a"."attnum" > 0 -- no system columns
AND NOT "a"."attisdropped" -- no dropped columns
ORDER BY
"a"."attnum"
;
Ook daar zul je nog wat parsing moeten doen voor serials maar dit vraag in ieder geval alleen op, het voert niets uit.
?
Onbekende gebruiker
09-11-2015 17:25
Ja precies, dat antwoord had ik ook gevonden ja.. maar het was nu net die parsing waarvan ik dacht: dat moet in PostgreSQL. Aan de andere kant, ach dan doen we dat laatste stukje parsing in PHP, dan ben ik er ook. Enig nadeel is dan dat het tijd kost om uit te zoeken. Default waarden als now(), current_timestamp, herkennen. Maar beter zo dan dat SQL wordt uitgevoerd bij het opvragen idd.
Je zou de parsing natuurlijk ook in de query kunnen doen, PostgreSQL kent ook regular expressions dus het kan noooit ingewikkeld zijn om sequences e.d. te herkennen.
Ik neem tenminste aan dat je alleen wilt weten of er een default is en of dat een vaste waarde is?
?
Onbekende gebruiker
09-11-2015 20:38
Ik wil in PHP weten wat de default waarden zijn. Tegelijkertijd wil ik zo min mogelijk in PHP met data doen, dat wil ik in PG doen. Het liefst maak ik niet eerst een lege rij aan, om te bewerken via de primary key(s). Want er moet een HTML-formuliertje uit komen waarmee een nieuwe rij van de tabel te bewerken is, met default waarden er al in, van het moment dat er op 'nieuw' geklikt is. Het formbuilder objectje moet dus weten welke kolommen er zijn, wat het datatype is, het commentaar (voor in de HTML-labels) en wat de defaultwaarden zijn, en wat de foreign key(s) zijn zodat je alleen geldige waarden kan selecteren in een HTML-select, net als bij een MySQL SET (gaat niet in PG) en een ENUM. Die code had ik dus al werkend voor MySQL, maar nu ben ik met een migratie naar PG bezig, want ik ben MySQL beu. Verder de keuze tussen het appje opnieuw schrijven of refactoren, en ik kies voor het laatste omdat dat stapsgewijs kan. Maar nu ik dit zo opschrijf ben ik van inzicht veranderd dat ik het dus liever een oplossing wil helemaal in PG, en vooral niet in PHP, dank! :)
[size=xsmall]Toevoeging op 09/11/2015 20:56:03:[/size]