Amazon Web Services ブログ

改元はどのように RDS で実行されている MySQL 互換エンジンに影響を与えるか

RDSもしあなたのソフトウェアやシステムが日本のお客様をサポートしており、さらにそのソフトウェアやシステムが元号を表示する必要がある場合、新しい元号を表示するように改修の必要があるかもしれません。新しい元号は、現在の天皇陛下が退位される 2019 年 5 月 1 日から有効になります。

このブログ記事では、かかる元号の変更(改元)にかかわる背景について説明し、その後、どのように改元の影響を調べるかを、私が RDS で実行される MySQL 互換のデータベースエンジンについて調査した際の方法を元に、詳しく解説します。またその調査の結果、RDS で実行される MySQL 互換のデータベースエンジンは改元の影響を受けない、という結果を得たことを報告します。

改元について

元号は、日本で、主に政府のシステムや公的な文書などを中心に、未だ広く使われています。そのようなシステムをサポートするために、いくつかのソフトウェアでは元号をサポートするための機能が実装されています。例えば、Windows では元号をレジストリに格納していたり、Oracle データベースは元号を表示するためのカレンダー・ファイルを持っていたり、glibc ライブラリの strftime()関数は元号を表示するための機能があり、日本語のロケール・ファイルには元号の情報が含まれていたりします。

来る 2019 年 4 月 30 日に、現在の天皇陛下が退位され、それにともない 2019 年 5 月 1 日から元号が変更されます(改元)。そのため、元号をサポートするソフトウェアは、新しい元号を表示できるように更新する必要があります。

新しい元号は2019 年 4 月 1 日に発表される予定となっており、ソフトウェアのアップデートを準備する時間は 1 ヶ月未満の短い期間しかありません。

条件の理解

基本的に、Linux ビルトインのソフトウェアのうち、元号の表示に対応しているものは glibc() ライブラリの strftime() 関数のみです。

strftime()は日付や時刻の表示フォーマットを変更するための関数で、元号を使用して日付を変更する機能を持ちます。日本語 (ja_JP) ロケールを使用しているシステムでフォーマット指定子 (format specification) として %EY 変換指定子を指定すると、コンソールに元号が出力されます。元号のリストは glibc パッケージによって主に/usr/share/i18n/locales/ja_JP に配置されるロケール・ファイルに格納されています。

例えば、dateコマンドは日付や時刻の表示フォーマットの変更のために strftime() を使用しています。そのため、%EY 変換指定子を日本語ロケールにおいて指定すると、元号を表示します。下記はその例です (元号はなぜか EUC-JPで格納されているため、UTF-8 に変換するために nkf コマンドにパイプしています):

$ LANG=ja_JP date +%EY -d 2019-01-01|nkf
平成31年

したがって、ソフトウェアが改元の影響を受け、改元に際してアップデートを必要とする条件は、

  • glibc ライブラリの strftime()関数を使用しており %EY 変換指定子をサポートしている
  • ja_JP ロケールをサポートしている
  • 元号を表示するための独自機能を持っている

となります。

調査1: glibc ライブラリの strftime()関数を使用しており %EY 変換指定子をサポートしている

strftime() 関数を使用しているかどうかは、ソースコードを grep することで簡単に確認することができます。例えば、以下のように、GitHub から MySQL 5.6.43 のソースコードをローカルマシンにクローンし、strftime() 関数の使用状況を確認することができます。

[~/work/]$ git clone https://github.com/mysql/mysql-server.git -b mysql-5.6.43 mysql-server-5.6.43
[~/work/]$ cd mysql-server-5.6.43
[~/work/mysql-server-5.6.43]$ grep -r strftime *
cmake/info_macros.cmake.in: "use warnings; use POSIX qw(strftime); "
cmake/info_macros.cmake.in: "print strftime \"%F %T %z\", localtime;")
libevent/http.c: if (strftime(date, sizeof(date),
scripts/mysqld_multi.sh:use POSIX qw(strftime getcwd);
scripts/mysqld_multi.sh: print strftime "%a %b %e %H:%M:%S %Y", localtime;
scripts/mysqld_multi.sh: print LOGFILE strftime "%a %b %e %H:%M:%S %Y", localtime if ($date_flag);
storage/ndb/test/crund/tws/tws_cpp/Driver.cpp: const int nchars = strftime(dest, size, format, localtime(&now));
storage/ndb/test/crund/src/crundndb/Driver.cpp: const int nchars = strftime(dest, size, format, localtime(&now));
storage/ndb/test/src/getarg.c: strftime(timestr, sizeof(timestr), "%B %e, %Y", localtime(&t));

出力の内容から strftime()はMySQL サーバ本体では使用されておらず、またその他の使用箇所もすべてハードコードされた %EY を含まないフォーマット指定子とともに使用されています。libevent/http.c での使用も、ハードコードされた %EY を含まないフォーマット指定子になります。

if (strftime(date, sizeof(date),
                          "%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) {
                          evhttp_add_header(headers, "Date", date);
                  }

以下では、私が調査した結果を共有します。

結論から言うと、RDS で実行されているすべての MySQL 互換エンジンで strftime() はお客様側で指定可能なフォーマット指定子やハードコードされた %EY を含むフォーマット指定子とは使用されていませんでした。
もし、各エンジンの詳細な結果について興味がなければ、次のセクション「調査 2: ja_JP ロケールをサポートしている」までお進みください。

MySQL 5.6

  • strftime() を使用しているサーバのコンポーネント
    • libevent (InnoDB memcache plugin で使用されている)
    • mysqld_multi … (RDS では使用されていない)
    • NDB テストスイート … (RDS では使用されていない)
  • libevent はstrftime() を使用していますが、ハードコードされた %EY を含まないフォーマット指定子のため、影響はありません。

MySQL 5.7

  • strftime() を使用しているサーバのコンポーネント
    • libevent (InnoDB memcache plugin で使用されている)
    • mysqld_multi … (RDS では使用されていない)
    • NDB 関連コンポーネント (テストスイート、MySQL Cluster Configurator) … (RDS では使用されていない)
  • libevent はstrftime() を使用していますが、ハードコードされた %EY を含まないフォーマット指定子のため、影響はありません。

MySQL 8.0

  • strftime() を使用しているサーバのコンポーネント
    • sql/log_event.cc
    • mysqld_multi … (RDS では使用されていない)
    • NDB 関連コンポーネント (テストスイート、MySQL Cluster Configurator) … (RDS では使用されていない)
    • MySQL Router (Duktape ライブラリ) … (RDS では使用されていない)
  • libevent はstrftime() を使用していますが、ハードコードされた %EY を含まないフォーマット指定子のため、影響はありません。
  • sql/log_event.ccstrftime() を使用していますが、ハードコードされた %EY を含まないフォーマット指定子のため、影響はありません。

MariaDB 10.0

  • strftime() を使用しているサーバのコンポーネント
    • mysqld_multi … (RDS では使用されていない)
    • RDS でサポートされていないストレージエンジン (Spider, Mroonga, CONNECT, NDB)

MariaDB 10.1 – 10.4

  • strftime() を使用しているサーバのコンポーネント
    • mysqld_multi … (RDS では使用されていない)
    • RDS でサポートされていないストレージエンジン (Spider, Mroonga, CONNECT, NDB)
  • RDS で使用されていないユーティリティ・ツール
    • innotop
    • innobackupex

Aurora MySQL 5.6/5.7

  • strftime() を使用しているサーバのコンポーネント
    • いくつかの内部向けロギング
    • Aurora 独自機能の実装に使用されているいくつかの外部ライブラリ
    • mysqld_multi … (RDS では使用されていない)
    • NDB 関連コンポーネント (テストスイート、MySQL Cluster Configurator) … (RDS では使用されていない)
  • strftime() を使用するすべてのコンポーネントは、ハードコードされた %EY を含まないフォーマット指定子を使用しているため、影響はありません。

調査 2: ja_JP ロケールをサポートしている

RDS では、システム・ロケールが en_US.UTF-8 に固定されています。しかし、日付・時刻型のロケールを変更することができる lc_time_names パラメータが、RDS MySQL および RDS MariaDBでは変更可能になっています。
Aurora MySQL 5.6 および 5.7 では、このパラメータは DB パラメータグループに含まれないため、変更ができません。

下記のように、AWS CLI を使用することで、エンジンが lc_time_names をサポートしているかを確認することができます。

$ aws rds describe-db-parameters --query 'Parameters[?ParameterName==`lc_time_names`].[ParameterName,AllowedValues,IsModifiable]' --db-parameter-group-name default.mysql5.6
[
    [
        "lc_time_names",
        "ar_AE,ar_BH,ar_DZ,ar_EG,ar_IN,ar_IQ,ar_JO,ar_KW,ar_LB,ar_LY,ar_MA,ar_OM,ar_QA,ar_SA,ar_SD,ar_SY,ar_TN,ar_YE,be_BY,bg_BG,ca_ES,cs_CZ,da_DK,de_AT,de_BE,de_CH,de_DE,de_LU,el_GR,en_AU,en_CA,en_GB,en_IN,en_NZ,en_PH,en_US,en_ZA,en_ZW,es_AR,es_BO,es_CL,es_CO,es_CR,es_DO,es_EC,es_ES,es_GT,es_HN,es_MX,es_NI,es_PA,es_PE,es_PR,es_PY,es_SV,es_US,es_UY,es_VE,et_EE,eu_ES,fi_FI,fo_FO,fr_BE,fr_CA,fr_CH,fr_FR,fr_LU,gl_ES,gu_IN,he_IL,hi_IN,hr_HR,hu_HU,id_ID,is_IS,it_CH,it_IT,ja_JP,ko_KR,lt_LT,lv_LV,mk_MK,mn_MN,ms_MY,nb_NO,nl_BE,nl_NL,no_NO,pl_PL,pt_BR,pt_PT,ro_RO,ru_RU,ru_UA,sk_SK,sl_SI,sq_AL,sr_RS,sv_FI,sv_SE,ta_IN,te_IN,th_TH,tr_TR,uk_UA,ur_PK,vi_VN,zh_CN,zh_HK,zh_TW",
        true
    ]
]

$ aws rds describe-db-parameters --query 'Parameters[?ParameterName==`lc_time_names`]'  --db-parameter-group-name default.aurora5.6
[]

$ aws rds describe-db-cluster-parameters --query 'Parameters[?ParameterName==`lc_time_names`]'  --db-cluster-parameter-group-name default.aurora5.6
[]

そのため、もし MySQL および MariaDB が日付のフォーマットを指定する機能において、元号をサポートしており、かつ lc_time_names の影響を受ける場合、改元の影響を受ける可能性があります。

調査 3: 元号を表示するための独自機能を持っている

MySQL における日付のフォーマットを変更する唯一の機能が DATE_FORMAT() 関数です。DATE_FORMAT() 関数は下記のように MySQL によって独自に実装されており、strftime() を使用していません。

MySQL 5.6.41: https://github.com/mysql/mysql-server/blob/mysql-5.6.41/sql/item_timefunc.cc#L521-L743
MySQL 5.7.22: https://github.com/mysql/mysql-server/blob/mysql-5.7.22/sql/item_timefunc.cc#L505-L734
MySQL 8.0.13: https://github.com/mysql/mysql-server/blob/mysql-8.0.13/sql/item_timefunc.cc#L501-L716
MariaDB 10.0: https://github.com/MariaDB/server/blob/10.0/sql/item_timefunc.cc#L451-L675
MariaDB 10.1: https://github.com/MariaDB/server/blob/10.1/sql/item_timefunc.cc#L454-L678
MariaDB 10.2: https://github.com/MariaDB/server/blob/10.2/sql/item_timefunc.cc#L454-L690
MariaDB 10.3: https://github.com/MariaDB/server/blob/10.3/sql/item_timefunc.cc#L455-L692
MariaDB 10.4: https://github.com/MariaDB/server/blob/10.4/sql/item_timefunc.cc#L476-L713
Aurora MySQL 5.6: Almost same as MySQL 5.6
Aurora MySQL 5.7: Almost same as MySQL 5.7

上記のソースコードより、すべてのエンジンバージョンにおいて、switch/case 文に含まれているサポートされている変換指定子のリストに %EY やその他の元号を表示し得る変換指定子は含まれていないことがわかります。

調査 2 の結果から、お客様は日付のロケールを ja_JPに変更できることがわかりましたが、DATE_FORMAT() 関数がそもそも元号を表示するための機能を持たないため、lc_time_names が変更可能であったとしても、改元の影響を受けることはありません。

まとめ

  • RDS で実行されている MySQL 互換エンジンは改元の影響を受けません。
    その理由として、
    strftime()がサーバのコンポーネントにおいて、お客様側で指定可能なフォーマット指定子やハードコードされた %EY を含むフォーマット指定子とともには使用されていない
  • DATE_FORMAT()strftime() を使用しておらず、また元号を表示する機能も持っていない

したがって、お客様は RDS で実行されているMySQL 互換エンジンにおいて、改元に備えて何かアクションを取る必要はまったくありません。


About the Author

Yoshihiko MatsuzakiはAmazon Web ServicesのRelational Database Services (RDS)チームのdatabase engineerです。