Archive for the ‘Code’ Category

Why does layout change in IE when UL is alone in a TD vs having an extra empty DIV?

Friday, July 31st, 2009

I’m trying to find an answer to my layout question — I posted it to stack overflow:Why does layout change in IE when UL is alone in a TD vs having an extra empty DIV?. I’m posting it here as well, so I can upload a screenshot.

Update: There is now an answer on the stackoverflow question; One of the css rules makes the li tag white — it doesn’t have to, because the a is white. IE takes the spaces between the lis, and puts them in the enclusing td. This pushes the li down, causing it to overlap the border line.


I’m adding css-based tab navigation to a site that is still using table-based layout. When I place my tab list inside a td, there is a visual “gap” that you can see. If I put an empty div with “width: 100%” in the td, then my tab list displays correctly. (It also works fine outside the table.)Why does the div make the tabs lay out correctly, and is there a better way to make them do so without adding a content-free div?Here’s my test case: Test Case: Why does layout change in IE when UL is alone in a TD vs having an extra empty DIV?And a Screen Shot:

Screen shot of the error in IE 7

Unit Test Abuses — Who Needs Mocks?

Friday, April 11th, 2008

So, when I fix a bug, I like to wrap a test around it to catch regressions. When I wrote the test for the bug discussed under Debugging adventures with DBD::Sybase, I had to make an unusual work-around…

eval {
    # ick. ick. ick. You didn't see me do this.
    no warnings 'redefine';
    local *App::is_schedule_found = sub { pass("called bogus func");  return (1, 'ok'); };
    ($ok, $msg) = App::process_row($dbh, $questionable_row);
    ok($ok, "processing row: $msg");
};
unlike($@, qr/^Panic: Can't have multiple statement handles on a single database handle when AutoCommit is OFF/,
        "Sybase Error Handling busted");

I’ve changed the package name to “App” to protect the guilty. process_row calls is_schedule_found, and bails out if it’s not found. Since this bug only show up when testing against the real database, I can’t fake out the data source. So I insert the appropriate prerequisite data, and then run the procedure. But I don’t want to build up the whole structure just to adjust one table. (The database doesn’t have integrity constraints… Not my preference, but that’s how it is today.)

So I replace the function that checks for the schedule with one that always returns true. I don’t need to dependency inject a mock with an interface, I just adjust the global symbol table.

Debugging adventures with DBD::Sybase

Tuesday, April 8th, 2008

So, I recently debugged an error in some code I inherited. It was a relatively bizarre corner case that I thought might be interested.

The code is Perl running on windows, accessing a sybase database using DBI and DBD::Sybase.

This was the basic structure of the code:

 sub process_record {
	my $record = shift;

	if (is_record_in_db($record)) {
		if (mark_existing_record_deleted($record)) {
			insert_record($record);
		}
	} else {
		insert_record($record);
	}
}

There was some other stuff in there too, but it doesn’t matter for this story.

This code had been in production for about a year, and it’s been working fine. Suddenly we start getting this error:

Panic: Can't have multiple statement handles on a single database handle when AutoCommit is OFF

It also gives a line number from the bowels of DBD::Sybase. I try to get a full stack trace by running it under -MCarp=verbose . But, DBD::Sybase doesn’t croak, it dies, so I can’t see which call of mine is killing it. I don’t feel like hitting the debugger yet, so I think some more.

Now, this error comes only after we’ve processed 5000 or so records, so I take a look to see what’s different about the record where it fails, and I notice that it takes the path which calls mark_existing_record_deleted, while none of the others do. (Inserts heavily outnumber updates on this application.)

(Note: all of the called routines access the database.) DBD::Sybase doesn’t allow you to have multiple statement handles. So I look in the code and see that, sure enough, mark_existing_record_deleted doesn’t have a call to $sth->finish . But neither does is_record_in_db! Now I’m wondering, “how does this thing work at all?”

The answer is, that DBD::Sybase automatically finishes the handle for you when you read past the last row. So when there’s no data in the database, the query in is_record_in_db returns no rows. One fetch is “past the end,” so the handle gets closed. But when there is data, the query handle is open, causing the application to die when you try to open another handle in mark_existing_record_deleted.

So, watch out for that when you write code against Sybase.