1

Hypersonic DB (HSQLDB) で次のクエリを実行しています。

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

"WHEN" 句の数が約 1000 を超えるとStackOverflowError、JDBC ドライバーによって Java がスローされますorg.hsqldb.jdbc.Util.sqlException()

ここに本当に奇妙な部分があります。CASEたとえば、100 個の WHEN 句の後にELSE ( CASE foo WHEN ... ) END. しかし、この書き直しでも、まったく同じ動作が得られます!

HSQLDBマニュアルには、1000の制限やその他の制限への言及はありません。ヘルプ!

4

3 に答える 3

2

CASEステートメントで 1000 語近くになることは決してありません。そのずっと前に、他の値を別のテーブルに入れ、結合してそれらを選択する必要があります。

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 は StackOverflowError について次のように述べています。

アプリケーションの再帰が深すぎるためにスタック オーバーフローが発生した場合にスローされます。

CASEしたがって、HSQLDB が式を解析するとき、各WHEN用語がランタイム スタックに別のレイヤーを追加すると推測します (実際には、おそらく 1 つにつきいくつかのレイヤーWHEN)。

ネストされた括弧が 1,000 レベルある算術式がある場合、おそらく同様の StackOverflowError が発生するでしょう。

1,000 の制限は、Java VM の実装、Java のバージョン、実行しているプラ​​ットフォーム、使用可能なメモリの量などによって、おそらく可変です。プラットフォーム固有の制限であり、HSQLDB に組み込まれているものではありません。

于 2009-01-12T22:27:23.267 に答える
1

CASE ステートメントを完全に削除します。

これらの 1000 個の値を使用してテーブルを作成し、そのテーブルに内部結合を実行します。

于 2009-01-12T22:28:01.287 に答える
1

ビルが言ったように、明らかな HSQL パーサーの設計を考えると、制限を取り除くことは不可能です。

制限を緩和する (つまり、制限を 1000 を超えるところまで押し上げるだけで 1000 のスイッチに到達できるようにする) という点では、2 つの選択肢があります。

  1. アプリの実行時に VM のスタック サイズを増やします。Sun の Hotspot VM を使用している場合は、たとえば -XX:ThreadStackSize=1024 を渡して、デフォルトの 512K ではなく、スレッドごとに 1MB のスタックを使用できるはずです。これにより、再帰の深さが深まる可能性があります。
  2. コンストラクター Thread(ThreadGroup, Runnable, String, long) によって作成された Thread で作業を実行できます。最後のパラメーターは要求されたスタック サイズです。これは機能する場合と機能しない場合があります。Javadoc を読んだ場合、それは提案です。VM は、この要求を無視することを歓迎します。ホットスポットが具体的に何をするのかはわかりませんが、役立つかもしれません。
于 2009-01-12T23:26:19.653 に答える