BCPでダンプ

プログラムでいろいろ試す前にまずは正統派ということで皆さん使う機会も多いであろうbcpユーティリティでCSVダンプを試みてみます。

C:>bcp geodb.dbo.tbl1 out "c:\wk\tbl1.out" -T -c -t, -r\n

Starting copy...

5 rows copied.
Network packet size (bytes): 4096
Clock Time (ms.) Total     : 10     Average : (500.00 rows per sec.)

C:>type c:\wk\tbl1.out
100,Harry Ord,E6100000010C00000000008041400000000000E06040,E6100000010C00000000008041400000000000E06040
101,Kihel Heim,CD100000010C00000000008041400000000000E06040,CD100000010C00000000008041400000000000E06040
--- 以下略 ---

座標値のあるべきところに16進数の羅列が出てますが、これ、WKBなんでしょうか?
試しにSQLでいくつか抽出して確認すると、

select tbl1.name, geom.STAsBinary()'WKB' from tbl1 where geom.STNumPoints() <= 1;

結果は、

name                 WKB
-------------------- ----------------------------------------------------
Harry Ord            0x010100000000000000008041400000000000E06040
Kihel Heim           0x010100000000000000008041400000000000E06040

VPCMCE(sa): (2 row(s) affected)

よく似てるけどbcpでダンプしたほうがWKBより1バイト長くて、それぞれ先頭数バイトに違いがあります。
Books Onlineには「WKBにはZ値とM値は入らない」と書いていますが、SRIDのみ異なるハリーとキエルがWKB表現だとまったく同じであることから、WKBにはSRIDも入らないことがわかります。
一方bcpダンプの先頭付近の0xE610や0xCD10はハリーとキエルで違いがあるため、これがSRIDを表しているワードらしいことがわかります。0xE610をリトルエンディアン読みすると0x10E6 = 4326 なので、めでたくSRIDと一致します。
で、SRIDの次の部分、WKBでは0x01000000の部分が、bcpダンプだと0x0000010Cになっていますが、ここはおそらくデータタイプの格納領域です。よくわかりませんがPOINTの場合は 0x0000010Cを入れとけばいいようです。見てのとおりgeometryとgeographyで違いはありません*1
残りの部分は、IEEE754表現の64ビット実数緯度および経度なのでWKBと互換のようです。POINT以外のタイプもだいたい同じルールと考えてよいでしょう*2

というわけで、これだけわかればとりあえず自作のスクリプトなどで作ったジオメトリをbcpに食わすことができます*3

*1:つまりgeometryで作ったデータをbcpでダンプしてgeographyの列にロードすると無理やり型変換できるということ

*2:てきとうに言ってるので何でも信じないように

*3:おなかこわしても私は責任もちません