【解決済み】PostgreSQLのPOSIX正規表現におけるバグ報告【'AC' ~ '^(A)(?:B)|(?:C)$'とsubstring('AC' from '^(A)(?:B)|(?:C)$') IS NOT NULLが一致しない】

勘違いでした。ごめんなさい。
(当時の内容は誤解を招く恐れがあるので非表示にしていますが、コメントアウトしているだけなのでソースなどでご覧いただけます。)

<!--

# 0.要点

- `str ~ pattern`が真にもかかわらず、`substring(str from pattern)`が`<NULL>`を返すことがある
- 本来は`substring(str from pattern) is not null`が`str ~ pattern`と同値でないといけない

# 1.問題の確認された環境
Windows10に入れたpostgresql

```
# select version();
                          version
------------------------------------------------------------
 PostgreSQL 11.7, compiled by Visual C++ build 1914, 64-bit
```
# 2.問題を引き起こすコードの例

```:sql
DO
$do$
    declare 
        pattern text := '^(A)(?:B)|(?:C)$';
        str text := 'AC';
        sub_str text;
        matched bool;
    begin
        matched := str ~ pattern;
        sub_str := substring(str from pattern);
        raise notice '%,%', matched, sub_str;
    end;
$do$;
```
結果: 上記コードを実行すると、次が表示される。

```
NOTICE:  t,<NULL>
DO
```

# 3.解説

`NOTICE:  t,<NULL>`について、
`t`は`str ~ pattern`が真であることを示しています。
`<NULL>`は`substring(str from pattern)`がnullを返却したことを示しています。
`str`と`pattern`は共にtext型変数です。

[PostgreSQLバージョン11のドキュメント和訳版](https://www.postgresql.jp/document/11/html/functions-matching.html)の9.3.7節によれば、`str ~ pattern`は、`str`がPOSIX正規表現(大文字と小文字を区別する)で`pattern`にマッチするときに真となります。

以下、同節の一部を引用します。

>表9.14 正規表現マッチ演算子
>
演算子|説明|例
:--|:--|:--
~|正規表現にマッチ、大文字小文字の区別あり|'thomas' ~ '.*thomas.*'
~*|正規表現にマッチ、大文字小文字の区別なし|'thomas' ~* '.*Thomas.*'
!~|正規表現にマッチしない、大文字小文字の区別あり|'thomas' !~ '.*Thomas.*'
!~*|正規表現にマッチしない、大文字小文字の区別なし|'thomas' !~* '.*vadim.*'

(中略)

>
例：
>
```
'abc' ~ 'abc'    true
'abc' ~ '^a'     true
'abc' ~ '(b|d)'  true
'abc' ~ '^(b|c)' false
```

一方、`substring(str from pattern)`はstrがPOSIX正規表現で`pattern`にマッチしないときに`NULL`を返すものです。
マッチした場合、その部分を文字列として返却します。

同じく9.3.7節で、`substring`に対して次のように説明されています。

>2つのパラメータを持つsubstring関数、substring(string from pattern)を使用して、POSIX正規表現パターンにマッチする部分文字列を取り出すことができます。 この関数は、マッチするものがない場合にはNULLを返し、ある場合はパターンにマッチしたテキストの一部を返します。 しかし、丸括弧を持つパターンの場合、最初の丸括弧内部分正規表現（左丸括弧が最初に来るもの）にマッチするテキストの一部が返されます。 この例外を起こさずにパターン中に丸括弧を使用したいのであれば、常に正規表現全体を丸括弧で囲むことができます。 パターン内の抽出対象の部分文字列より前に丸括弧が必要な場合、後述の捕捉されない丸括弧を参照してください。

「後述の捕捉されない丸括弧」については、表9.15内での説明のみ確認されました。

>
表9.15 正規表現のアトム
>
アトム|説明
:--|:--
(re)|（ここでre は任意の正規表現で、）reとのマッチに適合するもです。 マッチは可能である報告用と意味づけられます。
(?:re)|上と同じ。ただし、マッチは報告用と意味づけられません。（「捕捉されない」括弧の集合）（AREのみ）

(以下略)



以上のことより、本来は`str ~ pattern`と`substring(str from pattern)`がnullでないことは同値であるはずです。
それにもかかわらず、今回は`str ~ pattern`が真であるにもかかわらず、`substring(str from pattern)`がnullとなりました。


# 4. 原因の考察(未完成)
この問題はおそらく、字句解析の実装が`~`演算子と`substring`関数で異なっていて、そのことに起因するものと考えられます。
第1章に示したコードで、`pattern`や`str`を変え、`str ~ pattern` および `substring(str from pattern) is not null`の真偽値を調べたものを、表4-1に示します。

表4-1. 
「`str`と`pattern`の関係」

`str`|`str ~ '^(A)(?:B)｜(?:C)$'`|`substring(str from '^(A)(?:B)｜(?:C)$' is not null)`|`str ~ '^(A)(?:(?:B)｜(?:C))$'`|`substring(str from '^(A)(?:(?:B)｜(?:C))$' is not null)`|`str ~ '^(?:(A)(?:B))｜(?:C)$'`|`substring(str from '^(?:(A)(?:B))｜(?:C)$' is not null)`
:--|:--|:--|:--|:--|:--|:--
 AC  | t       | f           | t       | t           | t       | f
 C   | t       | f           | f       | f           | t       | f
 AB  | t       | t           | t       | t           | t       | t


-->