github.com/dolthub/go-mysql-server@v0.18.0/sql/types/multilinestring.go (about)

     1  // Copyright 2022 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 types
    16  
    17  import (
    18  	"math"
    19  	"reflect"
    20  
    21  	"github.com/dolthub/vitess/go/sqltypes"
    22  	"github.com/dolthub/vitess/go/vt/proto/query"
    23  	"gopkg.in/src-d/go-errors.v1"
    24  
    25  	"github.com/dolthub/go-mysql-server/sql"
    26  )
    27  
    28  // MultiLineStringType represents the MUTILINESTRING type.
    29  // https://dev.mysql.com/doc/refman/8.0/en/gis-class-multilinestring.html
    30  // The type of the returned value is MultiLineString.
    31  type MultiLineStringType struct {
    32  	SRID        uint32
    33  	DefinedSRID bool
    34  }
    35  
    36  // MultiLineString is the value type returned from MultiLineStringType. Implements GeometryValue.
    37  type MultiLineString struct {
    38  	SRID  uint32
    39  	Lines []LineString
    40  }
    41  
    42  var (
    43  	ErrNotMultiLineString = errors.NewKind("value of type %T is not a multilinestring")
    44  
    45  	multilinestringValueType = reflect.TypeOf(MultiLineString{})
    46  )
    47  
    48  var _ sql.Type = MultiLineStringType{}
    49  var _ sql.SpatialColumnType = MultiLineStringType{}
    50  var _ sql.CollationCoercible = MultiLineStringType{}
    51  var _ GeometryValue = MultiLineString{}
    52  
    53  // Compare implements Type interface.
    54  func (t MultiLineStringType) Compare(a interface{}, b interface{}) (int, error) {
    55  	return GeometryType{}.Compare(a, b)
    56  }
    57  
    58  // Convert implements Type interface.
    59  func (t MultiLineStringType) Convert(v interface{}) (interface{}, sql.ConvertInRange, error) {
    60  	switch buf := v.(type) {
    61  	case nil:
    62  		return nil, sql.InRange, nil
    63  	case []byte:
    64  		mline, _, err := GeometryType{}.Convert(buf)
    65  		if sql.ErrInvalidGISData.Is(err) {
    66  			return nil, sql.OutOfRange, sql.ErrInvalidGISData.New("MultiLineString.Convert")
    67  		}
    68  		return mline, sql.OutOfRange, err
    69  	case string:
    70  		return t.Convert([]byte(buf))
    71  	case MultiLineString:
    72  		if err := t.MatchSRID(buf); err != nil {
    73  			return nil, sql.OutOfRange, err
    74  		}
    75  		return buf, sql.InRange, nil
    76  	default:
    77  		return nil, sql.OutOfRange, sql.ErrSpatialTypeConversion.New()
    78  	}
    79  }
    80  
    81  // Equals implements the Type interface.
    82  func (t MultiLineStringType) Equals(otherType sql.Type) bool {
    83  	_, ok := otherType.(MultiLineStringType)
    84  	return ok
    85  }
    86  
    87  // MaxTextResponseByteLength implements the Type interface
    88  func (t MultiLineStringType) MaxTextResponseByteLength(_ *sql.Context) uint32 {
    89  	return GeometryMaxByteLength
    90  }
    91  
    92  // Promote implements the Type interface.
    93  func (t MultiLineStringType) Promote() sql.Type {
    94  	return t
    95  }
    96  
    97  // SQL implements Type interface.
    98  func (t MultiLineStringType) SQL(ctx *sql.Context, dest []byte, v interface{}) (sqltypes.Value, error) {
    99  	if v == nil {
   100  		return sqltypes.NULL, nil
   101  	}
   102  
   103  	v, _, err := t.Convert(v)
   104  	if err != nil {
   105  		return sqltypes.Value{}, nil
   106  	}
   107  
   108  	buf := v.(MultiLineString).Serialize()
   109  
   110  	return sqltypes.MakeTrusted(sqltypes.Geometry, buf), nil
   111  }
   112  
   113  // String implements Type interface.
   114  func (t MultiLineStringType) String() string {
   115  	return "multilinestring"
   116  }
   117  
   118  // Type implements Type interface.
   119  func (t MultiLineStringType) Type() query.Type {
   120  	return sqltypes.Geometry
   121  }
   122  
   123  // ValueType implements Type interface.
   124  func (t MultiLineStringType) ValueType() reflect.Type {
   125  	return multilinestringValueType
   126  }
   127  
   128  // Zero implements Type interface.
   129  func (t MultiLineStringType) Zero() interface{} {
   130  	return MultiLineString{Lines: []LineString{LineStringType{}.Zero().(LineString)}}
   131  }
   132  
   133  // CollationCoercibility implements sql.CollationCoercible interface.
   134  func (MultiLineStringType) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   135  	return sql.Collation_binary, 5
   136  }
   137  
   138  // GetSpatialTypeSRID implements SpatialColumnType interface.
   139  func (t MultiLineStringType) GetSpatialTypeSRID() (uint32, bool) {
   140  	return t.SRID, t.DefinedSRID
   141  }
   142  
   143  // SetSRID implements SpatialColumnType interface.
   144  func (t MultiLineStringType) SetSRID(v uint32) sql.Type {
   145  	t.SRID = v
   146  	t.DefinedSRID = true
   147  	return t
   148  }
   149  
   150  // MatchSRID implements SpatialColumnType interface
   151  func (t MultiLineStringType) MatchSRID(v interface{}) error {
   152  	val, ok := v.(MultiLineString)
   153  	if !ok {
   154  		return ErrNotMultiLineString.New(v)
   155  	}
   156  	if !t.DefinedSRID {
   157  		return nil
   158  	} else if t.SRID == val.SRID {
   159  		return nil
   160  	}
   161  	return sql.ErrNotMatchingSRID.New(val.SRID, t.SRID)
   162  }
   163  
   164  // implementsGeometryValue implements GeometryValue interface.
   165  func (p MultiLineString) implementsGeometryValue() {}
   166  
   167  // GetSRID implements GeometryValue interface.
   168  func (p MultiLineString) GetSRID() uint32 {
   169  	return p.SRID
   170  }
   171  
   172  // SetSRID implements GeometryValue interface.
   173  func (p MultiLineString) SetSRID(srid uint32) GeometryValue {
   174  	lines := make([]LineString, len(p.Lines))
   175  	for i, l := range p.Lines {
   176  		lines[i] = l.SetSRID(srid).(LineString)
   177  	}
   178  	return MultiLineString{
   179  		SRID:  srid,
   180  		Lines: lines,
   181  	}
   182  }
   183  
   184  // Serialize implements GeometryValue interface.
   185  func (p MultiLineString) Serialize() (buf []byte) {
   186  	var numPoints int
   187  	for _, l := range p.Lines {
   188  		numPoints += len(l.Points)
   189  	}
   190  	buf = AllocateGeoTypeBuffer(numPoints, len(p.Lines)+1, len(p.Lines))
   191  	WriteEWKBHeader(buf, p.SRID, WKBMultiLineID)
   192  	p.WriteData(buf[EWKBHeaderSize:])
   193  	return
   194  }
   195  
   196  // WriteData implements GeometryValue interface.
   197  func (p MultiLineString) WriteData(buf []byte) int {
   198  	WriteCount(buf, uint32(len(p.Lines)))
   199  	buf = buf[CountSize:]
   200  	count := CountSize
   201  	for _, l := range p.Lines {
   202  		WriteWKBHeader(buf, WKBLineID)
   203  		buf = buf[WKBHeaderSize:]
   204  		c := l.WriteData(buf)
   205  		buf = buf[c:]
   206  		count += WKBHeaderSize + c
   207  	}
   208  	return count
   209  }
   210  
   211  // Swap implements GeometryValue interface.
   212  func (p MultiLineString) Swap() GeometryValue {
   213  	lines := make([]LineString, len(p.Lines))
   214  	for i, l := range p.Lines {
   215  		lines[i] = l.Swap().(LineString)
   216  	}
   217  	return MultiLineString{
   218  		SRID:  p.SRID,
   219  		Lines: lines,
   220  	}
   221  }
   222  
   223  // BBox implements GeometryValue interface.
   224  func (p MultiLineString) BBox() (float64, float64, float64, float64) {
   225  	minX, minY, maxX, maxY := math.MaxFloat64, math.MaxFloat64, -math.MaxFloat64, -math.MaxFloat64
   226  	for _, l := range p.Lines {
   227  		lMinX, lMinY, lMaxX, lMaxY := l.BBox()
   228  		minX = math.Min(minX, lMinX)
   229  		minY = math.Min(minY, lMinY)
   230  		maxX = math.Max(maxX, lMaxX)
   231  		maxY = math.Max(maxY, lMaxY)
   232  	}
   233  	return minX, minY, maxX, maxY
   234  }