- Patch #342503 by Josh Waihi, Damien Tournoud et al: schema function findTables fails on PostgreSQL.
parent
a7b4bdef1d
commit
9af9e3de88
|
@ -380,14 +380,14 @@ abstract class DatabaseConnection extends PDO {
|
||||||
* Queries sent to Drupal should wrap all table names in curly brackets. This
|
* Queries sent to Drupal should wrap all table names in curly brackets. This
|
||||||
* function searches for this syntax and adds Drupal's table prefix to all
|
* function searches for this syntax and adds Drupal's table prefix to all
|
||||||
* tables, allowing Drupal to coexist with other systems in the same database
|
* tables, allowing Drupal to coexist with other systems in the same database
|
||||||
* if necessary.
|
* and/or schema if necessary.
|
||||||
*
|
*
|
||||||
* @param $sql
|
* @param $sql
|
||||||
* A string containing a partial or entire SQL query.
|
* A string containing a partial or entire SQL query.
|
||||||
* @return
|
* @return
|
||||||
* The properly-prefixed string.
|
* The properly-prefixed string.
|
||||||
*/
|
*/
|
||||||
protected function prefixTables($sql) {
|
public function prefixTables($sql) {
|
||||||
global $db_prefix;
|
global $db_prefix;
|
||||||
|
|
||||||
if (is_array($db_prefix)) {
|
if (is_array($db_prefix)) {
|
||||||
|
@ -428,7 +428,7 @@ abstract class DatabaseConnection extends PDO {
|
||||||
* A PDO prepared statement ready for its execute() method.
|
* A PDO prepared statement ready for its execute() method.
|
||||||
*/
|
*/
|
||||||
protected function prepareQuery($query, $cache = TRUE) {
|
protected function prepareQuery($query, $cache = TRUE) {
|
||||||
$query = self::prefixTables($query);
|
$query = $this->prefixTables($query);
|
||||||
if (empty($this->preparedStatements[$query])) {
|
if (empty($this->preparedStatements[$query])) {
|
||||||
// Call PDO::prepare.
|
// Call PDO::prepare.
|
||||||
$this->preparedStatements[$query] = parent::prepare($query);
|
$this->preparedStatements[$query] = parent::prepare($query);
|
||||||
|
|
|
@ -14,14 +14,29 @@
|
||||||
|
|
||||||
class DatabaseSchema_mysql extends DatabaseSchema {
|
class DatabaseSchema_mysql extends DatabaseSchema {
|
||||||
|
|
||||||
public function tableExists($table) {
|
/**
|
||||||
return (bool) $this->connection->query("SHOW TABLES LIKE '{" . $table . "}'", array(), array())->fetchField();
|
* Build a condition to match a table name against a standard information_schema.
|
||||||
}
|
*
|
||||||
|
* MySQL uses databases like schemas rather than catalogs so when we build
|
||||||
|
* a condition to query the information_schema.tables, we set the default
|
||||||
|
* database as the schema unless specified otherwise, and exclude table_catalog
|
||||||
|
* from the condition criteria.
|
||||||
|
*/
|
||||||
|
protected function buildTableNameCondition($table_name, $operator = '=') {
|
||||||
|
$info = Database::getConnectionInfo();
|
||||||
|
|
||||||
public function columnExists($table, $column) {
|
if (strpos($table_name, '.')) {
|
||||||
return (bool) $this->connection->query("SHOW COLUMNS FROM {" . $this->connection->escapeTable($table) . "} LIKE '" . $this->connection->escapeTable($column) . "'", array(), array())->fetchField();
|
list($schema, $table_name) = explode('.', $table_name);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$schema = $info['default']['database'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$condition = db_and()
|
||||||
|
->condition('table_schema', $schema)
|
||||||
|
->condition('table_name', $table_name, $operator);
|
||||||
|
return $condition;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate SQL to create a new table from a Drupal schema definition.
|
* Generate SQL to create a new table from a Drupal schema definition.
|
||||||
|
|
|
@ -13,14 +13,6 @@
|
||||||
|
|
||||||
class DatabaseSchema_pgsql extends DatabaseSchema {
|
class DatabaseSchema_pgsql extends DatabaseSchema {
|
||||||
|
|
||||||
public function tableExists($table) {
|
|
||||||
return (bool) db_result(db_query("SELECT COUNT(*) FROM pg_class WHERE relname = '{" . db_escape_table($table) . "}'"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function columnExists($table, $column) {
|
|
||||||
return (bool) db_result(db_query("SELECT COUNT(pg_attribute.attname) FROM pg_class, pg_attribute WHERE pg_attribute.attrelid = pg_class.oid AND pg_class.relname = '{" . db_escape_table($table) . "}' AND attname = '" . db_escape_table($column) . "'"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate SQL to create a new table from a Drupal schema definition.
|
* Generate SQL to create a new table from a Drupal schema definition.
|
||||||
*
|
*
|
||||||
|
|
|
@ -125,14 +125,95 @@ abstract class DatabaseSchema {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a table exists.
|
* Build a condition to match a table name against a standard information_schema.
|
||||||
|
*
|
||||||
|
* The information_schema is a SQL standard that provides information about the
|
||||||
|
* database server and the databases, schemas, tables, columns and users within
|
||||||
|
* it. This makes information_schema a useful tool to use across the drupal
|
||||||
|
* database drivers and is used by a few different functions. The function below
|
||||||
|
* describes the conditions to be meet when querying information_schema.tables
|
||||||
|
* for drupal tables or information associated with drupal tables. Even though
|
||||||
|
* this is the standard method, not all databases follow standards and so this
|
||||||
|
* method should be overwritten by a database driver if the database provider
|
||||||
|
* uses alternate methods. Because information_schema.tables is used in a few
|
||||||
|
* different functions, a database driver will only need to override this function
|
||||||
|
* to make all the others work. For example see includes/databases/mysql/schema.inc.
|
||||||
|
*
|
||||||
|
* @param $table_name
|
||||||
|
* The name of the table to explode.
|
||||||
|
* @param $operator
|
||||||
|
* The operator to apply on the 'table' part of the condition.
|
||||||
|
* @return
|
||||||
|
* A DatabaseCondition object.
|
||||||
*/
|
*/
|
||||||
abstract public function tableExists($table);
|
protected function buildTableNameCondition($table_name, $operator = '=') {
|
||||||
|
$info = Database::getConnectionInfo();
|
||||||
|
|
||||||
|
// The table name may describe the schema eg. schema.table.
|
||||||
|
if (strpos($table_name, '.')) {
|
||||||
|
list($schema, $table_name) = explode('.', $table_name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$schema = 'public';
|
||||||
|
}
|
||||||
|
|
||||||
|
$condition = db_and()
|
||||||
|
->condition('table_catalog', $info['default']['database'])
|
||||||
|
->condition('table_schema', $schema)
|
||||||
|
->condition('table_name', $table_name, $operator);
|
||||||
|
return $condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a table exists.
|
||||||
|
*
|
||||||
|
* @param $table
|
||||||
|
* The name of the table in drupal (no prefixing).
|
||||||
|
* @return
|
||||||
|
* false is no table exists otherwise the actual table name.
|
||||||
|
*/
|
||||||
|
public function tableExists($table) {
|
||||||
|
$condition = $this->buildTableNameCondition($this->connection->prefixTables('{' . $table . '}'));
|
||||||
|
$condition->compile($this->connection);
|
||||||
|
// 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
|
||||||
|
// information_schema.tables and the query would fail.
|
||||||
|
return db_query("SELECT table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchField();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all tables that are like the specified base table name.
|
||||||
|
*
|
||||||
|
* @param $table_expression
|
||||||
|
* An SQL expression, for example "simpletest%" (without the quotes).
|
||||||
|
* BEWARE: this is not prefixed, the caller should take care of that.
|
||||||
|
* @return
|
||||||
|
* Array, both the keys and the values are the matching tables.
|
||||||
|
*/
|
||||||
|
public function findTables($table_expression) {
|
||||||
|
$condition = $this->buildTableNameCondition($table_expression, 'LIKE');
|
||||||
|
$condition->compile($this->connection);
|
||||||
|
// 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
|
||||||
|
// information_schema.tables and the query would fail.
|
||||||
|
return db_query("SELECT table_name FROM information_schema.tables WHERE " . (string) $condition, $condition->arguments())->fetchAllKeyed(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a column exists in the given table.
|
* Check if a column exists in the given table.
|
||||||
*/
|
*/
|
||||||
abstract public function columnExists($table, $column);
|
public function columnExists($table, $column) {
|
||||||
|
$condition = $this->buildTableNameCondition($this->connection->prefixTables('{' . $table . '}'));
|
||||||
|
$condition->condition('column_name', $column);
|
||||||
|
$condition->compile($this->connection);
|
||||||
|
// 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
|
||||||
|
// information_schema.tables and the query would fail.
|
||||||
|
return db_query("SELECT column_name FROM information_schema.columns WHERE " . (string) $condition, $condition->arguments())->fetchAllKeyed(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This maps a generic data type in combination with its data size
|
* This maps a generic data type in combination with its data size
|
||||||
|
@ -404,25 +485,6 @@ abstract class DatabaseSchema {
|
||||||
}
|
}
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find all tables that are like the specified base table name.
|
|
||||||
*
|
|
||||||
* @param $table_expression
|
|
||||||
* An SQL expression, for example "simpletest%" (without the quotes).
|
|
||||||
* BEWARE: this is not prefixed, the caller should take care of that.
|
|
||||||
* @return
|
|
||||||
* Array, both the keys and the values are the matching tables.
|
|
||||||
*/
|
|
||||||
public function findTables($table_expression) {
|
|
||||||
global $db_prefix;
|
|
||||||
$info = Database::getConnectionInfo();
|
|
||||||
$result = db_query("SELECT table_name FROM information_schema.tables WHERE table_schema = :database AND table_name LIKE :table_name", array(
|
|
||||||
':database' => $info['default']['database'],
|
|
||||||
':table_name' => $table_expression,
|
|
||||||
));
|
|
||||||
return $result->fetchAllKeyed(0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue