I want to create some blocks that query an external database.

Per instructions on http://drupal.org/node/18429, I have been able to successfully do this as long as the connection is working. Since the database is on a different server, sometimes the connection may be broken. If the connection is broken, I get a big, ugly error page that kills the entire page.

My question is: how can I gracefully check to see that the connection to the secondary database is working and show a nice, friendly "sorry, this database isn't available", rather than a big giant error that breaks everything??

I looked at the DB abstraction layer page at http://api.drupal.org/api/group/database and couldn't find anything that works. I presume this is because the connection is defined in settings.php and the array variable exists for my block code to proceed even though the actual connection is broken.

Help!?!?

Comments

emackn’s picture

Would be nice if there was a built in function.

But there isn't so I did this:

  db_set_active('otherDB'); 
  // check to see if we have connected successfully
  $sql = 'SELECT value from {variable} WHERE name = "site_name"';
  $result = db_query($sql);
  $site = strtolower(unserialize(db_result($result)));

  if($site == "site_name_of_other_db") {  
    // do your stuff
  }
  else {
    // set error, etc
  }

  db_set_active();

It's not perfect, but might help. Also, it assumes you are connecting to another Drupal database, but you could make appropriate changes if you needed. Maybe add a custom table to your "other" database that does not exist on the default one.

isaac77’s picture

Thanks very much for the suggestion emackn, but the workaround you propose does not help me.

It seems that the db_set_active() call itself causes the _db_error_page to be returned, before we can even get to the test that checks if the current site name matches the "otherDB" site name.

Any other suggestions out there? It does not seems right that a connection problem to an external database must produce an error page, rather than returning a value that can be tested and acted on. Do we have to make do and write something with php functions for now?

gpk’s picture

>It does not seems right that a connection problem to an external database must produce an error page
Unfortunately (for you) that is the way it works at the moment. You would probably need to write a customized version of db_connect() (see http://api.drupal.org/api/drupal/includes--database.mysql.inc/6/source) and maybe also of http://api.drupal.org/api/function/db_set_active/6 so that if you can't connect then you can do something other than show the DB error page. Then invoke these from the block. Or put the whole lot into a small custom module.

inders’s picture

A module for such external database functionalty is prefered.

-Inder Singh
http://indersingh.com

mikeytown2’s picture

Title: How to validate connection using db_set_active » How to validate connection using db_set_active.
Version: 6.12 » 6.x-dev

Subscribe.

Problem is in db_connect()

  $connection = @pg_connect($conn_string);
  if (!$connection) {
    require_once './includes/unicode.inc';
    _db_error_page(decode_entities($php_errormsg));
  }

_db_error_page() then aborts everything with an exit. I think the best option ATM would be to add in a db_validate function as this wouldn't change the old behavior.

mikeytown2’s picture

Title: How to validate connection using db_set_active. » db_set_active errors out if db_connect fails. Add in the ability to handle this gracefully (don't always call _db_error_page).
Category: support » bug
StatusFileSize
new4.5 KB

db_validate would have duplicated a lot of code, I think this is a better way.

This adds a new input to db_set_active; the $abort variable. It's set to TRUE by default. Example code on how to use it

  global $db_url;

  // Get all vocabs with name as key
  $orginal_db = db_set_active();
  // Switch to the shared db
  $vocabulary = array();
  foreach ($db_url as $key => $value) {
    $alive = db_set_active($key, FALSE);
    if ($alive) {
      $query = db_query("SELECT * FROM {vocabulary} ORDER BY vid ASC");
      while ($row = db_fetch_array($query)) {
        $vocabulary[$row['name']] = $row;
      }
    }
  }
  // Put database back to previous state
  db_set_active($orginal_db);
mikeytown2’s picture

Status: Active » Needs review
mikeytown2’s picture

Status: Needs review » Needs work

$abort is not set

mikeytown2’s picture

Status: Needs work » Needs review
StatusFileSize
new4.79 KB

$abort is set at the top of the function. Anyway made this clearer and added in comments. Note that this is 100% backwards compatible.

mikeytown2’s picture

StatusFileSize
new3.55 KB

Status: Needs review » Needs work

The last submitted patch, drupal-496184_1.patch, failed testing.

mikeytown2’s picture

Status: Needs work » Needs review
willeaton’s picture

I'd like to bump this please. This is the perfect solution to my problem. I connect to 4 different databases in quite a large website as it requires integration with other systems. These systems are not critical so I don't really care if one or two of them fail. The problem is, if one of them fails then it drops the entire website which is not desirable at all.

We need a way to set if the database connection is critical or not, and the ability to include $abort in the connection is exactly what we are after

mikeytown2’s picture

@willeaton
we use this patch quite successfully to access 70+ databases over 3 different mysql servers.

mikeytown2’s picture

StatusFileSize
new4 KB

updated patch

Status: Needs review » Needs work

The last submitted patch, drupal-496184-15.patch, failed testing.

mikeytown2’s picture

Status: Needs work » Needs review
StatusFileSize
new5.52 KB

Patch for pressflow

mikeytown2’s picture

StatusFileSize
new6 KB

Re-rolled against pressflow 6.25

mikeytown2’s picture

StatusFileSize
new4 KB

Patch against core

jelo’s picture

Has this been committed to core? I would like to see this functionality added as well...

mikeytown2’s picture

This has not been committed to core and I don't think it will be as there is not enough interest here.

jelo’s picture

Well, I am not sure how the Drupal community normally handles this, but "interest" should not be the deciding factor if a critical bug has been identified and there is a fix for it. In essence, Drupal positions itself more and more as a framework that can integrate with and into various other systems. To me, being able to access multiple databases is at the essence of some of this. It sounds like a very bad idea to me to let a whole site break if for whatever reason a secondary database is not available. Could you please advice what needs to be done to get this committed?

mikeytown2’s picture

Status: Needs review » Needs work

@jelo
Have you tested the patch (#19) on your setup? Does it do what you need it to? If so say that the patch works and we can then look at moving the status from "needs review" to "reviewed and tested by the community". If the patch doesn't do what you need, say what needs to be changed and change the status to "needs work". Right now the patch has been tested by me, and it works great in my case (1400 domains connecting to 80 databases; one massive multisite). It needs to be vetted by more people before it has a shot of getting into core.

mikeytown2’s picture

Status: Needs work » Needs review

Status: Needs review » Closed (outdated)

Automatically closed because Drupal 6 is no longer supported. If the issue verifiably applies to later versions, please reopen with details and update the version.