SlideShare una empresa de Scribd logo
1 de 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
               :-)

Más contenido relacionado

La actualidad más candente

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?Kirill Chebunin
 
PHP Dependency Management with Composer
PHP Dependency Management with ComposerPHP Dependency Management with Composer
PHP Dependency Management with ComposerAdam Englander
 
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 CPANcharsbar
 
Vagrant move over, here is Docker
Vagrant move over, here is DockerVagrant move over, here is Docker
Vagrant move over, here is DockerNick Belhomme
 
Laravel 4 package development
Laravel 4 package developmentLaravel 4 package development
Laravel 4 package developmentTihomir Opačić
 
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 FeaturesMark Niebergall
 
Advanced debugging  techniques in different environments
Advanced debugging  techniques in different environmentsAdvanced debugging  techniques in different environments
Advanced debugging  techniques in different environmentsAndrii Soldatenko
 
Construire son JDK en 10 étapes
Construire son JDK en 10 étapesConstruire son JDK en 10 étapes
Construire son JDK en 10 étapesJosé Paumard
 
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 goAndrii Soldatenko
 
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 GitLabAlessandro Franceschi
 
Debugging concurrency programs in go
Debugging concurrency programs in goDebugging concurrency programs in go
Debugging concurrency programs in goAndrii Soldatenko
 
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!Jeff Jones
 
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 2011Wim Godden
 
Learn flask in 90mins
Learn flask in 90minsLearn flask in 90mins
Learn flask in 90minsLarry Cai
 
Debugging PHP with Xdebug - PHPUK 2018
Debugging PHP with Xdebug - PHPUK 2018Debugging PHP with Xdebug - PHPUK 2018
Debugging PHP with Xdebug - PHPUK 2018Mark Niebergall
 

La actualidad más candente (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
 

Destacado

Os Recordontutorial
Os RecordontutorialOs Recordontutorial
Os Recordontutorialoscon2007
 
大學學測衝刺
大學學測衝刺大學學測衝刺
大學學測衝刺thyung2001
 
Railsconf2007
Railsconf2007Railsconf2007
Railsconf2007oscon2007
 
Os Pruett Sessionnotes
Os Pruett SessionnotesOs Pruett Sessionnotes
Os Pruett Sessionnotesoscon2007
 
Os Keyshacks
Os KeyshacksOs Keyshacks
Os Keyshacksoscon2007
 
Os Urnerupdated
Os UrnerupdatedOs Urnerupdated
Os Urnerupdatedoscon2007
 

Destacado (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
 

Similar a Os Treat

Drupal and Open shift (and php)
Drupal and Open shift (and php)Drupal and Open shift (and php)
Drupal and Open shift (and php)Phase2
 
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 PHPRobert Lemke
 
Performance Profiling in Rust
Performance Profiling in RustPerformance Profiling in Rust
Performance Profiling in RustInfluxData
 
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 linuxchinkshady
 
Perl In The Command Line
Perl In The Command LinePerl In The Command Line
Perl In The Command LineMarcos Rebelo
 
Prepare for PHP Test Fest 2009
Prepare for PHP Test Fest 2009Prepare for PHP Test Fest 2009
Prepare for PHP Test Fest 2009PHPBelgium
 
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 RPMAlexander Shopov
 
Running PHP on a Java container
Running PHP on a Java containerRunning PHP on a Java container
Running PHP on a Java containernetinhoteixeira
 
PHP: The easiest language to learn.
PHP: The easiest language to learn.PHP: The easiest language to learn.
PHP: The easiest language to learn.Binny V A
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linuxtutorialsruby
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linuxtutorialsruby
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linuxtutorialsruby
 
mapserver_install_linux
mapserver_install_linuxmapserver_install_linux
mapserver_install_linuxtutorialsruby
 
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 cacheUlf Wendel
 
Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.catPablo Godel
 
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 2009Helgi Þormar Þorbjörnsson
 
PSGI and Plack from first principles
PSGI and Plack from first principlesPSGI and Plack from first principles
PSGI and Plack from first principlesPerl Careers
 
PM : code faster
PM : code fasterPM : code faster
PM : code fasterPHPPRO
 

Similar a 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
 

Más de oscon2007

J Ruby Whirlwind Tour
J Ruby Whirlwind TourJ Ruby Whirlwind Tour
J Ruby Whirlwind Touroscon2007
 
Solr Presentation5
Solr Presentation5Solr Presentation5
Solr Presentation5oscon2007
 
Os Fitzpatrick Sussman Wiifm
Os Fitzpatrick Sussman WiifmOs Fitzpatrick Sussman Wiifm
Os Fitzpatrick Sussman Wiifmoscon2007
 
Performance Whack A Mole
Performance Whack A MolePerformance Whack A Mole
Performance Whack A Moleoscon2007
 
Os Lanphier Brashears
Os Lanphier BrashearsOs Lanphier Brashears
Os Lanphier Brashearsoscon2007
 
Os Fitzpatrick Sussman Swp
Os Fitzpatrick Sussman SwpOs Fitzpatrick Sussman Swp
Os Fitzpatrick Sussman Swposcon2007
 
Os Berlin Dispelling Myths
Os Berlin Dispelling MythsOs Berlin Dispelling Myths
Os Berlin Dispelling Mythsoscon2007
 
Os Keysholistic
Os KeysholisticOs Keysholistic
Os Keysholisticoscon2007
 
Os Jonphillips
Os JonphillipsOs Jonphillips
Os Jonphillipsoscon2007
 
Adventures In Copyright Reform
Adventures In Copyright ReformAdventures In Copyright Reform
Adventures In Copyright Reformoscon2007
 

Más de 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
 

Último

Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native ApplicationsWSO2
 
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 DiscoveryTrustArc
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
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 SavingEdi Saputra
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfOverkill Security
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024The Digital Insurer
 
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...DianaGray10
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...apidays
 
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 2024The Digital Insurer
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 

Último (20)

Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
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
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
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
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
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...
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
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
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 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 :-)