This commit is contained in:
James Cor
2022-10-13 00:19:41 -07:00
parent 9e3848d6f1
commit cf48fb9bf1
4 changed files with 267 additions and 1 deletions

View File

@@ -0,0 +1,229 @@
// Copyright 2020 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package typeinfo
import (
"context"
"fmt"
"strconv"
"github.com/dolthub/go-mysql-server/sql"
"github.com/dolthub/dolt/go/store/types"
)
// This is a dolt implementation of the MySQL type Point, thus most of the functionality
// within is directly reliant on the go-mysql-server implementation.
type multipolygonType struct {
sqlMultiPolygonType sql.MultiPolygonType
}
var _ TypeInfo = (*multipolygonType)(nil)
var MultiPolygonType = &multipolygonType{sql.MultiPolygonType{}}
// ConvertNomsValueToValue implements TypeInfo interface.
func (ti *multipolygonType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
// Check for null
if _, ok := v.(types.Null); ok || v == nil {
return nil, nil
}
// Expect a types.MultiPolygon, return a sql.MultiPolygon
if val, ok := v.(types.MultiPolygon); ok {
return types.ConvertTypesMultiPolygonToSQLMultiPolygon(val), nil
}
return nil, fmt.Errorf(`"%v" cannot convert NomsKind "%v" to a value`, ti.String(), v.Kind())
}
// ReadFrom reads a go value from a noms types.CodecReader directly
func (ti *multipolygonType) ReadFrom(nbf *types.NomsBinFormat, reader types.CodecReader) (interface{}, error) {
k := reader.ReadKind()
switch k {
case types.MultiPolygonKind:
p, err := reader.ReadMultiPolygon()
if err != nil {
return nil, err
}
return ti.ConvertNomsValueToValue(p)
case types.NullKind:
return nil, nil
}
return nil, fmt.Errorf(`"%v" cannot convert NomsKind "%v" to a value`, ti.String(), k)
}
// ConvertValueToNomsValue implements TypeInfo interface.
func (ti *multipolygonType) ConvertValueToNomsValue(ctx context.Context, vrw types.ValueReadWriter, v interface{}) (types.Value, error) {
// Check for null
if v == nil {
return types.NullValue, nil
}
// Convert to sql.MultiPolygon
mpoly, err := ti.sqlMultiPolygonType.Convert(v)
if err != nil {
return nil, err
}
return types.ConvertSQLMultiPolygonToTypesMultiPolygon(mpoly.(sql.MultiPolygon)), nil
}
// Equals implements TypeInfo interface.
func (ti *multipolygonType) Equals(other TypeInfo) bool {
if other == nil {
return false
}
if o, ok := other.(*multipolygonType); ok {
// if either ti or other has defined SRID, then check SRID value; otherwise,
return (!ti.sqlMultiPolygonType.DefinedSRID && !o.sqlMultiPolygonType.DefinedSRID) || ti.sqlMultiPolygonType.SRID == o.sqlMultiPolygonType.SRID
}
return false
}
// FormatValue implements TypeInfo interface.
func (ti *multipolygonType) FormatValue(v types.Value) (*string, error) {
if val, ok := v.(types.MultiPolygon); ok {
resStr := string(types.SerializeMultiPolygon(val))
return &resStr, nil
}
if _, ok := v.(types.Null); ok || v == nil {
return nil, nil
}
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v.Kind())
}
// GetTypeIdentifier implements TypeInfo interface.
func (ti *multipolygonType) GetTypeIdentifier() Identifier {
return MultiPolygonTypeIdentifier
}
// GetTypeParams implements TypeInfo interface.
func (ti *multipolygonType) GetTypeParams() map[string]string {
return map[string]string{"SRID": strconv.FormatUint(uint64(ti.sqlMultiPolygonType.SRID), 10),
"DefinedSRID": strconv.FormatBool(ti.sqlMultiPolygonType.DefinedSRID)}
}
// IsValid implements TypeInfo interface.
func (ti *multipolygonType) IsValid(v types.Value) bool {
if _, ok := v.(types.MultiPolygon); ok {
return true
}
if _, ok := v.(types.Null); ok || v == nil {
return true
}
return false
}
// NomsKind implements TypeInfo interface.
func (ti *multipolygonType) NomsKind() types.NomsKind {
return types.MultiPolygonKind
}
// Promote implements TypeInfo interface.
func (ti *multipolygonType) Promote() TypeInfo {
return &multipolygonType{ti.sqlMultiPolygonType.Promote().(sql.MultiPolygonType)}
}
// String implements TypeInfo interface.
func (ti *multipolygonType) String() string {
return "MultiPolygon"
}
// ToSqlType implements TypeInfo interface.
func (ti *multipolygonType) ToSqlType() sql.Type {
return ti.sqlMultiPolygonType
}
// multipolygonTypeConverter is an internal function for GetTypeConverter that handles the specific type as the source TypeInfo.
func multipolygonTypeConverter(ctx context.Context, src *multipolygonType, destTi TypeInfo) (tc TypeConverter, needsConversion bool, err error) {
switch dest := destTi.(type) {
case *bitType:
return func(ctx context.Context, vrw types.ValueReadWriter, v types.Value) (types.Value, error) {
return types.Uint(0), nil
}, true, nil
case *blobStringType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *boolType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *datetimeType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *decimalType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *enumType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *floatType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *geometryType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *inlineBlobType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *intType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *jsonType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *linestringType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *multilinestringType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *multipointType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *multipolygonType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *pointType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *polygonType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *setType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *timeType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *uintType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *uuidType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *varBinaryType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *varStringType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
case *yearType:
return wrapConvertValueToNomsValue(dest.ConvertValueToNomsValue)
default:
return nil, false, UnhandledTypeConversion.New(src.String(), destTi.String())
}
}
func CreateMultiPolygonTypeFromParams(params map[string]string) (TypeInfo, error) {
var (
err error
sridVal uint64
def bool
)
if s, ok := params["SRID"]; ok {
sridVal, err = strconv.ParseUint(s, 10, 32)
if err != nil {
return nil, err
}
}
if d, ok := params["DefinedSRID"]; ok {
def, err = strconv.ParseBool(d)
if err != nil {
return nil, err
}
}
return &multipolygonType{sqlMultiPolygonType: sql.MultiPolygonType{SRID: uint32(sridVal), DefinedSRID: def}}, nil
}

View File

@@ -53,6 +53,7 @@ const (
PolygonTypeIdentifier Identifier = "polygon"
MultiPointTypeIdentifier Identifier = "multipoint"
MultiLineStringTypeIdentifier Identifier = "multilinestring"
MultiPolygonTypeIdentifier Identifier = "multipolygon"
)
var Identifiers = map[Identifier]struct{}{
@@ -81,6 +82,7 @@ var Identifiers = map[Identifier]struct{}{
PolygonTypeIdentifier: {},
MultiPointTypeIdentifier: {},
MultiLineStringTypeIdentifier: {},
MultiPolygonTypeIdentifier: {},
}
// TypeInfo is an interface used for encoding type information.
@@ -179,6 +181,8 @@ func FromSqlType(sqlType sql.Type) (TypeInfo, error) {
return &multipointType{}, nil
case sql.MultiLineStringType{}.String():
return &multilinestringType{}, nil
case sql.MultiPolygonType{}.String():
return &multipolygonType{}, nil
case sql.GeometryType{}.String():
return &geometryType{sqlGeometryType: sqlType.(sql.GeometryType)}, nil
default:
@@ -290,6 +294,8 @@ func FromTypeParams(id Identifier, params map[string]string) (TypeInfo, error) {
return CreateMultiPointTypeFromParams(params)
case MultiLineStringTypeIdentifier:
return CreateMultiLineStringTypeFromParams(params)
case MultiPolygonTypeIdentifier:
return CreateMultiPolygonTypeFromParams(params)
case SetTypeIdentifier:
return CreateSetTypeFromParams(params)
case TimeTypeIdentifier:

View File

@@ -286,6 +286,8 @@ func deserializeGeometry(buf []byte) (v interface{}) {
v, _ = sql.DeserializeMPoint(buf, false, srid)
case sql.WKBMultiLineID:
v, _ = sql.DeserializeMLine(buf, false, srid)
case sql.WKBMultiPolyID:
v, _ = sql.DeserializeMPoly(buf, false, srid)
default:
panic(fmt.Sprintf("unknown geometry type %d", typ))
}

View File

@@ -52,6 +52,7 @@ type CodecReader interface {
ReadPolygon() (Polygon, error)
ReadMultiPoint() (MultiPoint, error)
ReadMultiLineString() (MultiLineString, error)
ReadMultiPolygon() (MultiPolygon, error)
ReadBlob() (Blob, error)
ReadJSON() (JSON, error)
}
@@ -110,6 +111,10 @@ func (r *valueDecoder) ReadMultiLineString() (MultiLineString, error) {
return readMultiLineString(nil, r)
}
func (r *valueDecoder) ReadMultiPolygon() (MultiPolygon, error) {
return readMultiPolygon(nil, r)
}
func (r *valueDecoder) ReadJSON() (JSON, error) {
return readJSON(r.vrw.Format(), r)
}
@@ -449,11 +454,35 @@ func (r *valueDecoder) readValue(nbf *NomsBinFormat) (Value, error) {
if err != nil {
return nil, err
}
if geomType != WKBPolyID {
if geomType != WKBMultiPointID {
return nil, ErrUnknownType
}
buf = buf[EWKBHeaderSize:]
return DeserializeTypesMPoint(buf, false, srid), nil
case MultiLineStringKind:
r.skipKind()
buf := []byte(r.ReadString())
srid, _, geomType, err := DeserializeEWKBHeader(buf)
if err != nil {
return nil, err
}
if geomType != WKBMultiLineID {
return nil, ErrUnknownType
}
buf = buf[EWKBHeaderSize:]
return DeserializeTypesMLine(buf, false, srid), nil
case MultiPolygonKind:
r.skipKind()
buf := []byte(r.ReadString())
srid, _, geomType, err := DeserializeEWKBHeader(buf)
if err != nil {
return nil, err
}
if geomType != WKBMultiPolyID {
return nil, ErrUnknownType
}
buf = buf[EWKBHeaderSize:]
return DeserializeTypesMPoly(buf, false, srid), nil
case TypeKind:
r.skipKind()
return r.readType()