SlideShare ist ein Scribd-Unternehmen logo
1 von 102
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 to program inside the database
●


    using PHP
Let's see an example eh?
CREATE OR REPLACE FUNCTION hello_world()
RETURNS text
LANGUAGE plphp
AS $$
 $var = quot;howdy yallquot;;
 RETURN $var;
$$;
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)
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?
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/
●
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 access tables and whatnot
     –
So why do people use pl/php?
     Nicely integrates with PostgreSQL
 ●



         close to data
     –

         easily access tables and whatnot
     –


     Save on network traffic
 ●
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!
 ●
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 dependencies to your database
●




    Code is still green
●




    Small user community
●
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
                  PostgreSQL 8.1.9
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)
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
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
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@ridley:~/devel/plphp$
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
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$
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
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$
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
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
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
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
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
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
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.
    Should be easier than compiling
●
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...
●
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
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/postgresql/8.1/lib/plphp.soquot;: /usr/lib/libphp5.so:
undefined symbol: ap_loaded_modules
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...
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.
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
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=#
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.
●
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!
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!
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!
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!
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!
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!
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!
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!
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
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;
  };
$$;
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;
  };
$$;
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.
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;
  };
$$;
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;
  };
$$;
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;
  };
$$;
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)
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;
$$;
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
    ●                                                    ●
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;
$$;
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)
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)
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;
$$;
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)
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) );
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) );
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) );
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
●
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
    ●
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
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
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()
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()
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
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...
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...
    –
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...
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...
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;
$$;
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;
$$;
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;
$$;
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;
$$;
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
–
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);
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=#
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;
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
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]);
$$;
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]);
$$;
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]);
$$;
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
●
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 :-)
●
but wait, there's more!
    Composite data types
●



    Working with array types
●



    Global shared variables
●



    Polymorphic Arguments
●



    Polymorphic Return Types
●



    Composite Types
●
pl/php - caveats
    Rough around the edges
●


        sometimes uncover segfaults
    –

        lots of warnings / notices from php
    –

        no in / out parameters (8.1)
    –
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
●
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
●
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
●
Thanks!
      Command Prompt, Inc.
         Alvarro Herrera
          Alexey Klyukin
       Greg Sabino-Mullane
             OmniTI
The PHP & PostgreSQL Communities
               :-)

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

Composer - Package Management for PHP. Silver Bullet?
Composer - Package Management for PHP. Silver Bullet?Composer - Package Management for PHP. Silver Bullet?
Composer - Package Management for PHP. Silver Bullet?
 
PHP Dependency Management with Composer
PHP Dependency Management with ComposerPHP Dependency Management with Composer
PHP Dependency Management with Composer
 
Go Replicator
Go ReplicatorGo Replicator
Go Replicator
 
What you need to remember when you upload to CPAN
What you need to remember when you upload to CPANWhat you need to remember when you upload to CPAN
What you need to remember when you upload to CPAN
 
Vagrant move over, here is Docker
Vagrant move over, here is DockerVagrant move over, here is Docker
Vagrant move over, here is Docker
 
Laravel 4 package development
Laravel 4 package developmentLaravel 4 package development
Laravel 4 package development
 
PHP 5.6 New and Deprecated Features
PHP 5.6  New and Deprecated FeaturesPHP 5.6  New and Deprecated Features
PHP 5.6 New and Deprecated Features
 
Advanced debugging  techniques in different environments
Advanced debugging  techniques in different environmentsAdvanced debugging  techniques in different environments
Advanced debugging  techniques in different environments
 
Construire son JDK en 10 étapes
Construire son JDK en 10 étapesConstruire son JDK en 10 étapes
Construire son JDK en 10 étapes
 
Unit Testing Lots of Perl
Unit Testing Lots of PerlUnit Testing Lots of Perl
Unit Testing Lots of Perl
 
Building robust and friendly command line applications in go
Building robust and friendly command line applications in goBuilding robust and friendly command line applications in go
Building robust and friendly command line applications in go
 
Puppet Continuous Integration with PE and GitLab
Puppet Continuous Integration with PE and GitLabPuppet Continuous Integration with PE and GitLab
Puppet Continuous Integration with PE and GitLab
 
Debugging concurrency programs in go
Debugging concurrency programs in goDebugging concurrency programs in go
Debugging concurrency programs in go
 
Apache and PHP: Why httpd.conf is your new BFF!
Apache and PHP: Why httpd.conf is your new BFF!Apache and PHP: Why httpd.conf is your new BFF!
Apache and PHP: Why httpd.conf is your new BFF!
 
Containers for sysadmins
Containers for sysadminsContainers for sysadmins
Containers for sysadmins
 
Caching and tuning fun for high scalability @ FrOSCon 2011
Caching and tuning fun for high scalability @ FrOSCon 2011Caching and tuning fun for high scalability @ FrOSCon 2011
Caching and tuning fun for high scalability @ FrOSCon 2011
 
Python at Facebook
Python at FacebookPython at Facebook
Python at Facebook
 
Learn flask in 90mins
Learn flask in 90minsLearn flask in 90mins
Learn flask in 90mins
 
Debugging PHP with Xdebug - PHPUK 2018
Debugging PHP with Xdebug - PHPUK 2018Debugging PHP with Xdebug - PHPUK 2018
Debugging PHP with Xdebug - PHPUK 2018
 
PHP selber bauen
PHP selber bauenPHP selber bauen
PHP selber bauen
 

Andere mochten auch

Os Recordontutorial
Os RecordontutorialOs Recordontutorial
Os Recordontutorial
oscon2007
 
大學學測衝刺
大學學測衝刺大學學測衝刺
大學學測衝刺
thyung2001
 
Railsconf2007
Railsconf2007Railsconf2007
Railsconf2007
oscon2007
 
Os Pruett Sessionnotes
Os Pruett SessionnotesOs Pruett Sessionnotes
Os Pruett Sessionnotes
oscon2007
 
Os Keyshacks
Os KeyshacksOs Keyshacks
Os Keyshacks
oscon2007
 
Os Urnerupdated
Os UrnerupdatedOs Urnerupdated
Os Urnerupdated
oscon2007
 

Andere mochten auch (9)

Os Recordontutorial
Os RecordontutorialOs Recordontutorial
Os Recordontutorial
 
Os Sharp
Os SharpOs Sharp
Os Sharp
 
Os Napier
Os NapierOs Napier
Os Napier
 
大學學測衝刺
大學學測衝刺大學學測衝刺
大學學測衝刺
 
Railsconf2007
Railsconf2007Railsconf2007
Railsconf2007
 
Os Pruett Sessionnotes
Os Pruett SessionnotesOs Pruett Sessionnotes
Os Pruett Sessionnotes
 
Os Bowkett
Os BowkettOs Bowkett
Os Bowkett
 
Os Keyshacks
Os KeyshacksOs Keyshacks
Os Keyshacks
 
Os Urnerupdated
Os UrnerupdatedOs Urnerupdated
Os Urnerupdated
 

Ähnlich wie Os Treat

9 steps to install and configure postgre sql from source on linux
9 steps to install and configure postgre sql from source on linux9 steps to install and configure postgre sql from source on linux
9 steps to install and configure postgre sql from source on linux
chinkshady
 
Perl In The Command Line
Perl In The Command LinePerl In The Command Line
Perl In The Command Line
Marcos Rebelo
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linux
tutorialsruby
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linux
tutorialsruby
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linux
tutorialsruby
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linux
tutorialsruby
 
Website releases made easy with the PEAR installer, OSCON 2009
Website releases made easy with the PEAR installer, OSCON 2009Website releases made easy with the PEAR installer, OSCON 2009
Website releases made easy with the PEAR installer, OSCON 2009
Helgi Þormar Þorbjörnsson
 
PM : code faster
PM : code fasterPM : code faster
PM : code faster
PHPPRO
 

Ähnlich wie Os Treat (20)

Drupal and Open shift (and php)
Drupal and Open shift (and php)Drupal and Open shift (and php)
Drupal and Open shift (and php)
 
Lumen
LumenLumen
Lumen
 
A General Purpose Docker Image for PHP
A General Purpose Docker Image for PHPA General Purpose Docker Image for PHP
A General Purpose Docker Image for PHP
 
Performance Profiling in Rust
Performance Profiling in RustPerformance Profiling in Rust
Performance Profiling in Rust
 
9 steps to install and configure postgre sql from source on linux
9 steps to install and configure postgre sql from source on linux9 steps to install and configure postgre sql from source on linux
9 steps to install and configure postgre sql from source on linux
 
Perl In The Command Line
Perl In The Command LinePerl In The Command Line
Perl In The Command Line
 
Prepare for PHP Test Fest 2009
Prepare for PHP Test Fest 2009Prepare for PHP Test Fest 2009
Prepare for PHP Test Fest 2009
 
Bundling Packages and Deploying Applications with RPM
Bundling Packages and Deploying Applications with RPMBundling Packages and Deploying Applications with RPM
Bundling Packages and Deploying Applications with RPM
 
Running PHP on a Java container
Running PHP on a Java containerRunning PHP on a Java container
Running PHP on a Java container
 
PHP: The easiest language to learn.
PHP: The easiest language to learn.PHP: The easiest language to learn.
PHP: The easiest language to learn.
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linux
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linux
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linux
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linux
 
Award-winning technology: Oxid loves the query cache
Award-winning technology: Oxid loves the query cacheAward-winning technology: Oxid loves the query cache
Award-winning technology: Oxid loves the query cache
 
Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.cat
 
Git::Hooks
Git::HooksGit::Hooks
Git::Hooks
 
Website releases made easy with the PEAR installer, OSCON 2009
Website releases made easy with the PEAR installer, OSCON 2009Website releases made easy with the PEAR installer, OSCON 2009
Website releases made easy with the PEAR installer, OSCON 2009
 
PSGI and Plack from first principles
PSGI and Plack from first principlesPSGI and Plack from first principles
PSGI and Plack from first principles
 
PM : code faster
PM : code fasterPM : code faster
PM : code faster
 

Mehr von oscon2007

J Ruby Whirlwind Tour
J Ruby Whirlwind TourJ Ruby Whirlwind Tour
J Ruby Whirlwind Tour
oscon2007
 
Solr Presentation5
Solr Presentation5Solr Presentation5
Solr Presentation5
oscon2007
 
Os Fitzpatrick Sussman Wiifm
Os Fitzpatrick Sussman WiifmOs Fitzpatrick Sussman Wiifm
Os Fitzpatrick Sussman Wiifm
oscon2007
 
Performance Whack A Mole
Performance Whack A MolePerformance Whack A Mole
Performance Whack A Mole
oscon2007
 
Os Lanphier Brashears
Os Lanphier BrashearsOs Lanphier Brashears
Os Lanphier Brashears
oscon2007
 
Os Fitzpatrick Sussman Swp
Os Fitzpatrick Sussman SwpOs Fitzpatrick Sussman Swp
Os Fitzpatrick Sussman Swp
oscon2007
 
Os Berlin Dispelling Myths
Os Berlin Dispelling MythsOs Berlin Dispelling Myths
Os Berlin Dispelling Myths
oscon2007
 
Os Keysholistic
Os KeysholisticOs Keysholistic
Os Keysholistic
oscon2007
 
Os Jonphillips
Os JonphillipsOs Jonphillips
Os Jonphillips
oscon2007
 
Adventures In Copyright Reform
Adventures In Copyright ReformAdventures In Copyright Reform
Adventures In Copyright Reform
oscon2007
 

Mehr von oscon2007 (20)

J Ruby Whirlwind Tour
J Ruby Whirlwind TourJ Ruby Whirlwind Tour
J Ruby Whirlwind Tour
 
Solr Presentation5
Solr Presentation5Solr Presentation5
Solr Presentation5
 
Os Borger
Os BorgerOs Borger
Os Borger
 
Os Harkins
Os HarkinsOs Harkins
Os Harkins
 
Os Fitzpatrick Sussman Wiifm
Os Fitzpatrick Sussman WiifmOs Fitzpatrick Sussman Wiifm
Os Fitzpatrick Sussman Wiifm
 
Os Bunce
Os BunceOs Bunce
Os Bunce
 
Yuicss R7
Yuicss R7Yuicss R7
Yuicss R7
 
Performance Whack A Mole
Performance Whack A MolePerformance Whack A Mole
Performance Whack A Mole
 
Os Fogel
Os FogelOs Fogel
Os Fogel
 
Os Lanphier Brashears
Os Lanphier BrashearsOs Lanphier Brashears
Os Lanphier Brashears
 
Os Tucker
Os TuckerOs Tucker
Os Tucker
 
Os Fitzpatrick Sussman Swp
Os Fitzpatrick Sussman SwpOs Fitzpatrick Sussman Swp
Os Fitzpatrick Sussman Swp
 
Os Furlong
Os FurlongOs Furlong
Os Furlong
 
Os Berlin Dispelling Myths
Os Berlin Dispelling MythsOs Berlin Dispelling Myths
Os Berlin Dispelling Myths
 
Os Kimsal
Os KimsalOs Kimsal
Os Kimsal
 
Os Pruett
Os PruettOs Pruett
Os Pruett
 
Os Alrubaie
Os AlrubaieOs Alrubaie
Os Alrubaie
 
Os Keysholistic
Os KeysholisticOs Keysholistic
Os Keysholistic
 
Os Jonphillips
Os JonphillipsOs Jonphillips
Os Jonphillips
 
Adventures In Copyright Reform
Adventures In Copyright ReformAdventures In Copyright Reform
Adventures In Copyright Reform
 

Kürzlich hochgeladen

Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 

Kürzlich hochgeladen (20)

2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdf
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 

Os Treat

  • 1. An Introduction to pl/php by Robert Treat http://www.brighterlamp.org/
  • 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. Let's see an example eh? CREATE OR REPLACE FUNCTION hello_world() RETURNS text LANGUAGE plphp AS $$ $var = quot;howdy yallquot;; RETURN $var; $$;
  • 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. 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. 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. Who uses pl/php? We don't know... but it seems popular... ●
  • 10. So why do people use pl/php? Nicely integrates with PostgreSQL ● close to data – easily access tables and whatnot –
  • 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. 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. Any reason to avoid it? PostgreSQL specific ●
  • 14. Any reason to avoid it? PostgreSQL specific (well, maybe that's really ● a reason to use it)
  • 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. Installation Pre-requisites: ● PostgreSQL 8.1+ –
  • 17. Installation Pre-requisites: ● PostgreSQL 8.1+ – -bash-3.00$ pg_config --version
  • 18. Installation Pre-requisites: ● PostgreSQL 8.1+ – -bash-3.00$ pg_config --version PostgreSQL 8.1.9
  • 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. 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. 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. Installation Grab the latest release tarball, unpack it, configure ● and make (simple eh?)
  • 23. Installation Grab the latest release tarball, unpack it, configure ● and make (simple eh?) rob@ridley:~/devel/plphp$
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Installing pl/php into the Database Once .so is compiled, you need to install the ● language into your database.
  • 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. 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. 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. Installing pl/php into the Database pagila=#
  • 39. Installing pl/php into the Database pagila=# create language plphp;
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. pl/php triggers pagila=# INSERT INTO rental pagila-# VALUES (DEFAULT,now() - '1 month'::interval,2792,549,now(),1);
  • 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. 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. 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. 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. 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. 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. 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. 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. but wait, there's more! Composite data types ● Working with array types ● Global shared variables ● Polymorphic Arguments ● Polymorphic Return Types ● Composite Types ●
  • 98. pl/php - caveats Rough around the edges ● sometimes uncover segfaults – lots of warnings / notices from php – no in / out parameters (8.1) –
  • 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. 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. 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. Thanks! Command Prompt, Inc. Alvarro Herrera Alexey Klyukin Greg Sabino-Mullane OmniTI The PHP & PostgreSQL Communities :-)