Skip to content

Commit a95de96

Browse files
authored
Merge pull request #2394 from dolthub/daylon/binary-wire-tests
Implemented the binary wire format
2 parents de5347c + aeaf9c4 commit a95de96

33 files changed

+4424
-459
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ require (
3434
github.com/sirupsen/logrus v1.8.3
3535
github.com/stretchr/testify v1.11.1
3636
github.com/twpayne/go-geom v1.3.6
37+
github.com/xdg-go/scram v1.2.0
3738
github.com/xdg-go/stringprep v1.0.4
3839
golang.org/x/crypto v0.47.0
3940
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
@@ -184,6 +185,7 @@ require (
184185
github.com/tklauser/numcpus v0.11.0 // indirect
185186
github.com/twpayne/go-kml v1.5.2-0.20200728095708-9f2fd4dfcbfe // indirect
186187
github.com/vbauerster/mpb/v8 v8.0.2 // indirect
188+
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
187189
github.com/xitongsys/parquet-go v1.6.1 // indirect
188190
github.com/xitongsys/parquet-go-source v0.0.0-20211010230925-397910c5e371 // indirect
189191
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,10 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU
798798
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
799799
github.com/vbauerster/mpb/v8 v8.0.2 h1:alVQG69Jg5+Ku9Hu1dakDx50uACEHnIzS7i356NQ/Vs=
800800
github.com/vbauerster/mpb/v8 v8.0.2/go.mod h1:Z9VJYIzXls7xZwirZjShGsi+14enzJhQfGyb/XZK0ZQ=
801+
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
802+
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
803+
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
804+
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
801805
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
802806
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
803807
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=

server/cast/bit.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func bitImplicit() {
7373
if err != nil {
7474
return nil, err
7575
}
76-
expectedLength := pgtypes.GetCharLengthFromTypmod(targetType.GetAttTypMod())
76+
expectedLength := targetType.GetAttTypMod()
7777
if array.BitLen() != uint(expectedLength) {
7878
return nil, pgtypes.ErrWrongLengthBit.New(len(input), expectedLength)
7979
}
@@ -91,9 +91,8 @@ func bitImplicit() {
9191
}
9292
atttypmod := targetType.GetAttTypMod()
9393
if atttypmod != -1 {
94-
maxLength := pgtypes.GetCharLengthFromTypmod(atttypmod)
95-
if int32(array.BitLen()) > maxLength {
96-
return nil, pgtypes.ErrVarBitLengthExceeded.New(maxLength)
94+
if int32(array.BitLen()) > atttypmod {
95+
return nil, pgtypes.ErrVarBitLengthExceeded.New(atttypmod)
9796
}
9897
}
9998
return tree.AsStringWithFlags(array, tree.FmtPgwireText), nil

server/cast/varbit.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func varBitImplicit() {
3939
if err != nil {
4040
return nil, err
4141
}
42-
expectedLength := pgtypes.GetCharLengthFromTypmod(targetType.GetAttTypMod())
42+
expectedLength := targetType.GetAttTypMod()
4343
if array.BitLen() != uint(expectedLength) {
4444
return nil, pgtypes.ErrWrongLengthBit.New(len(input), expectedLength)
4545
}
@@ -57,9 +57,8 @@ func varBitImplicit() {
5757
}
5858
atttypmod := targetType.GetAttTypMod()
5959
if atttypmod != -1 {
60-
maxLength := pgtypes.GetCharLengthFromTypmod(atttypmod)
61-
if int32(array.BitLen()) > maxLength {
62-
return nil, pgtypes.ErrVarBitLengthExceeded.New(maxLength)
60+
if int32(array.BitLen()) > atttypmod {
61+
return nil, pgtypes.ErrVarBitLengthExceeded.New(atttypmod)
6362
}
6463
}
6564
return tree.AsStringWithFlags(array, tree.FmtPgwireText), nil

server/config/parameters_list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2990,7 +2990,7 @@ var postgresConfigParameters = map[string]sql.SystemVariable{
29902990
// schema on the path here.
29912991
"search_path": &Parameter{
29922992
Name: "search_path",
2993-
Default: "\"$user\", public,",
2993+
Default: "\"$user\", public",
29942994
Category: "Client Connection Defaults / Statement Behavior",
29952995
ShortDesc: "Sets the schema search order for names that are not schema-qualified.",
29962996
Context: ParameterContextUser,

server/connection_data.go

Lines changed: 10 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"github.com/dolthub/go-mysql-server/sql/expression"
2424
"github.com/dolthub/go-mysql-server/sql/plan"
2525
"github.com/dolthub/go-mysql-server/sql/transform"
26-
"github.com/dolthub/vitess/go/vt/proto/query"
2726
vitess "github.com/dolthub/vitess/go/vt/sqlparser"
2827
"github.com/jackc/pgx/v5/pgproto3"
2928
"github.com/lib/pq/oid"
@@ -94,6 +93,7 @@ type PortalData struct {
9493
IsEmptyQuery bool
9594
Fields []pgproto3.FieldDescription
9695
BoundPlan sql.Node
96+
FormatCodes []int16
9797
}
9898

9999
type PreparedStatementData struct {
@@ -133,15 +133,15 @@ func extractBindVarTypes(queryPlan sql.Node) ([]uint32, error) {
133133
case *plan.Offset:
134134
typOid = uint32(oid.T_int4)
135135
default:
136-
typOid, err = VitessTypeToObjectID(e.Type().Type())
136+
typOid, err = VitessTypeToObjectID(e.Type())
137137
if err != nil {
138138
err = errors.Errorf("could not determine OID for placeholder %s: %e", e.Name, err)
139139
return false
140140
}
141141
}
142142
} else {
143143
// TODO: should remove usage non doltgres type
144-
typOid, err = VitessTypeToObjectID(e.Type().Type())
144+
typOid, err = VitessTypeToObjectID(e.Type())
145145
if err != nil {
146146
err = errors.Errorf("could not determine OID for placeholder %s: %e", e.Name, err)
147147
return false
@@ -158,7 +158,7 @@ func extractBindVarTypes(queryPlan sql.Node) ([]uint32, error) {
158158
if doltgresType, ok := bindVar.Type().(*pgtypes.DoltgresType); ok {
159159
typOid = id.Cache().ToOID(doltgresType.ID.AsId())
160160
} else {
161-
typOid, err = VitessTypeToObjectID(e.Type().Type())
161+
typOid, err = VitessTypeToObjectID(e.Type())
162162
if err != nil {
163163
err = errors.Errorf("could not determine OID for placeholder %s: %e", bindVar.Name, err)
164164
return false
@@ -175,7 +175,7 @@ func extractBindVarTypes(queryPlan sql.Node) ([]uint32, error) {
175175
case *expression.Convert:
176176
if bindVar, ok := e.Child.(*expression.BindVar); ok {
177177
var typOid uint32
178-
typOid, err = VitessTypeToObjectID(e.Type().Type())
178+
typOid, err = VitessTypeToObjectID(e.Type())
179179
if err != nil {
180180
err = errors.Errorf("could not determine OID for placeholder %s: %e", bindVar.Name, err)
181181
return false
@@ -218,65 +218,10 @@ func extractBindVarTypes(queryPlan sql.Node) ([]uint32, error) {
218218

219219
// VitessTypeToObjectID returns a type, as defined by Vitess, into a type as defined by Postgres.
220220
// OIDs can be obtained with the following query: `SELECT oid, typname FROM pg_type ORDER BY 1;`
221-
func VitessTypeToObjectID(typ query.Type) (uint32, error) {
222-
switch typ {
223-
case query.Type_INT8:
224-
// Postgres doesn't make use of a small integer type for integer returns, which presents a bit of a conundrum.
225-
// GMS defines boolean operations as the smallest integer type, while Postgres has an explicit bool type.
226-
// We can't always assume that `INT8` means bool, since it could just be a small integer. As a result, we'll
227-
// always return this as though it's an `INT16`, which also means that we can't support bools right now.
228-
// OIDs 16 (bool) and 18 (char, ASCII only?) are the only single-byte types as far as I'm aware.
229-
return uint32(oid.T_int2), nil
230-
case query.Type_INT16:
231-
// The technically correct OID is 21 (2-byte integer), however it seems like some clients don't actually expect
232-
// this, so I'm not sure when it's actually used by Postgres. Because of this, we'll just pretend it's an `INT32`.
233-
return uint32(oid.T_int2), nil
234-
case query.Type_INT24:
235-
// Postgres doesn't have a 3-byte integer type, so just pretend it's `INT32`.
236-
return uint32(oid.T_int4), nil
237-
case query.Type_INT32:
238-
return uint32(oid.T_int4), nil
239-
case query.Type_INT64:
240-
return uint32(oid.T_int8), nil
241-
case query.Type_UINT8:
242-
return uint32(oid.T_int4), nil
243-
case query.Type_UINT16:
244-
return uint32(oid.T_int4), nil
245-
case query.Type_UINT24:
246-
return uint32(oid.T_int4), nil
247-
case query.Type_UINT32:
248-
// Since this has an upperbound greater than `INT32`, we'll treat it as `INT64`
249-
return uint32(oid.T_oid), nil
250-
case query.Type_UINT64:
251-
// Since this has an upperbound greater than `INT64`, we'll treat it as `NUMERIC`
252-
return uint32(oid.T_numeric), nil
253-
case query.Type_FLOAT32:
254-
return uint32(oid.T_float4), nil
255-
case query.Type_FLOAT64:
256-
return uint32(oid.T_float8), nil
257-
case query.Type_DECIMAL:
258-
return uint32(oid.T_numeric), nil
259-
case query.Type_CHAR:
260-
return uint32(oid.T_char), nil
261-
case query.Type_VARCHAR:
262-
return uint32(oid.T_varchar), nil
263-
case query.Type_TEXT:
264-
return uint32(oid.T_text), nil
265-
case query.Type_BLOB:
266-
return uint32(oid.T_bytea), nil
267-
case query.Type_JSON:
268-
return uint32(oid.T_json), nil
269-
case query.Type_TIMESTAMP, query.Type_DATETIME:
270-
return uint32(oid.T_timestamp), nil
271-
case query.Type_DATE:
272-
return uint32(oid.T_date), nil
273-
case query.Type_NULL_TYPE:
274-
return uint32(oid.T_text), nil // NULL is treated as TEXT on the wire
275-
case query.Type_ENUM:
276-
return uint32(oid.T_text), nil // TODO: temporary solution until we support CREATE TYPE
277-
case query.Type_EXPRESSION:
278-
return uint32(oid.T_text), nil // this most closely matches the behavior in postgres, which treats any unresolved type as a string (unless it has special handling)
279-
default:
280-
return 0, errors.Errorf("unsupported type: %s", typ)
221+
func VitessTypeToObjectID(typ sql.Type) (uint32, error) {
222+
doltgresType, err := pgtypes.FromGmsTypeToDoltgresType(typ)
223+
if err != nil {
224+
return 0, err
281225
}
226+
return id.Cache().ToOID(doltgresType.ID.AsId()), nil
282227
}

server/connection_handler.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,8 @@ func (h *ConnectionHandler) handleBind(message *pgproto3.Bind) error {
634634
varTypes: preparedData.BindVarTypes,
635635
formatCodes: message.ParameterFormatCodes,
636636
parameters: message.Parameters,
637-
})
637+
},
638+
message.ResultFormatCodes)
638639
if err != nil {
639640
return err
640641
}
@@ -644,10 +645,15 @@ func (h *ConnectionHandler) handleBind(message *pgproto3.Bind) error {
644645
return errors.Errorf("expected a sql.Node, got %T", analyzedPlan)
645646
}
646647

648+
resultFormatCodes, err := extendFormatCodes(len(fields), message.ResultFormatCodes)
649+
if err != nil {
650+
return err
651+
}
647652
h.portals[message.DestinationPortal] = PortalData{
648-
Query: preparedData.Query,
649-
Fields: fields,
650-
BoundPlan: boundPlan,
653+
Query: preparedData.Query,
654+
Fields: fields,
655+
BoundPlan: boundPlan,
656+
FormatCodes: resultFormatCodes,
651657
}
652658
return h.send(&pgproto3.BindComplete{})
653659
}
@@ -679,7 +685,7 @@ func (h *ConnectionHandler) handleExecute(message *pgproto3.Execute) error {
679685
rowsAffected := int32(0)
680686

681687
callback := h.spoolRowsCallback(query, &rowsAffected, true)
682-
err = h.doltgresHandler.ComExecuteBound(context.Background(), h.mysqlConn, query.String, portalData.BoundPlan, callback)
688+
err = h.doltgresHandler.ComExecuteBound(context.Background(), h.mysqlConn, query.String, portalData.BoundPlan, portalData.FormatCodes, callback)
683689
if err != nil {
684690
return err
685691
}
@@ -839,7 +845,7 @@ func (h *ConnectionHandler) handleCopyDataHelper(copyState *copyFromStdinState,
839845
}
840846

841847
callback := func(_ *sql.Context, _ *Result) error { return nil }
842-
err = h.doltgresHandler.ComExecuteBound(sqlCtx, h.mysqlConn, "COPY FROM", copyState.insertNode, callback)
848+
err = h.doltgresHandler.ComExecuteBound(sqlCtx, h.mysqlConn, "COPY FROM", copyState.insertNode, nil, callback)
843849
if err != nil {
844850
return false, false, err
845851
}

0 commit comments

Comments
 (0)