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/
●
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!
●
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
●
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 20060826 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
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.
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
–
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
:-)