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  }