If you use the db_set_active function to change to another database, and then run a query that contains invalid syntax, watchdog module tries to insert the error, but uses the currently active database, instead of the drupal database.

The errors in error_log are along the lines of:

[Thu Nov 18 09:30:51 2004] [error] PHP Fatal error: Table 'someotherdb.watchdog' doesn't exist
query: INSERT INTO watchdog (uid, type, message, link, location, hostname, timestamp) VALUES (2, 'error', 'user error: Unknown column \'favourite\' in \'field list\'
query: --SNIP BAD QUERY-- in /var/www/httpd/includes/database.mysql.inc on line 125.', '', '/addespy?awitem=26', '192.168.0.1', 1100770251) in /var/www/httpd/includes/database.mysql.inc on line 125
[Thu Nov 18 09:30:51 2004] [error] PHP Fatal error: Table 'someotherdb.sessions' doesn't exist
query: UPDATE sessions SET uid = 2, hostname = '192.168.0.1', session = 'messages|a:0:{}', timestamp = 1100770251 WHERE sid = '428af456a2ec4610951275d551ab6f6a' in /var/www/httpd/includes/database.mysql.inc on line 125
[Thu Nov 18 09:30:51 2004] [error] PHP Warning: Unknown(): A session is active. You cannot change the session module's ini settings at this time. in Unknown on line 0

Comments

Anonymous’s picture

not sure if this is the way to fix it or if there are deeper issues which need to be considered.

something along the lines of

database.inc add a function called db_get_active
then in the watchdog call the function before any logging to the drupal database if the returned name != 'default' then remember what it was set to, call db_get_active('default') then after the watchdog has logged anything set the active database back to it's previous value.

Thanks,

Sil

Dave Cohen’s picture

The problem is not exactly as you describe. If you add some prints to db_set_active, you'll see that the watchdog code is being called after you've called db_set_active a second time, returning to the default database. (At least, you had better be doing that. But you'll still have the problem)

My thinking is the problem has to do with PHP references. When you call db_set_active('your_db'), it calls

  // Set the active connection.
  $active_db = $db_conns[$name];

But at this point $active_db is a reference to the default database connection. Because of some nasty reference stuff, you''ve actually changed the default database connection to connect to your_db!

Later, when you call db_set_active(), you don't really change anything!

For me, the quickest fix was to simply change the if statement near the top of db_set_active...

  // if (!isset($db_conns[$name])) {
  if (true) {
	// Initiate a new connection, using the named DB URL specified.

This way the code to create a new connection is always called, and active_db always points where it should. Of course you no longer are cacheing connections, but the doc for mysql_connect states that it does that for you. And I'm using mysql so I'm not worried about it.

I tried an alternate fix, namely calling unset($active_db) before the line that sets it. That's supposed to get around the reference funkyness, but then the db connections failed every time. So for now I'm sticking with the fix above.

Dave Cohen’s picture

Priority: Minor » Normal

When I posted before I did not realize this was the bug report. I thought it was simply a forum post. I'll add a little more info. Also I'd like to see the priority higher than 'minor' doesn't anyone else use more than one database? (I'd submit a fix if I had one. I tried for a while but didn't come up with the right solution).

My version info is Drupal 4.5.2, php 4.3.10.

Here's my set_active_db with prints that helped me figure out what's going on. (Also I turned debugging on by default in db_query).

function db_set_active($name = 'default') {
  global $db_url, $db_type, $active_db;
  static $db_conns;
  
  print "<p>Setting active DB: $name</p>\n";
  if (!isset($db_conns[$name])) {
	// Initiate a new connection, using the named DB URL specified.
    if (is_array($db_url)) {
      $connect_url = array_key_exists($name, $db_url) ? $db_url[$name] : $db_url['default'];
    }
    else {
      $connect_url = $db_url;
    }

    $db_type = substr($connect_url, 0, strpos($connect_url, '://'));

    // TODO: Allow more than one database API to be present.
    if ($db_type == 'mysql') {
      include_once 'includes/database.mysql.inc';
    }
    else {
      include_once 'includes/database.pgsql.inc';
    }
	print "<p>Connecting active DB: $connect_url</p>\n";

    $db_conns[$name] = db_connect($connect_url);

  }
  // Set the active connection.
  $active_db = $db_conns[$name];
  
  print "<p>Setting active DB: $active_db</p>\n";
  print "<p>db_cons[default]: {$db_conns['default']}</p>\n";

}

And by the way, thanks for what seems like a great product. I have not used it long. I'm trying to figure out if I can convert my existing site (www.yogadex.org) to Drupal.

Dave Cohen’s picture

Title: changing database with db_set_active and watchdog module issue » db_set_active problems

Ok, one more post...

There may be two problems here. There may be a problem as described in the first post. That is, during a call to db_query on a secondary database the watchdog code may be called. That is, if there is an error in the first sql statement, that problem may occur.

However, if there is no problem with the sql, the problem I describe occurs. Basically, it makes db_set_active unusable. And therefore the whole multiple database feature is broken, as far as I can tell.

-Dave

adrian’s picture

I use multiple database connections extensively.

I set the default error handler to something else whenever I access my other database.

adrian’s picture

Assigned: Unassigned » vertice@www.drop.org

I've clarified the documentation in this patch : http://drupal.org/node/19522

That's pretty much all that can be done in this case.

killes@www.drop.org’s picture

Version: » x.y.z

Adrian: I am now also using multiple databases and it is a major pain to debug.
I'd really like to use Drupal's error handler instead of creating my own.
I think that switching back to the Drupal database would be most usefull.

adrian’s picture

That code is _ugly_, but i could do it.

killes@www.drop.org’s picture

Status: Active » Closed (duplicate)

this is a documentation issue which will be fixed by the referenced patch,

Chris Johnson’s picture

The second problem (multi-database not working at all) is fixed. The first problem, throwing a watchdog message, while an alternate database is active, still exists. See issue 42000.