Closed (fixed)
Project:
Drupal core
Version:
7.x-dev
Component:
base system
Priority:
Normal
Category:
Bug report
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
18 Jan 2010 at 16:30 UTC
Updated:
3 Jan 2014 at 01:08 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
Crell commentedThis issue forked off from #325169: Move error/exception handler higher up in the bootstrap process.
Comment #2
mundanity commentedI don't mind taking a stab at this (after #325169: Move error/exception handler higher up in the bootstrap process gets dealt with), but I'm not convinced the solution is to ditch db_is_active() altogether. While I get that try/catch should be utilized for this sort of thing (especially in core), because Drupal doesn't really have a "strict" OO flow, database calls are not well encapsulated. Having a D6 db_is_active() makes sense to me in that light, as it's a bit of a crapshoot to know if any particular API function actually makes a database call or not.
Since there are only four instances of db_is_active() in core, what about:
Comment #3
Crell commentedHere's the problem:
- The DB does not initialize, and therefore is not active, until called. So db_is_active() *should* return false if the connection hasn't been used yet, because it's not active. What you're asking for is a db_is_available().
- I'm fine with a db_is_available(), but the only way to confirm that the connection really is available is to try opening it, which would really just be a try-catch around Database::getConnection(); So there wouldn't be much savings there.
So either way we should convert core, and then we debate whether or not to provide a try-catch wrapper called db_is_available() for people that don't want to add their own try-catch. Mind you, that would also be used in an extremely small number of cases; really, who's going to check for a valid DB every time they use it? They shouldn't.
Comment #4
mundanity commentedRight but in D6 the logic is more db_is_available()ish. The four uses of it in core right now pretty much assume that the logic is "will the connection ever be available". My worry would be that contrib code relies on that, although I'd imagine the affected code by the logic change is rather small (but probably quite annoying to debug if it happens).
Or put it this way, since we're removing db_is_active() calls from code, it essentially is there solely for contrib code. We likely can't just remove it this late in the D7 cycle, and as such should it not act more like the D6 version?
Comment #5
Crell commentedHow many contrib modules even use that function?
I guess my point is that we're in alpha state. If we're going to allow an API change, let's do it right. I don't think "this function is really misnamed and will go away eventually, FYI" counts as "right". "Use an exception like everyone else" or "here's a function with a proper name" would both be "more right".
Comment #6
catchThe use of db_is_active() in #325169: Move error/exception handler higher up in the bootstrap process nearly caused a 30% regression for cached pages until I spent a decent amount of time benchmarking, then having to prove that the benchmarks weren't flawed, it has no use in its current state, so should be removed.
Comment #7
Crell commentedHere's a patch that takes a stab at stabbing db_is_active(). There's still one use of it in _drupal_maintenance_theme() that I'm not sure how to refactor. Someone who actually knows what that function is doing, please jump in here. :-)
It turns out that right now, we're returning NULL for an undefined connection rather than throwing an exception. However, PDO throws an exception when login credentials are invalid. That is inconsistent, and impossible for us to sanely error-handle. Aka, a bug. So this patch also introduces a new exception that gets thrown when an undefined connection is requested, which we then catch in places we used to use db_is_active().
Comment #8
dries commentedTypo: rebiuld should be rebuild.
What does it mean for a database connection not to be 'defined'. Should it be DatabaseConnectionNotAvailableException instead of DatabaseConnectionNotDefinedException?
Comment #9
Crell commentedBah, typos suck.
A database connection is not defined if the DB layer has not been told that the requested database key exists and what its login credentials are; that's slightly different from it having been told but the credentials being wrong or incomplete (which PDO will already throw an exception for). I'm flexible on the exception name, as long as we don't go bikeshedding it to death.
I'm still looking for someone to explain to me WTF the theme system is doing in the maintenance pathway so we can convert that, too. :-)
Comment #10
catch#719850: errors in update.php during bootstrap yield a blank page was duplicate, bumping this to critical based on WSOD over there.
Comment #11
catchComment #12
andypostSubscribe
Comment #13
Crell commentedI'd love to drive this home if someone can explain to me what the theme system is doing there so I know how to update it.
Comment #14
andypost@Crell some explanation you could find at #719850: errors in update.php during bootstrap yield a blank page
Comment #15
berdirOk, here is my try...
- Imho, we need to catch PDOException, not DatabaseNotDefinedExceptions. Because the latter is just thrown when the database is not defined at all.
- Changed DatabaseNotDefinedException to extend from PDOExecption instead of Exception so that it can be catched with PDOException too.
- try/catch doesn't work well for undefined functions/objects so I had to wrap a user_access() and a $user in an if clause
- The code in _drupal_maintenance_theme() does something in case the database is *not* available. I tried to do this by doing a simple, stupid SQL query but that's rather ugly. A better approach might be to simply try go forward and act once an exception happens on itself. But it might be complicated to actually handle it correctly from then on.
Another thing:
- The current "database down" maintenance page simply displays a PDO exception, that's not really nice but not something that needs to be handled here..
Comment #16
berdirups...
Comment #17
karschsp commentedI tried applying this patch to fix my "WSOD on update.php" problem and it didn't work. If I go to line 326 of update.php and change ini_set('display_errors', FALSE); to TRUE I get:
Fatal error: Call to undefined function _system_rebuild_theme_data() in /Volumes/Home/Users/stephenkarsch/webs/d7.stevekarsch.com/public_html/includes/theme.inc on line 586
(same error as before I applied the patch).
I will try to dig in but I think I'm in over my head! I'm happy to test though.
Comment #18
andypost@Berdir take a look at #719850: errors in update.php during bootstrap yield a blank page
EDIT: _system_rebuild_theme_data() could be unavailable
Comment #19
dries commentedThis patch looks good to be. Would be great to get sign-off from Crell. From the comments above, it sounds as if he'd be in support, but still.
Comment #20
Crell commentedI'll assume that the maintenance theme chunk makes sense, since I still find most of that to be black magic. :-)
My only other issue here is that I partially disagree with Berdir in #15. DatabaseNotDefinedException is not the same as a PDOException, and should not extend from it. If that means we have two catch statements, so be it. Ain't nothing wrong with having multiple catch statements. :-) If we really can't handle multiple catch statements (and possibly duplicating 3 lines of code), we could always just catch Exception.
Other than that, I think this is good to go.
Comment #21
berdirHm, ok. I just dislike extending all exceptions directly from Exception, but that's not something for this issue :)
Unless we actually do something different in those two catch's, I assume we can just simply catch Exception. Will do a reroll soon...
Comment #22
berdirI am working on a re-roll, just a short question...
I found out that the new exception actually can't be thrown at all.
Looking at the following code...
The second if is never going to be TRUE, because if the connection isn't set, we enter the first if which then bails out with a Exception in openConnection():
So we can simply drop the conditional stuff and optionally throw the DatabaseConnectionNotDefinedException inside openConnection(). There is also a similiar case, when there is no driver:
Opinions?
Comment #23
berdirAttached is a re-roll with the proposed changes from above.
This is getting quite a bit off-topic, we should eventually create a follow-up issue, especially if there is a disagreement on how to name the Exceptions or something like that :). There are also notices about undefined array indexes when commenting out the driver in settings.php to test that the exception gets thrown.
Simply doing a catch (Exception $e) now, since we probably don't act differently based on the thrown exception.
Comment #24
qasimzee commentedsubscribe
Comment #25
catchLooks good to me, very small nitpick with:
I had to do a double take because that looked like a path, could we expand it a bit like the comment further down? Apart from that looks RTBC, strongly agree about not bikeshedding exception names in this issue.
Comment #26
Crell commentedAgree with catch on cleaning up that comment, as I don't fully understand it. If a few lines down we try to set it, why do we even need to explain it there? It's just a default value.
Otherwise, Berdir's approach in #23 makes sense to me. Quick reroll and this should be good to go.
Comment #27
berdirOk..
I decided to move the user.module stuff out of the try/catch as it is going to fail anyway and added the defaults to the initial defaults array. It does look a bit strange in the patch but I think it's easier to understand when looking at the resulting code.
Comments might still need to be improved though :)
Comment #28
alexanderpas commentedThese should probaly extend from RuntmeException, just like PDOException
(see also: http://php.net/manual/spl.exceptions.php)
This should allow a more specific catch.
Powered by Dreditor.
Comment #29
berdirYou are most probably right, but see the middle paragraph in #23, I don't think this is the correct issue for doing that. Instead, we should probably change all Exceptions in database.inc change to extend from RuntimeException.
Comment #30
catchComment #31
dries commentedCommitted to CVS HEAD. Thanks.
Comment #32
andypostI see no commit message at http://drupal.org/project/cvs/3060
Comment #33
andypostAlso follow-up for maintenance mode #766100-6: Undefined function _system_rebuild_theme_data when trying to run update.php from D6 -> D7
Comment #34
David_Rothstein commentedPatch still applies :)
Comment #35
andypostA hunk from _drupal_maintenance_theme() should be
if (!class_exists('Database', FALSE)) {Details in #766100-10: Undefined function _system_rebuild_theme_data when trying to run update.php from D6 -> D7
Comment #36
catchRe-rolled minus the theme.maintenance.inc change - we can just do that in #766100: Undefined function _system_rebuild_theme_data when trying to run update.php from D6 -> D7.
Comment #38
catch#36: die.patch queued for re-testing.
Comment #39
catchSince this is just a re-roll without the hunk that was committed elsewhere, and was already RTBC before apart from that hunk, I'm setting it back.
Comment #40
berdir#36: die.patch queued for re-testing.
Comment #41
gustavb commentedAnother nitpick,
it should be
throw new DatabaseDriverNotSpecifiedException..., right?Comment #42
andypostReroll with changes:
1) "Throw" => throw
2) in list_themes() try-catch moved inside if() because only system_list() depends on DB
Comment #43
Crell commentedmfb has another issue that's dependent on this one. Let's resolve it and move on to a new era of errors. Or something.
Comment #44
mfbOne problem, there's still a call to db_is_active() in theme.maintenance.inc
Comment #45
andypostmfb: This was fixed already in #766100: Undefined function _system_rebuild_theme_data when trying to run update.php from D6 -> D7
Re-roll after #722978: Invalid header count for empty message in theme_table().
Same patch, just fix ofset
Comment #46
mfbThere's still a call to db_is_active() in theme.maintenance.inc -- but this patch removes the function.
Comment #47
mfbApparently my cvs is on crack. I mean, cvs update -D does bad things. RTBC
(sorry :)
Comment #48
webchickIt looks like Dries meant to commit this earlier and missed it. Oops!
Committed to HEAD.
Looks like we need to document this change in the 6 => 7 module upgrade docs.
Comment #49
andypostAdded placeholder http://drupal.org/update/modules/6/7#db_is_active
Needs explain better when use class_exists() [bootstrap] and when exception catching [after bootstrap]
Comment #50
Crell commentedDoes this really need a separate updating line item when we already have an item for "everything about the DB changed, here's the docs, go read 'em"? Did anyone outside of core even USE db_is_active()? :-) I really don't think we need a second line item here.
Comment #51
andypostCrell I've used this once in my custom module so I think this needs details mostly about replacing within bootstrap.
Comment #52
sivaji_ganesh_jojodae commented#779494: Notices on install screens is probably related to this.
Comment #53
Crell commentedI updated the module update page.