rfc:debugging_pdo_prepared_statement_emulation

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
rfc:debugging_pdo_prepared_statement_emulation [2016/10/26 15:56] – expanded introduction adambaratzrfc:debugging_pdo_prepared_statement_emulation [2016/11/16 23:03] – fix formatting around discussion links adambaratz
Line 1: Line 1:
 ====== PHP RFC: Debugging PDO Prepared Statement Emulation ====== ====== PHP RFC: Debugging PDO Prepared Statement Emulation ======
-  * Version: 0.2+  * Version: 0.4
   * Date: 2016-10-17   * Date: 2016-10-17
   * Author: Adam Baratz adambaratz@php.net   * Author: Adam Baratz adambaratz@php.net
-  * Status: Under Discussion+  * Status: In Discussion
   * First Published at: https://wiki.php.net/rfc/debugging_pdo_prepared_statement_emulation   * First Published at: https://wiki.php.net/rfc/debugging_pdo_prepared_statement_emulation
  
Line 14: Line 14:
  
 ===== Proposal ===== ===== Proposal =====
-People who use emulated prepared statements should be able to debug them within userland, without using additional tools. PDO already provides some debug functionality in the form of ''PDOStatement::debugDumpParams()''The goal would be to offer another slice on PDO internals, not to create another path for developers to communicate with a database. I would like to discuss three possible solutions to this problem. +People who use emulated prepared statements should be able to debug them within userland, without using additional tools. PDO already provides some debug functionality in the form of ''PDOStatement::debugDumpParams()''This method would be extended to include the parsed query string:
- +
-==== Consistency Between Prepared Statement Emulation And PDO::quote() ==== +
-The piece of functionality that usually needs to be debugged is how values are escaped. There is already a method, ''PDO::quote()'', that is meant to reveal this, but it typically behaves differently from the prepared statement emulator:+
  
 <code php> <code php>
-$db new PDO(...);+/* Execute a prepared statement by binding PHP variables */ 
 +$calories 150; 
 +$colour = 'red';
  
-$stmt = $db->query('SELECT :int'); +$sth = $dbh->prepare('SELECT name, colour, calories 
-$stmt->bindValue(':int', 1, PDO::PARAM_INT); +    FROM fruit 
-$stmt->execute(); // =SELECT 1+    WHERE calories < ? AND colour = ?'); 
 +$sth->bindParam(1, $calories, PDO::PARAM_INT); 
 +$sth->bindValue(2, $colour, PDO::PARAM_STR); 
 +$sth->execute();
  
-$stmt = $db->query('SELECT ' . $db->quote(1, PDO::PARAM_INT)); +$sth->debugDumpParams();
-$stmt->execute(); // => SELECT '1' +
-</code>+
  
-I say typically, because the behavior of PDO::quote() is determined by a driver's [[https://github.com/php/php-src/blob/master/ext/pdo/php_pdo_driver.h#L302|quoter]] function. While these functions are given the specified parameter type, they all ignore that value and assume all input should be handled as a string.+/*
  
-Currently, the prepared statement emulator escapes values like [[https://github.com/php/php-src/blob/master/ext/pdo/pdo_sql_parser.re#L251|this]]: +Output:
-  * Bool, int, and null values are handled within the emulator. +
-  * Other values have their zvals cast to a string, which is passed to the driver's quoter function.+
  
-This logic could be moved to a common PDO C APIwhich ''PDO::quote()'' could invoke. If a driver didn't define a quoter function, ''PDO::quote()'' could continue to return false.+SQL: [82] SELECT namecolour, calories 
 +    FROM fruit 
 +    WHERE calories < ? AND colour = ? 
 +Parsed SQL[88] SELECT namecolour, calories 
 +    FROM fruit 
 +    WHERE calories < 150 AND colour = 'red' 
 +Params 2 
 +KeyPosition #0: 
 +paramno=0 
 +name=[0] "" 
 +is_param=1 
 +param_type=1 
 +Key: Position #1: 
 +paramno=1 
 +name=[0] "" 
 +is_param=1 
 +param_type=2
  
-This approach doesn't feel ideal. It would be difficult to work out how people expect ''PDO::quote()'' to behave. That method would be changed in different ways for different drivers. And it wouldn't allow full debugging of the emulator. +*/
- +
-==== PDO::DBLIB_ATTR_ACTIVE_QUERY_STRING ==== +
-Since prepared statements are only mandatory for pdo_dblib, a driver-specific attribute could produce the parsed query: +
- +
-<code php> +
-$db = new PDO(...); +
- +
-// works with statements without bound values +
-$stmt = $db->query('SELECT 1'); +
-var_dump($stmt->getAttribute(PDO::DBLIB_ATTR_ACTIVE_QUERY_STRING)); // => string(8) "SELECT 1" +
- +
-$stmt = $db->prepare('SELECT :string'); +
-$stmt->bindValue(':string', 'foo'); +
- +
-// returns unparsed query before execution +
-var_dump($stmt->getAttribute(PDO::DBLIB_ATTR_ACTIVE_QUERY_STRING)); // => string(14) "SELECT :string" +
- +
-// returns parsed query after execution +
-$stmt->execute(); +
-var_dump($stmt->getAttribute(PDO::DBLIB_ATTR_ACTIVE_QUERY_STRING)); // => string(11) "SELECT 'foo'"+
 </code> </code>
  
-Since this would be a debug tool, the attribute shouldn't affect the state of the ''PDOStatement'' instance. You usually don't know something went wrong with the parsing until after execution, anyway. +The "Parsed SQLsection will only be shown if the prepared statement emulation is enabled.
- +
-This is a slightly awkward use of an attribute -- the existing debug hook, ''PDOStatement::debugDumpParams()'', is a method -- and users of other drivers could benefit from the functionality. It doesn't feel like good design to push special behavior into individual drivers. +
- +
-==== PDOStatement::activeQueryString() ==== +
-Similar to the above, but as an API addition: +
- +
-<code php> +
-$db = new PDO(...); +
- +
-// works with statements without bound values +
-$stmt = $db->query('SELECT 1'); +
-var_dump($stmt->activeQueryString()); // => string(8) "SELECT 1" +
- +
-$stmt = $db->prepare('SELECT :string'); +
-$stmt->bindValue(':string', 'foo'); +
- +
-// returns unparsed query before execution +
-var_dump($stmt->activeQueryString()); // => string(14) "SELECT :string" +
- +
-// returns parsed query after execution +
-$stmt->execute(); +
-var_dump($stmt->activeQueryString()); // => string(11) "SELECT 'foo'" +
-</code> +
- +
-This feels like the least disruptive solution to this problem. If more guardrails are desired, an error could be raised via ''pdo_raise_impl_error()'' if emulation isn't active or if the parser hasn't been used yet.+
  
 ===== Backward Incompatible Changes ===== ===== Backward Incompatible Changes =====
-The first proposal could introduce functionality changes, but they would be in the interest of more consistent behavior across PDO.+N/A
  
 ===== Proposed PHP Version(s) ===== ===== Proposed PHP Version(s) =====
 Next PHP 7.x. Next PHP 7.x.
- 
-===== RFC Impact ===== 
-The second proposal would introduce a new constant. 
  
 ===== Future Scope ===== ===== Future Scope =====
-It's been suggested that PDO shouldn't allow prepare statement emulation. Since the mssql extension was deprecated in PHP 7 in favor of pdo_dblibI don't think this is possible. But perhaps this functionality could be isolated in pdo_dblib as "grandfathered" functionality. If people feel strongly about this, the third proposal wouldn't be a good idea.+It's been suggested that PDO shouldn't allow prepare statement emulation. This new functionality would only engage if emulation is enabledso it will self-destruct if emulation is dropped.
  
 ===== Proposed Voting Choices ===== ===== Proposed Voting Choices =====
 This project requires a 50%+1 majority. This project requires a 50%+1 majority.
  
-===== Patches and Tests ===== +<doodle title="Debugging PDO Prepared Statement Emulation v0.4" auth="abaratz" voteType="single" closed="false"> 
-A working implementation, with tests, of the third proposal: https://github.com/php/php-src/pull/2159 +   * Yes 
- +   * No 
-If one of the other proposals is accepted, I could do the implementation myself.+</doodle>
  
 ===== References ===== ===== References =====
-Initial discussion of this proposal on the internals mailing list: http://marc.info/?l=php-internals&m=147638162506291&w=2+Initial discussion of this proposal on the internals mailing list: 
 +  * http://marc.info/?l=php-internals&m=147638162506291&w=2 
 +  * http://marc.info/?l=php-internals&m=147734024403899&w=2 
 +  * http://marc.info/?l=php-internals&m=147673258418764&w=2
rfc/debugging_pdo_prepared_statement_emulation.txt · Last modified: 2018/03/01 23:27 by carusogabriel