これはPGroonga 2.X and 3.X用のドキュメントです。古いPGroongaを使っているならPGroonga 1.xのドキュメントを見てください。

pgroonga_query_escape関数

1.1.9で追加。

概要

pgroonga_query_escape関数はクエリー構文で特別な意味を持つ文字をエスケープします。&@~演算子&@~|演算子などがクエリー構文を使っています。

pgroonga_query_escape関数はpgroonga_command関数経由でGroongaコマンドインジェクションが発生することを防ぐときに有用です。Groongaコマンドインジェクションを防ぐことについてはpgroonga_command_escape_value関数pgroonga_escape関数も参照してください。

構文

この関数の構文は次の通りです。

text pgroonga_query_escape(query)

queryクエリー構文を使っているtext型の値です。

pgroonga_query_escapetext型の値を返します。この値の中の特別な意味を持つ文字はすべてエスケープされています。

使い方

サンプルスキーマとデータは次の通りです。

CREATE TABLE memos (
  content text
);

CREATE INDEX pgroonga_memos_index
          ON memos
       USING pgroonga (content);

INSERT INTO memos VALUES ('PGroonga (PostgreSQL+Groonga) is great!');

クエリーが「(PostgreSQL」の場合はエラーが発生します。なぜなら対応する閉じカッコがないからです。

SELECT * FROM memos WHERE content @@ '(PostgreSQL';
-- ERROR:  pgroonga: failed to parse expression: Syntax error: <(PostgreSQL||>

pgroonga_query_escape関数を使うことで「(PostgreSQL」というクエリーそのもの(「(」を特別な文字として扱わない)で検索できます。

SELECT * FROM memos WHERE content @@ pgroonga_query_escape('(PostgreSQL');
--                  content                 
-- -----------------------------------------
--  PGroonga (PostgreSQL+Groonga) is great!
-- (1 row)

pgroonga_command関数でも同じことが発生します。

SELECT jsonb_pretty(
  pgroonga_command('select ' ||
                   '--table ' || pgroonga_table_name('pgroonga_memos_index') || ' ' ||
                   '--match_columns content ' ||
                   '--query "(PostgreSQL"')::jsonb
);
--                jsonb_pretty               
-- ------------------------------------------
--  [                                       +
--      [                                   +
--          -63,                            +
--          1480432652.751489,              +
--          0.0007565021514892578,          +
--          "Syntax error: <(PostgreSQL||>" +
--      ]                                   +
--  ]
-- (1 row)

pgroonga_query_escape関数をpgroonga_command_escape_value関数と一緒に使うとこのケースを防ぐことができます。

SELECT jsonb_pretty(
  pgroonga_command('select ' ||
                   '--table ' || pgroonga_table_name('pgroonga_memos_index') || ' ' ||
                   '--match_columns content ' ||
                   '--query ' || pgroonga_command_escape_value(pgroonga_query_escape('(PostgreSQL')))::jsonb
);
--                         jsonb_pretty                        
-- ------------------------------------------------------------
--  [                                                         +
--      [                                                     +
--          0,                                                +
--          1480432832.061276,                                +
--          0.0252687931060791                                +
--      ],                                                    +
--      [                                                     +
--          [                                                 +
--              [                                             +
--                  1                                         +
--              ],                                            +
--              [                                             +
--                  [                                         +
--                      "_id",                                +
--                      "UInt32"                              +
--                  ],                                        +
--                  [                                         +
--                      "content",                            +
--                      "LongText"                            +
--                  ],                                        +
--                  [                                         +
--                      "ctid",                               +
--                      "UInt64"                              +
--                  ]                                         +
--              ],                                            +
--              [                                             +
--                  1,                                        +
--                  "PGroonga (PostgreSQL+Groonga) is great!",+
--                  1                                         +
--              ]                                             +
--          ]                                                 +
--      ]                                                     +
--  ]
-- (1 row)

コマンドの引数を配列で指定するスタイルでpgroonga_command関数使ってもこのケースを防ぐことができます。

SELECT jsonb_pretty(
  pgroonga_command('select',
                   ARRAY[
                     'table', pgroonga_table_name('pgroonga_memos_index'),
                     'match_columns', 'content',
                     'query', pgroonga_query_escape('(PostgreSQL')
                   ])::jsonb
);
--                         jsonb_pretty                        
-- ------------------------------------------------------------
--  [                                                         +
--      [                                                     +
--          0,                                                +
--          1480433038.482539,                                +
--          0.0001201629638671875                             +
--      ],                                                    +
--      [                                                     +
--          [                                                 +
--              [                                             +
--                  1                                         +
--              ],                                            +
--              [                                             +
--                  [                                         +
--                      "_id",                                +
--                      "UInt32"                              +
--                  ],                                        +
--                  [                                         +
--                      "content",                            +
--                      "LongText"                            +
--                  ],                                        +
--                  [                                         +
--                      "ctid",                               +
--                      "UInt64"                              +
--                  ]                                         +
--              ],                                            +
--              [                                             +
--                  1,                                        +
--                  "PGroonga (PostgreSQL+Groonga) is great!",+
--                  1                                         +
--              ]                                             +
--          ]                                                 +
--      ]                                                     +
--  ]
-- (1 row)

参考