If you tryed to print "item" outside the template loop I bet it would print. This is because associate => $q is the same as doing $template->param(ITEM => $q->param('item')) for every param returned by cgi and TMPL_LOOPs introduce their own scope and can't use variables from outside the loop. If you set global_vars => 1 it should work.
Btw. in order to find I simplify your code by trying it without CGI::Application:
script:
#!/usr/bin/perl
use DBI;
use HTML::Template;
use CGI;
my $q = CGI->new();
my $dbh = DBI->connect('DBI:Pg:dbname=testdb', '', '');
$dbh->{RaiseError} = 1;
$aref = $dbh->selectall_arrayref( q/select foo, bar from test_table wh
+ere id = ?/, { Slice => {} }, $q->param('id') );
$dbh->disconnect;
my $template = HTML::Template->new(filename => 'test.tmpl', associate
+=> $q, global_vars => 1);
$template->param(TEST_LOOP => $aref);
print $template->output();
template:
id = <TMPL_VAR NAME=ID>
<!--remove global_vars and only this first ID will print-->
<TMPL_LOOP NAME=TEST_LOOP>
<p>
id: <TMPL_VAR NAME=ID> <br \>
foo: <TMPL_VAR NAME=FOO> <br \>
bar: <TMPL_VAR NAME=BAR>
</p>
</TMPL_LOOP>