Monday, January 30, 2012

Cannot find /Library/Tomcat/Home/bin/setclasspath.sh

When starting Tomcat on Lion:
$ /Library/Tomcat/bin/startup.sh 
And you encountered this error:
Cannot find /Library/Tomcat/Home/bin/setclasspath.sh This file is needed to run this program
just unset the CATALINA_HOME variable:
$ unset CATALINA_HOME

Then run this again:
/Library/Tomcat/bin/startup.sh 

Then visit http://127.0.0.1:8080

Troubleshooting idea got from this: http://www.malisphoto.com/tips/tomcatonosx.html


Another approach is to use sudo:

sudo /Library/Tomcat/bin/startup.sh 

Then visit http://127.0.0.1:8080

Thursday, September 29, 2011

Hi Mr. Everything's-a-Class, please copy other language's closure

If it's a hard pill to swallow for Mr. Everything's-a-Class to copy closure syntax from Mr. Method Pointers' language..

using System;

namespace TestCsharpClosures
{
    class Program
    {
        static void Main(string[] args)
        {
            var f = Test();
            Console.WriteLine("F: " + f());
            Console.WriteLine("F: " + f());
            Console.WriteLine("F: " + f());
            
            var g = Test();
            Console.WriteLine("G: " + g());
            Console.WriteLine("F: " + f());
            Console.WriteLine("G: " + g());
            Console.WriteLine("G: " + g());

            
        }

        public static Func<int> Test()
        {
            int a = 0;
            return new Func<int>(() => 
                {
                    return ++a;
                });

            // above line can be shortened to:
            // return new Func<int>(() => ++a);
        }
    }
}

Output:
F: 1
F: 2
F: 3
G: 1
F: 4
G: 2
G: 3


..at least Mr. Everything's-a-Class could copy closure syntax from its dumb kid brother:

<script type="text/javascript">

 var f = Test();
 WriteLine("F: " + f());
 WriteLine("F: " + f());
 WriteLine("F: " + f());
 
 
 var g = Test();
 WriteLine("G: " + g());
 WriteLine("F: " + f());
 WriteLine("G: " + g());
 WriteLine("G: " + g());

 function Test() {
  var a = 0;
  return function() {
   return ++a;
  };
 }

 function WriteLine(msg) {
  document.write('<div>' + msg + '</div>');
 } 
</script>

Output:

F: 1
F: 2
F: 3
G: 1
F: 4
G: 2
G: 3


Question of the week: What is the difference between a 'closure' and a 'lambda'?

Answer, there is none. Java don't have both of them :-)

Monday, September 12, 2011

Postgresql 9.1 is released now

Download Postgresql 9.1 now

One neat feature, we can now omit extraneous fields on GROUP BY, as long as primary key is already there


create table person
(
person_id serial not null primary key,
firstname text not null,
lastname text not null,
address text not null
);

create table visit
(
visit_id serial not null primary key,
person_id int not null references person(person_id),
url text not null
);


select
    p.person_id,
    p.firstname, p.lastname, p.address, 
    count(*)
from
    person p
    join visit v on p.person_id = v.person_id
group by p.person_id
    -- ,p.firstname, p.lastname, p.address; -- omitting other fields is now possible on 9.1


And it's still the same disciplined Postgresql
select    
    p.firstname, p.lastname, count(*)
from
    person p
    join visit v on p.person_id = v.person_id
group by p.firstname  -- this is not allowed, it's confusing which lastname to pick

Thursday, August 11, 2011

Postgresql exception-catching rocks!

Gotta love Postgres. It always yield back the control to you when an exception occur.

Given this:

create table z
(
i int not null primary key,
zzz int not null
);

Try both(one at a time) alter table z drop column aaa; and alter table z add column zzz int;, your code can detect the DDL exceptions


do $$


begin

    -- alter table z drop column aaa;
    alter table z add column zzz int;


exception when others then 

    raise notice 'The transaction is in an uncommittable state. '
                     'Transaction was rolled back';

    raise notice 'Yo this is good! --> % %', SQLERRM, SQLSTATE;
end;


$$ language 'plpgsql';

Here are the errors, both kind of errors are catchable:





Contrast that with Sql Server, try both(one at a time) alter table z drop column aaa; and
alter table z add zzz int;

begin try

    begin transaction

    -- alter table z drop column aaa;
    alter table z add zzz int;

    commit tran;

end try
begin catch 

    print 'hello';
    SELECT
        ERROR_NUMBER() as ErrorNumber,
        ERROR_MESSAGE() as ErrorMessage;

    IF (XACT_STATE()) = -1
    BEGIN
        PRINT
            N'The transaction is in an uncommittable state. ' +
            'Rolling back transaction.'
        ROLLBACK TRANSACTION;
    END;

end catch

print 'reached';

Here are the errors for SQL Server:

Catchable error:


Uncatchable error:



Sql Server won't let you catch the error on alter table z add column zzz int;

Saturday, July 30, 2011

Pad blank rows to Flexigrid

$('#nav').flexigrid({
 url: '/Person/Management/List',
 dataType: 'json',
 colModel: [
  { display: 'Username', name: 'Username', width: 150, sortable: true, align: 'left' },
  { display: 'Firstname', name: 'Firstname', width: 150, sortable: true, align: 'left' },
  { display: 'Lastname', name: 'Lastname', width: 150, sortable: true, align: 'left' },
  { display: 'Favorite#', name: 'FavoriteNumber', width: 150, sortable: true, align: 'left' }
 ],
 buttons: [
  { name: 'Add', bclass: 'add', onpress: add },
  { separator: true },
  { name: 'Edit', bclass: 'edit', onpress: edit },
  { separator: true },
  { name: 'Delete', bclass: 'delete', onpress: del }
 ],
 singleSelect: true,
 sortname: 'Lastname',
 sortorder: 'asc',
 usepager: true,
 title: 'Persons',
 useRp: true,
 rp: 5, 
 rpOptions: [5, 10, 15, 20, 25, 40],
 showTableToggleBtn: true,
 width: 560,
 height: 'auto',
 preProcess: function (data) {                

    var rp = getFgRowsPerPage($('#nav'));
    for (i = data.rows.length; i < rp; ++i) {
        data.rows.push({ 'id': '', 'cell': ['', '', '', ''] });
    }
    return data;
 }
});

function getFgRowsPerPage(tbl) {
    return $('select[name=rp] option:selected', tbl.closest('.flexigrid')).val();
}


Sample output(the last two rows are from the for loop):

Resize Flexigrid's Height

/*
Flexigrid's height is for table's tbody only, it does not include the chrome's (grid's navigation panel, title bar, etc) height. So if you pass 250 to flexigrid's height parameter, and you pass the same 250 to resizeFgHeight, it will actually make the flexigrid smaller.
*/
function resizeFgHeight(tbl, newHeight) {
    grd = tbl.closest('.flexigrid');
    var heightWithChromes = grd.height();
    
    var contentHeight = $('.bDiv', grd).height();
    var chromesHeight = heightWithChromes - contentHeight;    

    $('.bDiv', grd).height(newHeight - chromesHeight);
    grd.css('height', newHeight);
}

// This height is the same as flexigrid's height parameter. 
// Flexigrid's height parameter describes the the tbody's height of the table only,
// it does not include the chromes' heights
function resizeFgContentHeight(tbl, newHeight) {
    grd = tbl.closest('.flexigrid');
    $('.bDiv', grd).height(newHeight);
}

To use
<table id="nav"></table>

$(function() {
   $('#adjust').click(function() { 
      resizeFgHeight($('#nav'), 480);
   });
});

Thursday, July 28, 2011

Postgresql unnest function can do many wonders

I saw an interesting Postgres question on Stackoverflow

How to know if all the elements of the array are NULL?

This code works if you want to test if all the elements of the array are number 8, but doesn't work on NULLs:

SELECT 8 = ALL(ARRAY[8,8,8,8]::int[]); -- returns true


Unfortunately, you cannot use that same construct for comparing nulls, this return null:
SELECT NULL = ALL(ARRAY[NULL,NULL,NULL,NULL]::int[]);

And this returns a syntax error:
SELECT NULL IS ALL(ARRAY[NULL,NULL,NULL,NULL]::integer[]);

Fortunately, there's a function to un-nest an array to row elements; then from there, we can use the ALL construct for rows

So given this:

create table x
(
y serial,
z int[]
);

create table x
(
y serial,
z int[]
);

insert into x(z) values
(array[null,null,null]::int[]),
(array[null,7,null]::int[]),
(array[null,3,4]::int[]),
(array[null,null,null,null]::int[]),
(array[8,8,8,8]::int[]);

q_and_a=# select * from x;
 y |           z
---+-----------------------
 1 | {NULL,NULL,NULL}
 2 | {NULL,7,NULL}
 3 | {NULL,3,4}
 4 | {NULL,NULL,NULL,NULL}
 5 | {8,8,8,8}
(5 rows)


Then let's try to unnest array z from x:
q_and_a=# select *, unnest(z) from x;
 y |           z           | unnest
---+-----------------------+--------
 1 | {NULL,NULL,NULL}      |
 1 | {NULL,NULL,NULL}      |
 1 | {NULL,NULL,NULL}      |
 2 | {NULL,7,NULL}         |
 2 | {NULL,7,NULL}         |      7
 2 | {NULL,7,NULL}         |
 3 | {NULL,3,4}            |
 3 | {NULL,3,4}            |      3
 3 | {NULL,3,4}            |      4
 4 | {NULL,NULL,NULL,NULL} |
 4 | {NULL,NULL,NULL,NULL} |
 4 | {NULL,NULL,NULL,NULL} |
 4 | {NULL,NULL,NULL,NULL} |
 5 | {8,8,8,8}             |      8
 5 | {8,8,8,8}             |      8
 5 | {8,8,8,8}             |      8
 5 | {8,8,8,8}             |      8
(17 rows)

We can compare the element directly from select clause:

q_and_a=# select y, unnest(z), unnest(z) is null from x;
 y | unnest | ?column?
---+--------+----------
 1 |        | t
 1 |        | t
 1 |        | t
 2 |        | t
 2 |      7 | f
 2 |        | t
 3 |        | t
 3 |      3 | f
 3 |      4 | f
 4 |        | t
 4 |        | t
 4 |        | t
 4 |        | t
 5 |      8 | f
 5 |      8 | f
 5 |      8 | f
 5 |      8 | f
(17 rows)


Now, given that information on hand, we could proceed with this query:

with a as
(
    select y, unnest(z) as b
    from x
)
select 
 y, every(b is null)
from a 
group by y
order by y

Output:
 y | every
---+-------
 1 | t
 2 | f
 3 | f
 4 | t
 5 | f
(5 rows)


But the following is a lot better than that:

select
 y, true = ALL (select unnest(z) is null)
from x


Output:
 y | ?column?
---+----------
 1 | t
 2 | f
 3 | f
 4 | t
 5 | f
(5 rows)

If you want to make your query flexible(e.g. by way of concatenated query), you could do the following:

select
y, coalesce( true = ALL (select b is null from unnest(z) as a(b)), false )
from x

Then you can change the expression b is null to something else:

select
y, coalesce( true = ALL (select b = 8 from unnest(z) as a(b)), false )
from x