Bug Report #1049
Database::list_fields returns incorrect results for multiple databases which share table names
| Status: | Closed | Start date: | ||
|---|---|---|---|---|
| Priority: | High | Due date: | ||
| Assignee: | % Done: | 0% |
||
| Category: | Libraries:Database | |||
| Target version: | 2.3.3 | |||
| Resolution: | fixed | Points: |
Description
If you have two databases which both use MySQL driver and both have a table named 'foo' then:
Database::instance('db1')->list_fields('foo');
returns correctly, but
Database::instance('db2')->list_fields('foo');
will always return the contents of the previous call, regardless of the structure of db2.foo.
This is because list_fields() uses the table name as the cache key in a static var $tables.
Related issues
History
Updated by wvoq - about 3 years ago
P.S. A similar problem occurs with list_tables()
Updated by wvoq - about 3 years ago
Suggested fix (using hostname and db name as part of the cache key):
public function list_tables(Database $db)
{
static $tables;
$key = $this->db_config['connection']['host'].'/'.$this->db_config['connection']['database'];
if (empty($tables[$key]) AND $query = $db->query('SHOW TABLES FROM '.$this->escape_table($this->db_config['connection']['database'])))
{
$tables[$key] = array();
foreach ($query->result(FALSE) as $row)
{
$tables[$key][] = current($row);
}
}
return $tables[$key];
}
public function list_fields($table)
{
static $tables;
$key = $this->db_config['connection']['host'].'/'.$this->db_config['connection']['database'].'/'.$table;
if (empty($tables[$key]))
{
foreach ($this->field_data($table) as $row)
{
// Make an associative array
$tables[$key][$row->Field] = $this->sql_type($row->Type);
if ($row->Key === 'PRI' AND $row->Extra === 'auto_increment')
{
// For sequenced (AUTO_INCREMENT) tables
$tables[$key][$row->Field]['sequenced'] = TRUE;
}
if ($row->Null === 'YES')
{
// Set NULL status
$tables[$key][$row->Field]['null'] = TRUE;
}
}
}
if (!isset($tables[$key]))
throw new Kohana_Database_Exception('database.table_not_found', $table);
return $tables[$key];
}
Updated by Jeremy Bush about 3 years ago
If you have a fix, please attach a patch containing the fix, not raw code. Please read ticket submission guidelines: [TicketSubmissionGuidelines]
Updated by wvoq - about 3 years ago
Sorry! Patch attached. (I just used "diff -u", please let me know if that's not right.)
Updated by Chris Bandy about 3 years ago
Wow. I just did some testing and it looks like static variables within class methods are shared with the class. Wow.
PHP 5.2.8-pl1-gentoo (cli) (built: Jan 9 2009 18:33:09) Copyright (c) 1997-2008 The PHP Group Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
<?php
class cb_Class {
function increment() {
static $x;
$x += 1;
return $x;
}
}
$first = new cb_Class;
$second = new cb_Class;
echo $first->increment() ."\n";
echo $second->increment() ."\n";
?>
Results in
1 2
Updated by Chris Bandy about 3 years ago
Old, but PHP response is that this behaviour is correct...
Updated by Jeremy Bush about 3 years ago
Yes, it's well known and documented that static vars are shared between all instances. That's is expected behavior, but this ticket is still a valid bug.
Updated by Chris Bandy about 3 years ago
Regarding my above patch: Database_Driver instances are tied to Database instances. Information like table and field names should not be shared between Database_Driver instances.
Since static variables are actually class variables, table and field names are should be cached per instance in an instance variable.
Updated by John Heathco almost 3 years ago
Is this a bug in all database drivers?
Updated by wvoq - almost 3 years ago
The bug is in all drivers except Mysqli, for which list_fields() seems to work differently (it doesn't take a table name as argument).
Updated by Chris Bandy almost 3 years ago
#1062 has patches which specifically bypass the class attributes when implementing a method to clear the cache.
Updated by Bob - almost 3 years ago
Updated by Chris Bandy almost 3 years ago
This bug also relates directly to #1236.
Updated by Jeremy Bush over 2 years ago
- Status changed from New to Closed
- Resolution set to fixed