@@ -83,6 +83,7 @@ defmodule MyXQL.Protocol.Values do
83
83
defp column_def_to_type ( column_def ( type: :mysql_type_string ) ) , do: :binary
84
84
defp column_def_to_type ( column_def ( type: :mysql_type_bit , length: length ) ) , do: { :bit , length }
85
85
defp column_def_to_type ( column_def ( type: :mysql_type_null ) ) , do: :null
86
+ defp column_def_to_type ( column_def ( type: :mysql_type_geometry ) ) , do: :geometry
86
87
87
88
# Text values
88
89
@@ -308,7 +309,7 @@ defmodule MyXQL.Protocol.Values do
308
309
end
309
310
310
311
defp decode_binary_row ( << r :: bits >> , null_bitmap , [ :binary | t ] , acc ) ,
311
- do: decode_string_lenenc ( r , null_bitmap , t , acc )
312
+ do: decode_string_lenenc ( r , null_bitmap , t , acc , & & 1 )
312
313
313
314
defp decode_binary_row ( << r :: bits >> , null_bitmap , [ :int1 | t ] , acc ) ,
314
315
do: decode_int1 ( r , null_bitmap , t , acc )
@@ -361,10 +362,58 @@ defmodule MyXQL.Protocol.Values do
361
362
defp decode_binary_row ( << r :: bits >> , null_bitmap , [ { :bit , size } | t ] , acc ) ,
362
363
do: decode_bit ( r , size , null_bitmap , t , acc )
363
364
365
+ defp decode_binary_row ( << r :: bits >> , null_bitmap , [ :geometry | t ] , acc ) ,
366
+ do: decode_string_lenenc ( r , null_bitmap , t , acc , & decode_geometry / 1 )
367
+
364
368
defp decode_binary_row ( << >> , _null_bitmap , [ ] , acc ) do
365
369
Enum . reverse ( acc )
366
370
end
367
371
372
+ # this looks similar to WKB [1] but instead of:
373
+ #
374
+ # <<byte_order::8, type::32, ...>>
375
+ #
376
+ # we have:
377
+ #
378
+ # <<0::32, byte_order::8, type::32, ...>>
379
+ #
380
+ # so seems there's some extra padding in front. Maybe it's a 4-byte srid?
381
+ #
382
+ # byte_order is allegedly big endian (0x01) but we need to decode floats as little-endian. (lol.)
383
+ #
384
+ # Looking at [2]
385
+ #
386
+ # > Values should be stored in internal geometry format, but you can convert them to that
387
+ # > format from either Well-Known Text (WKT) or Well-Known Binary (WKB) format.
388
+ #
389
+ # so yeah, looks like mysql might be storing it in an internal format that is not WKB.
390
+ # There's a ST_ToBinary() function that allegedly returns data in WKB so this might be helpful
391
+ # for debugging.
392
+ #
393
+ # [1] https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry#Well-known_binary
394
+ # [2] https://dev.mysql.com/doc/refman/8.0/en/populating-spatial-columns.html
395
+ defp decode_geometry ( << 0 :: uint4 , 1 :: uint1 , type :: uint4 , r :: bits >> ) do
396
+ # ^ ^ big endian
397
+ # |
398
+ # some padding? maybe srid?
399
+ decode_geometry ( type , r )
400
+ end
401
+
402
+ defp decode_geometry ( 1 , << x :: 64 - signed - little - float , y :: 64 - signed - little - float >> ) ,
403
+ do: % MyXQL.Geometry.Point { x: x , y: y }
404
+
405
+ defp decode_geometry ( 4 , << size :: uint4 , r :: bits >> ) ,
406
+ do: decode_multipoint ( r , size , [ ] )
407
+
408
+ # <<1, 1, 0, 0, 0>> in front seems like some kind of header?
409
+ defp decode_multipoint ( << 1 , 1 , 0 , 0 , 0 , x :: 64 - signed - little - float , y :: 64 - signed - little - float , r :: bits >> , size , acc ) do
410
+ decode_multipoint ( r , size - 1 , [ { x , y } | acc ] )
411
+ end
412
+
413
+ defp decode_multipoint ( "" , 0 , acc ) do
414
+ % MyXQL.Geometry.Multipoint { points: Enum . reverse ( acc ) }
415
+ end
416
+
368
417
defp decode_int1 ( << v :: int1 , r :: bits >> , null_bitmap , t , acc ) ,
369
418
do: decode_binary_row ( r , null_bitmap >>> 1 , t , [ v | acc ] )
370
419
@@ -510,18 +559,36 @@ defmodule MyXQL.Protocol.Values do
510
559
}
511
560
end
512
561
513
- defp decode_string_lenenc ( << n :: uint1 , v :: string ( n ) , r :: bits >> , null_bitmap , t , acc )
562
+ defp decode_string_lenenc ( << n :: uint1 , v :: string ( n ) , r :: bits >> , null_bitmap , t , acc , decoder )
514
563
when n < 251 ,
515
- do: decode_binary_row ( r , null_bitmap >>> 1 , t , [ v | acc ] )
564
+ do: decode_binary_row ( r , null_bitmap >>> 1 , t , [ decoder . ( v ) | acc ] )
516
565
517
- defp decode_string_lenenc ( << 0xFC , n :: uint2 , v :: string ( n ) , r :: bits >> , null_bitmap , t , acc ) ,
518
- do: decode_binary_row ( r , null_bitmap >>> 1 , t , [ v | acc ] )
566
+ defp decode_string_lenenc (
567
+ << 0xFC , n :: uint2 , v :: string ( n ) , r :: bits >> ,
568
+ null_bitmap ,
569
+ t ,
570
+ acc ,
571
+ decoder
572
+ ) ,
573
+ do: decode_binary_row ( r , null_bitmap >>> 1 , t , [ decoder . ( v ) | acc ] )
519
574
520
- defp decode_string_lenenc ( << 0xFD , n :: uint3 , v :: string ( n ) , r :: bits >> , null_bitmap , t , acc ) ,
521
- do: decode_binary_row ( r , null_bitmap >>> 1 , t , [ v | acc ] )
575
+ defp decode_string_lenenc (
576
+ << 0xFD , n :: uint3 , v :: string ( n ) , r :: bits >> ,
577
+ null_bitmap ,
578
+ t ,
579
+ acc ,
580
+ decoder
581
+ ) ,
582
+ do: decode_binary_row ( r , null_bitmap >>> 1 , t , [ decoder . ( v ) | acc ] )
522
583
523
- defp decode_string_lenenc ( << 0xFE , n :: uint8 , v :: string ( n ) , r :: bits >> , null_bitmap , t , acc ) ,
524
- do: decode_binary_row ( r , null_bitmap >>> 1 , t , [ v | acc ] )
584
+ defp decode_string_lenenc (
585
+ << 0xFE , n :: uint8 , v :: string ( n ) , r :: bits >> ,
586
+ null_bitmap ,
587
+ t ,
588
+ acc ,
589
+ decoder
590
+ ) ,
591
+ do: decode_binary_row ( r , null_bitmap >>> 1 , t , [ decoder . ( v ) | acc ] )
525
592
526
593
defp decode_json ( << n :: uint1 , v :: string ( n ) , r :: bits >> , null_bitmap , t , acc ) when n < 251 ,
527
594
do: decode_binary_row ( r , null_bitmap >>> 1 , t , [ decode_json ( v ) | acc ] )
0 commit comments