heterodb/pg-strom

caseの条件式でdivision by zeroを回避出来ない。

Closed this issue · 4 comments

CASE文でid % 71の結果が0になる場合を回避しているが、以下SQLでdivizion by zeroが発生する。

SELECT id, CASE id % 71
           WHEN 0 THEN -1.0
           ELSE 1 / (id % 71)
            END v3
  FROM regtest_data
 WHERE id > 0;

エラーメッセージ

ERROR:  xpu_basetype.cu:683  int4div: division by zero
HINT:  device at GPU-0, function at pgfn_int4div

全体クエリ

DROP TABLE IF EXISTS regtest_data;
CREATE TABLE regtest_data (
  id    int,
  a     numeric
);

SELECT pgstrom.random_setseed(20190701);
INSERT INTO regtest_data (
  SELECT x, pgstrom.random_float(20,-100.0,100.0)::numeric(9,3)
    FROM generate_series(1,6000) x
);

SET enable_seqscan = off;
SET pg_strom.enabled = on;

SELECT id, CASE id % 71
           WHEN 0 THEN -1.0
           ELSE 1 / (id % 71)::real
            END v3
  FROM regtest_data
 WHERE id > 0;

以下のSQLは期待通り動作しますので、CASE <計算式> WHEN <値> ~の構文を処理する箇所で起きている可能性が高そうです。

SELECT id, CASE WHEN id % 71 = 0 THEN -1.0
           ELSE 1 / (id % 71)
            END v3
  FROM regtest_data
 WHERE id > 0;

これ、CASE ... WHEN 文全体をGPUで処理するのではなく、その一部だけを別個に処理するという判断をしている(サポートされていない演算子か?)ので、1 / (id % 71)::realをGPU Kernelから返していますね。
あんまインテリジェンスを働かさずに、全体をGPU実行できない場合は大人しくCPU実行にした方がいいかなぁ…。

hoge=# explain SELECT id, CASE id % 71
           WHEN 0 THEN -1.0
           ELSE 1 / (id % 71)::real
            END v3
  FROM regtest_data
 WHERE id > 0;
                                               QUERY PLAN
---------------------------------------------------------------------------------------------------------
 Custom Scan (GpuScan) on regtest_data  (cost=100.00..267.92 rows=5999 width=12)
   GPU Projection: id, (id % 71), 0, '-1'::double precision, ('1'::double precision / ((id % 71))::real)
   GPU Scan Quals: (id > 0) [rows: 6000 -> 5999]
   GPU-Direct SQL: enabled (GPU-0)
(4 rows)

72a8faa0324407a7ea3d02bca01107acfe44a15b0d0c3e7c596fc7e2e8ac4bf7c2c4e00cd4338ebb にて修正しています。2つの問題がありました。

まず、CASE WHEN ... な構文の際に出てくる CaseTestExpr のハンドリングに誤りがあった事。
もう一つは、GPUでの実行に対応していない構文が与えられた時に、GPUで計算できる部分だけでも計算するようにしていた事で、親切な事に 1 / (id % 71)::real もGPUで計算してこれをホストに返そうとしていたようでした。

確認しました。ご対応ありがとうございました。