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 }