github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/spatial/wkb.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package spatial 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/dolthub/go-mysql-server/sql" 22 "github.com/dolthub/go-mysql-server/sql/expression" 23 "github.com/dolthub/go-mysql-server/sql/types" 24 ) 25 26 // AsWKB is a function that converts a spatial type into WKB format (alias for AsBinary) 27 type AsWKB struct { 28 expression.UnaryExpression 29 } 30 31 var _ sql.FunctionExpression = (*AsWKB)(nil) 32 var _ sql.CollationCoercible = (*AsWKB)(nil) 33 34 // NewAsWKB creates a new point expression. 35 func NewAsWKB(e sql.Expression) sql.Expression { 36 return &AsWKB{expression.UnaryExpression{Child: e}} 37 } 38 39 // FunctionName implements sql.FunctionExpression 40 func (a *AsWKB) FunctionName() string { 41 return "st_aswkb" 42 } 43 44 // Description implements sql.FunctionExpression 45 func (a *AsWKB) Description() string { 46 return "returns binary representation of given spatial type." 47 } 48 49 // IsNullable implements the sql.Expression interface. 50 func (a *AsWKB) IsNullable() bool { 51 return a.Child.IsNullable() 52 } 53 54 // Type implements the sql.Expression interface. 55 func (a *AsWKB) Type() sql.Type { 56 return types.LongBlob 57 } 58 59 // CollationCoercibility implements the interface sql.CollationCoercible. 60 func (*AsWKB) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 61 return sql.Collation_binary, 4 62 } 63 64 func (a *AsWKB) String() string { 65 return fmt.Sprintf("%s(%s)", a.FunctionName(), a.Child.String()) 66 } 67 68 // WithChildren implements the Expression interface. 69 func (a *AsWKB) WithChildren(children ...sql.Expression) (sql.Expression, error) { 70 if len(children) != 1 { 71 return nil, sql.ErrInvalidChildrenNumber.New(a, len(children), 1) 72 } 73 return NewAsWKB(children[0]), nil 74 } 75 76 // Eval implements the sql.Expression interface. 77 func (a *AsWKB) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 78 val, err := a.Child.Eval(ctx, row) 79 if err != nil { 80 return nil, err 81 } 82 83 if val == nil { 84 return nil, nil 85 } 86 87 switch v := val.(type) { 88 case types.GeometryValue: 89 if v.GetSRID() == types.GeoSpatialSRID { 90 v = v.Swap() 91 } 92 return v.Serialize()[types.SRIDSize:], nil 93 default: 94 return nil, sql.ErrInvalidGISData.New(a.FunctionName()) 95 } 96 } 97 98 // GeomFromWKB is a function that returns a geometry type from a WKB byte array 99 type GeomFromWKB struct { 100 expression.NaryExpression 101 } 102 103 var _ sql.FunctionExpression = (*GeomFromWKB)(nil) 104 var _ sql.CollationCoercible = (*GeomFromWKB)(nil) 105 106 // NewGeomFromWKB creates a new geometry expression. 107 func NewGeomFromWKB(args ...sql.Expression) (sql.Expression, error) { 108 if len(args) < 1 || len(args) > 3 { 109 return nil, sql.ErrInvalidArgumentNumber.New("ST_GEOMFROMWKB", "1, 2, or 3", len(args)) 110 } 111 return &GeomFromWKB{expression.NaryExpression{ChildExpressions: args}}, nil 112 } 113 114 // FunctionName implements sql.FunctionExpression 115 func (g *GeomFromWKB) FunctionName() string { 116 return "st_geomfromwkb" 117 } 118 119 // Description implements sql.FunctionExpression 120 func (g *GeomFromWKB) Description() string { 121 return "returns a new geometry from a WKB string." 122 } 123 124 // Type implements the sql.Expression interface. 125 func (g *GeomFromWKB) Type() sql.Type { 126 return types.PointType{} // TODO: replace with generic geometry type 127 } 128 129 // CollationCoercibility implements the interface sql.CollationCoercible. 130 func (*GeomFromWKB) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 131 return sql.Collation_binary, 4 132 } 133 134 func (g *GeomFromWKB) String() string { 135 var args = make([]string, len(g.ChildExpressions)) 136 for i, arg := range g.ChildExpressions { 137 args[i] = arg.String() 138 } 139 return fmt.Sprintf("%s(%s)", g.FunctionName(), strings.Join(args, ",")) 140 } 141 142 // WithChildren implements the Expression interface. 143 func (g *GeomFromWKB) WithChildren(children ...sql.Expression) (sql.Expression, error) { 144 return NewGeomFromWKB(children...) 145 } 146 147 // ParseAxisOrder takes in a key, value string and determines the order of the xy coords 148 func ParseAxisOrder(s string) (bool, error) { 149 s = strings.ToLower(s) 150 s = strings.TrimSpace(s) 151 switch s { 152 case "axis-order=long-lat": 153 return true, nil 154 case "axis-order=lat-long", "axis-order=srid-defined": 155 return false, nil 156 default: 157 return false, sql.ErrInvalidArgument.New() 158 } 159 } 160 161 // EvalGeomFromWKB takes in arguments for the ST_FROMWKB functions, and parses them to their corresponding geometry type 162 func EvalGeomFromWKB(ctx *sql.Context, row sql.Row, exprs []sql.Expression, expectedGeomType int) (interface{}, error) { 163 val, err := exprs[0].Eval(ctx, row) 164 if err != nil { 165 return nil, err 166 } 167 168 if val == nil { 169 return nil, nil 170 } 171 172 buf, ok := val.([]byte) 173 if !ok { 174 return nil, sql.ErrInvalidGISData.New() 175 } 176 177 isBig, geomType, err := types.DeserializeWKBHeader(buf) 178 if err != nil { 179 return nil, err 180 } 181 buf = buf[types.WKBHeaderSize:] 182 183 if expectedGeomType != types.WKBUnknown && int(geomType) != expectedGeomType { 184 return nil, sql.ErrInvalidGISData.New() 185 } 186 187 srid := uint32(0) 188 if len(exprs) >= 2 { 189 s, err := exprs[1].Eval(ctx, row) 190 if err != nil { 191 return nil, err 192 } 193 if s == nil { 194 return nil, nil 195 } 196 s, _, err = types.Int64.Convert(s) 197 if err != nil { 198 return nil, err 199 } 200 if err = types.ValidateSRID(int(s.(int64)), "st_geomfromwkb"); err != nil { 201 return nil, err 202 } 203 srid = uint32(s.(int64)) 204 } 205 206 var geom types.GeometryValue 207 switch geomType { 208 case types.WKBPointID: 209 geom, _, err = types.DeserializePoint(buf, isBig, srid) 210 case types.WKBLineID: 211 geom, _, err = types.DeserializeLine(buf, isBig, srid) 212 case types.WKBPolyID: 213 geom, _, err = types.DeserializePoly(buf, isBig, srid) 214 case types.WKBMultiPointID: 215 geom, _, err = types.DeserializeMPoint(buf, isBig, srid) 216 case types.WKBMultiLineID: 217 geom, _, err = types.DeserializeMLine(buf, isBig, srid) 218 case types.WKBMultiPolyID: 219 geom, _, err = types.DeserializeMPoly(buf, isBig, srid) 220 case types.WKBGeomCollID: 221 geom, _, err = types.DeserializeGeomColl(buf, isBig, srid) 222 default: 223 return nil, sql.ErrInvalidGISData.New() 224 } 225 if err != nil { 226 return nil, err 227 } 228 229 order := false 230 if len(exprs) == 3 { 231 o, err := exprs[2].Eval(ctx, row) 232 if err != nil { 233 return nil, err 234 } 235 if o == nil { 236 return nil, nil 237 } 238 order, err = ParseAxisOrder(o.(string)) 239 if err != nil { 240 return nil, sql.ErrInvalidArgument.New() 241 } 242 } 243 if order { 244 geom = geom.Swap() 245 } 246 247 return geom, nil 248 } 249 250 // Eval implements the sql.Expression interface. 251 func (g *GeomFromWKB) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 252 geom, err := EvalGeomFromWKB(ctx, row, g.ChildExpressions, types.WKBUnknown) 253 if sql.ErrInvalidGISData.Is(err) { 254 return nil, sql.ErrInvalidGISData.New(g.FunctionName()) 255 } 256 return geom, err 257 } 258 259 // PointFromWKB is a function that returns a point type from a WKB byte array 260 type PointFromWKB struct { 261 expression.NaryExpression 262 } 263 264 var _ sql.FunctionExpression = (*PointFromWKB)(nil) 265 var _ sql.CollationCoercible = (*PointFromWKB)(nil) 266 267 // NewPointFromWKB creates a new point expression. 268 func NewPointFromWKB(args ...sql.Expression) (sql.Expression, error) { 269 if len(args) < 1 || len(args) > 3 { 270 return nil, sql.ErrInvalidArgumentNumber.New("ST_POINTFROMWKB", "1, 2, or 3", len(args)) 271 } 272 return &PointFromWKB{expression.NaryExpression{ChildExpressions: args}}, nil 273 } 274 275 // FunctionName implements sql.FunctionExpression 276 func (p *PointFromWKB) FunctionName() string { 277 return "st_pointfromwkb" 278 } 279 280 // Description implements sql.FunctionExpression 281 func (p *PointFromWKB) Description() string { 282 return "returns a new point from WKB format." 283 } 284 285 // Type implements the sql.Expression interface. 286 func (p *PointFromWKB) Type() sql.Type { 287 return types.PointType{} 288 } 289 290 // CollationCoercibility implements the interface sql.CollationCoercible. 291 func (*PointFromWKB) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 292 return sql.Collation_binary, 4 293 } 294 295 func (p *PointFromWKB) String() string { 296 var args = make([]string, len(p.ChildExpressions)) 297 for i, arg := range p.ChildExpressions { 298 args[i] = arg.String() 299 } 300 return fmt.Sprintf("%s(%s)", p.FunctionName(), strings.Join(args, ",")) 301 } 302 303 // WithChildren implements the Expression interface. 304 func (p *PointFromWKB) WithChildren(children ...sql.Expression) (sql.Expression, error) { 305 return NewPointFromWKB(children...) 306 } 307 308 // Eval implements the sql.Expression interface. 309 func (p *PointFromWKB) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 310 point, err := EvalGeomFromWKB(ctx, row, p.ChildExpressions, types.WKBPointID) 311 if sql.ErrInvalidGISData.Is(err) { 312 return nil, sql.ErrInvalidGISData.New(p.FunctionName()) 313 } 314 return point, err 315 } 316 317 // LineFromWKB is a function that returns a linestring type from a WKB byte array 318 type LineFromWKB struct { 319 expression.NaryExpression 320 } 321 322 var _ sql.FunctionExpression = (*LineFromWKB)(nil) 323 var _ sql.CollationCoercible = (*LineFromWKB)(nil) 324 325 // NewLineFromWKB creates a new point expression. 326 func NewLineFromWKB(args ...sql.Expression) (sql.Expression, error) { 327 if len(args) < 1 || len(args) > 3 { 328 return nil, sql.ErrInvalidArgumentNumber.New("ST_LINEFROMWKB", "1 or 2", len(args)) 329 } 330 return &LineFromWKB{expression.NaryExpression{ChildExpressions: args}}, nil 331 } 332 333 // FunctionName implements sql.FunctionExpression 334 func (l *LineFromWKB) FunctionName() string { 335 return "st_linefromwkb" 336 } 337 338 // Description implements sql.FunctionExpression 339 func (l *LineFromWKB) Description() string { 340 return "returns a new linestring from WKB format." 341 } 342 343 // Type implements the sql.Expression interface. 344 func (l *LineFromWKB) Type() sql.Type { 345 return types.LineStringType{} 346 } 347 348 // CollationCoercibility implements the interface sql.CollationCoercible. 349 func (*LineFromWKB) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 350 return sql.Collation_binary, 4 351 } 352 353 func (l *LineFromWKB) String() string { 354 var args = make([]string, len(l.ChildExpressions)) 355 for i, arg := range l.ChildExpressions { 356 args[i] = arg.String() 357 } 358 return fmt.Sprintf("%s(%s)", l.FunctionName(), strings.Join(args, ",")) 359 } 360 361 // WithChildren implements the Expression interface. 362 func (l *LineFromWKB) WithChildren(children ...sql.Expression) (sql.Expression, error) { 363 return NewLineFromWKB(children...) 364 } 365 366 // Eval implements the sql.Expression interface. 367 func (l *LineFromWKB) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 368 line, err := EvalGeomFromWKB(ctx, row, l.ChildExpressions, types.WKBLineID) 369 if sql.ErrInvalidGISData.Is(err) { 370 return nil, sql.ErrInvalidGISData.New(l.FunctionName()) 371 } 372 return line, err 373 } 374 375 // PolyFromWKB is a function that returns a polygon type from a WKB byte array 376 type PolyFromWKB struct { 377 expression.NaryExpression 378 } 379 380 var _ sql.FunctionExpression = (*PolyFromWKB)(nil) 381 var _ sql.CollationCoercible = (*PolyFromWKB)(nil) 382 383 // NewPolyFromWKB creates a new point expression. 384 func NewPolyFromWKB(args ...sql.Expression) (sql.Expression, error) { 385 if len(args) < 1 || len(args) > 3 { 386 return nil, sql.ErrInvalidArgumentNumber.New("ST_POLYFROMWKB", "1, 2, or 3", len(args)) 387 } 388 return &PolyFromWKB{expression.NaryExpression{ChildExpressions: args}}, nil 389 } 390 391 // FunctionName implements sql.FunctionExpression 392 func (p *PolyFromWKB) FunctionName() string { 393 return "st_polyfromwkb" 394 } 395 396 // Description implements sql.FunctionExpression 397 func (p *PolyFromWKB) Description() string { 398 return "returns a new polygon from WKB format." 399 } 400 401 // Type implements the sql.Expression interface. 402 func (p *PolyFromWKB) Type() sql.Type { 403 return types.PolygonType{} 404 } 405 406 // CollationCoercibility implements the interface sql.CollationCoercible. 407 func (*PolyFromWKB) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 408 return sql.Collation_binary, 4 409 } 410 411 func (p *PolyFromWKB) String() string { 412 var args = make([]string, len(p.ChildExpressions)) 413 for i, arg := range p.ChildExpressions { 414 args[i] = arg.String() 415 } 416 return fmt.Sprintf("%s(%s)", p.FunctionName(), strings.Join(args, ",")) 417 } 418 419 // WithChildren implements the Expression interface. 420 func (p *PolyFromWKB) WithChildren(children ...sql.Expression) (sql.Expression, error) { 421 return NewPolyFromWKB(children...) 422 } 423 424 // Eval implements the sql.Expression interface. 425 func (p *PolyFromWKB) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 426 poly, err := EvalGeomFromWKB(ctx, row, p.ChildExpressions, types.WKBPolyID) 427 if sql.ErrInvalidGISData.Is(err) { 428 return nil, sql.ErrInvalidGISData.New(p.FunctionName()) 429 } 430 return poly, err 431 } 432 433 // MPointFromWKB is a function that returns a linestring type from a WKB byte array 434 type MPointFromWKB struct { 435 expression.NaryExpression 436 } 437 438 var _ sql.FunctionExpression = (*MPointFromWKB)(nil) 439 var _ sql.CollationCoercible = (*MPointFromWKB)(nil) 440 441 // NewMPointFromWKB creates a new point expression. 442 func NewMPointFromWKB(args ...sql.Expression) (sql.Expression, error) { 443 if len(args) < 1 || len(args) > 3 { 444 return nil, sql.ErrInvalidArgumentNumber.New("ST_MPOINTFROMWKB", "1 or 2", len(args)) 445 } 446 return &MPointFromWKB{expression.NaryExpression{ChildExpressions: args}}, nil 447 } 448 449 // FunctionName implements sql.FunctionExpression 450 func (p *MPointFromWKB) FunctionName() string { 451 return "st_mpointfromwkb" 452 } 453 454 // Description implements sql.FunctionExpression 455 func (p *MPointFromWKB) Description() string { 456 return "returns a new multipoint from WKB format." 457 } 458 459 // Type implements the sql.Expression interface. 460 func (p *MPointFromWKB) Type() sql.Type { 461 return types.MultiPointType{} 462 } 463 464 // CollationCoercibility implements the interface sql.CollationCoercible. 465 func (*MPointFromWKB) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 466 return sql.Collation_binary, 4 467 } 468 469 func (p *MPointFromWKB) String() string { 470 var args = make([]string, len(p.ChildExpressions)) 471 for i, arg := range p.ChildExpressions { 472 args[i] = arg.String() 473 } 474 return fmt.Sprintf("%s(%s)", p.FunctionName(), strings.Join(args, ",")) 475 } 476 477 // WithChildren implements the Expression interface. 478 func (p *MPointFromWKB) WithChildren(children ...sql.Expression) (sql.Expression, error) { 479 return NewMPointFromWKB(children...) 480 } 481 482 // Eval implements the sql.Expression interface. 483 func (p *MPointFromWKB) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 484 mPoint, err := EvalGeomFromWKB(ctx, row, p.ChildExpressions, types.WKBMultiPointID) 485 if sql.ErrInvalidGISData.Is(err) { 486 return nil, sql.ErrInvalidGISData.New(p.FunctionName()) 487 } 488 return mPoint, err 489 } 490 491 // MLineFromWKB is a function that returns a polygon type from a WKB byte array 492 type MLineFromWKB struct { 493 expression.NaryExpression 494 } 495 496 var _ sql.FunctionExpression = (*MLineFromWKB)(nil) 497 var _ sql.CollationCoercible = (*MLineFromWKB)(nil) 498 499 // NewMLineFromWKB creates a new point expression. 500 func NewMLineFromWKB(args ...sql.Expression) (sql.Expression, error) { 501 if len(args) < 1 || len(args) > 3 { 502 return nil, sql.ErrInvalidArgumentNumber.New("ST_MLINEFROMWKB", "1, 2, or 3", len(args)) 503 } 504 return &MLineFromWKB{expression.NaryExpression{ChildExpressions: args}}, nil 505 } 506 507 // FunctionName implements sql.FunctionExpression 508 func (l *MLineFromWKB) FunctionName() string { 509 return "st_mlinefromwkb" 510 } 511 512 // Description implements sql.FunctionExpression 513 func (l *MLineFromWKB) Description() string { 514 return "returns a new polygon from WKB format." 515 } 516 517 // Type implements the sql.Expression interface. 518 func (l *MLineFromWKB) Type() sql.Type { 519 return types.PolygonType{} 520 } 521 522 // CollationCoercibility implements the interface sql.CollationCoercible. 523 func (*MLineFromWKB) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 524 return sql.Collation_binary, 4 525 } 526 527 func (l *MLineFromWKB) String() string { 528 var args = make([]string, len(l.ChildExpressions)) 529 for i, arg := range l.ChildExpressions { 530 args[i] = arg.String() 531 } 532 return fmt.Sprintf("%s(%s)", l.FunctionName(), strings.Join(args, ",")) 533 } 534 535 // WithChildren implements the Expression interface. 536 func (l *MLineFromWKB) WithChildren(children ...sql.Expression) (sql.Expression, error) { 537 return NewMLineFromWKB(children...) 538 } 539 540 // Eval implements the sql.Expression interface. 541 func (l *MLineFromWKB) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 542 mline, err := EvalGeomFromWKB(ctx, row, l.ChildExpressions, types.WKBMultiLineID) 543 if sql.ErrInvalidGISData.Is(err) { 544 return nil, sql.ErrInvalidGISData.New(l.FunctionName()) 545 } 546 return mline, err 547 } 548 549 // MPolyFromWKB is a function that returns a polygon type from a WKB byte array 550 type MPolyFromWKB struct { 551 expression.NaryExpression 552 } 553 554 var _ sql.FunctionExpression = (*MPolyFromWKB)(nil) 555 var _ sql.CollationCoercible = (*MPolyFromWKB)(nil) 556 557 // NewMPolyFromWKB creates a new multipolygon expression. 558 func NewMPolyFromWKB(args ...sql.Expression) (sql.Expression, error) { 559 if len(args) < 1 || len(args) > 3 { 560 return nil, sql.ErrInvalidArgumentNumber.New("ST_MPOLYFROMWKB", "1, 2, or 3", len(args)) 561 } 562 return &MPolyFromWKB{expression.NaryExpression{ChildExpressions: args}}, nil 563 } 564 565 // FunctionName implements sql.FunctionExpression 566 func (p *MPolyFromWKB) FunctionName() string { 567 return "st_mpolyfromwkb" 568 } 569 570 // Description implements sql.FunctionExpression 571 func (p *MPolyFromWKB) Description() string { 572 return "returns a new multipolygon from WKB format." 573 } 574 575 // Type implements the sql.Expression interface. 576 func (p *MPolyFromWKB) Type() sql.Type { 577 return types.MultiPolygonType{} 578 } 579 580 // CollationCoercibility implements the interface sql.CollationCoercible. 581 func (*MPolyFromWKB) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 582 return sql.Collation_binary, 4 583 } 584 585 func (p *MPolyFromWKB) String() string { 586 var args = make([]string, len(p.ChildExpressions)) 587 for i, arg := range p.ChildExpressions { 588 args[i] = arg.String() 589 } 590 return fmt.Sprintf("%s(%s)", p.FunctionName(), strings.Join(args, ",")) 591 } 592 593 // WithChildren implements the Expression interface. 594 func (p *MPolyFromWKB) WithChildren(children ...sql.Expression) (sql.Expression, error) { 595 return NewMPolyFromWKB(children...) 596 } 597 598 // Eval implements the sql.Expression interface. 599 func (p *MPolyFromWKB) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 600 mpoly, err := EvalGeomFromWKB(ctx, row, p.ChildExpressions, types.WKBPolyID) 601 if sql.ErrInvalidGISData.Is(err) { 602 return nil, sql.ErrInvalidGISData.New(p.FunctionName()) 603 } 604 return mpoly, err 605 } 606 607 // GeomCollFromWKB is a function that returns a polygon type from a WKB byte array 608 type GeomCollFromWKB struct { 609 expression.NaryExpression 610 } 611 612 var _ sql.FunctionExpression = (*GeomCollFromWKB)(nil) 613 var _ sql.CollationCoercible = (*GeomCollFromWKB)(nil) 614 615 // NewGeomCollFromWKB creates a new geometrycollection expression. 616 func NewGeomCollFromWKB(args ...sql.Expression) (sql.Expression, error) { 617 if len(args) < 1 || len(args) > 3 { 618 return nil, sql.ErrInvalidArgumentNumber.New("ST_GEOMCOLLFROMWKB", "1, 2, or 3", len(args)) 619 } 620 return &MPolyFromWKB{expression.NaryExpression{ChildExpressions: args}}, nil 621 } 622 623 // FunctionName implements sql.FunctionExpression 624 func (g *GeomCollFromWKB) FunctionName() string { 625 return "st_geomcollfromwkb" 626 } 627 628 // Description implements sql.FunctionExpression 629 func (g *GeomCollFromWKB) Description() string { 630 return "returns a new geometrycollection from WKB format." 631 } 632 633 // Type implements the sql.Expression interface. 634 func (g *GeomCollFromWKB) Type() sql.Type { 635 return types.GeomCollType{} 636 } 637 638 // CollationCoercibility implements the interface sql.CollationCoercible. 639 func (*GeomCollFromWKB) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 640 return sql.Collation_binary, 4 641 } 642 643 func (g *GeomCollFromWKB) String() string { 644 var args = make([]string, len(g.ChildExpressions)) 645 for i, arg := range g.ChildExpressions { 646 args[i] = arg.String() 647 } 648 return fmt.Sprintf("%s(%s)", g.FunctionName(), strings.Join(args, ",")) 649 } 650 651 // WithChildren implements the Expression interface. 652 func (g *GeomCollFromWKB) WithChildren(children ...sql.Expression) (sql.Expression, error) { 653 return NewGeomCollFromWKB(children...) 654 } 655 656 // Eval implements the sql.Expression interface. 657 func (g *GeomCollFromWKB) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 658 geom, err := EvalGeomFromWKB(ctx, row, g.ChildExpressions, types.WKBGeomCollID) 659 if sql.ErrInvalidGISData.Is(err) { 660 return nil, sql.ErrInvalidGISData.New(g.FunctionName()) 661 } 662 return geom, err 663 }