Wednesday, June 30, 2010

Experimenting with HTML Canvas

I am starting to get interested in using the HTML canvas element with GWT.
I have downloaded the gwt-canvas project, which provides a very nice API wrapper.  The first thing I did was extend it to add text support.  Okay, I only added text support for browsers that support it.

Anyway, that brings me to my first pain point.  Experimenting with canvas in GWT is extremely time consuming, as you must recompile to JavaScript every time you make a change.  (Canvas is not supported in hosted mode, AFAIK!)

However, there is an extremely easy way to experiment with the canvas:
  • Get firefox, and the firebug addon.
  • Save the following text to the file canvas.html :

<html>
<body>
<canvas id="canvas" width="300" height="200" style="border: 1px solid black;">Time to upgrade!</canvas>
</body>
</html>

  • In Firefox, select "File/Open File", and open the file you just saved.
  • You should see the following:


  • Open firebug (in the bottom right corner), and select the Console tab
  • You are now ready to experiment!  Just type your javascript into the console command prompt, ">>>".
  • For example, you might go to the Mozilla Drawing Graphics with Canvas tutorial, and copy those commands, one line at a time, into the command prompt:

There you have it! A command line interface for experimenting with canvas, with things you probably had lying around the home!

Wednesday, June 2, 2010

Deleting duplicate SQL rows

I know this is not really GWT related, but I ran into a problem with one of my database tables, where I somehow managed to get duplicate rows.

I don't know how it happened, but to prevent it happening again, I wanted to add a unique constraint on the 'username' column.

Before I could do that, however, I had to delete the duplicate entries.

I searched around using Google, and found a few solutions that seemed complicated, and not quite what I wanted. They seemed to involve copying data to another table, deleting dupes, deleting the original table rows, and then copying it back.

So, here is what I think is an easier way to do it, that is a bit more flexible:

  • Find the rows you want to keep
  • Delete the other rows.

Selecting the good rows

My table in question is 'usersettings'. It has 9 columns, but all I care about are the first two, 'id', and 'username'.

To find the rows I want to keep, I am going to select the lowest id per username. To do this, I used aggregation, with the group by clause, and the 'min' operator.


select min(id) as id from usersettings group by username;

This returns the lowest id for all unique usernames. These are the rows I want to keep.
This could easily be modified to take the highest id, using max.
I am sure there are lots of other ways to implement the criteria to select the ids that you want to keep.

We can dump this result set into a temporary table, or even just use it as a subquery expression.
To maximize database compatibility, I will just use a subquery.


Deleting the bad rows

Okay, first we will just 'select' the rows to be deleted, to make sure we are deleting the proper rows:
select * from usersettings where id not in (select min(id) as id from usersettings group by username);


Sure enough, this returns a result set containing the duplicate rows that have higher ids.

So, now that we know we are selecting the correct data, I can go ahead and delete it:
delete from usersettings where id not in (select min(id) as id from usersettings group by username);

Using a temp table

If you want to use a temporary table instead, with postgres you could do the following:

select min(id) as id into temp table goodids from usersettings group by username;
delete from usersettings where id not in (select * from goodids);


As always, you should really back up your database before deleting stuff!!!

Now that my usersettings.username only contains unique data, I am able to apply the unique constraint to it.