Saturday, October 25, 2008

Perl Test::More trick

Recently I was working on a rather large Perl module and writing unit tests for it. I had some tests already completely done and trying to debug another chunk of code & tests. It was hard with debugging on to see what was going on. I just wanted to see one set of tests and nothing from the other sets. At first I commented out the blocks of code that ran the tests I didn't care about. Then I realized there was an easier way.

Say you have a test that starts with something like:

sub my_batch_of_tests : Test(6) {


Easy way to disable these: turn the above line to something like

sub my_batch_of_tests { # : Test(6)


When you do run_tests() on this test module, it won't run this block of tests because this function will no longer register as a test.


NOTE: this tip assumes you are using Test::More and Test::Class and have it set up so all your tests are in a module and you have a script that loads that module and does ->run_tests on the module with your tests.

Wednesday, October 1, 2008

SQL - you can't compare NULL to anything

Here is a little mind-bender for any of you who are programmers who routinely work with SQL. Write a little code that checks to see if NULL equals NULL. It returns false. Now write code to see if NULL is not equal NULL. It will return false too. Now repeat with NULL and any value. NULL equals 42 returns false, NULL is not equal 42 returns false. * What in the world is going on here?

Here's what I found when I ran into this issue before. What we're seeing here is the impact of NULL being a mathematical concept. SQL is built on many mathematical concepts. The concept of NULL is an unknown value. Since NULL is an unknown value, it may be 42, it may be Fred. We simply don't know. So comparing anything at all to NULL (even comparing NULL to itself) will *ALWAYS* return false. This is why you need to specify IS NULL or IS NOT NULL if you want to see if something is or isn't NULL.

* I experienced this issue most recently working with Oracle, but it will work with any SQL database such as MySQL, PostgreSQL, and Microsoft SQL Server.

Friday, September 5, 2008

Using Windows environment variables

This post will be a little more basic than most things I write here. I'm used to using MacOS/X on the desktop and Linux on the server side. So when I have to use Windows for one reason or another it sometimes takes me a bit to figure things out.

Today I was helping a co-worker with Oracle Application Express (APEX for short) and the install directions said to run "cd $ORACLE_HOME/apex" and then run some commands. The cd command didn't work because Windows does environment variables different than Unix operating systems.

This article covers it in more detail but in short Windows indicates environment variables by putting a % (percent sign) before and after the variable. Variables are not case sensitive.

You can show them by running "echo %ENV_NAME%" and set them on the command line by running "ENV_NAME = new_value". You can make the setting part of your login profile by right-clicking on "My Computer", then click Properties, then Advanced, and then Environment Variables. This is for XP, the location may be different on Vista or other versions of Windows.

Saturday, June 7, 2008

MySQL++ meets Leopard on an Intel Mac

A friend of mine is learning C++ and also wants to learn MySQL. I decided to go ahead and show him how to connect MySQL to a database in C++. Once I started, I realized I've never done this with MySQL, only with PostgreSQL. Oh well, how different could it be???

I decided to install on my Mac Mini which is running MacOS/X 10.5 Leopard. Installing the latest stable version of MySQL from source was cake. I got the sample C program working with no problems and then I looked for how to hookup C++ to MySQL. MySQL itself does not come with a C++ API, only C. The C++ bindings are provided by a project called MySQL++. This is when the problems started.

First off, it gave me some errors about not being able to find some functions. This was the actual error:

./lib/mystring.cpp: In member function ‘int mysqlpp::String::compare(const std::string&) const’:
./lib/mystring.cpp:67: error: no matching function for call to ‘max(unsigned int, size_t)’
./lib/mystring.cpp: In member function ‘int mysqlpp::String::compare(const char*) const’:
./lib/mystring.cpp:81: error: no matching function for call to ‘max(unsigned int, size_t)’
./lib/mystring.cpp: In member function ‘int mysqlpp::String::compare(const std::string&) const’:
./lib/mystring.cpp:67: error: no matching function for call to ‘max(unsigned int, size_t)’
./lib/mystring.cpp: In member function ‘int mysqlpp::String::compare(const char*) const’:
./lib/mystring.cpp:81: error: no matching function for call to ‘max(unsigned int, size_t)’


A little googling around turns up this message on the MySQL++ mailing list. Apparently the way things were coded, this "max" function works perfectly fine on 32 bit processors, but not 64 bit. The fix is to change 1 line of the lib/mystring.h file in the source from "typedef unsigned int size_type;" to "typedef size_t size_type;". It sounds like this fix will be in the next release of MySQL++ and then no one will have to worry about it.

Another note here - the library for MySQL++ isn't libmysql++ or mysql++ as one may expect. It is mysqlpp. Just as well, special characters tend to mess things up sometimes.

The other problem I ran into was this error when trying to compile the sample program from the MySQL++ documentation:

ld: in /usr/local/lib, can't map file, errno=22
collect2: ld returned 1 exit status


This turned out to be one of those silly mistakes that causes a big problem. In specified the linker path, I had put

-L /usr/local/lib

When I changed it to

-L/usr/local/lib

it worked fine. This seems like something the GNU development utilities should be able to be smart enough to handle.

Thursday, June 5, 2008

Tortoise SVN for Windows tips

I just figured out two new features in Tortoise SVN today. First off, you can get SVN info showing up in Windows Explorer.

1. Go to a folder that contains files you checked out from SVN. Go to View -> Details
2. Right click on any column to get a list of available columns.
3. Select "More" and scroll down until you get to the list of "SVN" details. I highly recommend SVN Status & SVN Revision.
4. Click OK and then refresh the window. You'll have SVN status & revision # on all the files in the folder controlled by SVN.

5. (Optional) Go to Tools -> Folder Options and click the View tab. Hit Apply to All Folders & you'll have this same view for all folders next time you open them.

Trick #2.
1. Open up TortoiseSVN settings & go to "General".
2. Click on the "Set filedates to the "last commit time"
3. Hit Apply & then OK.

Your files from SVN will now show the last time you committed them as the modification time. One note here: this didn't seem to work for me until I deleted my files from my SVN working copies & checked them out again.

Friday, March 7, 2008

Ruby exceptions vs. logging

A while ago, I ran into a little problem with some software. We had some Ruby scripts running from cron. Going by the logs, they would start up and just go to the bit bucket never to be heard from again. After checking the code to try to figure out what was going wrong, I decided to just run them by hand to see what would happen.

BLAM!!! A nice big unhandled exception, which of course in Ruby makes whatever script you are running exploded in a rather show-stopping manner. Why wasn't this logged?

It turns out that this is all in how an exception actually works. If you don't handle an exception, the program keeps going up the call stack (function A calls function B, etc) until it finds something that can handle the exception. If nothing handles the exception, the program just stops right then & there and your exception becomes a fatal error.

This problem is possible in multiple scripts, and we didn't have time to rewrite them all the catch all possible exceptions, which sounds too time consuming anyway.

Here's the solution I ended up with.

It turns out in Ruby when a program exits normally or because of an unhandled exception, it sends the EXIT signal. So all you have to do is catch the EXIT signal and log any exceptions that come across.

This is one time that Ruby shows its Perl influence. The $! variable is whatever exception is present. So, trap the signal and check $! for the exception (aka the error).

There is one final twist on this, and it turns out a normally running Ruby program relies on exception handling, even if you don't know you're using exceptions.

If you do a call to the exit() function in your code, that actually throws a SystemExit exception, which causes Ruby to immediately stop your program.

So this is the code I ended up putting in our logger object, which is just an extension of the standard Ruby logger:


#Catch & log unhandled exceptions
Signal.trap("EXIT") {
unless $!.class.name == "SystemExit" || $!.nil?
self.fatal("Unhandled exception: #{$!.class.name}: #{$!.to_s}")
end
}


The log entries would end up looking something like:

Unhandled exception: FooException: Something went terribly wrong in the get_important_data method and the program cannot continue.


In retrospect, there are probably two better ways this could be done.

1. Make each program have an "execute" method of some sort that kicks off all the logic for the rest of the program. You could then wrap exception handling code around the call to "execute" and this would grab all your exceptions that aren't handled elsewhere in your code.

2. Assuming these are all scripts of some sort, likely to be run from cron, you could have a script that runs scripts. It could log anything that goes to standard output as "info" messages, standard error as "warning" messages, and any script that exits with a non-zero status (meaning an error) could be logged as a fatal error.

Tuesday, February 26, 2008

how to cheat with ruby gems

It's nice to have a quick reference of commands for whatever technology you are working with. I noticed a Capistrano cheatsheet hanging up in a coworkers cubicle today. I think it was the one that used to be available at this link: http://weblog.rubyonrails.org/2006/9/30/capistrano-cheat-sheet but it now seems to result in a Rails application error.

I went looking for a mirror of it and ended up finding something I like better. Ruby developers at ErrFree have set up a great gem called "cheat". More info on the cheat page. Short version:

You can install the "cheat" gem with "sudo gem install cheat" which works out of the box on MacOS/X Leopard. This will allow you to snag & view cheatsheets, which are downloaded into .cheats/ in your home directory.

To see how to use cheat run:
cheat cheat


Or to view any cheat simple run
cheat [cheatname]


And if you want to snag the latest version just run
cheat --new


The cheats are served up from a lightweight wiki, which you can add to and update. No usernames or passwords, just a kaptcha to keep spammers out. I added an entry to see if it was as easy as it looked. The Oracle cheat now contains


See current time:

SELECT SYSDATE FROM DUAL;