Log

いろいろ

} 2023 |^|%| || 03$||18

先日、ブログ移行時に下書き状態にしていた記事を復元しました。その中の一つ。

PostgreSQLのdate型に挿入できるフォーマット - Log

2020/02//03がエラーにならなかった。試しに2020/02/////////////////03とかやってもいけた。気になる。

なんとこれが記事の全文です。Twitterでやれ。

さて、この結果だけを見ると区切り文字はなんでもいいのかと思えます。ちょっと試してみる。

  • 2023$03$18: OK
  • 2023||||||||||03|18: OK
  • 2023a03a18: NG
  • 2023🥺03🥺18: NG

それらしき文字で区切られていればいいみたいですね。

それらしき文字?ふわふわなのでソースを取得して真相を確かめます。*1

wget https://ftp.postgresql.org/pub/source/v15.2/postgresql-15.2.tar.gz

gitリポジトリを含めると時間がかかるためソースのみ取得します。Chromiumをビルドをしたときから進歩しました。その際に、私のPCではデカいプロジェクトのビルドに耐えられないことに気付いたので今回はビルドしません。手元でコード見るだけ。不要なビルドを減らしてSDGs

Chromiumのビルドに21時間かかった

src/backend/utils/adt/datetime.cのParseDateTimeあたりがそれっぽい。

/* ParseDateTime()
 * Break string into tokens based on a date/time context.
 * Returns 0 if successful, DTERR code if bogus input detected.

これは解説記事ではないので処理が気になれば自分で読んでください。

https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/adt/datetime.c;h=be2e55bb29fa21e8081d022300487564f8b5124a;hb=HEAD#l756

処理を読み進めていきます。

/* Ignore spaces between fields */
if (isspace((unsigned char) *cp))
{
    cp++;
    continue;
}
/* date field? allow embedded text month */
else if (*cp == '-' || *cp == '/' || *cp == '.')
{
    /* save delimiting character to use later */
    char       delim = *cp;
/* ignore other punctuation but use as delimiter */
else if (ispunct((unsigned char) *cp))
{
    cp++;
    continue;
}

ispunct()〜〜。彼が区切り文字の番人のようでした。*2

ispunct | Programming Place Plus C言語編 標準ライブラリのリファレンス

実はPostgreSQL正規表現puntという文字クラスを利用できます。

9.7. パターンマッチ

SELECT '$' ~ '[[:punct:]]';
-- TRUE

SELECT 'a' ~ '[[:punct:]]';
-- FALSE

SELECT '🥺' ~ '[[:punct:]]';
-- FALSE

いつでもSQLpunctな文字を確認できますね。

ParseDateTime()の処理に話を戻します。

punct以外にも空白はスキップすること、- / .などの真っ当なdate型の区切り文字は特別であることも分かります。後者はこんな簡単な話ではありませんが、要は$などとは処理が異なってややこしいということです。これらを除けばpunctである文字はスキップしているだけなので、異なる文字でも問題ないことが分かります。

  • 2023|||||||03$18: OK
  • } 2023 |^|%| || 03$||18: OK

3年前より理解は進んでいたのでここらで引き上げます。C言語を読めるとQOL爆増するだろうなと思いました。SQL生活のビタミンC。

*1:ふわふわ、ソース、あまりにもオムライス!

*2:どのリファレンスが妥当なのか分からなかったのでテキトーにググったものを載せます。