No subject


Fri Mar 12 13:03:17 CET 2010


- get rid of "is_numeric" and use is_int when possible.
- cast with intval() when the parameter is supposed to be an integer

- added a $stmt->seek() because I use it some times. Strange thing that
PDO doesn't support it.

- enhanced some comments and error messages.

+1 on reading, reviewing and testing.

Cheers,
Ernesto

Xavier Perseguers schrieb am 16.08.2010 22:21:

> Please find v3 attached.
> 
> We had kind of a live discussion with other core devs this morning and
> here is the summary:
> 
> - "Old way" of creating queries ($GLOBALS['TYPO3_DB']->exec_* methods
> will still work as before. Only if you explicitly call the
> prepare_SELECTquery method will you gain access to enhanced DB API
> 
> - We want to provide a PDO-like syntax but we don't aim at having a
> PDO-compatible implementation. We can provide enhancements and we should
> not fear having some goodies. We want to learn from Extbase (this is why
> I added some chaining feature for instance)
> 
> What as changed basically with this new version:
> 
> - Took comments into account
> - Enhanced the documentation with some examples which render properly
> when compiling documentation with doxygen or phpdoc
> - Removed bindParam() method (borrowed from PDO) because we do not like
> this way of programming and it hardly make sense in TYPO3. In PDO it is
> used mainly for getting back parameters. We do not have that in TYPO3.
> - Added bindValues() which takes an array of parameters. A complement to
> the bindValue() method which acts as the parameter you may pass to
> execute() but with a potentially clearer separation.
> - Added chaining on both bindValue() and bindValues()
> 
> Sorry. Did not have time to provide unit tests.
> 
> Cheers
> Xavier
> 


--------------070602040709090700030606
Content-Type: text/plain;
 name="15457_core_v4.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="15457_core_v4.diff"

Index: t3lib/class.t3lib_sqlparser.php
===================================================================
--- t3lib/class.t3lib_sqlparser.php	(Revision 8607)
+++ t3lib/class.t3lib_sqlparser.php	(Arbeitskopie)
@@ -190,10 +190,11 @@
 	 * Parsing SELECT query
 	 *
 	 * @param	string		SQL string with SELECT query to parse
+	 * @param	array		Array holding references to either named (:name) or question mark (?) parameters found
 	 * @return	mixed		Returns array with components of SELECT query on success, otherwise an error message string.
 	 * @see compileSELECT()
 	 */
-	protected function parseSELECT($parseString) {
+	protected function parseSELECT($parseString, &$parameterReferences = NULL) {
 
 			// Removing SELECT:
 		$parseString = $this->trimSQL($parseString);
@@ -201,6 +202,10 @@
 
 			// Init output variable:
 		$result = array();
+		if ($parameterReferences === NULL) {
+			$result['parameters'] = array();
+			$parameterReferences = &$result['parameters'];
+		}
 		$result['type'] = 'SELECT';
 
 			// Looking for STRAIGHT_JOIN keyword:
@@ -221,7 +226,7 @@
 			if ($parseString)	{
 
 					// Get WHERE clause:
-				$result['WHERE'] = $this->parseWhereClause($parseString, '^(GROUP[[:space:]]+BY|ORDER[[:space:]]+BY|LIMIT)[[:space:]]+');
+				$result['WHERE'] = $this->parseWhereClause($parseString, '^(GROUP[[:space:]]+BY|ORDER[[:space:]]+BY|LIMIT)[[:space:]]+', $parameterReferences);
 				if ($this->parse_error)	{ return $this->parse_error; }
 
 					// If the WHERE clause parsing was stopped by GROUP BY, ORDER BY or LIMIT, then proceed with parsing:
@@ -1025,9 +1030,10 @@
 	 *
 	 * @param	string		WHERE clause to parse. NOTICE: passed by reference!
 	 * @param	string		Regular expressing to STOP parsing, eg. '^(GROUP BY|ORDER BY|LIMIT)([[:space:]]*)'
+	 * @param	array		Array holding references to either named (:name) or question mark (?) parameters found
 	 * @return	mixed		If successful parsing, returns an array, otherwise an error string.
 	 */
-	public function parseWhereClause(&$parseString, $stopRegex = '') {
+	public function parseWhereClause(&$parseString, $stopRegex = '', array &$parameterReferences = array()) {
 
 			// Prepare variables:
 		$parseString = $this->trimSQL($parseString);
@@ -1057,7 +1063,7 @@
 				if (preg_match('/^EXISTS[[:space:]]*[(]/i', $parseString)) {
 					$stack[$level][$pnt[$level]]['func']['type'] = $this->nextPart($parseString, '^(EXISTS)[[:space:]]*');
 					$parseString = trim(substr($parseString, 1));	// Strip of "("
-					$stack[$level][$pnt[$level]]['func']['subquery'] = $this->parseSELECT($parseString);
+					$stack[$level][$pnt[$level]]['func']['subquery'] = $this->parseSELECT($parseString, $parameterReferences);
 						// Seek to new position in parseString after parsing of the subquery
 					$parseString = $stack[$level][$pnt[$level]]['func']['subquery']['parseString'];
 					unset($stack[$level][$pnt[$level]]['func']['subquery']['parseString']);
@@ -1225,7 +1231,7 @@
 							$stack[$level][$pnt[$level]]['value'] = $values;
 						} else if (t3lib_div::inList('IN,NOT IN', $stack[$level][$pnt[$level]]['comparator']) && preg_match('/^[(][[:space:]]*SELECT[[:space:]]+/', $parseString)) {
 							$this->nextPart($parseString, '^([(])');
-							$stack[$level][$pnt[$level]]['subquery'] = $this->parseSELECT($parseString);
+							$stack[$level][$pnt[$level]]['subquery'] = $this->parseSELECT($parseString, $parameterReferences);
 								// Seek to new position in parseString after parsing of the subquery
 							$parseString = $stack[$level][$pnt[$level]]['subquery']['parseString'];
 							unset($stack[$level][$pnt[$level]]['subquery']['parseString']);
@@ -1241,7 +1247,7 @@
 							$stack[$level][$pnt[$level]]['values'][1] = $this->getValue($parseString);
 						} else {
 								// Finding value for comparator:
-							$stack[$level][$pnt[$level]]['value'] = $this->getValue($parseString, $stack[$level][$pnt[$level]]['comparator']);
+							$stack[$level][$pnt[$level]]['value'] = &$this->getValueOrParameter($parseString, $stack[$level][$pnt[$level]]['comparator'], '', $parameterReferences);
 							if ($this->parse_error)	{
 								return $this->parse_error;
 							}
@@ -1390,6 +1396,39 @@
 	}
 
 	/**
+	 * Finds value or either named (:name) or question mark (?) parameter markers at the beginning
+	 * of $parseString, returns result and strips it of parseString.
+	 * This method returns a pointer to the parameter or value that was found. In case of a parameter
+	 * the pointer is a reference to the corresponding item in array $parameterReferences.
+	 *
+	 * @param string $parseString The parseString
+	 * @param string $comparator The comparator used before.
+	 * @param string $mode The mode, e.g., "INDEX"
+	 * @param mixed The value (string/integer) or parameter (:name/?). Otherwise an array with error message in first key (0)
+	 */
+	protected function &getValueOrParameter(&$parseString, $comparator = '', $mode = '', array &$parameterReferences = array()) {
+		$parameter = $this->nextPart($parseString, '^(\\:[[:alnum:]_]+|\\?)');
+		if ($parameter === '?') {
+			if (!isset($parameterReferences['?'])) {
+				$parameterReferences['?'] = array();
+			}
+			$value = array('?');
+			$parameterReferences['?'][] = &$value;
+		} elseif ($parameter !== '') {	// named parameter
+			if (isset($parameterReferences[$parameter])) {
+					// Use the same reference as last time we encountered this parameter
+				$value = &$parameterReferences[$parameter];
+			} else {
+				$value = array($parameter);
+				$parameterReferences[$parameter] = &$value;
+			}
+		} else {
+			$value = $this->getValue($parseString, $comparator, $mode);
+		}
+		return $value;
+	}
+
+	/**
 	 * Finds value in beginning of $parseString, returns result and strips it of parseString
 	 *
 	 * @param	string		The parseString, eg. "(0,1,2,3) ..." or "('asdf','qwer') ..." or "1234 ..." or "'My string value here' ..."
Index: t3lib/class.t3lib_db.php
===================================================================
--- t3lib/class.t3lib_db.php	(Revision 8607)
+++ t3lib/class.t3lib_db.php	(Arbeitskopie)
@@ -676,11 +676,84 @@
 
 
 
+	/**************************************
+	 *
+	 * Prepared Query Support
+	 *
+	 **************************************/
 
+	/**
+	 * Creates a SELECT prepared SQL statement.
+	 *
+	 * @param string See exec_SELECTquery()
+	 * @param string See exec_SELECTquery()
+	 * @param string See exec_SELECTquery()
+	 * @param string See exec_SELECTquery()
+	 * @param string See exec_SELECTquery()
+	 * @param string See exec_SELECTquery()
+	 * @param array $input_parameters An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as t3lib_db_PreparedStatement::PARAM_AUTOTYPE.
+	 * @return t3lib_db_PreparedStatement Prepared statement
+	 */
+	public function prepare_SELECTquery($select_fields, $from_table, $where_clause, $groupBy = '', $orderBy = '', $limit = '', array $input_parameters = array()) {
+		$query = $this->SELECTquery($select_fields, $from_table, $where_clause, $groupBy, $orderBy, $limit);
+		$preparedStatement = t3lib_div::makeInstance('t3lib_db_PreparedStatement', $query, $from_table, array());
+		/* @var $preparedStatement t3lib_db_PreparedStatement */
 
+			// Bind values to parameters
+		foreach ($input_parameters as $key => $value) {
+			$preparedStatement->bindValue($key, $value, t3lib_db_PreparedStatement::PARAM_AUTOTYPE);
+		}
 
+			// Return prepared statement
+		return $preparedStatement;
+	}
 
+	/**
+	 * Creates a SELECT prepared SQL statement based on input query parts array
+	 *
+	 * @param array Query parts array
+	 * @param array $input_parameters An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as t3lib_db_PreparedStatement::PARAM_AUTOTYPE.
+	 * @return t3lib_db_PreparedStatement Prepared statement
+	 */
+	public function prepare_SELECTqueryArray(array $queryParts, array $input_parameters = array()) {
+		return $this->prepare_SELECTquery(
+			$queryParts['SELECT'],
+			$queryParts['FROM'],
+			$queryParts['WHERE'],
+			$queryParts['GROUPBY'],
+			$queryParts['ORDERBY'],
+			$queryParts['LIMIT'],
+			$input_parameters
+		);
+	}
 
+	/**
+	 * Executes a prepared query.
+	 * This method may only be called by t3lib_db_PreparedStatement.
+	 *
+	 * @param string $query The query to execute
+	 * @param array $queryComponents The components of the query to execute
+	 * @return pointer MySQL result pointer / DBAL object
+	 * @access private
+	 */
+	public function exec_PREPAREDquery($query, array $queryComponents) {
+		$res = mysql_query($query, $this->link);
+		if ($this->debugOutput) {
+			$this->debug('stmt_execute', $query);
+		}
+		return $res;
+	}
+
+
+
+
+
+
+
+
+
+
+
 	/**************************************
 	 *
 	 * Various helper functions
Index: t3lib/db/class.t3lib_db_PreparedStatement.php
===================================================================
--- t3lib/db/class.t3lib_db_PreparedStatement.php	(Revision 0)
+++ t3lib/db/class.t3lib_db_PreparedStatement.php	(Revision 0)
@@ -0,0 +1,459 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2010 Xavier Perseguers <typo3 at perseguers.ch>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * TYPO3 prepared statement for t3lib_db class.
+ *
+ * USE:
+ * In all TYPO3 scripts when you need to create a prepared query:
+ * <code>
+ * $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery('*', 'pages', 'uid = :uid');
+ * $statement->execute(array(':uid' => 2));
+ * while (($row = $statement->fetch()) !== FALSE) {
+ *    // ...
+ * }
+ * $statement->free();
+ * </code>
+ *
+ * @author	Xavier Perseguers <typo3 at perseguers.ch>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_db_PreparedStatement {
+
+	/**
+	 * Represents the SQL NULL data type.
+	 * @var integer
+	 */
+	const PARAM_NULL = 0;
+
+	/**
+	 * Represents the SQL INTEGER data type.
+	 * @var integer
+	 */
+	const PARAM_INT = 1;
+
+	/**
+	 * Represents the SQL CHAR, VARCHAR, or other string data type.
+	 * @var integer
+	 */
+	const PARAM_STR = 2;
+
+	/**
+	 * Represents a boolean data type.
+	 * @var integer
+	 */
+	const PARAM_BOOL = 3;
+
+	/**
+	 * Automatically detects underlying type
+	 * @var integer
+	 */
+	const PARAM_AUTOTYPE = 4;
+
+	/**
+	 * Specifies that the fetch method shall return each row as an array indexed by
+	 * column name as returned in the corresponding result set. If the result set
+	 * contains multiple columns with the same name, t3lib_db_PreparedStatement::FETCH_ASSOC
+	 * returns only a single value per column name.
+	 * @var integer
+	 */
+	const FETCH_ASSOC = 2;
+
+	/**
+	 * Specifies that the fetch method shall return each row as an array indexed by
+	 * column number as returned in the corresponding result set, starting at column 0.
+	 * @var integer
+	 */
+	const FETCH_NUM = 3;
+
+	/**
+	 * Query to be executed.
+	 * @var string
+	 */
+	protected $query;
+
+	/**
+	 * Components of the query to be executed.
+	 * @var array
+	 */
+	protected $precompiledQueryParts;
+
+	/**
+	 * Table (used to call $GLOBALS['TYPO3_DB']->fullQuoteStr().
+	 * @var string
+	 */
+	protected $table;
+
+	/**
+	 * Binding parameters.
+	 * @var array
+	 */
+	protected $parameters;
+
+	/**
+	 * Default fetch mode.
+	 * @var integer
+	 */
+	protected $defaultFetchMode = self::FETCH_ASSOC;
+
+	/**
+	 * MySQL result pointer (of SELECT query) / DBAL object.
+	 * @var pointer
+	 */
+	protected $resource;
+
+	/**
+	 * Creates a new PreparedStatement. Either $query or $queryComponents
+	 * should be used. Typically $query will be used by native MySQL TYPO3_DB
+	 * on a ready-to-be-executed query. On the other hand, DBAL will have
+	 * parse the query and will be able to safely know where parameters are used
+	 * and will use $queryComponents instead.
+	 * This constructor may only be used by t3lib_DB.
+	 *
+	 * @param string $query SQL query to be executed
+	 * @param string FROM table, used to call $GLOBALS['TYPO3_DB']->fullQuoteStr().
+	 * @param array $precompiledQueryParts Components of the query to be executed
+	 * @access private
+	 */
+	public function __construct($query, $table, array $precompiledQueryParts = array()) {
+		$this->query = $query;
+		$this->precompiledQueryParts = $precompiledQueryParts;
+		$this->table = $table;
+		$this->parameters = array();
+		$this->resource = NULL;
+	}
+
+	/**
+	 * Binds an array of values to corresponding named or question mark placeholders in the SQL
+	 * statement that was use to prepare the statement.
+	 *
+	 * Example 1:
+	 * <code>
+	 * $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery('*', 'bugs', 'reported_by = ? AND bug_status = ?');
+	 * $statement->bindValues(array('goofy', 'FIXED'));
+	 * </code>
+	 *
+	 * Example 2:
+	 * <code>
+	 * $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery('*', 'bugs', 'reported_by = :nickname AND bug_status = :status');
+	 * $statement->bindValues(array(':nickname' => 'goofy', ':status' => 'FIXED'));
+	 * </code>
+	 *
+	 * @param array $values The values to bind to the parameter. Data type will be set to t3lib_db_PreparedStatement::PARAM_AUTOTYPE.
+	 * @return t3lib_db_PreparedStatement The current prepared statement to allow method chaining
+	 * @api
+	 */
+	public function bindValues(array $values) {
+		foreach ($values as $parameter => $value) {
+			$key = is_int($parameter) ? $parameter + 1 : $parameter;
+			$this->bindValue($key, $value, self::PARAM_AUTOTYPE);
+		}
+
+		return $this;
+	}
+
+	/**
+	 * Binds a value to a corresponding named or question mark placeholder in the SQL
+	 * statement that was use to prepare the statement.
+	 *
+	 * Example 1:
+	 * <code>
+	 * $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery('*', 'bugs', 'reported_by = ? AND bug_status = ?');
+	 * $statement->bindValue(1, 'goofy');
+	 * $statement->bindValue(2, 'FIXED');
+	 * </code>
+	 *
+	 * Example 2:
+	 * <code>
+	 * $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery('*', 'bugs', 'reported_by = :nickname AND bug_status = :status');
+	 * $statement->bindValue(':nickname', 'goofy');
+	 * $statement->bindValue(':status', 'FIXED');
+	 * </code>
+	 *
+	 * @param mixed $parameter Parameter identifier. For a prepared statement using named placeholders, this will be a parameter name of the form :name. For a prepared statement using question mark placeholders, this will be the 1-indexed position of the parameter.
+	 * @param mixed $value The value to bind to the parameter.
+	 * @param integer $data_type Explicit data type for the parameter using the t3lib_db_PreparedStatement::PARAM_* constants. If not given, the PHP type of the value will be used instead (int, string, boolean)
+	 * @return t3lib_db_PreparedStatement The current prepared statement to allow method chaining
+	 * @api
+	 */
+	public function bindValue($parameter, $value, $data_type = self::PARAM_AUTOTYPE) {
+		switch ($data_type) {
+			case self::PARAM_INT:
+				if (!is_int($value)) {
+					throw new InvalidArgumentException('$value is not an integer as expected: ' . $value, 1281868686);
+				}
+				break;
+			case self::PARAM_BOOL:
+				if (!is_bool($value)) {
+					throw new InvalidArgumentException('$value is not a boolean as expected: ' . $value, 1281868687);
+				}
+				break;
+		}
+
+		$key = is_int($parameter) ? $parameter - 1 : $parameter;
+		$this->parameters[$key] = array(
+			'value' => $value,
+			'type'  => ($data_type == self::PARAM_AUTOTYPE ? $this->guessValueType($value) : $data_type),
+		);
+
+		return $this;
+	}
+
+	/**
+	 * Executes the prepared statement. If the prepared statement included parameter
+	 * markers, you must either:
+	 * - call {@link t3lib_db_PreparedStatement::bindParam()} to bind PHP variables
+	 *   to the parameter markers: bound variables pass their value as input
+	 * - or pass an array of input-only parameter values
+	 *
+	 * @param array $input_parameters An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as t3lib_db_PreparedStatement::PARAM_AUTOTYPE.
+	 * @return boolean Returns TRUE on success or FALSE on failure.
+	 * @api
+	 */
+	public function execute(array $input_parameters = array()) {
+		$query = $this->query;
+		$precompiledQueryParts = $this->precompiledQueryParts;
+		$parameterValues = $this->parameters;
+
+		if (count($input_parameters) > 0) {
+			$parameterValues = array();
+			foreach ($input_parameters as $value) {
+				$parameterValues[] = array(
+					'value' => $value,
+					'type'  => $this->guessValueType($value),
+				);
+			}
+		}
+
+		$this->replaceValuesInQuery($query, $precompiledQueryParts, $parameterValues);
+		if (count($precompiledQueryParts) > 0) {
+			$query = implode('', $precompiledQueryParts['queryParts']);
+		}
+		$this->resource = $GLOBALS['TYPO3_DB']->exec_PREPAREDquery($query, $precompiledQueryParts);
+
+			// Empty binding parameters
+		$this->parameters = array();
+
+			// Return the success flag
+		return ($this->resource ? TRUE : FALSE);
+	}
+
+	/**
+	 * Fetches a row from a result set associated with a t3lib_db_PreparedStatement object.
+	 *
+	 * @param integer $fetch_style Controls how the next row will be returned to the caller. This value must be one of the t3lib_db_PreparedStatement::FETCH_* constants. If omitted, default fetch mode for this prepared query will be used.
+	 * @return array Array of rows or FALSE if there are no more rows.
+	 * @api
+	 */
+	public function fetch($fetch_style = 0) {
+		if ($fetch_style == 0) {
+			$fetch_style = $this->defaultFetchMode;
+		}
+		switch ($fetch_style) {
+			case self::FETCH_ASSOC:
+				$row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($this->resource);
+				break;
+			case self::FETCH_NUM:
+				$row = $GLOBALS['TYPO3_DB']->sql_fetch_row($this->resource);
+				break;
+			default:
+				throw new InvalidArgumentException('$fetch_style must be either t3lib_db_PreparedStatement::FETCH_ASSOC or t3lib_db_PreparedStatement::FETCH_NUM', 1281646455);
+		}
+		return $row;
+	}
+
+	/**
+	 * Returns an array containing all of the result set rows.
+	 *
+	 * @param integer $fetch_style Controls the contents of the returned array as documented in {@link t3lib_db_PreparedStatement::fetch()}.
+	 * @return array Array of rows.
+	 * @api
+	 */
+	public function fetchAll($fetch_style = 0) {
+		$rows = array();
+		while (($row = $this->fetch($fetch_style)) !== FALSE) {
+			$rows[] = $row;
+		}
+		return $rows;
+	}
+
+	/**
+	 * Releases the cursor. Should always be call after having fetched rows from
+	 * a query execution.
+	 *
+	 * @return void
+	 * @api
+	 */
+	public function free() {
+		$GLOBALS['TYPO3_DB']->sql_free_result($this->resource);
+	}
+
+	/**
+	 * Returns the number of rows affected by the last SQL statement.
+	 *
+	 * @return integer The number of rows.
+	 * @api
+	 */
+	public function rowCount() {
+		return $GLOBALS['TYPO3_DB']->sql_num_rows($this->resource);
+	}
+
+	/**
+	 * Move internal result pointer
+	 *
+	 * @param integer $rowNumber Where to place the result pointer (0 = start)
+	 * @return boolean Returns TRUE on success or FALSE on failure.
+	 * @api
+	 */
+	public function seek($rowNumber) {
+		return $GLOBALS['TYPO3_DB']->sql_data_seek($this->resource, intval($rowNumber));
+	}
+
+
+
+	/**
+	 * Returns the error number on the last execute() call.
+	 *
+	 * @return integer Driver specific error code.
+	 * @api
+	 */
+	public function errorCode() {
+		return $GLOBALS['TYPO3_DB']->sql_errno();
+	}
+
+	/**
+	 * Returns an array of error information about the last operation performed by this statement handle.
+	 * The array consists of the following fields:
+	 * <ol start="0">
+	 *  <li>Driver specific error code.</li>
+	 *  <li>Driver specific error message</li>
+	 * </ol>
+	 *
+	 * @return array Array of error information.
+	 */
+	public function errorInfo() {
+		return array(
+			$GLOBALS['TYPO3_DB']->sql_errno(),
+			$GLOBALS['TYPO3_DB']->sql_error(),
+		);
+	}
+
+	/**
+	 * Sets the default fetch mode for this prepared query.
+	 *
+	 * @param integer $mode One of the t3lib_db_PreparedStatement::FETCH_* constants
+	 * @return void
+	 * @api
+	 */
+	public function setFetchMode($mode) {
+		switch ($mode) {
+			case self::FETCH_ASSOC:
+			case self::FETCH_NUM:
+				$this->defaultFetchMode = $mode;
+				break;
+			default:
+				throw new InvalidArgumentException('$mode must be either t3lib_db_PreparedStatement::FETCH_ASSOC or t3lib_db_PreparedStatement::FETCH_NUM', 1281875340);
+		}
+	}
+
+	/**
+	 * Guesses the type of a given value.
+	 *
+	 * @param mixed $value
+	 * @return integer One of the t3lib_db_PreparedStatement::PARAM_* constants
+	 */
+	protected function guessValueType($value) {
+		if (is_bool($value)) {
+			$type = self::PARAM_BOOL;
+		} elseif (t3lib_div::testInt($value))) {
+			$type = self::PARAM_INT;
+		} elseif (is_null($value) || strtoupper($value) === 'NULL') {
+			$type = self::PARAM_NULL;
+		} else {
+			$type = self::PARAM_STR;
+		}
+
+		return $type;
+	}
+
+	/**
+	 * Replaces values for each parameter in a query.
+	 *
+	 * @param string $query
+	 * @param array $precompiledQueryParts
+	 * @param array $parameterValues
+	 * @return void
+	 */
+	protected function replaceValuesInQuery(&$query, array &$precompiledQueryParts, array $parameterValues) {
+		foreach ($this->parameters as $key => $typeValue) {
+			switch ($typeValue['type']) {
+				case self::PARAM_NULL:
+					$value = 'NULL';
+					break;
+				case self::PARAM_INT:
+					$value = intval($typeValue['value']);
+					break;
+				case self::PARAM_STR:
+					$value = $GLOBALS['TYPO3_DB']->fullQuoteStr($typeValue['value'], $this->table);
+					break;
+				case self::PARAM_BOOL:
+					$value = $typeValue['value'] ? 1 : 0;
+					break;
+				default:
+					throw new InvalidArgumentException(
+						sprintf('Unknown type %s used for parameter %s.', $typeValue['type'], $key),
+						1281859196
+					);
+			}
+
+			if (is_int($key)) {
+				if (count($precompiledQueryParts['queryParts']) > 0) {
+					$precompiledQueryParts['queryParts'][2 * $key + 1] = $value;
+				} else {
+					$parts = explode('?', $query, 2);
+					$parts[0] .= $value;
+					$query = implode('', $parts);
+				}
+			} else {
+				for ($i = 1; $i < count($precompiledQueryParts['queryParts']); $i++) {
+					if ($precompiledQueryParts['queryParts'][$i] === $key) {
+						$precompiledQueryParts['queryParts'][$i] = $value;
+					}
+					$query = str_replace($key, $value, $query);
+				}
+			}
+		}
+	}
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/db/class.t3lib_db_PreparedStatement.php']) {
+	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/db/class.t3lib_db_PreparedStatement.php']);
+}
+
+?>
\ Kein Zeilenvorschub am Ende der Datei
Index: t3lib/core_autoload.php
===================================================================
--- t3lib/core_autoload.php	(Revision 8607)
+++ t3lib/core_autoload.php	(Arbeitskopie)
@@ -20,6 +20,7 @@
 	't3lib_compressor' => PATH_t3lib . 'class.t3lib_compressor.php',
 	't3lib_cs' => PATH_t3lib . 'class.t3lib_cs.php',
 	't3lib_db' => PATH_t3lib . 'class.t3lib_db.php',
+	't3lib_db_preparedstatement' => PATH_t3lib . 'db/class.t3lib_db_PreparedStatement.php',
 	't3lib_diff' => PATH_t3lib . 'class.t3lib_diff.php',
 	't3lib_div' => PATH_t3lib . 'class.t3lib_div.php',
 	't3lib_exception' => PATH_t3lib . 'class.t3lib_exception.php',

--------------070602040709090700030606
Content-Type: text/plain;
 name="15457-v3-v4.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="15457-v3-v4.diff"

diff -ur trunk-15457-v3/t3lib/class.t3lib_db.php trunk-15457-v4/t3lib/class.t3lib_db.php
--- trunk-15457-v3/t3lib/class.t3lib_db.php	2010-08-17 12:39:20.000000000 +0200
+++ trunk-15457-v4/t3lib/class.t3lib_db.php	2010-08-17 12:38:27.000000000 +0200
@@ -736,7 +736,7 @@
 	 * @return pointer MySQL result pointer / DBAL object
 	 * @access private
 	 */
-	public function exec_PREPAREDquery ($query, array $queryComponents) {
+	public function exec_PREPAREDquery($query, array $queryComponents) {
 		$res = mysql_query($query, $this->link);
 		if ($this->debugOutput) {
 			$this->debug('stmt_execute', $query);
Nur in trunk-15457-v4/t3lib: class.t3lib_db.php.rej.
Nur in trunk-15457-v3/t3lib: class.t3lib_sqlparser.php.rej.
Nur in trunk-15457-v3/t3lib: core_autoload.php.rej.
diff -ur trunk-15457-v3/t3lib/db/class.t3lib_db_PreparedStatement.php trunk-15457-v4/t3lib/db/class.t3lib_db_PreparedStatement.php
--- trunk-15457-v3/t3lib/db/class.t3lib_db_PreparedStatement.php	2010-08-17 12:39:20.000000000 +0200
+++ trunk-15457-v4/t3lib/db/class.t3lib_db_PreparedStatement.php	2010-08-17 13:11:34.000000000 +0200
@@ -31,7 +31,7 @@
  * USE:
  * In all TYPO3 scripts when you need to create a prepared query:
  * <code>
- * $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery('*', 'pages', 'pid = :pid');
+ * $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery('*', 'pages', 'uid = :uid');
  * $statement->execute(array(':uid' => 2));
  * while (($row = $statement->fetch()) !== FALSE) {
  *    // ...
@@ -170,7 +170,7 @@
 	 */
 	public function bindValues(array $values) {
 		foreach ($values as $parameter => $value) {
-			$key = is_numeric($parameter) ? intval($parameter) + 1 : $parameter;
+			$key = is_int($parameter) ? $parameter + 1 : $parameter;
 			$this->bindValue($key, $value, self::PARAM_AUTOTYPE);
 		}
 
@@ -197,21 +197,25 @@
 	 *
 	 * @param mixed $parameter Parameter identifier. For a prepared statement using named placeholders, this will be a parameter name of the form :name. For a prepared statement using question mark placeholders, this will be the 1-indexed position of the parameter.
 	 * @param mixed $value The value to bind to the parameter.
-	 * @param integer $data_type Explicit data type for the parameter using the t3lib_db_PreparedStatement::PARAM_* constants.
+	 * @param integer $data_type Explicit data type for the parameter using the t3lib_db_PreparedStatement::PARAM_* constants. If not given, the PHP type of the value will be used instead (int, string, boolean)
 	 * @return t3lib_db_PreparedStatement The current prepared statement to allow method chaining
 	 * @api
 	 */
 	public function bindValue($parameter, $value, $data_type = self::PARAM_AUTOTYPE) {
 		switch ($data_type) {
 			case self::PARAM_INT:
+				if (!is_int($value)) {
+					throw new InvalidArgumentException('$value is not an integer as expected: ' . $value, 1281868686);
+				}
+				break;
 			case self::PARAM_BOOL:
-				if (!is_numeric($value)) {
-					throw new InvalidArgumentException('$value is not a numeric type: ' . $value, 1281868686);
+				if (!is_bool($value)) {
+					throw new InvalidArgumentException('$value is not a boolean as expected: ' . $value, 1281868687);
 				}
 				break;
 		}
 
-		$key = is_numeric($parameter) ? intval($parameter) - 1 : $parameter;
+		$key = is_int($parameter) ? $parameter - 1 : $parameter;
 		$this->parameters[$key] = array(
 			'value' => $value,
 			'type'  => ($data_type == self::PARAM_AUTOTYPE ? $this->guessValueType($value) : $data_type),
@@ -278,7 +282,7 @@
 				$row = $GLOBALS['TYPO3_DB']->sql_fetch_row($this->resource);
 				break;
 			default:
-				throw new InvalidArgumentException('$fetch_style must be either FETCH_ASSOC or FETCH_NUM', 1281646455);
+				throw new InvalidArgumentException('$fetch_style must be either t3lib_db_PreparedStatement::FETCH_ASSOC or t3lib_db_PreparedStatement::FETCH_NUM', 1281646455);
 		}
 		return $row;
 	}
@@ -320,6 +324,19 @@
 	}
 
 	/**
+	 * Move internal result pointer
+	 *
+	 * @param integer $rowNumber Where to place the result pointer (0 = start)
+	 * @return boolean Returns TRUE on success or FALSE on failure.
+	 * @api
+	 */
+	public function seek($rowNumber) {
+		return $GLOBALS['TYPO3_DB']->sql_data_seek($this->resource, intval($rowNumber));
+	}
+
+
+
+	/**
 	 * Returns the error number on the last execute() call.
 	 *
 	 * @return integer Driver specific error code.
@@ -360,7 +377,7 @@
 				$this->defaultFetchMode = $mode;
 				break;
 			default:
-				throw new InvalidArgumentException('$mode must be either FETCH_ASSOC or FETCH_NUM', 1281875340);
+				throw new InvalidArgumentException('$mode must be either t3lib_db_PreparedStatement::FETCH_ASSOC or t3lib_db_PreparedStatement::FETCH_NUM', 1281875340);
 		}
 	}
 
@@ -373,9 +390,9 @@
 	protected function guessValueType($value) {
 		if (is_bool($value)) {
 			$type = self::PARAM_BOOL;
-		} elseif (is_numeric($value)) {
+		} elseif (t3lib_div::testInt($value))) {
 			$type = self::PARAM_INT;
-		} elseif (strtoupper($value) === 'NULL') {
+		} elseif (is_null($value) || strtoupper($value) === 'NULL') {
 			$type = self::PARAM_NULL;
 		} else {
 			$type = self::PARAM_STR;
@@ -399,7 +416,7 @@
 					$value = 'NULL';
 					break;
 				case self::PARAM_INT:
-					$value = $typeValue['value'];
+					$value = intval($typeValue['value']);
 					break;
 				case self::PARAM_STR:
 					$value = $GLOBALS['TYPO3_DB']->fullQuoteStr($typeValue['value'], $this->table);
@@ -414,7 +431,7 @@
 					);
 			}
 
-			if (is_numeric($key)) {
+			if (is_int($key)) {
 				if (count($precompiledQueryParts['queryParts']) > 0) {
 					$precompiledQueryParts['queryParts'][2 * $key + 1] = $value;
 				} else {

--------------070602040709090700030606--


More information about the TYPO3-team-core mailing list