An Introduction to pl/php



             by Robert   Treat
             http://www.brighterlamp.org/
What is pl/php
    aka PL/PHP, Pl/PHP, pl/PHP
●




    Database procedural language based on
●


    PHP

    Allows you ...
Let's see an example eh?
CREATE OR REPLACE FUNCTION hello_world()
RETURNS text
LANGUAGE plphp
AS $$
 $var = quot;howdy yal...
Let's see an example eh?
CREATE OR REPLACE FUNCTION hello_world()
RETURNS text
LANGUAGE plphp
AS $$
 $var = quot;howdy yal...
Let's see an example eh?
CREATE OR REPLACE FUNCTION hello_world()
RETURNS text
LANGUAGE plphp
AS $$
 $var = quot;howdy yal...
Where does pl/php come from?
    Originally developed by Command Prompt, Inc.
●




    Currently maintained by Alvaro Her...
Who uses pl/php?
    We don't know... but it seems popular...
●
Who uses pl/php?
Who uses pl/php?
So why do people use pl/php?
     Nicely integrates with PostgreSQL
 ●



         close to data
     –

         easily a...
So why do people use pl/php?
     Nicely integrates with PostgreSQL
 ●



         close to data
     –

         easily a...
So why do people use pl/php?
     Nicely integrates with PostgreSQL
 ●



         close to data
     –

         easily a...
Any reason to avoid it?
    PostgreSQL specific
●
Any reason to avoid it?
    PostgreSQL specific (well, maybe that's really
●


    a reason to use it)
Any reason to avoid it?
    PostgreSQL specific (well, maybe that's really
●


    a reason to use it)
    Adds dependenci...
Installation
    Pre-requisites:
●


        PostgreSQL 8.1+
    –
Installation
    Pre-requisites:
●


        PostgreSQL 8.1+
    –

                  -bash-3.00$ pg_config --version
Installation
    Pre-requisites:
●


        PostgreSQL 8.1+
    –

                  -bash-3.00$ pg_config --version
    ...
Installation
    Pre-requisites:
●


        PostgreSQL 8.1+
    –

                   -bash-3.00$ pg_config --version
   ...
Installation
    Pre-requisites:
●


        PostgreSQL 8.1+
    –

                    -bash-3.00$ pg_config --version
  ...
Installation
    Pre-requisites:
●


        PostgreSQL 8.1+
    –

                    -bash-3.00$ pg_config --version
  ...
Installation
    Grab the latest release tarball, unpack it, configure
●


    and make (simple eh?)
Installation
        Grab the latest release tarball, unpack it, configure
    ●


        and make (simple eh?)
rob@ridle...
Installation
        Grab the latest release tarball, unpack it, configure
    ●


        and make (simple eh?)
rob@ridle...
Installation
        Grab the latest release tarball, unpack it, configure
    ●


        and make (simple eh?)
rob@ridle...
Installation
        Grab the latest release tarball, unpack it, configure
    ●


        and make (simple eh?)
rob@ridle...
Installation
        Grab the latest release tarball, unpack it, configure
    ●


        and make (simple eh?)
rob@ridle...
Installation
        Grab the latest release tarball, unpack it, configure
    ●


        and make (simple eh?)
rob@ridle...
Installation
        Grab the latest release tarball, unpack it, configure
    ●


        and make (simple eh?)
rob@ridle...
Installation – libphp5

    no longer supports building against mod_php
●



    most distributions don't ship static php ...
Installation – libphp5

    no longer supports building against mod_php
●



    most distributions don't ship static php ...
Installation
      configure plphp
  ●



                                        ./configure –with-php=/home/rob/devel/pl...
Installation
     sudo make install
●




    rob@ridley:~/devel/plphp/plphp-1.3.3$ sudo make install
    <snip>
    /bin/...
Installing pl/php into the Database
    Once .so is compiled, you need to install the
●


    language into your database.
Installing pl/php into the Database
    Once .so is compiled, you need to install the
●


    language into your database....
Installing pl/php into the Database
    Once .so is compiled, you need to install the
●


    language into your database....
Installing pl/php into the Database
    pagila=# INSERT INTO pg_pltemplate VALUES
    pagila-# ('plphpu', 'f', 'plphp_call...
Installing pl/php into the Database
pagila=#
Installing pl/php into the Database
pagila=# create language plphp;
Installing pl/php into the Database
pagila=# create language plphpu;
ERROR: could not load library quot;/usr/lib/postgresq...
Installing pl/php into the Database
pagila=# create language plphpu;
ERROR: could not load library quot;/usr/lib/postgresq...
Installing pl/php into the Database
pagila=# create language plphp;
ERROR: could not load library quot;/usr/lib/pgsql/plph...
Installing pl/php into the Database
[root@localhost pgsql]# locate libphp5.so
/usr/lib/httpd/modules/libphp5.so

[root@loc...
Installing pl/php into the Database
  [root@localhost pgsql]# psql -U postgres pagila
  Welcome to psql 8.1.1, the Postgre...
pl/php vs. pl/phpu ?
    PostgreSQL offers “trusted” and “untrusted”
●


    languages
    Untrusted means it can access t...
pl/php basics
CREATE OR REPLACE FUNCTION iheartphp(text)
RETURNS text
LANGUAGE plphpu
STRICT
AS $$
       $retval = $args[...
pl/php basics
CREATE OR REPLACE FUNCTION iheartphp(text)
RETURNS text
LANGUAGE plphpu
STRICT
AS $$
       $retval = $args[...
pl/php basics
CREATE OR REPLACE FUNCTION iheartphp(text)
RETURNS text
LANGUAGE plphpu
STRICT
AS $$
       $retval = $args[...
pl/php basics
CREATE OR REPLACE FUNCTION iheartphp(text)
RETURNS text
LANGUAGE plphpu
STRICT
AS $$
       $retval = $args[...
pl/php basics
CREATE OR REPLACE FUNCTION iheartphp(text)
RETURNS text
LANGUAGE plphpu
STRICT
AS $$
       $retval = $args[...
pl/php basics
CREATE OR REPLACE FUNCTION iheartphp(text)
RETURNS text
LANGUAGE plphpu
STRICT
AS $$
       $retval = $args[...
pl/php basics
CREATE OR REPLACE FUNCTION iheartphp(text)
RETURNS text
LANGUAGE plphpu
STRICT
AS $$
       $retval = $args[...
pl/php basics
CREATE OR REPLACE FUNCTION iheartphp(text)
RETURNS text
LANGUAGE plphpu
STRICT
AS $$
       $retval = $args[...
pl/php not so basics
    Need a page to show us inventory
●




    An item is in stock if we have no rows in our
●


    ...
CREATE OR REPLACE FUNCTION movie_in_stock(integer)
RETURNS Boolean
LANGUAGE plphpu
AS $$
  $sql = quot;SELECT count(*) FRO...
CREATE OR REPLACE FUNCTION movie_in_stock(integer)
RETURNS Boolean
LANGUAGE plphpu
AS $$
  $sql = quot;SELECT count(*) FRO...
spi functions?
    Internal functions for interacting with the db
●



        spi_exec :: execute a query with optional l...
CREATE OR REPLACE FUNCTION movie_in_stock(integer)
RETURNS Boolean
LANGUAGE plphpu
AS $$
  $sql = quot;SELECT count(*) FRO...
CREATE OR REPLACE FUNCTION movie_in_stock(integer)
RETURNS Boolean
LANGUAGE plphpu
AS $$
  $sql = quot;SELECT count(*) FRO...
CREATE OR REPLACE FUNCTION movie_in_stock(integer)
RETURNS Boolean
LANGUAGE plphpu
AS $$
  $sql = quot;SELECT count(*) FRO...
PHP Functions
         Most PHP functions can be used inside
     ●


         pl/php functions
CREATE OR REPLACE FUNCTION...
PHP Functions
CREATE OR REPLACE FUNCTION notsimplefunc()
RETURNS text
LANGUAGE plphpu
AS $$
  $sql = quot;select version()...
PHP Functions
pagila=# SELECT notsimplefunc();
                                       nosimplefunc
-----------------------...
PHP Functions
CREATE OR REPLACE FUNCTION wickedfunc()
RETURNS text
LANGUAGE plphpu
as $$
  $c = mysql_connect(quot;10.225....
PHP Functions
CREATE OR REPLACE FUNCTION wickedfunc()
RETURNS text
LANGUAGE plphpu
as $$
  $c = mysql_connect(quot;10.225....
the PEAR example
    Can use PEAR modules inside functions
●




    Walk through example for validating email
●




    P...
the Pear example

CREATE OR REPLACE FUNCTION valid_email(text)
RETURNS boolean
IMMUTABLE
LANGUAGE plphpu
AS $$
  require_o...
the Pear example
pagila=# SELECT valid_email('xzilla@users.sourceforge.net');
valid_email
--------------------

t
(1 row)
...
the Pear example
    Functions may inter-operate with any other
●


    part of the database system


             CREATE ...
the Pear example
    Functions may inter-operate with any other
●


    part of the database system


             CREATE ...
the Pear example
    Functions may inter-operate with any other
●


    part of the database system


             CREATE ...
the Pear example
     pagila=# ALTER TABLE customer ALTER email TYPE validemail ;
     ALTER TABLE



    All data must pa...
the Pear example
pagila=# INSERT INTO customer (store_id, first_name, last_name, email, address_id, active)
pagila-# VALUE...
pl/php triggers
    pl/php functions can be used as triggers too
●




    Can access new and old data in the table
●




...
pl/php triggers
    pl/php functions can be used as triggers too
●




    Can access new and old data in the table
●




...
pl/php triggers
pagila=# d customer
                                   Table quot;public.customerquot;
   Column |        ...
pl/php triggers
pagila=# d rental
                                   Table quot;public.rentalquot;
   Column |            ...
pl/php triggers
               CREATE TABLE overdue_log
               (
                  overdue_log_id serial,
        ...
pl/php triggers
                CREATE TABLE overdue_log
                (
                   overdue_log_id serial,
     ...
pl/php triggers – special variables
    $_TD[“old”] - Old data being removed from
●


    table
    $_TD[“new”] - New data...
pl/php trigger function
CREATE OR REPLACE FUNCTION watch_overdue()
RETURNS trigger
LANGUAGE plphpu
AS $$
  $new =& $_TD['n...
pl/php trigger function
CREATE OR REPLACE FUNCTION watch_overdue()
RETURNS trigger
LANGUAGE plphpu
AS $$
  $new =& $_TD['n...
pl/php trigger function
continued...

pg_raise('notice',$r['due_date']);
pg_raise('notice',$new['return_date']);
  if ($ne...
pl/php trigger function
continued...

pg_raise('notice',$r['due_date']);
pg_raise('notice',$new['return_date']);
  if ($ne...
pl/php trigger function
continued...

pg_raise('notice',$r['due_date']);
pg_raise('notice',$new['return_date']);
  if ($ne...
pl/php trigger function
continued...

pg_raise('notice',$r['due_date']);
pg_raise('notice',$new['return_date']);
  if ($ne...
pl/php triggers (the trigger)
            CREATE TRIGGER watch_overdue
            AFTER insert or update
            ON r...
pl/php triggers


pagila=# INSERT INTO rental
pagila-# VALUES (DEFAULT,now() - '1 month'::interval,2792,549,now(),1);
pl/php triggers


pagila=# INSERT INTO rental
pagila-# VALUES (DEFAULT,now() - '1 month'::interval,2792,549,now(),1);
NOTI...
pl/php triggers


pagila=# INSERT INTO rental
pagila-# VALUES (DEFAULT,now() - '1 month'::interval,2792,549,now(),1);
NOTI...
pl/php triggers


pagila=# INSERT INTO rental
pagila-# VALUES (DEFAULT,now() - '1 month'::interval,2792,549,now(),1);
NOTI...
pl/php – one more example
CREATE OR REPLACE FUNCTION text_array_to_result(text[])
RETURNS setof text
LANGUAGE plphpu
AS $$...
pl/php – one more example
CREATE OR REPLACE FUNCTION text_array_to_result(text[])
RETURNS setof text
LANGUAGE plphpu
AS $$...
pl/php – one more example
CREATE OR REPLACE FUNCTION text_array_to_result(text[])
RETURNS setof text
LANGUAGE plphpu
AS $$...
pl/php – one more example
      pagila=# SELECT * FROM text_array_to_result('{txt arg 1,txt arg 2}');
       text_array_to...
pl/php – one more example
      pagila=# SELECT * FROM text_array_to_result('{txt arg 1,txt arg 2}');
       text_array_to...
but wait, there's more!
    Composite data types
●



    Working with array types
●



    Global shared variables
●



 ...
pl/php - caveats
    Rough around the edges
●


        sometimes uncover segfaults
    –

        lots of warnings / noti...
pl/php - caveats
    Rough around the edges
●


        sometimes uncover segfaults
    –

        lots of warnings / noti...
pl/php - caveats
    Rough around the edges
●


        sometimes uncover segfaults
    –

        lots of warnings / noti...
pl/php - caveats
    Rough around the edges
●


        sometimes uncover segfaults
    –

        lots of warnings / noti...
Thanks!
      Command Prompt, Inc.
         Alvarro Herrera
          Alexey Klyukin
       Greg Sabino-Mullane
          ...
Upcoming SlideShare
Loading in...5
×

Os Treat

880

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
880
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Os Treat"

  1. 1. An Introduction to pl/php by Robert Treat http://www.brighterlamp.org/
  2. 2. What is pl/php aka PL/PHP, Pl/PHP, pl/PHP ● Database procedural language based on ● PHP Allows you to program inside the database ● using PHP
  3. 3. Let's see an example eh? CREATE OR REPLACE FUNCTION hello_world() RETURNS text LANGUAGE plphp AS $$ $var = quot;howdy yallquot;; RETURN $var; $$;
  4. 4. Let's see an example eh? CREATE OR REPLACE FUNCTION hello_world() RETURNS text LANGUAGE plphp AS $$ $var = quot;howdy yallquot;; RETURN $var; $$; pagila=# select hello_world(); hello_world ---------------- howdy yall (1 row)
  5. 5. Let's see an example eh? CREATE OR REPLACE FUNCTION hello_world() RETURNS text LANGUAGE plphp AS $$ $var = quot;howdy yallquot;; RETURN $var; $$; pagila=# select hello_world(); hello_world ---------------- howdy yall (1 row) Fancy huh?
  6. 6. Where does pl/php come from? Originally developed by Command Prompt, Inc. ● Currently maintained by Alvaro Herrera, Alexey ● Klyukin (both work for Command Prompt) Has gone through a number of re-writes ● http://plphp.commandprompt.com/ ●
  7. 7. Who uses pl/php? We don't know... but it seems popular... ●
  8. 8. Who uses pl/php?
  9. 9. Who uses pl/php?
  10. 10. So why do people use pl/php? Nicely integrates with PostgreSQL ● close to data – easily access tables and whatnot –
  11. 11. So why do people use pl/php? Nicely integrates with PostgreSQL ● close to data – easily access tables and whatnot – Save on network traffic ●
  12. 12. So why do people use pl/php? Nicely integrates with PostgreSQL ● close to data – easily access tables and whatnot – Save on network traffic ● You can use PHP to write it! ●
  13. 13. Any reason to avoid it? PostgreSQL specific ●
  14. 14. Any reason to avoid it? PostgreSQL specific (well, maybe that's really ● a reason to use it)
  15. 15. Any reason to avoid it? PostgreSQL specific (well, maybe that's really ● a reason to use it) Adds dependencies to your database ● Code is still green ● Small user community ●
  16. 16. Installation Pre-requisites: ● PostgreSQL 8.1+ –
  17. 17. Installation Pre-requisites: ● PostgreSQL 8.1+ – -bash-3.00$ pg_config --version
  18. 18. Installation Pre-requisites: ● PostgreSQL 8.1+ – -bash-3.00$ pg_config --version PostgreSQL 8.1.9
  19. 19. Installation Pre-requisites: ● PostgreSQL 8.1+ – -bash-3.00$ pg_config --version PostgreSQL 8.1.9 Also need php development package (yum install – php-devel)
  20. 20. Installation Pre-requisites: ● PostgreSQL 8.1+ – -bash-3.00$ pg_config --version PostgreSQL 8.1.9 Also need php development package (yum install – php-devel) [root@localhost html]# php-config --version
  21. 21. Installation Pre-requisites: ● PostgreSQL 8.1+ – -bash-3.00$ pg_config --version PostgreSQL 8.1.9 Also need php development package (yum install – php-devel) [root@localhost html]# php-config --version 5.1.2
  22. 22. Installation Grab the latest release tarball, unpack it, configure ● and make (simple eh?)
  23. 23. Installation Grab the latest release tarball, unpack it, configure ● and make (simple eh?) rob@ridley:~/devel/plphp$
  24. 24. Installation Grab the latest release tarball, unpack it, configure ● and make (simple eh?) rob@ridley:~/devel/plphp$ tar zxvf plphp-1.3.3.tar.gz
  25. 25. Installation Grab the latest release tarball, unpack it, configure ● and make (simple eh?) rob@ridley:~/devel/plphp$ tar zxvf plphp-1.3.3.tar.gz ./plphp-1.3.3/ ./plphp-1.3.3/sql/ <snip> ./plphp-1.3.3/plphp.c rob@ridley:~/devel/plphp$
  26. 26. Installation Grab the latest release tarball, unpack it, configure ● and make (simple eh?) rob@ridley:~/devel/plphp$ tar zxvf plphp-1.3.3.tar.gz ./plphp-1.3.3/ ./plphp-1.3.3/sql/ <snip> ./plphp-1.3.3/plphp.c rob@ridley:~/devel/plphp$ cd plphp-1.3.3
  27. 27. Installation Grab the latest release tarball, unpack it, configure ● and make (simple eh?) rob@ridley:~/devel/plphp$ tar zxvf plphp-1.3.3.tar.gz ./plphp-1.3.3/ ./plphp-1.3.3/sql/ <snip> ./plphp-1.3.3/plphp.c rob@ridley:~/devel/plphp$ cd plphp-1.3.3 rob@ridley:~/devel/plphp/plphp-1.3.3$
  28. 28. Installation Grab the latest release tarball, unpack it, configure ● and make (simple eh?) rob@ridley:~/devel/plphp$ tar zxvf plphp-1.3.3.tar.gz ./plphp-1.3.3/ ./plphp-1.3.3/sql/ <snip> ./plphp-1.3.3/plphp.c rob@ridley:~/devel/plphp$ cd plphp-1.3.3 rob@ridley:~/devel/plphp/plphp-1.3.3$ ./configure
  29. 29. Installation Grab the latest release tarball, unpack it, configure ● and make (simple eh?) rob@ridley:~/devel/plphp$ tar zxvf plphp-1.3.3.tar.gz ./plphp-1.3.3/ ./plphp-1.3.3/sql/ <snip> ./plphp-1.3.3/plphp.c rob@ridley:~/devel/plphp$ cd plphp-1.3.3 rob@ridley:~/devel/plphp/plphp-1.3.3$ ./configure checking for gcc... gcc <snip> checking for pg_config... /usr/bin/pg_config checking for existence of /usr/lib/postgresql/8.1/lib/pgxs/src/makefiles/pgxs.mk... yes checking for PostgreSQL version... 8.1.9 checking for php-config... /usr/bin/php-config checking for php_module_startup in -lphp5... no checking for php_module_startup in -lphp4... no configure: error: Cannot locate a proper php library
  30. 30. Installation – libphp5 no longer supports building against mod_php ● most distributions don't ship static php library ● don't be fooled! ● rob@ridley:~$ locate libphp ● /usr/lib/libphp5.so /usr/lib/apache2/modules/libphp5.so rob@ridley:~$ ls ­al /usr/lib/libphp5.so lrwxrwxrwx 1 root root 35 2006­08­26 20:43  /usr/lib/libphp5.so ­> /usr/lib/apache2/modules/libphp5.so
  31. 31. Installation – libphp5 no longer supports building against mod_php ● most distributions don't ship static php library ● need to build your own php libs ● make libphp5.la install ● configure –enable-embed –prefix=your_dir; ● make install
  32. 32. Installation configure plphp ● ./configure –with-php=/home/rob/devel/plphp/embedphp/ rob@ridley:~/devel/plphp/plphp-1.3.3$ checking for gcc... gcc <snip> checking for pg_config... /usr/bin/pg_config checking for existence of /usr/lib/postgresql/8.1/lib/pgxs/src/makefiles/pgxs.mk... yes checking for PostgreSQL version... 8.1.9 checking for php-config... /home/rob/devel/plphp/embedphp//bin/php-config checking for php_module_startup in -lphp5... yes configure: creating ./config.status config.status: creating Makefile config.status: creating config.h
  33. 33. Installation sudo make install ● rob@ridley:~/devel/plphp/plphp-1.3.3$ sudo make install <snip> /bin/sh /usr/lib/postgresql/8.1/lib/pgxs/src/makefiles/../../config/install-sh -c -m 755 libplphp.so.0.0 /usr/lib/postgresql/8.1/lib/plphp.so
  34. 34. Installing pl/php into the Database Once .so is compiled, you need to install the ● language into your database.
  35. 35. Installing pl/php into the Database Once .so is compiled, you need to install the ● language into your database. Should be easier than compiling ●
  36. 36. Installing pl/php into the Database Once .so is compiled, you need to install the ● language into your database. Should be easier than compiling ● Probably won't be... ●
  37. 37. Installing pl/php into the Database pagila=# INSERT INTO pg_pltemplate VALUES pagila-# ('plphpu', 'f', 'plphp_call_handler', 'plphp_validator', '$libdir/plphp', NULL); INSERT 0 1 Creates an entry into the shared catalogs ● Does not mean that pl/php is installed! ● But you can now install it into any database ● using the “Create Language” command
  38. 38. Installing pl/php into the Database pagila=#
  39. 39. Installing pl/php into the Database pagila=# create language plphp;
  40. 40. Installing pl/php into the Database pagila=# create language plphpu; ERROR: could not load library quot;/usr/lib/postgresql/8.1/lib/plphp.soquot;: /usr/lib/libphp5.so: undefined symbol: ap_loaded_modules
  41. 41. Installing pl/php into the Database pagila=# create language plphpu; ERROR: could not load library quot;/usr/lib/postgresql/8.1/lib/plphp.soquot;: /usr/lib/libphp5.so: undefined symbol: ap_loaded_modules See? Simple...
  42. 42. Installing pl/php into the Database pagila=# create language plphp; ERROR: could not load library quot;/usr/lib/pgsql/plphp.soquot;: libphp5.so: cannot open shared object file: No such file or directory See? Simple... PostgreSQL can't find the php shared library ● We need to find libphp5.so and set ● PostgreSQL up to find it.
  43. 43. Installing pl/php into the Database [root@localhost pgsql]# locate libphp5.so /usr/lib/httpd/modules/libphp5.so [root@localhost pgsql]# pg_config --libdir /usr/lib [root@localhost pgsql]# ln -sf /usr/lib/httpd/modules/libphp5.so /usr/lib/ [root@localhost pgsql]# createlang -U postgres plphp pagila CREATE LANGUAGE
  44. 44. Installing pl/php into the Database [root@localhost pgsql]# psql -U postgres pagila Welcome to psql 8.1.1, the PostgreSQL interactive terminal. Type: copyright for distribution terms h for help with SQL commands ? for help with psql commands g or terminate with semicolon to execute query q to quit pagila=# create language plphpu; CREATE LANGUAGE pagila=#
  45. 45. pl/php vs. pl/phpu ? PostgreSQL offers “trusted” and “untrusted” ● languages Untrusted means it can access the file system ● More flexible, more useful, likely a good ● choice when working with any complexity Opens small security hole; be aware. ●
  46. 46. pl/php basics CREATE OR REPLACE FUNCTION iheartphp(text) RETURNS text LANGUAGE plphpu STRICT AS $$ $retval = $args[0] . ' loves PHP!'; return $retval; $$; CREATE FUNCTION pagila=# SELECT iheartphp('Robert'); iheartphp ------------------- Robert loves PHP! (1 row) How useful!
  47. 47. pl/php basics CREATE OR REPLACE FUNCTION iheartphp(text) RETURNS text LANGUAGE plphpu STRICT AS $$ $retval = $args[0] . ' loves PHP!'; return $retval; $$; CREATE FUNCTION pagila=# SELECT iheartphp('Robert'); iheartphp ------------------- Robert loves PHP! (1 row) How useful!
  48. 48. pl/php basics CREATE OR REPLACE FUNCTION iheartphp(text) RETURNS text LANGUAGE plphpu STRICT AS $$ $retval = $args[0] . ' loves PHP!'; return $retval; $$; CREATE FUNCTION pagila=# SELECT iheartphp('Robert'); iheartphp ------------------- Robert loves PHP! (1 row) How useful!
  49. 49. pl/php basics CREATE OR REPLACE FUNCTION iheartphp(text) RETURNS text LANGUAGE plphpu STRICT AS $$ $retval = $args[0] . ' loves PHP!'; return $retval; $$; CREATE FUNCTION pagila=# SELECT iheartphp('Robert'); iheartphp ------------------- Robert loves PHP! (1 row) How useful!
  50. 50. pl/php basics CREATE OR REPLACE FUNCTION iheartphp(text) RETURNS text LANGUAGE plphpu STRICT AS $$ $retval = $args[0] . ' loves PHP!'; return $retval; $$; CREATE FUNCTION pagila=# SELECT iheartphp('Robert'); iheartphp ------------------- Robert loves PHP! (1 row) How useful!
  51. 51. pl/php basics CREATE OR REPLACE FUNCTION iheartphp(text) RETURNS text LANGUAGE plphpu STRICT AS $$ $retval = $args[0] . ' loves PHP!'; return $retval; $$; CREATE FUNCTION pagila=# SELECT iheartphp('Robert'); iheartphp ------------------- Robert loves PHP! (1 row) How useful!
  52. 52. pl/php basics CREATE OR REPLACE FUNCTION iheartphp(text) RETURNS text LANGUAGE plphpu STRICT AS $$ $retval = $args[0] . ' loves PHP!'; return $retval; $$; CREATE FUNCTION pagila=# SELECT iheartphp('Robert'); iheartphp ------------------- Robert loves PHP! (1 row) How useful!
  53. 53. pl/php basics CREATE OR REPLACE FUNCTION iheartphp(text) RETURNS text LANGUAGE plphpu STRICT AS $$ $retval = $args[0] . ' loves PHP!'; return $retval; $$; CREATE FUNCTION pagila=# SELECT iheartphp('Robert'); iheartphp ------------------- Robert loves PHP! (1 row) How useful!
  54. 54. pl/php not so basics Need a page to show us inventory ● An item is in stock if we have no rows in our ● rental table, or all rows have a return date Normally this would be two queries ● Making it a function will consolidate logic and ● save round trips
  55. 55. CREATE OR REPLACE FUNCTION movie_in_stock(integer) RETURNS Boolean LANGUAGE plphpu AS $$ $sql = quot;SELECT count(*) FROM rental WHERE inventory_id = quot;.$args[0]; $res = spi_exec($sql); $row = spi_fetch_row($res); if ($row['count'] == 0) return 1; $sql = quot;SELECT count(rental_id) FROM inventory LEFT JOIN rental USING (inventory_id) WHERE inventory.inventory_id = quot;.$args[0].quot; AND rental.return_date IS NULLquot;; $res = spi_exec($sql); $row = spi_fetch_row($res); if ($row['count'] > 0) { return 0 ; } else { return 1; }; $$;
  56. 56. CREATE OR REPLACE FUNCTION movie_in_stock(integer) RETURNS Boolean LANGUAGE plphpu AS $$ $sql = quot;SELECT count(*) FROM rental WHERE inventory_id = quot;.$args[0]; $res = spi_exec($sql); $row = spi_fetch_row($res); if ($row['count'] == 0) return 1; $sql = quot;SELECT count(rental_id) FROM inventory LEFT JOIN rental USING (inventory_id) WHERE inventory.inventory_id = quot;.$args[0].quot; AND rental.return_date IS NULLquot;; $res = spi_exec($sql); $row = spi_fetch_row($res); if ($row['count'] > 0) { return 0 ; } else { return 1; }; $$;
  57. 57. spi functions? Internal functions for interacting with the db ● spi_exec :: execute a query with optional limit. – spi_status :: return status of a previous query. – spi_fetch_row :: return associative array of the – row's results. spi_processed :: return the number of tuples in a – result. spi_rewind :: put the row cursor at the beginning – of the result.
  58. 58. CREATE OR REPLACE FUNCTION movie_in_stock(integer) RETURNS Boolean LANGUAGE plphpu AS $$ $sql = quot;SELECT count(*) FROM rental WHERE inventory_id = quot;.$args[0]; $res = spi_exec($sql); $row = spi_fetch_row($res); if ($row['count'] == 0) return 1; $sql = quot;SELECT count(rental_id) FROM inventory LEFT JOIN rental USING (inventory_id) WHERE inventory.inventory_id = quot;.$args[0].quot; AND rental.return_date IS NULLquot;; $res = spi_exec($sql); $row = spi_fetch_row($res); if ($row['count'] > 0) { return 0 ; } else { return 1; }; $$;
  59. 59. CREATE OR REPLACE FUNCTION movie_in_stock(integer) RETURNS Boolean LANGUAGE plphpu AS $$ $sql = quot;SELECT count(*) FROM rental WHERE inventory_id = quot;.$args[0]; $res = spi_exec($sql); $row = spi_fetch_row($res); if ($row['count'] == 0) return 1; $sql = quot;SELECT count(rental_id) FROM inventory LEFT JOIN rental USING (inventory_id) WHERE inventory.inventory_id = quot;.$args[0].quot; AND rental.return_date IS NULLquot;; $res = spi_exec($sql); $row = spi_fetch_row($res); if ($row['count'] > 0) { return 0 ; } else { return 1; }; $$;
  60. 60. CREATE OR REPLACE FUNCTION movie_in_stock(integer) RETURNS Boolean LANGUAGE plphpu AS $$ $sql = quot;SELECT count(*) FROM rental WHERE inventory_id = quot;.$args[0]; $res = spi_exec($sql); $row = spi_fetch_row($res); if ($row['count'] == 0) return 1; $sql = quot;SELECT count(rental_id) FROM inventory LEFT JOIN rental USING (inventory_id) WHERE inventory.inventory_id = quot;.$args[0].quot; AND rental.return_date IS NULLquot;; $res = spi_exec($sql); $row = spi_fetch_row($res); if ($row['count'] > 0) { return 0 ; } else { return 1; }; $$;
  61. 61. PHP Functions Most PHP functions can be used inside ● pl/php functions CREATE OR REPLACE FUNCTION simplefunc(text,text) RETURNS text LANGUAGE plphpu AS $$ return 'Did you know '. ucwords(strrev($args[0])) .' is '. strtolower($args[1]) .' backwards?'; $$; pagila=# select simplefunc('inside out','outside in'); simplefunc ------------------------------------------------------ Did you know Tuo Edisni is outside in backwards? (1 row)
  62. 62. PHP Functions CREATE OR REPLACE FUNCTION notsimplefunc() RETURNS text LANGUAGE plphpu AS $$ $sql = quot;select version()quot;; $c = pg_connect(quot;host=10.225.105.53 dbname=template1 user=postgresquot;); $r = pg_query($c,$sql); $v = pg_fetch_result($r,0,0); return $v; $$;
  63. 63. PHP Functions pagila=# SELECT notsimplefunc(); nosimplefunc ----------------------------------------------------------------------------------------------------------- PostgreSQL 8.1.1 on i686-redhat-linux-gnu, compiled by GCC gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3) (1 row) pagila=# SELECT version(); version ------------------------------------------------------------------------------------------------------- PostgreSQL 8.1.1 on i686-redhat-linux-gnu, compiled by GCC gcc (GCC) 4.0.1 20050727 (Red Hat 4.0.1-5) (1 row) Connect to external database Does have scary implications ● ● Normally not recommended But this kind of flexibility can be cool ● ●
  64. 64. PHP Functions CREATE OR REPLACE FUNCTION wickedfunc() RETURNS text LANGUAGE plphpu as $$ $c = mysql_connect(quot;10.225.105.94quot;,quot;sakilaquot;); $v = mysql_get_server_info(); return $v; $$;
  65. 65. PHP Functions CREATE OR REPLACE FUNCTION wickedfunc() RETURNS text LANGUAGE plphpu as $$ $c = mysql_connect(quot;10.225.105.94quot;,quot;sakilaquot;); $v = mysql_get_server_info(); return $v; $$; pagila=# SELECT wickedfunc(); wickedfunc -------------- 5.1.9-beta (1 row)
  66. 66. the PEAR example Can use PEAR modules inside functions ● Walk through example for validating email ● Pagila database ● (http://pgfoundry.org/projects/dbsamples/) Validate package ● (http://pear.php.net/package/Validate)
  67. 67. the Pear example CREATE OR REPLACE FUNCTION valid_email(text) RETURNS boolean IMMUTABLE LANGUAGE plphpu AS $$ require_once 'Validate.php'; $validate = new Validate(); return $validate->email(quot;$args[0]quot;,array(“check_domain”=>false,”use_rfc822”=>true)) ? 1 : 0; $$;
  68. 68. the Pear example pagila=# SELECT valid_email('xzilla@users.sourceforge.net'); valid_email -------------------- t (1 row) pagila=# SELECT valid_email ('Robert Treat <xzilla@ users . sf . net>'); valid_email --------------------- t (1 row) pagila=# SELECT valid_email('www.brighterlamp.org'); valid_email --------------------- f (1 row)
  69. 69. the Pear example Functions may inter-operate with any other ● part of the database system CREATE DOMAIN validemail AS text NOT NULL CHECK ( valid_email(VALUE) );
  70. 70. the Pear example Functions may inter-operate with any other ● part of the database system CREATE DOMAIN validemail AS text NOT NULL CHECK ( valid_email(VALUE) );
  71. 71. the Pear example Functions may inter-operate with any other ● part of the database system CREATE DOMAIN validemail AS text NOT NULL CHECK ( valid_email(VALUE) );
  72. 72. the Pear example pagila=# ALTER TABLE customer ALTER email TYPE validemail ; ALTER TABLE All data must pass through our function ● Validates all data in table ● Validates all data inserts and updates ●
  73. 73. the Pear example pagila=# INSERT INTO customer (store_id, first_name, last_name, email, address_id, active) pagila-# VALUES (2,'pete','hache-pee','l33t@aol',40,1); ERROR: value for domain validemail violates check constraint quot;validemail_checkquot; No special syntax needed ● Error messages reference function ● We can tweak rules by modifying the function ●
  74. 74. pl/php triggers pl/php functions can be used as triggers too ● Can access new and old data in the table ● PostgreSQL gives us access to special trigger ● specific information
  75. 75. pl/php triggers pl/php functions can be used as triggers too ● Can access new and old data in the table ● PostgreSQL gives us access to special trigger ● specific information Example: Log overdue rental returns for ● customers automatically through functions
  76. 76. pl/php triggers pagila=# d customer Table quot;public.customerquot; Column | Type | Modifiers -------------+-----------------------------+---------------------------------------------------------------- customer_id | integer | not null default nextval('customer_customer_id_seq'::regclass) store_id | smallint | not null first_name | character varying(45) | not null last_name | character varying(45) | not null email | character varying(50) | address_id | smallint | not null activebool | boolean | not null default true create_date | date | not null default ('now'::text)::date last_update | timestamp without time zone | default now() active | integer | Indexes: quot;customer_pkeyquot; PRIMARY KEY, btree (customer_id) quot;idx_fk_address_idquot; btree (address_id) quot;idx_fk_store_idquot; btree (store_id) quot;idx_last_namequot; btree (last_name) Foreign-key constraints: quot;customer_address_id_fkeyquot; FOREIGN KEY (address_id) REFERENCES address(address_id) ON UPDATE CASCADE ON DELETE RESTRICT quot;customer_store_id_fkeyquot; FOREIGN KEY (store_id) REFERENCES store(store_id) ON UPDATE CASCADE ON DELETE RESTRICT Triggers: last_updated BEFORE UPDATE ON customer FOR EACH ROW EXECUTE PROCEDURE last_updated()
  77. 77. pl/php triggers pagila=# d rental Table quot;public.rentalquot; Column | Type | Modifiers --------------+-----------------------------+------------------------------------------------------------ rental_id | integer | not null default nextval('rental_rental_id_seq'::regclass) rental_date | timestamp without time zone | not null inventory_id | integer | not null customer_id | smallint | not null return_date | timestamp without time zone | staff_id | smallint | not null last_update | timestamp without time zone | not null default now() Indexes: quot;rental_pkeyquot; PRIMARY KEY, btree (rental_id) quot;idx_unq_rental_rental_date_inventory_id_customer_idquot; UNIQUE, btree (rental_date, inventory_id, customer_id) quot;idx_fk_inventory_idquot; btree (inventory_id) Foreign-key constraints: quot;rental_customer_id_fkeyquot; FOREIGN KEY (customer_id) REFERENCES customer(customer_id) ON UPDATE CASCADE ON DELETE RESTRICT quot;rental_inventory_id_fkeyquot; FOREIGN KEY (inventory_id) REFERENCES inventory(inventory_id) ON UPDATE CASCADE ON DELETE RESTRICT quot;rental_staff_id_fkeyquot; FOREIGN KEY (staff_id) REFERENCES staff(staff_id) ON UPDATE CASCADE ON DELETE RESTRICT Triggers: last_updated BEFORE UPDATE ON rental FOR EACH ROW EXECUTE PROCEDURE last_updated()
  78. 78. pl/php triggers CREATE TABLE overdue_log ( overdue_log_id serial, customer_id integer, days_overdue integer ); Each record gets a logical primary key ● Store the customer id and the number of days ● rental was overdue
  79. 79. pl/php triggers CREATE TABLE overdue_log ( overdue_log_id serial, customer_id integer, days_overdue integer ); Each record gets a logical primary key ● Store the customer id and the number of days ● rental was overdue Yes, this table is fake... no FK's, no ● timestamps, etc...
  80. 80. pl/php triggers – special variables $_TD[“old”] - Old data being removed from ● table $_TD[“new”] - New data being written to table ● Associative arrays, indexed by field names ● Null values not included ● Other special variables ● trigger name, trigger action, table name, etc... –
  81. 81. pl/php trigger function CREATE OR REPLACE FUNCTION watch_overdue() RETURNS trigger LANGUAGE plphpu AS $$ $new =& $_TD['new']; $sql = quot;SELECT rental_date + (rental_duration * '1 day'::interval) as due_date FROM rental INNER JOIN inventory USING (inventory_id) INNER JOIN film USING (film_id) WHERE rental_id =quot;. $new['rental_id']; $rs = spi_exec($sql); $r = spi_fetch_row($rs); continued...
  82. 82. pl/php trigger function CREATE OR REPLACE FUNCTION watch_overdue() RETURNS trigger LANGUAGE plphpu AS $$ $new =& $_TD['new']; $sql = quot;SELECT rental_date + (rental_duration * '1 day'::interval) as due_date FROM rental INNER JOIN inventory USING (inventory_id) INNER JOIN film USING (film_id) WHERE rental_id =quot;. $new['rental_id']; $rs = spi_exec($sql); $r = spi_fetch_row($rs); continued...
  83. 83. pl/php trigger function continued... pg_raise('notice',$r['due_date']); pg_raise('notice',$new['return_date']); if ($new['return_date'] > $r['due_date']) { /* rental is overdue, we need to convert our dates to php time values, find the difference between them, and then convert that to days */ $dayo = (strtotime($new['return_date']) - strtotime($r['due_date']))/60/60/24; pg_raise('notice',$dayo); $sql = quot;INSERT INTO overdue_log (customer_id,days_overdue) VALUES (quot;.$new['customer_id'].quot;,quot;.$dayo.quot;)quot;; $rs = spi_exec($sql); }; return null; $$;
  84. 84. pl/php trigger function continued... pg_raise('notice',$r['due_date']); pg_raise('notice',$new['return_date']); if ($new['return_date'] > $r['due_date']) { /* rental is overdue, we need to convert our dates to php time values, find the difference between them, and then convert that to days */ $dayo = (strtotime($new['return_date']) - strtotime($r['due_date']))/60/60/24; pg_raise('notice',$dayo); $sql = quot;INSERT INTO overdue_log (customer_id,days_overdue) VALUES (quot;.$new['customer_id'].quot;,quot;.$dayo.quot;)quot;; $rs = spi_exec($sql); }; return null; $$;
  85. 85. pl/php trigger function continued... pg_raise('notice',$r['due_date']); pg_raise('notice',$new['return_date']); if ($new['return_date'] > $r['due_date']) { /* rental is overdue, we need to convert our dates to php time values, find the difference between them, and then convert that to days */ $dayo = (strtotime($new['return_date']) - strtotime($r['due_date']))/60/60/24; pg_raise('notice',$dayo); $sql = quot;INSERT INTO overdue_log (customer_id,days_overdue) VALUES (quot;.$new['customer_id'].quot;,quot;.$dayo.quot;)quot;; $rs = spi_exec($sql); }; return null; $$;
  86. 86. pl/php trigger function continued... pg_raise('notice',$r['due_date']); pg_raise('notice',$new['return_date']); if ($new['return_date'] > $r['due_date']) { /* rental is overdue, we need to convert our dates to php time values, find the difference between them, and then convert that to days */ $dayo = (strtotime($new['return_date']) - strtotime($r['due_date']))/60/60/24; pg_raise('notice',$dayo); $sql = quot;INSERT INTO overdue_log (customer_id,days_overdue) VALUES (quot;.$new['customer_id'].quot;,quot;.$dayo.quot;)quot;; $rs = spi_exec($sql); }; return null; $$;
  87. 87. pl/php triggers (the trigger) CREATE TRIGGER watch_overdue AFTER insert or update ON rental FOR EACH row EXECUTE PROCEDURE watch_overdue(); No special syntax needed – Trigger fires on any insert or update – We can tweak rules by modifying the function –
  88. 88. pl/php triggers pagila=# INSERT INTO rental pagila-# VALUES (DEFAULT,now() - '1 month'::interval,2792,549,now(),1);
  89. 89. pl/php triggers pagila=# INSERT INTO rental pagila-# VALUES (DEFAULT,now() - '1 month'::interval,2792,549,now(),1); NOTICE: plphp: 2006-07-30 11:27:56.854139 NOTICE: plphp: 2006-08-25 11:27:56.854139 NOTICE: plphp: 26 INSERT 0 1 pagila=#
  90. 90. pl/php triggers pagila=# INSERT INTO rental pagila-# VALUES (DEFAULT,now() - '1 month'::interval,2792,549,now(),1); NOTICE: plphp: 2006-07-30 11:27:56.854139 NOTICE: plphp: 2006-08-25 11:27:56.854139 NOTICE: plphp: 26 INSERT 0 1 pagila=# SELECT * FROM overdue_log;
  91. 91. pl/php triggers pagila=# INSERT INTO rental pagila-# VALUES (DEFAULT,now() - '1 month'::interval,2792,549,now(),1); NOTICE: plphp: 2006-07-30 11:27:56.854139 NOTICE: plphp: 2006-08-25 11:27:56.854139 NOTICE: plphp: 26 INSERT 0 1 pagila=# SELECT * FROM overdue_log; overdue_log_id | customer_id | days_overdue ----------------------+-----------------+---------------- 1| 549 | 26
  92. 92. pl/php – one more example CREATE OR REPLACE FUNCTION text_array_to_result(text[]) RETURNS setof text LANGUAGE plphpu AS $$ // TRICKY!! $args[0] refers to the first argument of the function // so $args[0][0] refers to the first value of the array passed into the first argument! $i=0; while ($args[0][$i]) { $ret = $args[0][$i]; return_next($ret); $i++; } #pg_raise('notice',$args[0]); $$;
  93. 93. pl/php – one more example CREATE OR REPLACE FUNCTION text_array_to_result(text[]) RETURNS setof text LANGUAGE plphpu AS $$ // TRICKY!! $args[0] refers to the first argument of the function // so $args[0][0] refers to the first value of the array passed into the first argument! $i=0; while ($args[0][$i]) { $ret = $args[0][$i]; return_next($ret); $i++; } #pg_raise('notice',$args[0]); $$;
  94. 94. pl/php – one more example CREATE OR REPLACE FUNCTION text_array_to_result(text[]) RETURNS setof text LANGUAGE plphpu AS $$ // TRICKY!! $args[0] refers to the first argument of the function // so $args[0][0] refers to the first value of the array passed into the first argument! $i=0; while ($args[0][$i]) { $ret = $args[0][$i]; return_next($ret); $i++; } #pg_raise('notice',$args[0]); $$;
  95. 95. pl/php – one more example pagila=# SELECT * FROM text_array_to_result('{txt arg 1,txt arg 2}'); text_array_to_result ---------------------- txt arg 1 txt arg 2 (2 rows) Works with arrays ● Works for set returning functions ●
  96. 96. pl/php – one more example pagila=# SELECT * FROM text_array_to_result('{txt arg 1,txt arg 2}'); text_array_to_result ---------------------- txt arg 1 txt arg 2 (2 rows) Works with arrays ● Works for set returning functions ● Oh yeah... no special syntax :-) ●
  97. 97. but wait, there's more! Composite data types ● Working with array types ● Global shared variables ● Polymorphic Arguments ● Polymorphic Return Types ● Composite Types ●
  98. 98. pl/php - caveats Rough around the edges ● sometimes uncover segfaults – lots of warnings / notices from php – no in / out parameters (8.1) –
  99. 99. pl/php - caveats Rough around the edges ● sometimes uncover segfaults – lots of warnings / notices from php – no in / out parameters (8.1) – Can't call other pl/php functions directly ●
  100. 100. pl/php - caveats Rough around the edges ● sometimes uncover segfaults – lots of warnings / notices from php – no in / out parameters (8.1) – Can't call other pl/php functions directly ● Not fully tested against all PHP functions ●
  101. 101. pl/php - caveats Rough around the edges ● sometimes uncover segfaults – lots of warnings / notices from php – no in / out parameters (8.1) – Can't call other pl/php functions directly ● Not fully tested against all PHP functions ● Needs some C developers to contribute ●
  102. 102. Thanks! Command Prompt, Inc. Alvarro Herrera Alexey Klyukin Greg Sabino-Mullane OmniTI The PHP & PostgreSQL Communities :-)

×