Commit fb0275fa authored by Dries's avatar Dries

- Patch #496500 by chx: remove global placeholder counter.

parent eca9c6cc
......@@ -372,11 +372,11 @@ public function getComment($table, $column = NULL) {
$condition = $this->buildTableNameCondition($this->connection->prefixTables('{' . $table . '}'));
if (isset($column)) {
$condition->condition('column_name', $column);
$condition->compile($this->connection);
$condition->compile($this->connection, $this);
// Don't use {} around information_schema.columns table.
return db_query("SELECT column_comment FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchField();
}
$condition->compile($this->connection);
$condition->compile($this->connection, $this);
// Don't use {} around information_schema.tables table.
$comment = db_query("SELECT table_comment FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField();
// Work-around for MySQL 5.0 bug http://bugs.mysql.com/bug.php?id=11379
......
......@@ -111,8 +111,11 @@ public function arguments();
*
* @param $connection
* The database connection for which to compile the conditionals.
* @param $query
* The query this condition belongs to. If not given, the current query is
* used.
*/
public function compile(DatabaseConnection $connection);
public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL);
}
......@@ -196,12 +199,22 @@ public function addMetaData($key, $object);
public function getMetaData($key);
}
/**
* Interface for a query that accepts placeholders.
*/
interface QueryPlaceholderInterface {
/**
* Returns the next placeholder for the query.
*/
function nextPlaceholder();
}
/**
* Base class for the query builders.
*
* All query builders inherit from a common base class.
*/
abstract class Query {
abstract class Query implements QueryPlaceholderInterface {
/**
* The connection object on which to run this query.
......@@ -217,6 +230,11 @@ public function getMetaData($key);
*/
protected $queryOptions;
/**
* The placeholder counter.
*/
protected $nextPlaceholder = 0;
public function __construct(DatabaseConnection $connection, $options) {
$this->connection = $connection;
$this->queryOptions = $options;
......@@ -236,6 +254,10 @@ public function __construct(DatabaseConnection $connection, $options) {
* A prepared statement query string for this object.
*/
abstract public function __toString();
public function nextPlaceholder() {
return $this->nextPlaceholder++;
}
}
/**
......@@ -866,14 +888,14 @@ public function where($snippet, $args = array()) {
return $this;
}
public function compile(DatabaseConnection $connection) {
return $this->condition->compile($connection);
public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
return $this->condition->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this);
}
public function execute() {
$values = array();
if (count($this->condition)) {
$this->condition->compile($this->connection);
$this->condition->compile($this->connection, $this);
$values = $this->condition->arguments();
}
......@@ -884,7 +906,7 @@ public function __toString() {
$query = 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} ';
if (count($this->condition)) {
$this->condition->compile($this->connection);
$this->condition->compile($this->connection, $this);
$query .= "\nWHERE " . $this->condition;
}
......@@ -911,8 +933,8 @@ public function __construct(DatabaseConnection $connection, $table, array $optio
$this->table = $table;
}
public function compile(DatabaseConnection $connection) {
return $this->condition->compile($connection);
public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
return $this->condition->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this);
}
public function execute() {
......@@ -971,7 +993,6 @@ class UpdateQuery extends Query implements QueryConditionInterface {
*/
protected $expressionFields = array();
public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
$options['return'] = Database::RETURN_AFFECTED;
parent::__construct($connection, $options);
......@@ -1008,8 +1029,8 @@ public function where($snippet, $args = array()) {
return $this;
}
public function compile(DatabaseConnection $connection) {
return $this->condition->compile($connection);
public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
return $this->condition->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this);
}
/**
......@@ -1073,7 +1094,7 @@ public function execute() {
}
if (count($this->condition)) {
$this->condition->compile($this->connection);
$this->condition->compile($this->connection, $this);
$update_values = array_merge($update_values, $this->condition->arguments());
}
......@@ -1098,7 +1119,7 @@ public function __toString() {
$query = 'UPDATE {' . $this->connection->escapeTable($this->table) . '} SET ' . implode(', ', $update_fields);
if (count($this->condition)) {
$this->condition->compile($this->connection);
$this->condition->compile($this->connection, $this);
// There is an implicit string cast on $this->condition.
$query .= "\nWHERE " . $this->condition;
}
......@@ -1178,17 +1199,8 @@ public function arguments() {
return $this->arguments;
}
public function compile(DatabaseConnection $connection) {
// This value is static, so it will increment across the entire request
// rather than just this query. That is OK, because we only need definitive
// placeholder names if we're going to use them for _alter hooks, which we
// are not. The alter hook would intervene before compilation.
// $next_placeholder does not use drupal_static as it increments and should
// never be reset during a request.
static $next_placeholder = 1;
public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
if ($this->changed) {
$condition_fragments = array();
$arguments = array();
......@@ -1205,7 +1217,7 @@ public function compile(DatabaseConnection $connection) {
// It's a structured condition, so parse it out accordingly.
if ($condition['field'] instanceof QueryConditionInterface) {
// Compile the sub-condition recursively and add it to the list.
$condition['field']->compile($connection);
$condition['field']->compile($connection, $queryPlaceholder);
$condition_fragments[] = '(' . (string)$condition['field'] . ')';
$arguments += $condition['field']->arguments();
}
......@@ -1238,7 +1250,7 @@ public function compile(DatabaseConnection $connection) {
}
if ($operator['use_value']) {
foreach ($condition['value'] as $value) {
$placeholder = ':db_condition_placeholder_' . $next_placeholder++;
$placeholder = ':db_condition_placeholder_' . $queryPlaceholder->nextPlaceholder();
$arguments[$placeholder] = $value;
$placeholders[] = $placeholder;
}
......@@ -1263,6 +1275,15 @@ public function __toString() {
return $this->stringVersion;
}
function __clone() {
$this->changed = TRUE;
foreach ($this->conditions as $key => $condition) {
if ($condition['field'] instanceOf QueryConditionInterface) {
$this->conditions[$key]['field'] = clone($condition['field']);
}
}
}
/**
* Gets any special processing requirements for the condition operator.
*
......
......@@ -146,14 +146,24 @@
* @see drupal_install_schema()
*/
abstract class DatabaseSchema {
abstract class DatabaseSchema implements QueryPlaceholderInterface {
protected $connection;
/**
* The placeholder counter.
*/
protected $placeholder = 0;
public function __construct($connection) {
$this->connection = $connection;
}
public function nextPlaceholder() {
return $this->placeholder++;
}
/**
* Build a condition to match a table name against a standard information_schema.
*
......@@ -204,7 +214,7 @@ protected function buildTableNameCondition($table_name, $operator = '=') {
*/
public function tableExists($table) {
$condition = $this->buildTableNameCondition($this->connection->prefixTables('{' . $table . '}'));
$condition->compile($this->connection);
$condition->compile($this->connection, $this);
// Normally, we would heartily discourage the use of string
// concatination for conditionals like this however, we
// couldn't use db_select() here because it would prefix
......@@ -224,7 +234,7 @@ public function tableExists($table) {
*/
public function findTables($table_expression) {
$condition = $this->buildTableNameCondition($table_expression, 'LIKE');
$condition->compile($this->connection);
$condition->compile($this->connection, $this);
// Normally, we would heartily discourage the use of string
// concatination for conditionals like this however, we
// couldn't use db_select() here because it would prefix
......@@ -239,7 +249,7 @@ public function findTables($table_expression) {
public function columnExists($table, $column) {
$condition = $this->buildTableNameCondition($this->connection->prefixTables('{' . $table . '}'));
$condition->condition('column_name', $column);
$condition->compile($this->connection);
$condition->compile($this->connection, $this);
// Normally, we would heartily discourage the use of string
// concatination for conditionals like this however, we
// couldn't use db_select() here because it would prefix
......
......@@ -35,7 +35,7 @@ public function extend($extender_name);
/**
* Interface definition for a Select Query object.
*/
interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableInterface, QueryExtendableInterface {
interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableInterface, QueryExtendableInterface, QueryPlaceholderInterface {
/* Alter accessors to expose the query data to alter hooks. */
......@@ -114,10 +114,14 @@ public function &getTables();
/**
* Compiles and returns an associative array of the arguments for this prepared statement.
*
* @param $queryPlaceholder
* When collecting the arguments of a subquery, the main placeholder
* object should be passed as this parameter.
*
* @return
* An associative array of all placeholder arguments for this query.
*/
public function getArguments();
public function getArguments(QueryPlaceholderInterface $queryPlaceholder = NULL);
/* Query building operations */
......@@ -400,12 +404,22 @@ class SelectQueryExtender implements SelectQueryInterface {
*/
protected $connection;
/**
* The placeholder counter.
*/
protected $placeholder = 0;
public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) {
$this->query = $query;
$this->connection = $connection;
}
/* Implementations of QueryPlaceholderInterface. */
public function nextPlaceholder() {
return $this->placeholder++;
}
/* Implementations of QueryAlterableInterface. */
public function addTag($tag) {
......@@ -454,8 +468,8 @@ public function where($snippet, $args = array()) {
return $this;
}
public function compile(DatabaseConnection $connection) {
return $this->query->compile($connection);
public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
return $this->condition->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this);
}
/* Implmeentations of QueryConditionInterface for the HAVING clause. */
......@@ -510,8 +524,8 @@ public function &getTables() {
return $this->query->getTables();
}
public function getArguments() {
return $this->query->getArguments();
public function getArguments(QueryPlaceholderInterface $queryPlaceholder = NULL) {
return $this->query->getArguments($queryPlaceholder);
}
public function isPrepared() {
......@@ -826,9 +840,8 @@ public function isNotNull($field) {
return $this;
}
public function compile(DatabaseConnection $connection) {
return $this->where->compile($connection);
public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) {
return $this->where->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this);
}
/* Implmeentations of QueryConditionInterface for the HAVING clause. */
......@@ -855,7 +868,7 @@ public function having($snippet, $args = array()) {
}
public function havingCompile(DatabaseConnection $connection) {
return $this->having->compile($connection);
return $this->having->compile($connection, $this);
}
/* Implementations of QueryExtendableInterface. */
......@@ -897,9 +910,12 @@ public function &getTables() {
return $this->tables;
}
public function getArguments() {
$this->where->compile($this->connection);
$this->having->compile($this->connection);
public function getArguments(QueryPlaceholderInterface $queryPlaceholder = NULL) {
if (!isset($queryPlaceholder)) {
$queryPlaceholder = $this;
}
$this->where->compile($this->connection, $queryPlaceholder);
$this->having->compile($this->connection, $queryPlaceholder);
$args = $this->where->arguments() + $this->having->arguments();
foreach ($this->tables as $table) {
if ($table['arguments']) {
......@@ -907,7 +923,7 @@ public function getArguments() {
}
// If this table is a subquery, grab its arguments recursively.
if ($table['table'] instanceof SelectQueryInterface) {
$args += $table['table']->getArguments();
$args += $table['table']->getArguments($queryPlaceholder);
}
}
foreach ($this->expressions as $expression) {
......@@ -1179,7 +1195,7 @@ public function __toString() {
// WHERE
if (count($this->where)) {
$this->where->compile($this->connection);
$this->where->compile($this->connection, $this);
// There is an implicit string cast on $this->condition.
$query .= "\nWHERE " . $this->where;
}
......@@ -1191,7 +1207,7 @@ public function __toString() {
// HAVING
if (count($this->having)) {
$this->having->compile($this->connection);
$this->having->compile($this->connection, $this);
// There is an implicit string cast on $this->having.
$query .= "\nHAVING " . $this->having;
}
......@@ -1207,7 +1223,6 @@ public function __toString() {
}
// RANGE is database specific, so we can't do it here.
return $query;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment