PostgreSQL eval() functie

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

09/11/2015 12:48:49
Quote Anchor link
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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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"
;

Krijg ik de default waarde niet, maar wel de expressie die leidt tot de default waarde. Nu wil ik de default waarden het liefst in 1 query selecteren met iets als een eval() functie. Die bestaat niet in PG maar is makkelijk zelf te maken http://stackoverflow.com/questions/7433201/are-there-any-way-to-execute-a-query-inside-the-string-value-like-eval-in-post

Maar weet iemand misschien een makkelijker manier? Wat ik tot nu toe heb lijkt me een beetje gepunnik in de marge.
Gewijzigd op 09/11/2015 12:51:52 door
 
PHP hulp

PHP hulp

24/12/2024 17:48:05
 
Ben van Velzen

Ben van Velzen

09/11/2015 12:59:45
Quote Anchor link
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.
 
Pg Vincent

Pg Vincent

09/11/2015 13:12:07
Quote Anchor link
Je moet inderdaad goed weten wat voor defaults je veilig kunt opvragen en hoe je ze precies moet opvragen.

Over de vraag zelf: dat kun je doen met een stored-function:http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
 

09/11/2015 16:47:48
Quote Anchor link
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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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"
;


Met de hamvraag; hoe kan het beter in PG?
Gewijzigd op 09/11/2015 16:48:30 door
 
Pg Vincent

Pg Vincent

09/11/2015 17:01:33
Quote Anchor link
Volgens Peter Eisentraut (een PG-committer) kan het zo:

SELECT column_name, column_default
FROM information_schema.columns
WHERE (table_schema, table_name) = ('public', 'mytable')
ORDER BY ordinal_position;

Zie ook:
http://stackoverflow.com/questions/8146448/get-the-default-values-of-table-columns-in-postgres

Ook daar zul je nog wat parsing moeten doen voor serials maar dit vraag in ieder geval alleen op, het voert niets uit.
 

09/11/2015 17:25:54
Quote Anchor link
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.
 
Pg Vincent

Pg Vincent

09/11/2015 20:26:25
Quote Anchor link
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?
 

09/11/2015 20:38:17
Quote Anchor link
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! :)

Toevoeging op 09/11/2015 20:56:03:

Ben niet de enige die dat wil: http://stackoverflow.com/questions/24131640/how-to-retrieve-the-actual-default-value-for-a-column-before-insertion
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.