MySQLのSpatial型カラムにSRIDは必須ではなかった

 私自身が勘違いしたまま先日も発表してしまった事があるようなので、追確認を行いました。ことの発端は、id:dupont_kedama さんの
MySQL8.0でGIS機能を試す No.1 - Ingressのリンク可能判定 - untitled .engineer
を見て、「あれっ?DDLでSRID指定していないのに、通るの、これ?」と twitter で伺ったことから。

 先日の発表での私の勘違いは:

誤: 位置(度またはメートル)を格納するカラムには、必ず 使用したい SRID を指定する必要がある。そして、INSERTとかをする時にも、同じSRIDを指定しないとエラーになる

正: 位置(度またはメートル)を格納するカラムには、使用したい SRID を指定することができる。指定した場合は、INSERTとかをする時にも、同じSRIDを指定しないとエラーになる。指定しない場合は、あらゆるSRIDをそのカラムは受け入れることができる

改めて以下のスライドのページを見ると、必ずしも「誤」と取れる書き方はしていませんが、私が「誤」の内容で思い込んでいたので、そのように言葉では言ったかもしれません。訂正します。
https://www.slideshare.net/sakaik/mysql-gis-clubmysql-4/38


以下はおためしの記録。

1)SRIDを指定しない GEOMETRY 型に様々な値をつっこむ

mysql> CREATE TABLE g1 (id integer, g GEOMETRY);

mysql> INSERT INTO g1 VALUES (1, ST_GeomFromText('POINT(1 3)'));
mysql> INSERT INTO g1 VALUES (1, ST_GeomFromText('POINT(135 35)'));
mysql> INSERT INTO g1 VALUES (1, ST_GeomFromText('POINT(35 135)'));
mysql> INSERT INTO g1 VALUES (1, ST_GeomFromText('POINT(35 135)', 4326));

mysql> INSERT INTO g1 VALUES (1, ST_GeomFromText('POINT(135 35)', 4326));
ERROR 3617 (22S03): Latitude 135.000000 is out of range in function st_geomfromtext. It must be within [-90.000000, 90.000000].

 SRID無指定の値のセットも、SRID 4326 の値のセットも受け入れられます。
SRID=4326 のときに、緯度経度を逆に指定してしまった場合には、「北緯135度なんてないよ」という(意訳)エラーがでます(正常動作)。

mysql> SELECT id, ST_AsText(g), HEX(g), ST_SRID(g) FROM g1;
+------+---------------+----------------------------------------------------+------------+
| id   | ST_AsText(g)  | HEX(g)                                             | ST_SRID(g) |
+------+---------------+----------------------------------------------------+------------+
|    1 | POINT(1 3)    | 000000000101000000000000000000F03F0000000000000840 |          0 |
|    1 | POINT(135 35) | 0000000001010000000000000000E060400000000000804140 |          0 |
|    1 | POINT(35 135) | 00000000010100000000000000008041400000000000E06040 |          0 |
|    1 | POINT(35 135) | E610000001010000000000000000E060400000000000804140 |       4326 |
+------+---------------+----------------------------------------------------+------------+

 登録された結果は、以上のとおり。ST_SRID() により、同じ (35 135)でも、SRIDが異なることが判断できます。


2)SRIDを指定しないPOINT型で試す
 GEOMETRY型は許容力が大きいのだ、POINT型ならSRIDが一致しないとエラーになるはずだ、と仮説を立ててPOINT型で同じ事を試してみた。結果は、GEOMETRY型と同じく問題なく格納される。

CREATE TABLE g2 (id integer, g POINT);
INSERT INTO g2 VALUES (1, ST_GeomFromText('POINT(1 3)'));
INSERT INTO g2 VALUES (1, ST_GeomFromText('POINT(135 35)'));
INSERT INTO g2 VALUES (1, ST_GeomFromText('POINT(35 135)'));
INSERT INTO g2 VALUES (1, ST_GeomFromText('POINT(35 135)', 4326));

mysql> INSERT INTO g2 VALUES (1, ST_GeomFromText('POINT(35 135)', 4326));

 結果:

mysql> select id, ST_AsText(g),HEX(g), ST_SRID(g) FROM g2;
+------+---------------+----------------------------------------------------+------------+
| id   | ST_AsText(g)  | HEX(g)                                             | ST_SRID(g) |
+------+---------------+----------------------------------------------------+------------+
|    1 | POINT(1 3)    | 000000000101000000000000000000F03F0000000000000840 |          0 |
|    1 | POINT(135 35) | 0000000001010000000000000000E060400000000000804140 |          0 |
|    1 | POINT(35 135) | 00000000010100000000000000008041400000000000E06040 |          0 |
|    1 | POINT(35 135) | E610000001010000000000000000E060400000000000804140 |       4326 |
+------+---------------+----------------------------------------------------+------------+

3)カラムにSRIDを明示したときだけ制約されるのか?と気づき試し

CREATE TABLE g3 (id integer, g POINT SRID 6668);

mysql> INSERT INTO g3 VALUES (1, ST_GeomFromText('POINT(1 3)'));
ERROR 3643 (HY000): The SRID of the geometry does not match the SRID of the column 'g'. The SRID of the geometry is 0, but the SRID of the column is 6668. Consider changing the SRID of the geometry or the SRID property of the column.

mysql> INSERT INTO g3 VALUES (1, ST_GeomFromText('POINT(135 35)'));
ERROR 3643 (HY000): The SRID of the geometry does not match the SRID of the column 'g'. The SRID of the geometry is 0, but the SRID of the column is 6668. Consider changing the SRID of the geometry or the SRID property of the column.

mysql> INSERT INTO g3 VALUES (1, ST_GeomFromText('POINT(35 135)'));
ERROR 3643 (HY000): The SRID of the geometry does not match the SRID of the column 'g'. The SRID of the geometry is 0, but the SRID of the column is 6668. Consider changing the SRID of the geometry or the SRID property of the column.

mysql> INSERT INTO g3 VALUES (1, ST_GeomFromText('POINT(35 135)', 4326));
ERROR 3643 (HY000): The SRID of the geometry does not match the SRID of the column 'g'. The SRID of the geometry is 4326, but the SRID of the column is 6668. Consider changing the SRID of the geometry or the SRID property of the column.

mysql> INSERT INTO g3 VALUES (1, ST_GeomFromText('POINT(35 135)', 6668));

 DDLで SRID=6668 を明示しているので、INSERT時の ST_GeomFromText の第2引数でSRIDを指定しない時(=SRID が ゼロと見なされる)は、SRIDが一致しないとのエラーとなる。一番最後の カラムと一致するSRID(6668)を指定したときのみ、正常に受け入れられることがわかる。
  
結果:

mysql> select id, ST_AsText(g),HEX(g), ST_SRID(g) FROM g3;                                                                       
+------+---------------+----------------------------------------------------+------------+
| id   | ST_AsText(g)  | HEX(g)                                             | ST_SRID(g) |
+------+---------------+----------------------------------------------------+------------+
|    1 | POINT(35 135) | 0C1A000001010000000000000000E060400000000000804140 |       6668 |
+------+---------------+----------------------------------------------------+------------+


ということで、私の勘違いは以下のように言い換えることもできるかも。

誤: CREATE TABLE で spatial型のカラムに対して SRID を指定しない場合は、SRID=0 が指定されたものとして動作する

正: CREATE TABLE で spatial型のカラムに対して SRID を指定しない場合は、INSERT文で都度都度与えられたSRIDを受け入れて動作する

 そもそも、MySQLの内部バイナリ(≠ WKB)は、WKBにSRIDを付加したものなので、色々なSRIDをそのまま受け入れることができるように作られているんですよね。
 なお、CREATE TABLE では「SRIDを指定しないときはゼロとされる」が誤り(勘違い)でしたが、ST_GeomFromText() 等では、「SRIDを指定しないときはゼロと見做される」で正しいので、お間違いなく。


 またひとつかしこくなった! kedama さんありがとうございます!




#なお、せっかく id 列を用意しているのに全部 1 なのはご愛敬(まちがえた。。)