Project

General

Profile

Documentation » History » Version 18

Álvaro Herrera, 10/16/2008 01:26 PM

1 1 bford -
2 18 Álvaro Herrera
h1. PL/php - PHP Procedural Language for [[PostgreSQL]]
3
4
5 1 bford -
[[PageOutline(2-3,Contents,inline)]]
6
7
8 18 Álvaro Herrera
h2. What is PL/php?
9
10
11
PL/php is a procedural language with hooks into the [[PostgreSQL]]
12 1 bford -
database sytem, intended to allow writing of PHP functions for
13 18 Álvaro Herrera
use as functions inside the [[PostgreSQL]] database.
14 1 bford -
It was written by Command Prompt, Inc. and has since
15 18 Álvaro Herrera
been open sourced and licensed under the PHP and [[PostgreSQL]] (BSD)
16 1 bford -
licenses.
17
18
19 18 Álvaro Herrera
h2. Download and Installation
20 1 bford -
21 17 Álvaro Herrera
22 18 Álvaro Herrera
Please see [[InstallDocs|the installation documentation]].
23
24
25
h2. Creating the PL/php language
26
27
28
Please see the documentation on [[CreateLang|how to create the language in a database]]
29 3 Álvaro Herrera
once the library is installed.
30 1 bford -
31
32 18 Álvaro Herrera
h2. Functions and Arguments
33
34
35 1 bford -
To create a function, use the standard syntax:
36
37
38 18 Álvaro Herrera
<pre>
39 6 Álvaro Herrera
CREATE FUNCTION funcname (argument-types) RETURNS return-type AS $$
40 1 bford -
   # plphp function body here
41
$$ LANGUAGE 'plphp';
42 18 Álvaro Herrera
</pre>
43 1 bford -
44
45
Arguments are passed in the $args array and the result value is returned
46 2 Álvaro Herrera
with the 'return' statement.
47 1 bford -
48 6 Álvaro Herrera
49 18 Álvaro Herrera
<pre>
50 1 bford -
CREATE FUNCTION plphp_max(integer, integer) RETURNS integer AS $$
51 18 Álvaro Herrera
   if ($argsr0 > $argsr1) {
52
      return $argsr0;
53 1 bford -
   } else {
54 18 Álvaro Herrera
      return $argsr1;
55 1 bford -
   }     
56
$$ STRICT LANGUAGE 'plphp'
57 18 Álvaro Herrera
</pre>
58 17 Álvaro Herrera
59
60
> NOTE: The use of the STRICT clause saves us from having to
61
> think about NULL input values to our function.  In a STRICT function,
62
> when a NULL value is passed, the function will not be run at all,
63 1 bford -
> but the system will just return a NULL result automatically.
64
>
65
> In a non-strict function, if the actual value of an argument is NULL,
66 17 Álvaro Herrera
> the corresponding $args[n-1] variable will be set to an empty string
67
> (unset).
68 1 bford -
69
70
71 18 Álvaro Herrera
h2. Data Types and Returns
72
73
74 3 Álvaro Herrera
The arguments passed into your PL/php function are converted to text
75 1 bford -
so you can manipulate them with the loose typing enjoyed in typical
76
PHP scripts.  Conversely, the return command will accept any string
77
that is acceptable input format for the function's declared return
78
type.
79 3 Álvaro Herrera
80 1 bford -
81
82 18 Álvaro Herrera
h2. Global Shared Variable
83
84
85 6 Álvaro Herrera
There is a global variable that can be used to store data between
86
function calls, called $_SHARED.
87 1 bford -
88 18 Álvaro Herrera
<pre>
89 1 bford -
CREATE FUNCTION set_var(text) RETURNS text AS $$
90 6 Álvaro Herrera
   global $_SHARED;
91 18 Álvaro Herrera
   $_SHARED['first']=$argsr0;
92 6 Álvaro Herrera
   return 'ok';
93 1 bford -
$$ LANGUAGE 'plphp';
94 6 Álvaro Herrera
95 1 bford -
CREATE FUNCTION get_var() RETURNS text AS $$
96
   global $_SHARED;
97
   return $_SHARED['first'];
98
$$ LANGUAGE 'plphp';
99
100
SELECT set_var('hello plphp');
101
SELECT get_var(); -- will return 'hello plphp'
102 18 Álvaro Herrera
</pre>
103 3 Álvaro Herrera
104 1 bford -
NOTE: The shared global variable is connection-specific.  This is
105
useful for passing information around a single script execution,
106
but it is wiped when the connection is closed.
107
108
109
110 18 Álvaro Herrera
h2. [[PostgreSQL]] Array Support
111
112
113 1 bford -
There is support for multi-dimensional arrays.
114 6 Álvaro Herrera
115 1 bford -
For example:
116
117 18 Álvaro Herrera
<pre>
118 1 bford -
CREATE FUNCTION php_array() RETURNS text[][] AS $$
119
   $return = array(array("Steven", "Klassen"),
120 6 Álvaro Herrera
                   array("Jonathan", "Daugherty"));
121 1 bford -
122
   return $return;
123
$$ LANGUAGE 'plphp';
124 18 Álvaro Herrera
</pre>
125 1 bford -
126
127 18 Álvaro Herrera
<pre>
128 1 bford -
sklassen=# select php_array();
129
                php_array                
130
-----------------------------------------
131
 {{Steven,Klassen},{Jonathan,Daugherty}}
132
(1 row)
133 18 Álvaro Herrera
</pre>
134 1 bford -
135
136
137 18 Álvaro Herrera
h2. Polymorphic Arguments and Return Types
138
139
140 1 bford -
Functions may be declared to accept and return the polymorphic types
141 18 Álvaro Herrera
'anyelement', 'anyarray', and 'anyrecord'.  See the [[PostgreSQL]]
142 1 bford -
documentation section 33.2.5 for a more detailed explanation of
143
polymorphic functions.
144
145
For example,
146
147 18 Álvaro Herrera
<pre>
148 1 bford -
CREATE FUNCTION array_three_values(anyelement, anyelement, anyelement) RETURNS anyarray AS '
149 18 Álvaro Herrera
   $retr0 = $argsr0;
150
   $retr1 = $argsr1;
151
   $retr2 = $argsr2;
152 1 bford -
   return $ret;
153
' LANGUAGE 'plphp';
154
155
SELECT array_three_values(3,2,1);
156
 array_three_values
157
--------------------
158
 {3,2,1}
159
(1 row)
160
161
CREATE OR REPLACE FUNCTION php_row(integer) RETURNS record AS '
162 18 Álvaro Herrera
   $ret[f1]=$argsr0;
163 1 bford -
   $ret[f2]="hello";
164
   $ret[f3]="world";
165
   return $ret;
166
' LANGUAGE 'plphp';
167
168
select * FROM php_row(1) AS (f1 integer, f2 text, f3 text);
169 18 Álvaro Herrera
</pre>
170 12 Álvaro Herrera
171
172
173 18 Álvaro Herrera
h2. Database Access (SPI)
174
175
176 12 Álvaro Herrera
Some functions are provided for database access.
177
178
 1. spi_exec - Execute a query with optional limit.
179 18 Álvaro Herrera
<pre>
180 1 bford -
resource spi_exec(string query[, int limit])
181 18 Álvaro Herrera
</pre>
182 12 Álvaro Herrera
 1. spi_fetch_row - Return an associative array of the row's results.
183 18 Álvaro Herrera
<pre>
184 1 bford -
array spi_fetch_row(resource result)
185 18 Álvaro Herrera
</pre>
186 12 Álvaro Herrera
 1. spi_status - Return the status of a previous query.  If this is SPI_OK_SELECT you can obtain tuples from the result using spi_fetch_row.
187 18 Álvaro Herrera
<pre>
188 1 bford -
string spi_status(resource result)
189 18 Álvaro Herrera
</pre>
190 1 bford -
 1. spi_processed - Return the number of tuples in a result.
191 18 Álvaro Herrera
<pre>
192 1 bford -
int spi_processed(resource result)
193 18 Álvaro Herrera
</pre>
194 1 bford -
 1. spi_rewind - Put the row cursor at the beginning of the result, so spi_fetch_row will continue fetching tuples from the beginning of the result.
195 18 Álvaro Herrera
<pre>
196 1 bford -
void spi_rewind(resource result)
197 18 Álvaro Herrera
</pre>
198 1 bford -
199
For example:
200
201
This isn't a particularly useful function, but it will illustrate the
202
above-described access functions.  You provide an integer id and it
203
returns the username text field.
204
205 18 Álvaro Herrera
<pre>
206 12 Álvaro Herrera
CREATE FUNCTION get_username(integer) RETURNS text AS $$
207 1 bford -
   # Assign the query to a variable.
208 18 Álvaro Herrera
   $query = "SELECT username FROM users WHERE id = " .$argsr0;
209 1 bford -
210
   # Run the query and get the $result object.
211
   $result = spi_exec_query($query);
212
213
   # Fetch the row from the $result.
214
   $row = spi_fetch_row($result);
215
216
   return $row['username'];
217 12 Álvaro Herrera
$$ LANGUAGE 'plphp';
218
219 1 bford -
sklassen=# select get_username(1);
220
 get_username 
221
--------------
222
 sklassen
223
(1 row)
224 18 Álvaro Herrera
</pre>
225 14 Álvaro Herrera
226 1 bford -
Note that results from spi_exec_query are allocated in RAM as a whole, so if you need to process huge result sets, you need to use a cursor.  This is not possible with the current interface however, so if you need to do this, bug the developers.
227 4 Álvaro Herrera
228 1 bford -
229 18 Álvaro Herrera
h2. Triggers
230
231
232 1 bford -
When a function is being used to return a trigger, the associative
233
array $_TD contains trigger-related values.
234
235 18 Álvaro Herrera
 $_TD[[new]]::
236 9 Álvaro Herrera
   An associative array containing the values of the new table row for
237 1 bford -
   INSERT/UPDATE actions, or empty for DELETE.  The array is indexed
238 9 Álvaro Herrera
   by field name.  Important note: Fields that are NULL will not
239 1 bford -
   appear in the array!
240 18 Álvaro Herrera
 $_TD[[old]]::
241 4 Álvaro Herrera
   An associative array containing the values of the old table row for
242 1 bford -
   UPDATE/DELETE actions, or empty for INSERT.  The array is indexed
243
   by field name.  Important note: Fields that are NULL will not
244
   appear in the array!
245 18 Álvaro Herrera
 $_TD[[name]]::
246 1 bford -
   Contains the trigger name itself.
247 18 Álvaro Herrera
 $_TD[[event]]::
248 1 bford -
   Contains one of the values: "INSERT", "UPDATE", "DELETE".
249 18 Álvaro Herrera
 $_TD[[when]]::
250 1 bford -
   Contains one of the values: "BEFORE", "AFTER".
251 18 Álvaro Herrera
 $_TD[[level]]::
252 1 bford -
   Contains one of the values: "ROW", "STATEMENT".
253 18 Álvaro Herrera
 $_TD[[relid]]::
254 4 Álvaro Herrera
   Contains the relation ID of the table on which the trigger occured.
255 18 Álvaro Herrera
 $_TD[[relname]]::
256 1 bford -
   Contains the relation name.
257
258 18 Álvaro Herrera
 $_TD[[args]]::
259 1 bford -
   An array of arguments passed to the trigger, if any.  They can be
260 18 Álvaro Herrera
   accessed as $_TD[[args"][idx]  For example $_TD["args]].
261
 $_TD[[argc]]::
262 1 bford -
  The number of arguments passed to the trigger, 0 if none.
263
264
265 18 Álvaro Herrera
h3. Example of an AFTER INSERT trigger
266
267
268 1 bford -
Suppose you have a users table with the typical columns and an
269
activity table that you're using to track page accesses.  On row
270
271
INSERT to the activity table, you want to update the last_seen field
272
of the appropriate user's record.
273
274
Consider the following table definitions:
275
276 18 Álvaro Herrera
<pre>
277 1 bford -
CREATE TABLE users (
278
    id serial PRIMARY KEY NOT NULL,
279
    username text NOT NULL,
280
    email text,
281
    last_seen timestamp without time zone,
282
    active boolean DEFAULT true NOT NULL
283
);
284
285
CREATE TABLE activity (
286
    id serial PRIMARY KEY NOT NULL,
287
    users_id integer NOT NULL,
288
    file_accessed text NOT NULL,
289
    stamp timestamp without time zone DEFAULT now() NOT NULL,
290 13 Álvaro Herrera
    CONSTRAINT users_id_exists FOREIGN KEY (users_id) REFERENCES users(id)
291
);
292 1 bford -
293 13 Álvaro Herrera
CREATE FUNCTION update_lastseen() RETURNS trigger AS $$
294
    $new =& $_TD['new'];
295
296 1 bford -
    if (isset($new['users_id']) && isset($new['stamp'])) {
297 13 Álvaro Herrera
        $query = "UPDATE users SET last_seen = '" .$new['stamp'].
298 1 bford -
                 "' WHERE id = " .$new['users_id'];
299
300
        $rv = spi_exec($query);
301 13 Álvaro Herrera
    }
302 1 bford -
303
    return;
304
$$ LANGUAGE 'plphp';
305
306
CREATE TRIGGER after_update_lastseen_trigger
307
    AFTER INSERT ON activity FOR EACH ROW EXECUTE PROCEDURE update_lastseen();
308
309 18 Álvaro Herrera
</pre>
310 1 bford -
311 18 Álvaro Herrera
*1. We'll insert a new user row.*
312 1 bford -
313
314 18 Álvaro Herrera
<pre>
315 1 bford -
sklassen=# insert into users (username, email) values ('sklassen','sklassen@commandprompt.com');
316
INSERT 1
317
318
sklassen=# select * from users where username = 'sklassen';
319
320
 id | username |           email            | last_seen | active 
321
----+----------+----------------------------+-----------+--------
322
  1 | sklassen | sklassen@commandprompt.com |           | t
323
(1 row)
324 18 Álvaro Herrera
</pre>
325 1 bford -
326
327 18 Álvaro Herrera
*2. Insert a new row into the activity table.*
328 1 bford -
329
330 18 Álvaro Herrera
<pre>
331 1 bford -
sklassen=# insert into activity (users_id, file_accessed) values (1,'index.html');
332
INSERT 1
333 18 Álvaro Herrera
</pre>
334 1 bford -
335 18 Álvaro Herrera
*3. Check and make sure our trigger fired as expected.*
336 1 bford -
337 18 Álvaro Herrera
<pre>
338 1 bford -
sklassen=# select * from users where username = 'sklassen';
339
 id | username |           email            |         last_seen          | active 
340
----+----------+----------------------------+----------------------------+--------
341
  1 | sklassen | sklassen@commandprompt.com | 2005-01-10 09:48:57.191595 | t
342
(1 row)
343 18 Álvaro Herrera
</pre>
344 1 bford -
345
346 18 Álvaro Herrera
h3. Example of a BEFORE INSERT OR UPDATE trigger
347
348
349 1 bford -
Let's say we have a user named admin that we want to prevent the
350
application from modifying.  We'll create a BEFORE DELETE trigger that
351 12 Álvaro Herrera
prevents them from deleting the row and a BEFORE UPDATE trigger that
352
prevents them modifying the username on which the previous trigger
353
depends.
354
355 18 Álvaro Herrera
<pre>
356 12 Álvaro Herrera
CREATE TABLE users (username text, email text);
357
INSERT INTO users VALUES ('admin', 'admin@commandprompt.com');
358
INSERT INTO users VALUES ('darcy', 'darcy@example.com');
359
360 1 bford -
CREATE OR REPLACE FUNCTION immortal() RETURNS trigger AS $$
361
   # The record may not be deleted if the username is "admin".
362
   if ($_TD['old']['username'] == 'admin') {
363
      pg_raise('notice', "You cannot delete the admin user");
364 12 Álvaro Herrera
      return 'SKIP';
365 1 bford -
   }
366
   return;
367 12 Álvaro Herrera
$$ LANGUAGE 'plphp';
368
369
CREATE TRIGGER before_delete_immortal_trigger BEFORE DELETE ON users
370 1 bford -
FOR EACH ROW EXECUTE PROCEDURE immortal();
371 12 Álvaro Herrera
372
CREATE OR REPLACE FUNCTION protect_admin() RETURNS trigger AS $$
373 1 bford -
   # Do not let them modify the username of the admin account.
374 12 Álvaro Herrera
   $oldUsername = $_TD['old']['username'];
375
   $newUsername = $_TD['new']['username'];
376 1 bford -
377
   if ($oldUsername == 'admin' && ($oldUsername != $newUsername)) {
378
      pg_raise('notice', "You cannot change the admin username.");
379 12 Álvaro Herrera
      return 'SKIP';
380 1 bford -
   } else {
381
      return;
382
   }
383 12 Álvaro Herrera
$$ LANGUAGE 'plphp';
384
385 1 bford -
CREATE TRIGGER before_update_protect_admin_trigger BEFORE UPDATE ON
386
users FOR EACH ROW EXECUTE PROCEDURE protect_admin();
387 18 Álvaro Herrera
</pre>
388 12 Álvaro Herrera
389
Now the user admin cannot be deleted, nor its username can be changed:
390
391 18 Álvaro Herrera
<pre>
392 1 bford -
pl_regression=# select * from users;
393 12 Álvaro Herrera
 username |          email          
394
----------+-------------------------
395
 admin    | admin@commandprompt.com
396 1 bford -
 darcy    | darcy@example.com
397 12 Álvaro Herrera
(2 rows)
398 1 bford -
399 12 Álvaro Herrera
pl_regression=# update users set username = 'foobar';
400
NOTICE:  plphp: You cannot change the admin username.
401
UPDATE 1
402
403
pl_regression=# select * from users;
404 1 bford -
 username |          email          
405 12 Álvaro Herrera
----------+-------------------------
406
 admin    | admin@commandprompt.com
407 1 bford -
 foobar   | darcy@example.com
408 12 Álvaro Herrera
(2 rows)
409
410
pl_regression=# delete from users;
411 1 bford -
NOTICE:  plphp: You cannot delete the admin user
412
DELETE 1
413
414
pl_regression=# select * from users;
415
 username |          email          
416
----------+-------------------------
417
 admin    | admin@commandprompt.com
418
(1 row)
419 18 Álvaro Herrera
</pre>
420 1 bford -
421
422
423 18 Álvaro Herrera
h2. Trusted vs. Untrusted
424
425
426 1 bford -
Normally, PL/php is installed as a "trusted" procedural language named
427
'plphp'.  In this configuration, PHP will run in "safe mode".  Read
428
more about the restrictions here:
429
430
http://www.php.net/manual/en/features.safe-mode.functions.php
431
432
In general, the operations that are restricted are those that interact
433
with the environment.  This includes file operations, require, and use
434
(for external modules).
435
436
Since there is no way to gain access to the internals of the database
437
backend process or the operating system itself, any unprivileged
438
database user may use functions written in this language.
439
440
An example of a NON-working function due to security constraints:
441
442 18 Álvaro Herrera
<pre>
443 1 bford -
CREATE FUNCTION read_passwd_file() RETURNS text AS '
444
   readfile("/etc/passwd");
445
   return 0;
446
' LANGUAGE 'plphp';
447 18 Álvaro Herrera
</pre>
448 1 bford -
449
It will appear to execute, but depending on your log level, you'll may
450
see something like the following:
451
452 18 Álvaro Herrera
<pre>
453 1 bford -
Warning: readfile(): SAFE MODE Restriction in effect. The script
454 4 Álvaro Herrera
whose uid is 500 is not allowed to access /etc/passwd owned by uid 0
455
in Command line code on line 3
456 1 bford -
457
Warning: readfile(/etc/passwd): failed to open stream: Success in
458
plphp function source on line 3
459 18 Álvaro Herrera
</pre>
460 1 bford -
461
Sometimes it is desirable to write PHP functions that are not
462 12 Álvaro Herrera
restricted.  In this case, you can create the language as 'plphpu' to
463 1 bford -
enable the previously unavailable functions.
464 4 Álvaro Herrera
  
465 18 Álvaro Herrera
<pre>
466 1 bford -
 CREATE LANGUAGE plphpu;
467 18 Álvaro Herrera
</pre>
468 1 bford -
469
470
471 18 Álvaro Herrera
h2. Composite Type Arguments
472
473
474 1 bford -
Composite-type arguments are passed to the function as associative
475
array. The keys of the array are the attribute names of
476
the composite type. Here is an example:
477
478 18 Álvaro Herrera
<pre>
479 1 bford -
CREATE TABLE employee (
480
   name text,
481
   basesalary integer,
482
   bonus integer
483
);
484
485
CREATE FUNCTION empcomp(employee) RETURNS integer AS '
486 18 Álvaro Herrera
   return $argsr0[_basesalary_] + $argsr0[_bonus_];
487 1 bford -
' LANGUAGE 'plphp';
488
489
INSERT INTO employee values ('Josh', 1000, 10);
490 12 Álvaro Herrera
INSERT INTO employee values ('Darcy', 500, 20);
491 1 bford -
492 12 Álvaro Herrera
SELECT name, empcomp(employee) FROM employee;
493 18 Álvaro Herrera
</pre>
494 1 bford -
495
This example results in the following output:
496
497 18 Álvaro Herrera
<pre>
498 12 Álvaro Herrera
 name  | empcomp 
499 1 bford -
-------+---------
500 12 Álvaro Herrera
 Josh  |    1010
501
 Darcy |     520
502
(2 rows)
503 18 Álvaro Herrera
</pre>
504 12 Álvaro Herrera
505
506 18 Álvaro Herrera
h2. Returning A Row (composite type)
507
508
509 1 bford -
To return a row or composite-type value from a PL/php-language
510
function, you can use an indexed array:
511
512 18 Álvaro Herrera
<pre>
513 1 bford -
CREATE TYPE php_row AS (f1 integer, f2 text, f3 text);
514
515
CREATE OR REPLACE FUNCTION php_row(integer) RETURNS php_row AS $$
516 18 Álvaro Herrera
   $ret['f1'] = $argsr0;
517 1 bford -
   $ret['f3'] = "world";
518 12 Álvaro Herrera
   $ret['f2'] = "hello";
519
   return $ret;
520
$$ LANGUAGE 'plphp';
521
522 1 bford -
SELECT * FROM php_row(1);
523 18 Álvaro Herrera
</pre>
524 1 bford -
525 12 Álvaro Herrera
Will return:
526 18 Álvaro Herrera
<pre>
527 6 Álvaro Herrera
 f1 |  f2   |  f3
528 1 bford -
----+-------+-------
529 12 Álvaro Herrera
  1 | hello | world
530 18 Álvaro Herrera
</pre>
531 2 Álvaro Herrera
532 1 bford -
533
534 18 Álvaro Herrera
h2. Returning multiple rows (SRF functions)
535
536
537 1 bford -
SRF stands for "set-returning functions".  This means you can return
538
multiple rows, like in the following example:
539 2 Álvaro Herrera
540 18 Álvaro Herrera
<pre>
541 1 bford -
CREATE TYPE php_row AS (f1 integer, f2 text, f3 text);
542 15 Álvaro Herrera
543 1 bford -
CREATE OR REPLACE FUNCTION php_set(integer) RETURNS SETOF php_row AS $$
544 18 Álvaro Herrera
   $ret['f1'] = $argsr0;
545 14 Álvaro Herrera
   $ret['f2'] = "hello";
546
   $ret['f3'] = "world";
547
   return_next($ret);
548
549 18 Álvaro Herrera
   $ret['f1'] = 2 * $argsr0;
550 14 Álvaro Herrera
   $ret['f2'] = "hello";
551
   $ret['f3'] = "postgres";
552
   return_next($ret);
553
554 18 Álvaro Herrera
   $ret['f1'] = 3 * $argsr0;
555 14 Álvaro Herrera
   $ret['f2'] = "hello";
556
   $ret['f3'] = "plphp";
557
   return_next($ret);
558
$$ LANGUAGE 'plphp';
559 18 Álvaro Herrera
</pre>
560 14 Álvaro Herrera
561 1 bford -
This will result in:
562 18 Álvaro Herrera
<pre>
563 14 Álvaro Herrera
pl_regression=# SELECT * FROM php_set(1);
564
 f1 |  f2   |    f3
565 1 bford -
----+-------+----------
566
  1 | hello | world
567
  2 | hello | postgres
568 3 Álvaro Herrera
  3 | hello | plphp
569 1 bford -
(3 rows)
570 18 Álvaro Herrera
</pre>
571 1 bford -
572 18 Álvaro Herrera
The important thing to notice here is the @return_next()@ function.  This function must be called with a single parameter, which must be an array with one element per attribute of the return type.  Note that currently the names of the array elements are ignored; the elements are assigned to attributes in order.  If you must return a null value, asign a null value to an array element.  This may be fixed in a future release.
573 14 Álvaro Herrera
574 18 Álvaro Herrera
Finishing a SRF is done by either calling @return@ or by falling off the end of the function.  At that point the entire results are delivered back to the outer query, be it directly to the user or to be joined to other tables/SRFs/etc.
575 14 Álvaro Herrera
576
The return tuples are written to a Postgres "tuplestore", which is disk-backed, and thus do not need to fit entirely in RAM.
577
578
579 18 Álvaro Herrera
h2. Function Argument Names
580
581
582 16 Alexey Klyukin
You can assign names to pl/php function arguments:
583
584 18 Álvaro Herrera
<pre>
585 16 Alexey Klyukin
CREATE FUNCTION plphp_match(document text, word text) RETURNS BOOL AS
586
$$
587
   if (strstr($document, $word))
588
       return TRUE;
589
   else
590
       return FALSE;
591
$$ LANGUAGE 'plphp';
592
593
Example output:
594
595
template1=# select plphp_match('PostgreSQL', 'SQL');
596
 plphp_match 
597
-------------
598
 t
599
(1 row)
600
601 18 Álvaro Herrera
</pre>
602 16 Alexey Klyukin
603
Both $name and $args[position] variable access methods are supported.
604 12 Álvaro Herrera
605 18 Álvaro Herrera
606
h2. Limitations
607
608 14 Álvaro Herrera
609
PL/php functions cannot call each other directly because their names
610 1 bford -
are mangled.
611
612
SPI calls have the whole results allocated in memory, so processing huge results may be problematic.  Also it's not possible to use cursors with SPI.