SlideShare uma empresa 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
               :-)

Mais conteúdo relacionado

Mais procurados

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
 

Mais procurados (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
 

Destaque

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
 

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

Semelhante 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
 

Semelhante 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
 

Mais 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
 

Mais 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

Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Neo4j
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Unlocking the Potential of the Cloud for IBM Power Systems
Unlocking the Potential of the Cloud for IBM Power SystemsUnlocking the Potential of the Cloud for IBM Power Systems
Unlocking the Potential of the Cloud for IBM Power SystemsPrecisely
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 

Último (20)

Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Unlocking the Potential of the Cloud for IBM Power Systems
Unlocking the Potential of the Cloud for IBM Power SystemsUnlocking the Potential of the Cloud for IBM Power Systems
Unlocking the Potential of the Cloud for IBM Power Systems
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 

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 :-)