Question

I'm running the following query in Hypersonic DB (HSQLDB):

SELECT (CASE foo WHEN 'a' THEN 'bar' WHEN 'b' THEN 'biz' ....
        ELSE 'fin' END ) FROM MyTable LIMIT 1

When the number of "WHEN" clauses exceeds about 1000, I get a Java StackOverflowError thrown by the JDBC driver in org.hsqldb.jdbc.Util.sqlException().

Here's the really weird part: I tried breaking up my CASE statement into pieces with e.g. 100 WHEN clauses followed by ELSE ( CASE foo WHEN ... ) END. But even with this rewrite I get exactly the same behavior!

I don't see any reference to a limit of 1000 or anything else in the HSQLDB manual. Help!

Was it helpful?

Solution

You should never get anywhere near 1000 terms in a CASE statement. Long before that, you should put the other values into a separate table and pick them by joining.

INSERT INTO MappingTable (foo, string) VALUES
  ('a', 'bar'), ('b', 'biz'), ...

SELECT COALESCE(m.string, 'fin')
FROM MyTable t LEFT OUTER JOIN MappingTable m USING (foo)
LIMIT 1;

Java API says about StackOverflowError:

Thrown when a stack overflow occurs because an application recurses too deeply.

So I would guess that when HSQLDB parses a CASE expression, each WHEN term adds another layer to the runtime stack (actually probably several layers per WHEN).

You'd probably get a similar StackOverflowError if you had an arithmetic expression with 1,000 levels of nested parentheses.

The limit of 1,000 is probably variable, depending on the implementation of the Java VM, the version of Java, the platform you're running on, the amount of memory available, etc. They may not document it in the HSQLDB documentation because it's a platform-specific limit, not something built into HSQLDB.

OTHER TIPS

Eliminate the CASE statement entirely.

Make a table using those 1000 values, then just do an inner join to that table.

As Bill said, it's impossible to remove the limit given the apparent HSQL parser design.

In terms of alleviating the limit (i.e. letting yourself get to 1000 switches by just pushing the limit up to... somewhere over 1000), you have two options.

  1. Increase the stack size in the VM when running your app. If you're using Sun's Hotspot VM, you should be able to pass e.g. -XX:ThreadStackSize=1024 to use a 1MB stack per thread, instead of the default 512K. That may let you get to a greater recursion depth.
  2. You can run your work in a Thread created by the constructor Thread(ThreadGroup, Runnable, String, long), where the last parameter is a requested stack size. This may or may not work; if you read the Javadoc, it's a suggestion -- VMs are more than welcome to ignore this request. Not sure what Hotspot does specifically, but it might help.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top