Bug #64852 [Asn->Wfx]: Allow binding arrays in PDO
| From: | wez@php.net | Date: | Fri, 13 Dec 2013 07:53:47 +0000 |
| Subject: | Bug #64852 [Asn->Wfx]: Allow binding arrays in PDO | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-183306@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=64852&edit=1
ID: 64852
Updated by: wez@php.net
Reported by: vrana@php.net
Summary: Allow binding arrays in PDO
-Status: Assigned
+Status: Wont fix
Type: Bug
Package: PDO related
Operating System: Any
PHP Version: 5.5.0RC1
Assigned To: wez
Block user comment: N
Private report: N
Previous Comments:
------------------------------------------------------------------------
[2013-05-20 06:16:55] wez@php.net
It would be nice, but unfortunately it can't be done in a sane way at the PDO level; there is
no
consistent way to express how to handle data binding to array types and in the absence of that, the
parameter binding needs to explicitly specify each parameter.
This would require a much more powerful SQL parsing layer to resolve and make it work properly,
This sort of feature is better implemented in a layer on top of PDO.
------------------------------------------------------------------------
[2013-05-16 05:23:12] vrana@php.net
Wez, do you think it's reasonable?
------------------------------------------------------------------------
[2013-05-16 05:22:04] vrana@php.net
Description:
------------
Binding arrays would be useful in these queries:
WHERE id IN ?
INSERT INTO ... VALUES ?
Most database systems don't support binding complex data structures on server side but PDO
supports client side data binding so it can expand arrays to scalars and use them. Example:
<?php
$stmt = $pdo->prepare("SELECT * FROM table WHERE id IN ?");
$stmt->execute([ array('1', '2', '3') ]);
// This will be executed with client side data binding:
// SELECT * FROM table WHERE id IN ('1', '2', '3')
// With server side data binding:
// SELECT * FROM table WHERE id IN (?, ?, ?) -- bind values: '1', '2',
'3'
?>
It means that with server side data binding, arrays will be expanded to variable number of
placeholders and the elements in the array will be bound.
There is a risk that the same statement would be used with a differently structured array or with
non-array. Example:
<?php
$stmt = $pdo->prepare("SELECT * FROM table WHERE id IN ?");
// Expands query to: SELECT * FROM table WHERE id IN (?, ?, ?)
$stmt->execute([ array(1, 2, 3) ]);
// This subsequent call should throw.
$stmt->execute([ array(1, 2, 3, 4) ]);
// This subsequent call should also throw.
$stmt->execute([ 1 ]);
?>
This is a very rare usage and throwing an error in this case seems like a good solution.
=== Named parameters ===
Named parameters could expand to name-key pair:
<?php
$stmt = $pdo->prepare("SELECT * FROM table WHERE id IN :ids");
// Expands query to: SELECT * FROM table WHERE id IN (:ids_0, :ids_1, :ids_2)
$stmt->execute([ 'ids' => array(1, 2, 3) ]);
?>
However, there could be a collision: "WHERE id = :ids_0 OR id IN :ids". PDO could solve it
by some sort of escaping - e.g. by prepending a magic string to all array names or by prepending
something else also to all non-array names. Or it could just throw as this would be a rare and
easily fixable problem.
=== Nested arrays ===
Expanding arrays should be recursive to support these queries:
<?php
$stmt = $pdo->prepare("SELECT * FROM table WHERE (type, type_id) IN ?");
// Expands to SELECT * FROM table WHERE (type, type_id) IN ((?, ?), (?, ?))
$types = array();
$types[] = array('article', 1);
$types[] = array('comment', 11);
$stmt->execute([ $types ]);
?>
=== Braces or no braces ===
Array should expand to comma-delimited, braces-enclosed string. This expansion would support queries
"WHERE (type, type_id) IN ?". It unfortunately wouldn't support this query:
INSERT INTO ... VALUES (...), (...), ...
This query needs braces in inner array and no braces in outer array so there's no consistent
way to support this type of query.
=== Empty arrays ===
Empty arrays should be treated same as other arrays so they should expand to (). "INSERT INTO
table () VALUES ()" is a valid query, at least in MySQL (it inserts a row with all default
values). This would cause a syntax error in query "WHERE id IN ()" but that's a good
behavior as there's no way to tell database to not match anything. "WHERE id IN
(NULL)" would be a solution in this particular query (as NULL doesn't equal to NULL) but
"WHERE id NOT IN (NULL)" wouldn't return NULL rows. So empty array must expand to ().
=== Debugging ===
PDO should disclose a method returning the real query sent to the server. It would be useful even
without arrays, especially with client-side binding.
=== Implementation ===
Implementation would be tricky as the statement couldn't be prepared until it's executed.
It means that PDO wouldn't talk to the database server in prepare() even with server-side
binding (this is the current behavior with client-side binding). The query would be both prepared
and executed in execute().
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=64852&edit=1