├── .gitignore ├── INSTALL ├── LICENSE ├── Mysqlx ├── mysqlx.pb.go └── mysqlx.proto ├── Mysqlx_Connection ├── mysqlx_connection.pb.go └── mysqlx_connection.proto ├── Mysqlx_Crud ├── mysqlx_crud.pb.go └── mysqlx_crud.proto ├── Mysqlx_Datatypes ├── mysqlx_datatypes.pb.go └── mysqlx_datatypes.proto ├── Mysqlx_Expect └── Mysql_Expect │ └── mysqlx_expect.pb.go ├── Mysqlx_Expr ├── mysqlx_expr.pb.go └── mysqlx_expr.proto ├── Mysqlx_Notice ├── mysqlx_notice.pb.go └── mysqlx_notice.proto ├── Mysqlx_Resultset ├── mysqlx_resultset.pb.go └── mysqlx_resultset.proto ├── Mysqlx_Session ├── mysqlx_session.pb.go └── mysqlx_session.proto ├── Mysqlx_Sql ├── mysqlx_sql.pb.go └── mysqlx_sql.proto ├── PENDING_TESTS ├── README ├── appengine.go ├── buffer.go ├── capability └── capability.go ├── cmd ├── bigmsg │ └── main.go ├── invalid_msg │ └── main.go └── zerolength │ └── main.go ├── collations.go ├── config.go ├── connection.go ├── const.go ├── convert.go ├── datatypes.go ├── debug └── debug.go ├── driver.go ├── dsn_test.go ├── errors.go ├── mysql41.go ├── protocol.go ├── result.go ├── rows.go ├── state.go ├── tests ├── charset_test.go ├── common_test.go ├── connect1_test.go ├── multi_row_test.go ├── mysql41_test.go ├── system_variable_test.go ├── tls_test.go ├── type_test.go └── xprotocol_test.sql ├── utils.go ├── vendor ├── github.com │ ├── golang │ │ └── protobuf │ │ │ ├── AUTHORS │ │ │ ├── CONTRIBUTORS │ │ │ ├── LICENSE │ │ │ ├── Make.protobuf │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ └── proto │ │ │ ├── Makefile │ │ │ ├── clone.go │ │ │ ├── decode.go │ │ │ ├── encode.go │ │ │ ├── equal.go │ │ │ ├── extensions.go │ │ │ ├── lib.go │ │ │ ├── message_set.go │ │ │ ├── pointer_reflect.go │ │ │ ├── pointer_unsafe.go │ │ │ ├── properties.go │ │ │ ├── text.go │ │ │ └── text_parser.go │ └── sjmudd │ │ └── mysql-server-rapid-plugin-x-protocol │ │ ├── README.md │ │ ├── mysqlx.proto │ │ ├── mysqlx_connection.proto │ │ ├── mysqlx_crud.proto │ │ ├── mysqlx_datatypes.proto │ │ ├── mysqlx_expect.proto │ │ ├── mysqlx_expr.proto │ │ ├── mysqlx_notice.proto │ │ ├── mysqlx_resultset.proto │ │ ├── mysqlx_session.proto │ │ └── mysqlx_sql.proto └── vendor.json └── xconfig.go /.gitignore: -------------------------------------------------------------------------------- 1 | cmd/bigmsg/bigmsg 2 | cmd/invalid_msg/invalid_msg 3 | cmd/zerolength/zerolength 4 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation 2 | ------------ 3 | 4 | Install the driver with govendor fetch github.com/sjmudd/go-mysqlx-driver 5 | which places the driver under vendor/ and records in vendor/vendor.json details 6 | of the exact state of the repository that was retrieved. 7 | 8 | To use this driver reference it in your go code like this: 9 | 10 | Sample Code 11 | ----------- 12 | 13 | ``` 14 | import ( 15 | "database/sql" 16 | "fmt" 17 | 18 | _ "github.com/sjmudd/go-mysqlx-driver" 19 | ) 20 | 21 | const xprotocolDriver = "mysql/xprotocol" 22 | 23 | func main() { 24 | dsn := "user:pass@tcp(127.0.0.1:33060)/db?xprotocol=1" 25 | db, err := sql.Open(xprotocolDriver, dsn) 26 | if err != nil { 27 | err = fmt.Fatalf("failed to open connection to driver: %q, dsn: %q: %+v", xprotocolDriver, dsn, err) 28 | } 29 | 30 | // do stuff 31 | 32 | db.Close() 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /Mysqlx/mysqlx.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | 20 | // tell protobuf 3.0 to use protobuf 2.x rules 21 | syntax = "proto2"; 22 | 23 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 24 | 25 | package Mysqlx; 26 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 27 | 28 | import "mysqlx_sql.proto"; 29 | import "mysqlx_resultset.proto"; 30 | import "mysqlx_crud.proto"; 31 | import "mysqlx_session.proto"; 32 | import "mysqlx_connection.proto"; 33 | import "mysqlx_expect.proto"; 34 | import "mysqlx_notice.proto"; 35 | 36 | // style-guide: 37 | // 38 | // see https://developers.google.com/protocol-buffers/docs/style 39 | // 40 | // message CamelCaseMsg { 41 | // enum CamelCaseEnum { 42 | // FIRST_VALUE = 1; 43 | // } 44 | // required CamelCaseEnum some_enum = 1; 45 | // } 46 | // 47 | 48 | 49 | // IDs of messages that can be sent from client to the server 50 | // 51 | // .. note:: 52 | // this message is never sent on the wire. It is only used to let ``protoc`` 53 | // 54 | // * generate constants 55 | // * check for uniqueness 56 | message ClientMessages { 57 | enum Type { 58 | CON_CAPABILITIES_GET = 1; 59 | CON_CAPABILITIES_SET = 2; 60 | CON_CLOSE = 3; 61 | 62 | SESS_AUTHENTICATE_START = 4; 63 | SESS_AUTHENTICATE_CONTINUE = 5; 64 | SESS_RESET = 6; 65 | SESS_CLOSE = 7; 66 | 67 | SQL_STMT_EXECUTE = 12; 68 | 69 | CRUD_FIND = 17; 70 | CRUD_INSERT = 18; 71 | CRUD_UPDATE = 19; 72 | CRUD_DELETE = 20; 73 | 74 | EXPECT_OPEN = 24; 75 | EXPECT_CLOSE = 25; 76 | } 77 | } 78 | 79 | // IDs of messages that can be sent from server to client 80 | // 81 | // .. note:: 82 | // this message is never sent on the wire. It is only used to let ``protoc`` 83 | // 84 | // * generate constants 85 | // * check for uniqueness 86 | message ServerMessages { 87 | enum Type { 88 | OK = 0; 89 | ERROR = 1; 90 | 91 | CONN_CAPABILITIES = 2; 92 | 93 | SESS_AUTHENTICATE_CONTINUE = 3; 94 | SESS_AUTHENTICATE_OK = 4; 95 | 96 | // NOTICE has to stay at 11 forever 97 | NOTICE = 11; 98 | 99 | RESULTSET_COLUMN_META_DATA = 12; 100 | RESULTSET_ROW = 13; 101 | RESULTSET_FETCH_DONE = 14; 102 | RESULTSET_FETCH_SUSPENDED = 15; 103 | RESULTSET_FETCH_DONE_MORE_RESULTSETS = 16; 104 | 105 | SQL_STMT_EXECUTE_OK = 17; 106 | RESULTSET_FETCH_DONE_MORE_OUT_PARAMS = 18; 107 | }; 108 | } 109 | 110 | 111 | // generic Ok message 112 | message Ok { 113 | optional string msg = 1; 114 | } 115 | 116 | 117 | // generic Error message 118 | // 119 | // A ``severity`` of ``ERROR`` indicates the current message sequence is 120 | // aborted for the given error and the session is ready for more. 121 | // 122 | // In case of a ``FATAL`` error message the client should not expect 123 | // the server to continue handling any further messages and should 124 | // close the connection. 125 | // 126 | // :param severity: severity of the error message 127 | // :param code: error-code 128 | // :param sql_state: SQL state 129 | // :param msg: human readable error message 130 | message Error { 131 | optional Severity severity = 1 [ default = ERROR ]; 132 | required uint32 code = 2; 133 | required string sql_state = 4; 134 | required string msg = 3; 135 | 136 | enum Severity { 137 | ERROR = 0; 138 | FATAL = 1; 139 | }; 140 | } 141 | -------------------------------------------------------------------------------- /Mysqlx_Connection/mysqlx_connection.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: mysqlx_connection.proto 3 | // DO NOT EDIT! 4 | 5 | /* 6 | Package Mysqlx_Connection is a generated protocol buffer package. 7 | 8 | It is generated from these files: 9 | mysqlx_connection.proto 10 | 11 | It has these top-level messages: 12 | Capability 13 | Capabilities 14 | CapabilitiesGet 15 | CapabilitiesSet 16 | Close 17 | */ 18 | package Mysqlx_Connection 19 | 20 | import proto "github.com/golang/protobuf/proto" 21 | import fmt "fmt" 22 | import math "math" 23 | import "github.com/sjmudd/go-mysqlx-driver/Mysqlx_Datatypes" 24 | 25 | // Reference imports to suppress errors if they are not otherwise used. 26 | var _ = proto.Marshal 27 | var _ = fmt.Errorf 28 | var _ = math.Inf 29 | 30 | // This is a compile-time assertion to ensure that this generated file 31 | // is compatible with the proto package it is being compiled against. 32 | const _ = proto.ProtoPackageIsVersion1 33 | 34 | // a Capability 35 | // 36 | // a tuple of a ``name`` and a :protobuf:msg:`Mysqlx.Datatypes::Any` 37 | type Capability struct { 38 | Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` 39 | Value *Mysqlx_Datatypes.Any `protobuf:"bytes,2,req,name=value" json:"value,omitempty"` 40 | XXX_unrecognized []byte `json:"-"` 41 | } 42 | 43 | func (m *Capability) Reset() { *m = Capability{} } 44 | func (m *Capability) String() string { return proto.CompactTextString(m) } 45 | func (*Capability) ProtoMessage() {} 46 | func (*Capability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 47 | 48 | func (m *Capability) GetName() string { 49 | if m != nil && m.Name != nil { 50 | return *m.Name 51 | } 52 | return "" 53 | } 54 | 55 | func (m *Capability) GetValue() *Mysqlx_Datatypes.Any { 56 | if m != nil { 57 | return m.Value 58 | } 59 | return nil 60 | } 61 | 62 | // Capabilities 63 | type Capabilities struct { 64 | Capabilities []*Capability `protobuf:"bytes,1,rep,name=capabilities" json:"capabilities,omitempty"` 65 | XXX_unrecognized []byte `json:"-"` 66 | } 67 | 68 | func (m *Capabilities) Reset() { *m = Capabilities{} } 69 | func (m *Capabilities) String() string { return proto.CompactTextString(m) } 70 | func (*Capabilities) ProtoMessage() {} 71 | func (*Capabilities) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 72 | 73 | func (m *Capabilities) GetCapabilities() []*Capability { 74 | if m != nil { 75 | return m.Capabilities 76 | } 77 | return nil 78 | } 79 | 80 | // get supported connection capabilities and their current state 81 | // 82 | // :returns: :protobuf:msg:`Mysqlx.Connection::Capabilities` or :protobuf:msg:`Mysqlx::Error` 83 | // 84 | type CapabilitiesGet struct { 85 | XXX_unrecognized []byte `json:"-"` 86 | } 87 | 88 | func (m *CapabilitiesGet) Reset() { *m = CapabilitiesGet{} } 89 | func (m *CapabilitiesGet) String() string { return proto.CompactTextString(m) } 90 | func (*CapabilitiesGet) ProtoMessage() {} 91 | func (*CapabilitiesGet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } 92 | 93 | // sets connection capabilities atomically 94 | // 95 | // only provided values are changed, other values are left unchanged. 96 | // If any of the changes fails, all changes are discarded. 97 | // 98 | // :precond: active sessions == 0 99 | // :returns: :protobuf:msg:`Mysqlx::Ok` or :protobuf:msg:`Mysqlx::Error` 100 | type CapabilitiesSet struct { 101 | Capabilities *Capabilities `protobuf:"bytes,1,req,name=capabilities" json:"capabilities,omitempty"` 102 | XXX_unrecognized []byte `json:"-"` 103 | } 104 | 105 | func (m *CapabilitiesSet) Reset() { *m = CapabilitiesSet{} } 106 | func (m *CapabilitiesSet) String() string { return proto.CompactTextString(m) } 107 | func (*CapabilitiesSet) ProtoMessage() {} 108 | func (*CapabilitiesSet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } 109 | 110 | func (m *CapabilitiesSet) GetCapabilities() *Capabilities { 111 | if m != nil { 112 | return m.Capabilities 113 | } 114 | return nil 115 | } 116 | 117 | // announce to the server that the client wants to close the connection 118 | // 119 | // it discards any session state of the server 120 | // 121 | // :Returns: :protobuf:msg:`Mysqlx::Ok` 122 | type Close struct { 123 | XXX_unrecognized []byte `json:"-"` 124 | } 125 | 126 | func (m *Close) Reset() { *m = Close{} } 127 | func (m *Close) String() string { return proto.CompactTextString(m) } 128 | func (*Close) ProtoMessage() {} 129 | func (*Close) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } 130 | 131 | func init() { 132 | proto.RegisterType((*Capability)(nil), "Mysqlx.Connection.Capability") 133 | proto.RegisterType((*Capabilities)(nil), "Mysqlx.Connection.Capabilities") 134 | proto.RegisterType((*CapabilitiesGet)(nil), "Mysqlx.Connection.CapabilitiesGet") 135 | proto.RegisterType((*CapabilitiesSet)(nil), "Mysqlx.Connection.CapabilitiesSet") 136 | proto.RegisterType((*Close)(nil), "Mysqlx.Connection.Close") 137 | } 138 | 139 | var fileDescriptor0 = []byte{ 140 | // 213 bytes of a gzipped FileDescriptorProto 141 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0xcf, 0xad, 0x2c, 0x2e, 142 | 0xcc, 0xa9, 0x88, 0x4f, 0xce, 0xcf, 0xcb, 0x4b, 0x4d, 0x2e, 0xc9, 0xcc, 0xcf, 0xd3, 0x2b, 0x28, 143 | 0xca, 0x2f, 0xc9, 0x17, 0x12, 0xf4, 0x05, 0x4b, 0xe8, 0x39, 0xc3, 0x25, 0xa4, 0xc4, 0xa0, 0x6a, 144 | 0x53, 0x12, 0x4b, 0x12, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, 0x21, 0x4a, 0x95, 0x1c, 0xb8, 0xb8, 0x9c, 145 | 0x13, 0x0b, 0x12, 0x93, 0x32, 0x73, 0x32, 0x4b, 0x2a, 0x85, 0x78, 0xb8, 0x58, 0xf2, 0x12, 0x73, 146 | 0x53, 0x25, 0x18, 0x15, 0x98, 0x34, 0x38, 0x85, 0x54, 0xb8, 0x58, 0xcb, 0x12, 0x73, 0x4a, 0x53, 147 | 0x25, 0x98, 0x80, 0x5c, 0x6e, 0x23, 0x51, 0x3d, 0xa8, 0xb1, 0x2e, 0x70, 0x33, 0x1c, 0xf3, 0x2a, 148 | 0x95, 0x9c, 0xb9, 0x78, 0xe0, 0x26, 0x64, 0xa6, 0x16, 0x0b, 0x19, 0x73, 0xf1, 0x24, 0x23, 0xf1, 149 | 0x81, 0x66, 0x31, 0x03, 0x35, 0xcb, 0xea, 0x61, 0xb8, 0x49, 0x0f, 0x61, 0xb1, 0x92, 0x20, 0x17, 150 | 0x3f, 0xb2, 0x21, 0xee, 0xa9, 0x25, 0x4a, 0x1e, 0xa8, 0x42, 0xc1, 0xa9, 0x25, 0x42, 0xa6, 0x18, 151 | 0x46, 0x83, 0xdc, 0x25, 0x8f, 0xcf, 0x68, 0xa0, 0x32, 0x25, 0x76, 0x2e, 0x56, 0xe7, 0x9c, 0xfc, 152 | 0xe2, 0x54, 0x27, 0x39, 0x2e, 0x99, 0xe4, 0xfc, 0x5c, 0x3d, 0x70, 0x50, 0xe8, 0x25, 0x67, 0x41, 153 | 0x18, 0x15, 0x90, 0x90, 0x48, 0x2a, 0x4d, 0x03, 0x04, 0x00, 0x00, 0xff, 0xff, 0x96, 0xbd, 0xe1, 154 | 0x56, 0x51, 0x01, 0x00, 0x00, 155 | } 156 | -------------------------------------------------------------------------------- /Mysqlx_Connection/mysqlx_connection.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | import "mysqlx_datatypes.proto"; 24 | 25 | package Mysqlx.Connection; 26 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 27 | 28 | // a Capability 29 | // 30 | // a tuple of a ``name`` and a :protobuf:msg:`Mysqlx.Datatypes::Any` 31 | message Capability { 32 | required string name = 1; 33 | required Mysqlx.Datatypes.Any value = 2; 34 | } 35 | 36 | // Capabilities 37 | message Capabilities { 38 | repeated Capability capabilities = 1; 39 | } 40 | 41 | // get supported connection capabilities and their current state 42 | // 43 | // :returns: :protobuf:msg:`Mysqlx.Connection::Capabilities` or :protobuf:msg:`Mysqlx::Error` 44 | // 45 | message CapabilitiesGet { 46 | }; 47 | 48 | // sets connection capabilities atomically 49 | // 50 | // only provided values are changed, other values are left unchanged. 51 | // If any of the changes fails, all changes are discarded. 52 | // 53 | // :precond: active sessions == 0 54 | // :returns: :protobuf:msg:`Mysqlx::Ok` or :protobuf:msg:`Mysqlx::Error` 55 | message CapabilitiesSet { 56 | required Capabilities capabilities = 1; 57 | }; 58 | 59 | // announce to the server that the client wants to close the connection 60 | // 61 | // it discards any session state of the server 62 | // 63 | // :Returns: :protobuf:msg:`Mysqlx::Ok` 64 | message Close { 65 | }; 66 | 67 | -------------------------------------------------------------------------------- /Mysqlx_Crud/mysqlx_crud.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | // Basic CRUD operations 24 | package Mysqlx.Crud; 25 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 26 | 27 | import "mysqlx_expr.proto"; 28 | import "mysqlx_datatypes.proto"; 29 | 30 | // column definition 31 | message Column { 32 | optional string name = 1; 33 | optional string alias = 2; 34 | repeated Mysqlx.Expr.DocumentPathItem document_path = 3; 35 | } 36 | 37 | // a projection 38 | // 39 | // :param source: the expression identifying an element from the source data 40 | // which can include a column identifier or any expression 41 | // :param alias: optional alias. Required for DOCUMENTs (clients may use 42 | // the source string as default) 43 | message Projection { 44 | required Mysqlx.Expr.Expr source = 1; 45 | optional string alias = 2; 46 | } 47 | 48 | // DataModel to use for filters, names, ... 49 | enum DataModel { 50 | DOCUMENT = 1; 51 | TABLE = 2; 52 | }; 53 | 54 | // collection 55 | message Collection { 56 | required string name = 1; 57 | optional string schema = 2; 58 | } 59 | 60 | // limit 61 | // 62 | // :param row_count: maximum rows to filter 63 | // :param offset: maximum rows to skip before applying the row_count 64 | message Limit { 65 | required uint64 row_count = 1; 66 | optional uint64 offset = 2; 67 | } 68 | 69 | // sort order 70 | message Order { 71 | enum Direction { 72 | ASC = 1; 73 | DESC = 2; 74 | }; 75 | 76 | required Mysqlx.Expr.Expr expr = 1; 77 | optional Direction direction = 2 [ default=ASC ]; 78 | } 79 | 80 | // update operations 81 | // 82 | // :param source: specification of the value to be updated 83 | // if data_model is TABLE, a column name may be specified and also a document path, if the column has type JSON 84 | // if data_model is DOCUMENT, only document paths are allowed 85 | // in both cases, schema and table must be not set 86 | // :param operation: the type of operation to be performed 87 | // :param value: an expression to be computed as the new value for the operation 88 | message UpdateOperation { 89 | enum UpdateType { 90 | SET = 1; // only allowed for TABLE 91 | ITEM_REMOVE = 2; // no value (removes the identified path from a object or array) 92 | ITEM_SET = 3; // sets the new value on the identified path 93 | ITEM_REPLACE = 4; // replaces a value if the path exists 94 | ITEM_MERGE = 5; // source and value must be documents 95 | ARRAY_INSERT = 6; // insert the value in the array at the index identified in the source path 96 | ARRAY_APPEND = 7; // append the value on the array at the identified path 97 | } 98 | required Mysqlx.Expr.ColumnIdentifier source = 1; 99 | required UpdateType operation = 2; 100 | optional Mysqlx.Expr.Expr value = 3; 101 | } 102 | 103 | // Find Documents/Rows in a Collection/Table 104 | // 105 | // .. uml:: 106 | // 107 | // client -> server: Find 108 | // ... one or more Resultset ... 109 | // 110 | // :param collection: collection to insert into 111 | // :param data_model: datamodel that the operations refer to 112 | // :param projection: list of column projections that shall be returned 113 | // :param args: values for parameters used in filter expression 114 | // :param criteria: filter criteria 115 | // :param limit: numbers of rows that shall be skipped and returned 116 | // :param order: sort-order in which the rows/document shall be returned in 117 | // :param grouping: column expression list for aggregation (GROUP BY) 118 | // :param grouping_criteria: filter criteria for aggregated groups 119 | // :Returns: :protobuf:msg:`Mysqlx.Resultset::` 120 | message Find { 121 | required Collection collection = 2; 122 | 123 | optional DataModel data_model = 3; 124 | repeated Projection projection = 4; 125 | optional Mysqlx.Expr.Expr criteria = 5; 126 | repeated Mysqlx.Datatypes.Scalar args = 11; 127 | optional Limit limit = 6; 128 | repeated Order order = 7; 129 | repeated Mysqlx.Expr.Expr grouping = 8; 130 | optional Mysqlx.Expr.Expr grouping_criteria = 9; 131 | }; 132 | 133 | // Insert documents/rows into a collection/table 134 | // 135 | // :param collection: collection to insert into 136 | // :param data_model: datamodel that the operations refer to 137 | // :param projection: name of the columns to insert data into (empty if data_model is DOCUMENT) 138 | // :param row: set of rows to insert into the collection/table (a single expression with a JSON document literal or an OBJECT expression) 139 | // :param args: values for parameters used in row expressions 140 | // :Returns: :protobuf:msg:`Mysqlx.Resultset::` 141 | message Insert { 142 | required Collection collection = 1; 143 | 144 | optional DataModel data_model = 2; 145 | repeated Column projection = 3; 146 | 147 | message TypedRow { 148 | repeated Mysqlx.Expr.Expr field = 1; 149 | }; 150 | repeated TypedRow row = 4; 151 | repeated Mysqlx.Datatypes.Scalar args = 5; 152 | }; 153 | 154 | // Update documents/rows in a collection/table 155 | // 156 | // :param collection: collection to change 157 | // :param data_model: datamodel that the operations refer to 158 | // :param criteria: filter expression to match rows that the operations will apply on 159 | // :param args: values for parameters used in filter expression 160 | // :param limit: limits the number of rows to match 161 | // :param order: specifies order of matched rows 162 | // :param operation: list of operations to be applied. Valid operations will depend on the data_model. 163 | // :Returns: :protobuf:msg:`Mysqlx.Resultset::` 164 | message Update { 165 | required Collection collection = 2; 166 | 167 | optional DataModel data_model = 3; 168 | optional Mysqlx.Expr.Expr criteria = 4; 169 | repeated Mysqlx.Datatypes.Scalar args = 8; 170 | optional Limit limit = 5; 171 | repeated Order order = 6; 172 | 173 | repeated UpdateOperation operation = 7; 174 | }; 175 | 176 | // Delete documents/rows from a Collection/Table 177 | // 178 | // :param collection: collection to change 179 | // :param data_model: datamodel that the operations refer to 180 | // :param criteria: filter expression to match rows that the operations will apply on 181 | // :param args: values for parameters used in filter expression 182 | // :param limit: limits the number of rows to match 183 | // :param order: specifies order of matched rows 184 | // :Returns: :protobuf:msg:`Mysqlx.Resultset::` 185 | message Delete { 186 | required Collection collection = 1; 187 | 188 | optional DataModel data_model = 2; 189 | optional Mysqlx.Expr.Expr criteria = 3; 190 | repeated Mysqlx.Datatypes.Scalar args = 6; 191 | optional Limit limit = 4; 192 | repeated Order order = 5; 193 | }; 194 | 195 | -------------------------------------------------------------------------------- /Mysqlx_Datatypes/mysqlx_datatypes.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | package Mysqlx.Datatypes; 24 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 25 | 26 | 27 | // a scalar 28 | message Scalar { 29 | // a string with a charset/collation 30 | message String { 31 | required bytes value = 1; 32 | optional uint64 collation = 2; 33 | }; 34 | 35 | // an opaque octet sequence, with an optional content_type 36 | // See ``Mysqlx.Resultset.ColumnMetadata`` for list of known values. 37 | message Octets { 38 | required bytes value = 1; 39 | optional uint32 content_type = 2; 40 | }; 41 | 42 | enum Type { 43 | V_SINT = 1; 44 | V_UINT = 2; 45 | V_NULL = 3; 46 | V_OCTETS = 4; 47 | V_DOUBLE = 5; 48 | V_FLOAT = 6; 49 | V_BOOL = 7; 50 | V_STRING = 8; 51 | }; 52 | 53 | required Type type = 1; 54 | 55 | optional sint64 v_signed_int = 2; 56 | optional uint64 v_unsigned_int = 3; 57 | // 4 is unused, was Null which doesn't have a storage anymore 58 | optional Octets v_octets = 5; 59 | optional double v_double = 6; 60 | optional float v_float = 7; 61 | optional bool v_bool = 8; 62 | optional String v_string = 9; 63 | } 64 | 65 | // a object 66 | message Object { 67 | message ObjectField { 68 | required string key = 1; 69 | required Any value = 2; 70 | } 71 | 72 | repeated ObjectField fld = 1; 73 | } 74 | 75 | // a Array 76 | message Array { 77 | repeated Any value = 1; 78 | } 79 | 80 | // a helper to allow all field types 81 | message Any { 82 | enum Type { 83 | SCALAR = 1; 84 | OBJECT = 2; 85 | ARRAY = 3; 86 | }; 87 | 88 | required Type type = 1; 89 | 90 | optional Scalar scalar = 2; 91 | optional Object obj = 3; 92 | optional Array array = 4; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /Mysqlx_Expect/Mysql_Expect/mysqlx_expect.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: mysqlx_expect.proto 3 | // DO NOT EDIT! 4 | 5 | /* 6 | Package Mysqlx_Expect is a generated protocol buffer package. 7 | 8 | Expect operations 9 | 10 | It is generated from these files: 11 | mysqlx_expect.proto 12 | 13 | It has these top-level messages: 14 | Open 15 | Close 16 | */ 17 | package Mysqlx_Expect 18 | 19 | import proto "github.com/golang/protobuf/proto" 20 | import fmt "fmt" 21 | import math "math" 22 | 23 | // Reference imports to suppress errors if they are not otherwise used. 24 | var _ = proto.Marshal 25 | var _ = fmt.Errorf 26 | var _ = math.Inf 27 | 28 | // This is a compile-time assertion to ensure that this generated file 29 | // is compatible with the proto package it is being compiled against. 30 | const _ = proto.ProtoPackageIsVersion1 31 | 32 | type Open_CtxOperation int32 33 | 34 | const ( 35 | // copy the operations from the parent Expect-block 36 | Open_EXPECT_CTX_COPY_PREV Open_CtxOperation = 0 37 | // start with a empty set of operations 38 | Open_EXPECT_CTX_EMPTY Open_CtxOperation = 1 39 | ) 40 | 41 | var Open_CtxOperation_name = map[int32]string{ 42 | 0: "EXPECT_CTX_COPY_PREV", 43 | 1: "EXPECT_CTX_EMPTY", 44 | } 45 | var Open_CtxOperation_value = map[string]int32{ 46 | "EXPECT_CTX_COPY_PREV": 0, 47 | "EXPECT_CTX_EMPTY": 1, 48 | } 49 | 50 | func (x Open_CtxOperation) Enum() *Open_CtxOperation { 51 | p := new(Open_CtxOperation) 52 | *p = x 53 | return p 54 | } 55 | func (x Open_CtxOperation) String() string { 56 | return proto.EnumName(Open_CtxOperation_name, int32(x)) 57 | } 58 | func (x *Open_CtxOperation) UnmarshalJSON(data []byte) error { 59 | value, err := proto.UnmarshalJSONEnum(Open_CtxOperation_value, data, "Open_CtxOperation") 60 | if err != nil { 61 | return err 62 | } 63 | *x = Open_CtxOperation(value) 64 | return nil 65 | } 66 | func (Open_CtxOperation) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } 67 | 68 | type Open_Condition_ConditionOperation int32 69 | 70 | const ( 71 | // set the condition 72 | // 73 | // set, if not set 74 | // overwrite, if set 75 | Open_Condition_EXPECT_OP_SET Open_Condition_ConditionOperation = 0 76 | // unset the condition 77 | Open_Condition_EXPECT_OP_UNSET Open_Condition_ConditionOperation = 1 78 | ) 79 | 80 | var Open_Condition_ConditionOperation_name = map[int32]string{ 81 | 0: "EXPECT_OP_SET", 82 | 1: "EXPECT_OP_UNSET", 83 | } 84 | var Open_Condition_ConditionOperation_value = map[string]int32{ 85 | "EXPECT_OP_SET": 0, 86 | "EXPECT_OP_UNSET": 1, 87 | } 88 | 89 | func (x Open_Condition_ConditionOperation) Enum() *Open_Condition_ConditionOperation { 90 | p := new(Open_Condition_ConditionOperation) 91 | *p = x 92 | return p 93 | } 94 | func (x Open_Condition_ConditionOperation) String() string { 95 | return proto.EnumName(Open_Condition_ConditionOperation_name, int32(x)) 96 | } 97 | func (x *Open_Condition_ConditionOperation) UnmarshalJSON(data []byte) error { 98 | value, err := proto.UnmarshalJSONEnum(Open_Condition_ConditionOperation_value, data, "Open_Condition_ConditionOperation") 99 | if err != nil { 100 | return err 101 | } 102 | *x = Open_Condition_ConditionOperation(value) 103 | return nil 104 | } 105 | func (Open_Condition_ConditionOperation) EnumDescriptor() ([]byte, []int) { 106 | return fileDescriptor0, []int{0, 0, 0} 107 | } 108 | 109 | // open an Expect block and set/unset the conditions that have to be fulfilled 110 | // 111 | // if any of the conditions fail, all enclosed messages will fail with 112 | // a Mysqlx.Error message. 113 | // 114 | // :returns: :protobuf:msg:`Mysqlx::Ok` on success, :protobuf:msg:`Mysqlx::Error` on error 115 | // 116 | type Open struct { 117 | Op *Open_CtxOperation `protobuf:"varint,1,opt,name=op,enum=Mysqlx.Expect.Open_CtxOperation,def=0" json:"op,omitempty"` 118 | Cond []*Open_Condition `protobuf:"bytes,2,rep,name=cond" json:"cond,omitempty"` 119 | XXX_unrecognized []byte `json:"-"` 120 | } 121 | 122 | func (m *Open) Reset() { *m = Open{} } 123 | func (m *Open) String() string { return proto.CompactTextString(m) } 124 | func (*Open) ProtoMessage() {} 125 | func (*Open) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 126 | 127 | const Default_Open_Op Open_CtxOperation = Open_EXPECT_CTX_COPY_PREV 128 | 129 | func (m *Open) GetOp() Open_CtxOperation { 130 | if m != nil && m.Op != nil { 131 | return *m.Op 132 | } 133 | return Default_Open_Op 134 | } 135 | 136 | func (m *Open) GetCond() []*Open_Condition { 137 | if m != nil { 138 | return m.Cond 139 | } 140 | return nil 141 | } 142 | 143 | type Open_Condition struct { 144 | ConditionKey *uint32 `protobuf:"varint,1,req,name=condition_key" json:"condition_key,omitempty"` 145 | ConditionValue []byte `protobuf:"bytes,2,opt,name=condition_value" json:"condition_value,omitempty"` 146 | Op *Open_Condition_ConditionOperation `protobuf:"varint,3,opt,name=op,enum=Mysqlx.Expect.Open_Condition_ConditionOperation,def=0" json:"op,omitempty"` 147 | XXX_unrecognized []byte `json:"-"` 148 | } 149 | 150 | func (m *Open_Condition) Reset() { *m = Open_Condition{} } 151 | func (m *Open_Condition) String() string { return proto.CompactTextString(m) } 152 | func (*Open_Condition) ProtoMessage() {} 153 | func (*Open_Condition) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } 154 | 155 | const Default_Open_Condition_Op Open_Condition_ConditionOperation = Open_Condition_EXPECT_OP_SET 156 | 157 | func (m *Open_Condition) GetConditionKey() uint32 { 158 | if m != nil && m.ConditionKey != nil { 159 | return *m.ConditionKey 160 | } 161 | return 0 162 | } 163 | 164 | func (m *Open_Condition) GetConditionValue() []byte { 165 | if m != nil { 166 | return m.ConditionValue 167 | } 168 | return nil 169 | } 170 | 171 | func (m *Open_Condition) GetOp() Open_Condition_ConditionOperation { 172 | if m != nil && m.Op != nil { 173 | return *m.Op 174 | } 175 | return Default_Open_Condition_Op 176 | } 177 | 178 | // close a Expect block 179 | // 180 | // closing a Expect block restores the state of the previous Expect block 181 | // for the following messages 182 | // 183 | // :returns: :protobuf:msg:`Mysqlx::Ok` on success, :protobuf:msg:`Mysqlx::Error` on error 184 | type Close struct { 185 | XXX_unrecognized []byte `json:"-"` 186 | } 187 | 188 | func (m *Close) Reset() { *m = Close{} } 189 | func (m *Close) String() string { return proto.CompactTextString(m) } 190 | func (*Close) ProtoMessage() {} 191 | func (*Close) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 192 | 193 | func init() { 194 | proto.RegisterType((*Open)(nil), "Mysqlx.Expect.Open") 195 | proto.RegisterType((*Open_Condition)(nil), "Mysqlx.Expect.Open.Condition") 196 | proto.RegisterType((*Close)(nil), "Mysqlx.Expect.Close") 197 | proto.RegisterEnum("Mysqlx.Expect.Open_CtxOperation", Open_CtxOperation_name, Open_CtxOperation_value) 198 | proto.RegisterEnum("Mysqlx.Expect.Open_Condition_ConditionOperation", Open_Condition_ConditionOperation_name, Open_Condition_ConditionOperation_value) 199 | } 200 | 201 | var fileDescriptor0 = []byte{ 202 | // 283 bytes of a gzipped FileDescriptorProto 203 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0xce, 0xad, 0x2c, 0x2e, 204 | 0xcc, 0xa9, 0x88, 0x4f, 0xad, 0x28, 0x48, 0x4d, 0x2e, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 205 | 0xe2, 0xf5, 0x05, 0x0b, 0xea, 0xb9, 0x82, 0x05, 0x95, 0x1a, 0x98, 0xb9, 0x58, 0xfc, 0x0b, 0x52, 206 | 0xf3, 0x84, 0x9c, 0xb8, 0x98, 0xf2, 0x0b, 0x24, 0x18, 0x15, 0x18, 0x35, 0xf8, 0x8c, 0x14, 0xf4, 207 | 0x50, 0x14, 0xe9, 0x81, 0x14, 0xe8, 0x39, 0x97, 0x54, 0x00, 0xe9, 0xa2, 0xc4, 0x92, 0xcc, 0xfc, 208 | 0x3c, 0x2b, 0x11, 0xd7, 0x88, 0x00, 0x57, 0xe7, 0x90, 0x78, 0xe7, 0x90, 0x88, 0x78, 0x67, 0xff, 209 | 0x80, 0xc8, 0xf8, 0x80, 0x20, 0xd7, 0x30, 0x21, 0x6d, 0x2e, 0x96, 0xe4, 0xfc, 0xbc, 0x14, 0x09, 210 | 0x26, 0x05, 0x66, 0x0d, 0x6e, 0x23, 0x59, 0xac, 0xa6, 0x00, 0xe5, 0x33, 0x41, 0x46, 0x48, 0x1d, 211 | 0x63, 0xe4, 0xe2, 0x84, 0xf3, 0x84, 0x44, 0xb9, 0x78, 0x93, 0x61, 0x9c, 0xf8, 0xec, 0xd4, 0x4a, 212 | 0xa0, 0x4b, 0x98, 0x34, 0x78, 0x85, 0xc4, 0xb9, 0xf8, 0x11, 0xc2, 0x65, 0x89, 0x39, 0xa5, 0xa9, 213 | 0x40, 0xc3, 0x19, 0x35, 0x78, 0x84, 0xbc, 0xc1, 0xce, 0x65, 0x06, 0x3b, 0xd7, 0x00, 0xaf, 0x45, 214 | 0x08, 0x16, 0xc2, 0xf9, 0xbc, 0x50, 0xe7, 0xfb, 0x07, 0xc4, 0x07, 0xbb, 0x86, 0x28, 0xd9, 0x70, 215 | 0x09, 0x61, 0x2a, 0x12, 0x12, 0xe4, 0x42, 0x55, 0x26, 0xc0, 0x20, 0x24, 0xcc, 0xc5, 0x8f, 0x10, 216 | 0x0a, 0xf5, 0x03, 0x09, 0x32, 0x2a, 0xd9, 0x71, 0xf1, 0x20, 0x87, 0x8d, 0x90, 0x04, 0x17, 0xd6, 217 | 0xd0, 0x01, 0x6a, 0x17, 0xe1, 0x12, 0x40, 0x92, 0x71, 0xf5, 0x0d, 0x08, 0x89, 0x04, 0xea, 0x67, 218 | 0xe7, 0x62, 0x75, 0xce, 0xc9, 0x2f, 0x4e, 0x75, 0x92, 0xe3, 0x92, 0x49, 0xce, 0xcf, 0xd5, 0x03, 219 | 0xc7, 0x9a, 0x5e, 0x72, 0x16, 0x84, 0x51, 0x01, 0x89, 0xb7, 0xa4, 0xd2, 0x34, 0x40, 0x00, 0x00, 220 | 0x00, 0xff, 0xff, 0xa1, 0xdf, 0xfe, 0xb9, 0xd0, 0x01, 0x00, 0x00, 221 | } 222 | -------------------------------------------------------------------------------- /Mysqlx_Expr/mysqlx_expr.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | // Expression syntax 24 | // 25 | // expr is the fundamental structure in various places 26 | // of the SQL language: 27 | // 28 | // * ``SELECT AS ...`` 29 | // * ``WHERE `` 30 | // 31 | // The structures can be used to: 32 | // 33 | // * build an Item-tree in the MySQL Server 34 | // * generate SQL from it 35 | // * use as filter condition in CRUD's Find(), Update() and Delete() calls. 36 | package Mysqlx.Expr; 37 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 38 | 39 | import "mysqlx_datatypes.proto"; 40 | 41 | // Expressions 42 | // 43 | // the "root" of the expression tree 44 | // 45 | // .. productionlist:: 46 | // expr: `operator` | 47 | // : `identifier` | 48 | // : `function_call` | 49 | // : variable | 50 | // : `literal` | 51 | // : placeholder 52 | // 53 | // If expression type is PLACEHOLDER then it refers to the value of a parameter 54 | // specified when executing a statement (see `args` field of `StmtExecute` command). 55 | // Field `position` (which must be present for such an expression) gives 0-based 56 | // position of the parameter in the parameter list. 57 | // 58 | message Expr { 59 | enum Type { 60 | IDENT = 1; 61 | LITERAL = 2; 62 | VARIABLE = 3; 63 | FUNC_CALL = 4; 64 | OPERATOR = 5; 65 | PLACEHOLDER = 6; 66 | OBJECT = 7; 67 | ARRAY = 8; 68 | }; 69 | 70 | required Type type = 1; 71 | 72 | optional ColumnIdentifier identifier = 2; 73 | optional string variable = 3; 74 | optional Mysqlx.Datatypes.Scalar literal = 4; 75 | optional FunctionCall function_call = 5; 76 | optional Operator operator = 6; 77 | optional uint32 position = 7; 78 | optional Object object = 8; 79 | optional Array array = 9; 80 | } 81 | 82 | // identifier: name, schame.name 83 | // 84 | // .. productionlist:: 85 | // identifier: string "." string | 86 | // : string 87 | message Identifier { 88 | required string name = 1; 89 | optional string schema_name = 2; 90 | } 91 | 92 | // DocumentPathItem 93 | // 94 | // .. productionlist:: 95 | // document_path: path_item | path_item document_path 96 | // path_item : member | array_index | "**" 97 | // member : "." string | "." "*" 98 | // array_index : "[" number "]" | "[" "*" "]" 99 | // 100 | message DocumentPathItem { 101 | enum Type { 102 | MEMBER = 1; // .member 103 | MEMBER_ASTERISK = 2; // .* 104 | ARRAY_INDEX = 3; // [index] 105 | ARRAY_INDEX_ASTERISK = 4; // [*] 106 | DOUBLE_ASTERISK = 5; // ** 107 | }; 108 | required Type type = 1; 109 | optional string value = 2; 110 | optional uint32 index = 3; 111 | } 112 | 113 | 114 | // col_identifier (table): col@doc_path, tbl.col@doc_path col, tbl.col, schema.tbl.col 115 | // col_identifier (document): doc_path 116 | // 117 | // .. productionlist:: 118 | // col_identifier: string "." string "." string | 119 | // : string "." string | 120 | // : string | 121 | // : string "." string "." string "@" document_path | 122 | // : string "." string "@" document_path | 123 | // : string "@" document_path | 124 | // : document_path 125 | // document_path: member | arrayLocation | doubleAsterisk 126 | // member = "." string | "." "*" 127 | // arrayLocation = "[" index "]" | "[" "*" "]" 128 | // doubleAsterisk = "**" 129 | // 130 | message ColumnIdentifier { 131 | repeated Mysqlx.Expr.DocumentPathItem document_path = 1; 132 | optional string name = 2; 133 | optional string table_name = 3; 134 | optional string schema_name = 4; 135 | } 136 | 137 | // function call: ``func(a, b, "1", 3)`` 138 | // 139 | // .. productionlist:: 140 | // function_call: `identifier` "(" [ `expr` ["," `expr` ]* ] ")" 141 | message FunctionCall { 142 | required Identifier name = 1; 143 | repeated Expr param = 2; 144 | } 145 | 146 | // operator: ``<<(a, b)`` 147 | // 148 | // .. note:: 149 | // 150 | // Non-authoritative list of operators implemented (case sensitive): 151 | // 152 | // Nullary 153 | // * ``*`` 154 | // * ``default`` 155 | // 156 | // Unary 157 | // * ``!`` 158 | // * ``sign_plus`` 159 | // * ``sign_minus`` 160 | // * ``~`` 161 | // 162 | // Binary 163 | // * ``&&`` 164 | // * ``||`` 165 | // * ``xor`` 166 | // * ``==`` 167 | // * ``!=`` 168 | // * ``>`` 169 | // * ``>=`` 170 | // * ``<`` 171 | // * ``<=`` 172 | // * ``&`` 173 | // * ``|`` 174 | // * ``^`` 175 | // * ``<<`` 176 | // * ``>>`` 177 | // * ``+`` 178 | // * ``-`` 179 | // * ``*`` 180 | // * ``/`` 181 | // * ``div`` 182 | // * ``%`` 183 | // * ``is`` 184 | // * ``is_not`` 185 | // * ``regexp`` 186 | // * ``not_regexp`` 187 | // * ``like`` 188 | // * ``not_like`` 189 | // * ``cast`` 190 | // 191 | // Using special representation, with more than 2 params 192 | // * ``in`` (param[0] IN (param[1], param[2], ...)) 193 | // * ``not_in`` (param[0] NOT IN (param[1], param[2], ...)) 194 | // 195 | // Ternary 196 | // * ``between`` 197 | // * ``between_not`` 198 | // * ``date_add`` 199 | // * ``date_sub`` 200 | // 201 | // Units for date_add/date_sub 202 | // * ``MICROSECOND`` 203 | // * ``SECOND`` 204 | // * ``MINUTE`` 205 | // * ``HOUR`` 206 | // * ``DAY`` 207 | // * ``WEEK`` 208 | // * ``MONTH`` 209 | // * ``QUARTER`` 210 | // * ``YEAR`` 211 | // * ``SECOND_MICROSECOND`` 212 | // * ``MINUTE_MICROSECOND`` 213 | // * ``MINUTE_SECOND`` 214 | // * ``HOUR_MICROSECOND`` 215 | // * ``HOUR_SECOND`` 216 | // * ``HOUR_MINUTE`` 217 | // * ``DAY_MICROSECOND`` 218 | // * ``DAY_SECOND`` 219 | // * ``DAY_MINUTE`` 220 | // * ``DAY_HOUR`` 221 | // 222 | // Types for cast 223 | // * ``BINARY[(N)]`` 224 | // * ``CHAR[(N)]`` 225 | // * ``DATE`` 226 | // * ``DATETIME`` 227 | // * ``DECIMAL[(M[,D])]`` 228 | // * ``JSON`` 229 | // * ``SIGNED [INTEGER]`` 230 | // * ``TIME`` 231 | // * ``UNSIGNED [INTEGER]`` 232 | // 233 | // .. productionlist:: 234 | // operator: `name` "(" [ `expr` ["," `expr` ]* ] ")" 235 | message Operator { 236 | required string name = 1; 237 | repeated Expr param = 2; 238 | } 239 | 240 | // an object (with expression values) 241 | message Object { 242 | message ObjectField { 243 | required string key = 1; 244 | required Expr value = 2; 245 | } 246 | 247 | repeated ObjectField fld = 1; 248 | } 249 | 250 | // a Array of expressions 251 | message Array { 252 | repeated Expr value = 1; 253 | } 254 | -------------------------------------------------------------------------------- /Mysqlx_Notice/mysqlx_notice.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | 20 | // tell protobuf 3.0 to use protobuf 2.x rules 21 | syntax = "proto2"; 22 | 23 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 24 | 25 | // Notices 26 | // 27 | // A notice 28 | // 29 | // * is sent from the server to the client 30 | // * may be global or relate to the current message sequence 31 | package Mysqlx.Notice; 32 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 33 | 34 | import "mysqlx_datatypes.proto"; 35 | 36 | // Common Frame for all Notices 37 | // 38 | // ===================================================== ===== 39 | // .type value 40 | // ===================================================== ===== 41 | // :protobuf:msg:`Mysqlx.Notice::Warning` 1 42 | // :protobuf:msg:`Mysqlx.Notice::SessionVariableChanged` 2 43 | // :protobuf:msg:`Mysqlx.Notice::SessionStateChanged` 3 44 | // ===================================================== ===== 45 | // 46 | // :param type: the type of the payload 47 | // :param payload: the payload of the notification 48 | // :param scope: global or local notification 49 | // 50 | message Frame { 51 | enum Scope { 52 | GLOBAL = 1; 53 | LOCAL = 2; 54 | }; 55 | required uint32 type = 1; 56 | optional Scope scope = 2 [ default = GLOBAL ]; 57 | optional bytes payload = 3; 58 | } 59 | 60 | // Server-side warnings and notes 61 | // 62 | // ``.scope`` == ``local`` 63 | // ``.level``, ``.code`` and ``.msg`` map the content of 64 | // 65 | // .. code-block:: sql 66 | // 67 | // SHOW WARNINGS 68 | // 69 | // ``.scope`` == ``global`` 70 | // (undefined) will be used for global, unstructured messages like: 71 | // 72 | // * server is shutting down 73 | // * a node disconnected from group 74 | // * schema or table dropped 75 | // 76 | // ========================================== ======================= 77 | // :protobuf:msg:`Mysqlx.Notice::Frame` field value 78 | // ========================================== ======================= 79 | // ``.type`` 1 80 | // ``.scope`` ``local`` or ``global`` 81 | // ========================================== ======================= 82 | // 83 | // :param level: warning level: Note or Warning 84 | // :param code: warning code 85 | // :param msg: warning message 86 | message Warning { 87 | enum Level { 88 | NOTE = 1; 89 | WARNING = 2; 90 | ERROR = 3; 91 | }; 92 | optional Level level = 1 [ default = WARNING ]; 93 | required uint32 code = 2; 94 | required string msg = 3; 95 | } 96 | 97 | // Notify clients about changes to the current session variables 98 | // 99 | // Every change to a variable that is accessable through: 100 | // 101 | // .. code-block:: sql 102 | // 103 | // SHOW SESSION VARIABLES 104 | // 105 | // ========================================== ========= 106 | // :protobuf:msg:`Mysqlx.Notice::Frame` field value 107 | // ========================================== ========= 108 | // ``.type`` 2 109 | // ``.scope`` ``local`` 110 | // ========================================== ========= 111 | // 112 | // :param namespace: namespace that param belongs to 113 | // :param param: name of the variable 114 | // :param value: the changed value of param 115 | message SessionVariableChanged { 116 | required string param = 1; 117 | optional Mysqlx.Datatypes.Scalar value = 2; 118 | } 119 | 120 | 121 | // Notify clients about changes to the internal session state 122 | // 123 | // ========================================== ========= 124 | // :protobuf:msg:`Mysqlx.Notice::Frame` field value 125 | // ========================================== ========= 126 | // ``.type`` 3 127 | // ``.scope`` ``local`` 128 | // ========================================== ========= 129 | // 130 | // :param param: parameter key 131 | // :param value: updated value 132 | message SessionStateChanged { 133 | enum Parameter { 134 | CURRENT_SCHEMA = 1; 135 | ACCOUNT_EXPIRED = 2; 136 | GENERATED_INSERT_ID = 3; 137 | ROWS_AFFECTED = 4; 138 | ROWS_FOUND = 5; 139 | ROWS_MATCHED = 6; 140 | TRX_COMMITTED = 7; 141 | TRX_ROLLEDBACK = 9; 142 | PRODUCED_MESSAGE = 10; 143 | CLIENT_ID_ASSIGNED = 11; 144 | // .. more to be added 145 | } 146 | required Parameter param = 1; 147 | optional Mysqlx.Datatypes.Scalar value = 2; 148 | } 149 | 150 | -------------------------------------------------------------------------------- /Mysqlx_Session/mysqlx_session.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: mysqlx_session.proto 3 | // DO NOT EDIT! 4 | 5 | /* 6 | Package Mysqlx_Session is a generated protocol buffer package. 7 | 8 | Messages to manage Sessions 9 | 10 | .. uml:: 11 | 12 | == session start == 13 | Client -> Server: AuthenticateStart 14 | opt 15 | Server --> Client: AuthenticateContinue 16 | Client --> Server: AuthenticateContinue 17 | end 18 | alt 19 | Server --> Client: AuthenticateOk 20 | else 21 | Server --> Client: Error 22 | end 23 | ... 24 | == session reset == 25 | Client -> Server: Reset 26 | Server --> Client: Ok 27 | == session end == 28 | Client -> Server: Close 29 | Server --> Client: Ok 30 | 31 | 32 | It is generated from these files: 33 | mysqlx_session.proto 34 | 35 | It has these top-level messages: 36 | AuthenticateStart 37 | AuthenticateContinue 38 | AuthenticateOk 39 | Reset 40 | Close 41 | */ 42 | package Mysqlx_Session 43 | 44 | import proto "github.com/golang/protobuf/proto" 45 | import fmt "fmt" 46 | import math "math" 47 | 48 | // Reference imports to suppress errors if they are not otherwise used. 49 | var _ = proto.Marshal 50 | var _ = fmt.Errorf 51 | var _ = math.Inf 52 | 53 | // This is a compile-time assertion to ensure that this generated file 54 | // is compatible with the proto package it is being compiled against. 55 | const _ = proto.ProtoPackageIsVersion1 56 | 57 | // the initial message send from the client to the server to start the 58 | // authentication proccess 59 | // 60 | // :param mech_name: authentication mechanism name 61 | // :param auth_data: authentication data 62 | // :param initial_response: initial response 63 | // :Returns: :protobuf:msg:`Mysqlx.Session::AuthenticateContinue` 64 | type AuthenticateStart struct { 65 | MechName *string `protobuf:"bytes,1,req,name=mech_name" json:"mech_name,omitempty"` 66 | AuthData []byte `protobuf:"bytes,2,opt,name=auth_data" json:"auth_data,omitempty"` 67 | InitialResponse []byte `protobuf:"bytes,3,opt,name=initial_response" json:"initial_response,omitempty"` 68 | XXX_unrecognized []byte `json:"-"` 69 | } 70 | 71 | func (m *AuthenticateStart) Reset() { *m = AuthenticateStart{} } 72 | func (m *AuthenticateStart) String() string { return proto.CompactTextString(m) } 73 | func (*AuthenticateStart) ProtoMessage() {} 74 | func (*AuthenticateStart) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 75 | 76 | func (m *AuthenticateStart) GetMechName() string { 77 | if m != nil && m.MechName != nil { 78 | return *m.MechName 79 | } 80 | return "" 81 | } 82 | 83 | func (m *AuthenticateStart) GetAuthData() []byte { 84 | if m != nil { 85 | return m.AuthData 86 | } 87 | return nil 88 | } 89 | 90 | func (m *AuthenticateStart) GetInitialResponse() []byte { 91 | if m != nil { 92 | return m.InitialResponse 93 | } 94 | return nil 95 | } 96 | 97 | // send by client or server after a :protobuf:msg:`Mysqlx.Session::AuthenticateStart` to 98 | // exchange more auth data 99 | // 100 | // :param auth_data: authentication data 101 | // :Returns: :protobuf:msg:`Mysqlx.Session::AuthenticateContinue` 102 | type AuthenticateContinue struct { 103 | AuthData []byte `protobuf:"bytes,1,req,name=auth_data" json:"auth_data,omitempty"` 104 | XXX_unrecognized []byte `json:"-"` 105 | } 106 | 107 | func (m *AuthenticateContinue) Reset() { *m = AuthenticateContinue{} } 108 | func (m *AuthenticateContinue) String() string { return proto.CompactTextString(m) } 109 | func (*AuthenticateContinue) ProtoMessage() {} 110 | func (*AuthenticateContinue) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 111 | 112 | func (m *AuthenticateContinue) GetAuthData() []byte { 113 | if m != nil { 114 | return m.AuthData 115 | } 116 | return nil 117 | } 118 | 119 | // sent by the server after successful authentication 120 | // 121 | // :param auth_data: authentication data 122 | type AuthenticateOk struct { 123 | AuthData []byte `protobuf:"bytes,1,opt,name=auth_data" json:"auth_data,omitempty"` 124 | XXX_unrecognized []byte `json:"-"` 125 | } 126 | 127 | func (m *AuthenticateOk) Reset() { *m = AuthenticateOk{} } 128 | func (m *AuthenticateOk) String() string { return proto.CompactTextString(m) } 129 | func (*AuthenticateOk) ProtoMessage() {} 130 | func (*AuthenticateOk) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } 131 | 132 | func (m *AuthenticateOk) GetAuthData() []byte { 133 | if m != nil { 134 | return m.AuthData 135 | } 136 | return nil 137 | } 138 | 139 | // reset the current session 140 | // 141 | // :Returns: :protobuf:msg:`Mysqlx::Ok` 142 | type Reset struct { 143 | XXX_unrecognized []byte `json:"-"` 144 | } 145 | 146 | func (m *Reset) Reset() { *m = Reset{} } 147 | func (m *Reset) String() string { return proto.CompactTextString(m) } 148 | func (*Reset) ProtoMessage() {} 149 | func (*Reset) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } 150 | 151 | // close the current session 152 | // 153 | // :Returns: :protobuf:msg:`Mysqlx::Ok` 154 | type Close struct { 155 | XXX_unrecognized []byte `json:"-"` 156 | } 157 | 158 | func (m *Close) Reset() { *m = Close{} } 159 | func (m *Close) String() string { return proto.CompactTextString(m) } 160 | func (*Close) ProtoMessage() {} 161 | func (*Close) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } 162 | 163 | func init() { 164 | proto.RegisterType((*AuthenticateStart)(nil), "Mysqlx.Session.AuthenticateStart") 165 | proto.RegisterType((*AuthenticateContinue)(nil), "Mysqlx.Session.AuthenticateContinue") 166 | proto.RegisterType((*AuthenticateOk)(nil), "Mysqlx.Session.AuthenticateOk") 167 | proto.RegisterType((*Reset)(nil), "Mysqlx.Session.Reset") 168 | proto.RegisterType((*Close)(nil), "Mysqlx.Session.Close") 169 | } 170 | 171 | var fileDescriptor0 = []byte{ 172 | // 197 bytes of a gzipped FileDescriptorProto 173 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x5c, 0x8f, 0x41, 0x4b, 0x86, 0x40, 174 | 0x10, 0x86, 0xf9, 0xbe, 0x88, 0x70, 0x10, 0x49, 0xf1, 0xb0, 0x87, 0x08, 0xb1, 0x8b, 0x5d, 0xf6, 175 | 0x3f, 0x94, 0xe7, 0x08, 0xf2, 0x07, 0x2c, 0xdb, 0x36, 0xe1, 0x96, 0xbb, 0x6b, 0xce, 0x08, 0xf6, 176 | 0xef, 0x73, 0xf5, 0x62, 0xdf, 0xed, 0xe5, 0x99, 0x87, 0x07, 0x06, 0x4a, 0xf7, 0x4b, 0x3f, 0xc3, 177 | 0xa2, 0x08, 0x89, 0x6c, 0xf0, 0x72, 0x9c, 0x02, 0x87, 0x22, 0x7b, 0xd9, 0xa8, 0xec, 0x76, 0x5a, 178 | 0x77, 0x90, 0x3f, 0xcd, 0xdc, 0xa3, 0x67, 0x6b, 0x34, 0x63, 0xc7, 0x7a, 0xe2, 0x22, 0x87, 0xc4, 179 | 0xa1, 0xe9, 0x95, 0xd7, 0x0e, 0xc5, 0xa9, 0x3a, 0x37, 0x49, 0x44, 0x7a, 0xf5, 0xd4, 0x87, 0x66, 180 | 0x2d, 0xce, 0xd5, 0xa9, 0x49, 0x0b, 0x01, 0xb7, 0xd6, 0x5b, 0xb6, 0x7a, 0x50, 0x13, 0xd2, 0x18, 181 | 0x3c, 0xa1, 0xb8, 0x8a, 0x97, 0xfa, 0x11, 0xca, 0x63, 0xb4, 0x0d, 0xeb, 0xf0, 0x33, 0xfe, 0x8f, 182 | 0xc4, 0x6e, 0x5a, 0x3f, 0x40, 0x76, 0x54, 0x5f, 0xbf, 0x2f, 0xa5, 0xd8, 0xbb, 0x81, 0xeb, 0x37, 183 | 0x24, 0xe4, 0x38, 0xda, 0x21, 0x10, 0x3e, 0xdf, 0xc3, 0x9d, 0x09, 0x4e, 0x6e, 0x2f, 0x4a, 0xf3, 184 | 0xb5, 0x8f, 0x65, 0xff, 0xf1, 0x7d, 0xfe, 0xfc, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x4c, 0x01, 0xbc, 185 | 0xe9, 0xfd, 0x00, 0x00, 0x00, 186 | } 187 | -------------------------------------------------------------------------------- /Mysqlx_Session/mysqlx_session.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | // Messages to manage Sessions 24 | // 25 | // .. uml:: 26 | // 27 | // == session start == 28 | // Client -> Server: AuthenticateStart 29 | // opt 30 | // Server --> Client: AuthenticateContinue 31 | // Client --> Server: AuthenticateContinue 32 | // end 33 | // alt 34 | // Server --> Client: AuthenticateOk 35 | // else 36 | // Server --> Client: Error 37 | // end 38 | // ... 39 | // == session reset == 40 | // Client -> Server: Reset 41 | // Server --> Client: Ok 42 | // == session end == 43 | // Client -> Server: Close 44 | // Server --> Client: Ok 45 | // 46 | package Mysqlx.Session; 47 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 48 | 49 | // the initial message send from the client to the server to start the 50 | // authentication proccess 51 | // 52 | // :param mech_name: authentication mechanism name 53 | // :param auth_data: authentication data 54 | // :param initial_response: initial response 55 | // :Returns: :protobuf:msg:`Mysqlx.Session::AuthenticateContinue` 56 | message AuthenticateStart { 57 | required string mech_name = 1; 58 | optional bytes auth_data = 2; 59 | optional bytes initial_response = 3; 60 | } 61 | 62 | // send by client or server after a :protobuf:msg:`Mysqlx.Session::AuthenticateStart` to 63 | // exchange more auth data 64 | // 65 | // :param auth_data: authentication data 66 | // :Returns: :protobuf:msg:`Mysqlx.Session::AuthenticateContinue` 67 | message AuthenticateContinue { 68 | required bytes auth_data = 1; 69 | } 70 | 71 | // sent by the server after successful authentication 72 | // 73 | // :param auth_data: authentication data 74 | message AuthenticateOk { 75 | optional bytes auth_data = 1; 76 | } 77 | 78 | // reset the current session 79 | // 80 | // :Returns: :protobuf:msg:`Mysqlx::Ok` 81 | message Reset { 82 | } 83 | 84 | // close the current session 85 | // 86 | // :Returns: :protobuf:msg:`Mysqlx::Ok` 87 | message Close { 88 | } 89 | 90 | -------------------------------------------------------------------------------- /Mysqlx_Sql/mysqlx_sql.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: mysqlx_sql.proto 3 | // DO NOT EDIT! 4 | 5 | /* 6 | Package Mysqlx_Sql is a generated protocol buffer package. 7 | 8 | Messages of the MySQL Package 9 | 10 | It is generated from these files: 11 | mysqlx_sql.proto 12 | 13 | It has these top-level messages: 14 | StmtExecute 15 | StmtExecuteOk 16 | */ 17 | package Mysqlx_Sql 18 | 19 | import proto "github.com/golang/protobuf/proto" 20 | import fmt "fmt" 21 | import math "math" 22 | import "github.com/sjmudd/go-mysqlx-driver/Mysqlx_Datatypes" 23 | 24 | // Reference imports to suppress errors if they are not otherwise used. 25 | var _ = proto.Marshal 26 | var _ = fmt.Errorf 27 | var _ = math.Inf 28 | 29 | // This is a compile-time assertion to ensure that this generated file 30 | // is compatible with the proto package it is being compiled against. 31 | const _ = proto.ProtoPackageIsVersion1 32 | 33 | // execute a statement in the given namespace 34 | // 35 | // .. uml:: 36 | // 37 | // client -> server: StmtExecute 38 | // ... zero or more Resultsets ... 39 | // server --> client: StmtExecuteOk 40 | // 41 | // Notices: 42 | // This message may generate a notice containing WARNINGs generated by its execution. 43 | // This message may generate a notice containing INFO messages generated by its execution. 44 | // 45 | // :param namespace: namespace of the statement to be executed 46 | // :param stmt: statement that shall be executed. 47 | // :param args: values for wildcard replacements 48 | // :param compact_metadata: send only type information for :protobuf:msg:`Mysqlx.Resultset::ColumnMetadata`, skipping names and others 49 | // :returns: 50 | // * zero or one :protobuf:msg:`Mysqlx.Resultset::` followed by :protobuf:msg:`Mysqlx.Sql::StmtExecuteOk` 51 | type StmtExecute struct { 52 | Namespace *string `protobuf:"bytes,3,opt,name=namespace,def=sql" json:"namespace,omitempty"` 53 | Stmt []byte `protobuf:"bytes,1,req,name=stmt" json:"stmt,omitempty"` 54 | Args []*Mysqlx_Datatypes.Any `protobuf:"bytes,2,rep,name=args" json:"args,omitempty"` 55 | CompactMetadata *bool `protobuf:"varint,4,opt,name=compact_metadata,def=0" json:"compact_metadata,omitempty"` 56 | XXX_unrecognized []byte `json:"-"` 57 | } 58 | 59 | func (m *StmtExecute) Reset() { *m = StmtExecute{} } 60 | func (m *StmtExecute) String() string { return proto.CompactTextString(m) } 61 | func (*StmtExecute) ProtoMessage() {} 62 | func (*StmtExecute) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 63 | 64 | const Default_StmtExecute_Namespace string = "sql" 65 | const Default_StmtExecute_CompactMetadata bool = false 66 | 67 | func (m *StmtExecute) GetNamespace() string { 68 | if m != nil && m.Namespace != nil { 69 | return *m.Namespace 70 | } 71 | return Default_StmtExecute_Namespace 72 | } 73 | 74 | func (m *StmtExecute) GetStmt() []byte { 75 | if m != nil { 76 | return m.Stmt 77 | } 78 | return nil 79 | } 80 | 81 | func (m *StmtExecute) GetArgs() []*Mysqlx_Datatypes.Any { 82 | if m != nil { 83 | return m.Args 84 | } 85 | return nil 86 | } 87 | 88 | func (m *StmtExecute) GetCompactMetadata() bool { 89 | if m != nil && m.CompactMetadata != nil { 90 | return *m.CompactMetadata 91 | } 92 | return Default_StmtExecute_CompactMetadata 93 | } 94 | 95 | // statement executed successful 96 | type StmtExecuteOk struct { 97 | XXX_unrecognized []byte `json:"-"` 98 | } 99 | 100 | func (m *StmtExecuteOk) Reset() { *m = StmtExecuteOk{} } 101 | func (m *StmtExecuteOk) String() string { return proto.CompactTextString(m) } 102 | func (*StmtExecuteOk) ProtoMessage() {} 103 | func (*StmtExecuteOk) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 104 | 105 | func init() { 106 | proto.RegisterType((*StmtExecute)(nil), "Mysqlx.Sql.StmtExecute") 107 | proto.RegisterType((*StmtExecuteOk)(nil), "Mysqlx.Sql.StmtExecuteOk") 108 | } 109 | 110 | var fileDescriptor0 = []byte{ 111 | // 199 bytes of a gzipped FileDescriptorProto 112 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0xc8, 0xad, 0x2c, 0x2e, 113 | 0xcc, 0xa9, 0x88, 0x07, 0x12, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x5c, 0xbe, 0x60, 0x11, 114 | 0xbd, 0xe0, 0xc2, 0x1c, 0x29, 0x31, 0xa8, 0x6c, 0x4a, 0x62, 0x49, 0x62, 0x49, 0x65, 0x41, 0x6a, 115 | 0x31, 0x44, 0x8d, 0x52, 0x25, 0x17, 0x77, 0x70, 0x49, 0x6e, 0x89, 0x6b, 0x45, 0x6a, 0x72, 0x69, 116 | 0x49, 0xaa, 0x90, 0x18, 0x17, 0x67, 0x5e, 0x62, 0x6e, 0x6a, 0x71, 0x41, 0x62, 0x72, 0xaa, 0x04, 117 | 0xb3, 0x02, 0xa3, 0x06, 0xa7, 0x15, 0x33, 0x50, 0x9f, 0x10, 0x0f, 0x17, 0x4b, 0x31, 0x50, 0x99, 118 | 0x04, 0xa3, 0x02, 0x93, 0x06, 0x8f, 0x90, 0x32, 0x17, 0x4b, 0x62, 0x51, 0x7a, 0xb1, 0x04, 0x93, 119 | 0x02, 0xb3, 0x06, 0xb7, 0x91, 0xa8, 0x1e, 0xd4, 0x1e, 0x17, 0xb8, 0xd9, 0x8e, 0x79, 0x95, 0x42, 120 | 0xf2, 0x5c, 0x02, 0xc9, 0xf9, 0xb9, 0x40, 0x83, 0x4a, 0xe2, 0x73, 0x53, 0x4b, 0x12, 0x41, 0x16, 121 | 0x4b, 0xb0, 0x00, 0x4d, 0xe4, 0xb0, 0x62, 0x4d, 0x4b, 0xcc, 0x29, 0x4e, 0x55, 0xe2, 0xe7, 0xe2, 122 | 0x45, 0xb2, 0xda, 0x3f, 0xdb, 0x49, 0x8e, 0x4b, 0x06, 0xa8, 0x43, 0x0f, 0xec, 0x52, 0xbd, 0xe4, 123 | 0x2c, 0x08, 0xa3, 0x02, 0xe2, 0xd0, 0xa4, 0xd2, 0x34, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc5, 124 | 0x35, 0x9a, 0x03, 0xe2, 0x00, 0x00, 0x00, 125 | } 126 | -------------------------------------------------------------------------------- /Mysqlx_Sql/mysqlx_sql.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | // Messages of the MySQL Package 24 | package Mysqlx.Sql; 25 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 26 | 27 | import "mysqlx_datatypes.proto"; 28 | 29 | // execute a statement in the given namespace 30 | // 31 | // .. uml:: 32 | // 33 | // client -> server: StmtExecute 34 | // ... zero or more Resultsets ... 35 | // server --> client: StmtExecuteOk 36 | // 37 | // Notices: 38 | // This message may generate a notice containing WARNINGs generated by its execution. 39 | // This message may generate a notice containing INFO messages generated by its execution. 40 | // 41 | // :param namespace: namespace of the statement to be executed 42 | // :param stmt: statement that shall be executed. 43 | // :param args: values for wildcard replacements 44 | // :param compact_metadata: send only type information for :protobuf:msg:`Mysqlx.Resultset::ColumnMetadata`, skipping names and others 45 | // :returns: 46 | // * zero or one :protobuf:msg:`Mysqlx.Resultset::` followed by :protobuf:msg:`Mysqlx.Sql::StmtExecuteOk` 47 | message StmtExecute { 48 | optional string namespace = 3 [ default = "sql" ]; 49 | required bytes stmt = 1; 50 | repeated Mysqlx.Datatypes.Any args = 2; 51 | optional bool compact_metadata = 4 [ default = false ]; 52 | } 53 | 54 | // statement executed successful 55 | message StmtExecuteOk { 56 | } 57 | 58 | -------------------------------------------------------------------------------- /PENDING_TESTS: -------------------------------------------------------------------------------- 1 | 2 | This lists the current tests done by the driver. 3 | or perhaps those that still need to be done. 4 | 5 | - connect in TLS mode works 6 | - send a packet which is too large to fit in mysqlx_max_allowed_packet 7 | - character set behaviour with "odd character sets" 8 | - figure out session character set 9 | - figure out change in settings 10 | - add a lot more unit tests 11 | - add tests for protocol failure situations 12 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a project I started to see what would be required to create 2 | a database/sql driver for the MySQL X protocol which was announced 3 | as part of the MySQL 5.7.12 server release. 4 | 5 | Documentation of the MySQL X protocol can be found here: 6 | https://dev.mysql.com/doc/internals/en/x-protocol.html. 7 | 8 | The code in this project is based very heavily on the original MySQL 9 | driver which was available on https://github.com/go-sql-driver/mysql 10 | as of the time that the MySQL X protocol was announced. 11 | 12 | Copyright (C) 2016 Simon J Mudd 13 | 14 | KNOWN ISSUES 15 | ============ 16 | 17 | This file lists the current known issues with the driver where I 18 | have bothered to find them. They can be split into the following 19 | types: 20 | 21 | [A] Issues with the driver itself 22 | --------------------------------- 23 | 24 | A1. Use of TLS mode is not possible yet if the appropriate seting 25 | is provided with the DSN. 26 | 27 | A2. No way to determine mysqlx_max_allowed_packet short of doing a 28 | full query after authorisation. This will add several round trips 29 | to the connection to get this information and is needed to set 30 | internal buffers but to also to prevent sending "too large packets" 31 | to the server. 32 | 33 | A3. No way to provide parameters to SQL queries 34 | 35 | A4. Support of understanding all datatypes is incomplete 36 | 37 | A5. Documentation of the mapping of the MySQL datatypes to the value 38 | provided back to the caller is not done. This is actually quite 39 | important to ensure that behavour is clearly defined. 40 | 41 | A6. No character set support. The X protocol is also rather vague 42 | about expectations for client and server initial setups which does 43 | not help. However some character data that's received from the MySQL 44 | server may require conversion to Go's utf8 etc and that is not done 45 | as the Go driver does not expose the server's internal datatypes. 46 | 47 | [B] Issues with using the X protocol using github.com/golang/go-sql-driver because the 48 | driver does not support the functionality needed by X protocol or expose them to the 49 | client. 50 | --------------------------------- 51 | 52 | B1. No way to disconnect a session and re-authenticate, allowed by 53 | X protocol but not by go driver. Close() is likely to drop the 54 | connection to ensure that previous state does not remain in the 55 | "previous connection". 56 | 57 | B2. No way to determine capabilities prior to logging in. Perhaps 58 | not critical but not currently possible. X protocol allows this 59 | which may be convenient. 60 | 61 | B3. No way to use the XAPI type JSON/document store interface. This 62 | probably makes sense as database/sql assumes you're going to talk 63 | SQL. 64 | 65 | B4. No way to pipeline commands. You must wait for a single statement 66 | to complete prior to sending the next one. The pool functionality 67 | of the go driver would allow you to use another connection transparently 68 | but that's not the same. 69 | 70 | B5. No way to change TLS setting once connected. The attribute is 71 | a connection setting and while it may not be common to want to 72 | change behaviour it might be convenient. 73 | 74 | B6. No support for anything like init_connect which can be used 75 | frequently. I think really this should be negoatiated as part of 76 | the X protocol but that functionality is not currently present. 77 | -------------------------------------------------------------------------------- /appengine.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // +build appengine 10 | 11 | package mysql 12 | 13 | import ( 14 | "appengine/cloudsql" 15 | ) 16 | 17 | func init() { 18 | RegisterDial("cloudsql", cloudsql.Dial) 19 | } 20 | -------------------------------------------------------------------------------- /buffer.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | import "io" 12 | 13 | const defaultBufSize = 4096 14 | 15 | // A buffer which is used for both reading and writing. 16 | // This is possible since communication on each connection is synchronous. 17 | // In other words, we can't write and read simultaneously on the same connection. 18 | // The buffer is similar to bufio.Reader / Writer but zero-copy-ish 19 | // Also highly optimized for this particular use case. 20 | type buffer struct { 21 | buf []byte 22 | rd io.Reader 23 | idx int 24 | length int 25 | } 26 | 27 | func newBuffer(rd io.Reader) buffer { 28 | var b [defaultBufSize]byte 29 | return buffer{ 30 | buf: b[:], 31 | rd: rd, 32 | } 33 | } 34 | 35 | // fill reads into the buffer until at least _need_ bytes are in it 36 | func (b *buffer) fill(need int) error { 37 | n := b.length 38 | 39 | // move existing data to the beginning 40 | if n > 0 && b.idx > 0 { 41 | copy(b.buf[0:n], b.buf[b.idx:]) 42 | } 43 | 44 | // grow buffer if necessary 45 | // TODO: let the buffer shrink again at some point 46 | // Maybe keep the org buf slice and swap back? 47 | if need > len(b.buf) { 48 | // Round up to the next multiple of the default size 49 | newBuf := make([]byte, ((need/defaultBufSize)+1)*defaultBufSize) 50 | copy(newBuf, b.buf) 51 | b.buf = newBuf 52 | } 53 | 54 | b.idx = 0 55 | 56 | for { 57 | nn, err := b.rd.Read(b.buf[n:]) 58 | n += nn 59 | 60 | switch err { 61 | case nil: 62 | if n < need { 63 | continue 64 | } 65 | b.length = n 66 | return nil 67 | 68 | case io.EOF: 69 | if n >= need { 70 | b.length = n 71 | return nil 72 | } 73 | return io.ErrUnexpectedEOF 74 | 75 | default: 76 | return err 77 | } 78 | } 79 | } 80 | 81 | // returns next N bytes from buffer. 82 | // The returned slice is only guaranteed to be valid until the next read 83 | func (b *buffer) readNext(need int) ([]byte, error) { 84 | if b.length < need { 85 | // refill 86 | if err := b.fill(need); err != nil { 87 | return nil, err 88 | } 89 | } 90 | 91 | offset := b.idx 92 | b.idx += need 93 | b.length -= need 94 | return b.buf[offset:b.idx], nil 95 | } 96 | -------------------------------------------------------------------------------- /capability/capability.go: -------------------------------------------------------------------------------- 1 | package capability 2 | 3 | import ( 4 | "fmt" 5 | 6 | // "bitbucket.org/sjmudd/go-mysqlx-driver/debug" 7 | ) 8 | 9 | // Capabilities are indexed by name and can be one of 7 protobuf types (including nesting...). 10 | // - see: mysqlx_datatypes.proto 'Type' 11 | // So rather complex and messy even if in reality most combinations won't be used. 12 | // - currently handled combinations are: 13 | // - scalar string 14 | // - scalar bool 15 | // - array of string 16 | 17 | type capabilityType uint8 18 | 19 | const ( 20 | // CapabilityString is a string 21 | CapabilityString capabilityType = iota 22 | // CapabilityBool is a boolean 23 | CapabilityBool 24 | ) 25 | 26 | // ugly! 27 | type capability struct { 28 | capabilityType capabilityType 29 | capabilityBool bool 30 | capabilityString string 31 | } 32 | 33 | func (c *capability) Type() string { 34 | var t string 35 | if c != nil { 36 | switch c.capabilityType { 37 | case CapabilityBool: t = "bool" 38 | case CapabilityString: t = "string" 39 | } 40 | } 41 | return t 42 | } 43 | 44 | func (c *capability) String() string { 45 | if c != nil && c.capabilityType == CapabilityString { 46 | return c.capabilityString 47 | } 48 | return "" 49 | } 50 | 51 | func (c *capability) Bool() bool { 52 | if c != nil && c.capabilityType == CapabilityBool { 53 | return c.capabilityBool 54 | } 55 | return false 56 | } 57 | 58 | // Values contains an array of capabilities 59 | type Values []capability 60 | 61 | // ServerCapabilities is a named map of capability values 62 | type ServerCapabilities map[string]Values 63 | 64 | // NewServerCapabilities returns a structure containing the named capabilities of the server 65 | func NewServerCapabilities() ServerCapabilities { 66 | return make(map[string]Values) 67 | } 68 | 69 | // Exists returns true if the named capability exists 70 | func (sc ServerCapabilities) Exists(name string) bool { 71 | if sc == nil { 72 | return false 73 | } 74 | _, found := sc[name] 75 | 76 | return found 77 | } 78 | 79 | // Values returns the named Values 80 | func (sc ServerCapabilities) Values(name string) Values { 81 | if sc == nil { 82 | return nil 83 | } 84 | 85 | // get the values 86 | values, found := sc[name] 87 | // not necessary to do this explicitly? 88 | if !found { 89 | return nil 90 | } 91 | return values 92 | } 93 | 94 | // AddScalarString adds the given string value to the named capability 95 | func (sc ServerCapabilities) AddScalarString(name string, value string) error { 96 | // debug.Msg("ServerCapabilities.AddScalarString(%q,%q)", name, value) 97 | if sc == nil { 98 | return fmt.Errorf("ServerCapabilities.AddScalarString() on nil value") 99 | } 100 | values := sc.Values(name) 101 | values = append(values, capability{capabilityType: CapabilityString, capabilityString: value}) 102 | sc[name] = values 103 | 104 | return nil 105 | } 106 | 107 | // AddScalarBool adds the given boolean value to the named capability 108 | func (sc ServerCapabilities) AddScalarBool(name string, value bool) error { 109 | // debug.Msg("ServerCapabilities.AddScalar(%q,%+v)", name, value) 110 | if sc == nil { 111 | return fmt.Errorf("ServerCapabilities.AddScalarBool() on nil value") 112 | } 113 | values := sc.Values(name) 114 | values = append(values, capability{capabilityType: CapabilityBool, capabilityBool: value}) 115 | sc[name] = values 116 | 117 | return nil 118 | } 119 | 120 | // AddArrayString adds the given array of strings to the named capability 121 | func (sc ServerCapabilities) AddArrayString(name string, values []string) error { 122 | // debug.Msg("ServerCapabilities.AddArrayString(%q,%+v)", name, values) 123 | if sc == nil { 124 | return fmt.Errorf("ServerCapabilities.AddArrayString() on nil value") 125 | } 126 | for i := range values { 127 | if err := sc.AddScalarString(name, values[i]); err != nil { 128 | return err 129 | } 130 | } 131 | 132 | return nil 133 | } 134 | -------------------------------------------------------------------------------- /cmd/bigmsg/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | ) 7 | 8 | const ( 9 | destination = "127.0.0.1:33060" 10 | waitSize = 4 // 4 message length bytes we expect to get back 11 | ) 12 | 13 | var ( 14 | fullMsg = []byte{255, 255, 255, 255, 255} // to send: 2^32-1 bytes of message type 255 (does not exist) 15 | ) 16 | 17 | func main() { 18 | conn, err := net.Dial("tcp", destination) 19 | if err != nil { 20 | log.Fatalf("net.Dial failed: %v", err) 21 | } 22 | log.Printf("connected to: %v", destination) 23 | 24 | var bytes int 25 | bytes, err = conn.Write(fullMsg) 26 | if bytes != 5 || err != nil { 27 | log.Fatalf("net.Write failed: only wrote %d of %d bytes: %v", bytes, len(fullMsg), err) 28 | } 29 | log.Printf("Wrote %d bytes indicating full length message size", bytes) 30 | 31 | var buf = make([]byte, waitSize) // bytes to wait for 32 | 33 | log.Printf("Waiting for %d bytes of response", waitSize) 34 | bytes, err = conn.Read(buf) 35 | 36 | if err != nil { 37 | log.Fatalf("net.Read failed: only read %d of %d bytes: %v", bytes, len(buf), err) 38 | } 39 | log.Printf("Read %d bytes of buf Message", bytes) 40 | 41 | if err = conn.Close(); err != nil { 42 | log.Fatalf("conn.Close failed: %v", err) 43 | } 44 | log.Printf("closed connected to: %v", destination) 45 | 46 | } 47 | -------------------------------------------------------------------------------- /cmd/invalid_msg/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | ) 7 | 8 | const ( 9 | bufSize = 1024 10 | destination = "127.0.0.1:33060" 11 | msgType = 255 // invalid message, currently unknown 12 | waitSize = 4 // 4 message length bytes we expect to get back 13 | msgText = "hello" 14 | ) 15 | 16 | func prepare(msgType uint8, msgText []byte) []byte { 17 | 18 | b := make([]byte, len(msgText)+5) 19 | len := uint8(len(msgText) + 1) // horrible hack 20 | 21 | b[0] = len // little endian hack (ignoring top 3 bytes) 22 | b[4] = msgType 23 | copy(b[5:], msgText) 24 | 25 | return b 26 | } 27 | 28 | func main() { 29 | conn, err := net.Dial("tcp", destination) 30 | if err != nil { 31 | log.Fatalf("net.Dial failed: %v", err) 32 | } 33 | log.Printf("connected to: %v", destination) 34 | 35 | // create msg 36 | b := prepare(255, []byte(msgText)) 37 | 38 | var bytes int 39 | bytes, err = conn.Write(b) 40 | if bytes != len(b) || err != nil { 41 | log.Fatalf("net.Write failed: only wrote %d of %d bytes: %v", bytes, len(b), err) 42 | } 43 | log.Printf("Wrote %d bytes indicating full length message: %q", bytes, msgText) 44 | 45 | var buf = make([]byte, waitSize, bufSize) // bytes to wait for 46 | 47 | log.Printf("Waiting for %d bytes of response", waitSize) 48 | bytes, err = conn.Read(buf) 49 | 50 | if err != nil { 51 | log.Fatalf("net.Read failed: only read %d of %d bytes: %v", bytes, len(buf), err) 52 | } 53 | log.Printf("Read %d bytes of message length: %+v", bytes, buf) 54 | 55 | // horrible hack, only look at length first byte 56 | msgLen := buf[0] 57 | buf = make([]byte, msgLen) 58 | log.Printf("Reading %d bytes as message content", msgLen) 59 | bytes, err = conn.Read(buf) 60 | if err != nil { 61 | log.Fatalf("net.Read failed: only read %d of %d bytes (trying to pull in msg): %v", bytes, msgLen, err) 62 | } 63 | log.Printf("msg type: %d", buf[0]) 64 | log.Printf("msg text (raw): %+v", string(buf[1:])) 65 | 66 | // try to read some more data (connection expected to be dropped so expect to get EOF) 67 | log.Printf("Trying to read more data if its there") 68 | buf = make([]byte, 1) 69 | bytes, err = conn.Read(buf) 70 | if err != nil { 71 | if err.Error() == "EOF" { 72 | log.Printf("We're at EOF (as expected)") 73 | } else { 74 | log.Fatalf("net.Read failed: only read %d of %d bytes (trying to pull in extra data): %v", bytes, len(buf), err) 75 | } 76 | } 77 | 78 | if err = conn.Close(); err != nil { 79 | log.Fatalf("conn.Close failed: %v", err) 80 | } 81 | log.Printf("closed connected to: %v", destination) 82 | 83 | } 84 | -------------------------------------------------------------------------------- /cmd/zerolength/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | ) 7 | 8 | const ( 9 | inputBufSize = 1024 10 | destination = "127.0.0.1:33060" 11 | waitSize = 4 // 4 message length bytes we expect to get back 12 | ) 13 | 14 | var ( 15 | nullMsg = []byte{0, 0, 0, 0} // to send 16 | ) 17 | 18 | func main() { 19 | conn, err := net.Dial("tcp", destination) 20 | if err != nil { 21 | log.Fatalf("net.Dial failed: %v", err) 22 | } 23 | log.Printf("connected to: %v", destination) 24 | 25 | var bytes int 26 | bytes, err = conn.Write(nullMsg) 27 | if bytes != len(nullMsg) || err != nil { 28 | log.Fatalf("net.Write failed: only wrote %d of %d bytes: %v", bytes, len(nullMsg), err) 29 | } 30 | log.Printf("wrote %d bytes of null message length", bytes) 31 | 32 | var buf = make([]byte, waitSize, inputBufSize) 33 | 34 | log.Printf("waiting for %d bytes of response", waitSize) 35 | bytes, err = conn.Read(buf) 36 | 37 | if err != nil { 38 | log.Fatalf("net.Read failed: only read %d of %d bytes: %v", bytes, len(buf), err) 39 | } 40 | log.Printf("read %d bytes of buf Message", bytes) 41 | 42 | if err = conn.Close(); err != nil { 43 | log.Fatalf("conn.Close failed: %v", err) 44 | } 45 | log.Printf("closed connected to: %v", destination) 46 | 47 | } 48 | -------------------------------------------------------------------------------- /collations.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2014 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | const defaultCollation byte = 33 // utf8_general_ci 12 | 13 | // A list of available collations mapped to the internal ID. 14 | // To update this map use the following MySQL query: 15 | // SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS 16 | var collations = map[string]byte{ 17 | "big5_chinese_ci": 1, 18 | "latin2_czech_cs": 2, 19 | "dec8_swedish_ci": 3, 20 | "cp850_general_ci": 4, 21 | "latin1_german1_ci": 5, 22 | "hp8_english_ci": 6, 23 | "koi8r_general_ci": 7, 24 | "latin1_swedish_ci": 8, 25 | "latin2_general_ci": 9, 26 | "swe7_swedish_ci": 10, 27 | "ascii_general_ci": 11, 28 | "ujis_japanese_ci": 12, 29 | "sjis_japanese_ci": 13, 30 | "cp1251_bulgarian_ci": 14, 31 | "latin1_danish_ci": 15, 32 | "hebrew_general_ci": 16, 33 | "tis620_thai_ci": 18, 34 | "euckr_korean_ci": 19, 35 | "latin7_estonian_cs": 20, 36 | "latin2_hungarian_ci": 21, 37 | "koi8u_general_ci": 22, 38 | "cp1251_ukrainian_ci": 23, 39 | "gb2312_chinese_ci": 24, 40 | "greek_general_ci": 25, 41 | "cp1250_general_ci": 26, 42 | "latin2_croatian_ci": 27, 43 | "gbk_chinese_ci": 28, 44 | "cp1257_lithuanian_ci": 29, 45 | "latin5_turkish_ci": 30, 46 | "latin1_german2_ci": 31, 47 | "armscii8_general_ci": 32, 48 | "utf8_general_ci": 33, 49 | "cp1250_czech_cs": 34, 50 | "ucs2_general_ci": 35, 51 | "cp866_general_ci": 36, 52 | "keybcs2_general_ci": 37, 53 | "macce_general_ci": 38, 54 | "macroman_general_ci": 39, 55 | "cp852_general_ci": 40, 56 | "latin7_general_ci": 41, 57 | "latin7_general_cs": 42, 58 | "macce_bin": 43, 59 | "cp1250_croatian_ci": 44, 60 | "utf8mb4_general_ci": 45, 61 | "utf8mb4_bin": 46, 62 | "latin1_bin": 47, 63 | "latin1_general_ci": 48, 64 | "latin1_general_cs": 49, 65 | "cp1251_bin": 50, 66 | "cp1251_general_ci": 51, 67 | "cp1251_general_cs": 52, 68 | "macroman_bin": 53, 69 | "utf16_general_ci": 54, 70 | "utf16_bin": 55, 71 | "utf16le_general_ci": 56, 72 | "cp1256_general_ci": 57, 73 | "cp1257_bin": 58, 74 | "cp1257_general_ci": 59, 75 | "utf32_general_ci": 60, 76 | "utf32_bin": 61, 77 | "utf16le_bin": 62, 78 | "binary": 63, 79 | "armscii8_bin": 64, 80 | "ascii_bin": 65, 81 | "cp1250_bin": 66, 82 | "cp1256_bin": 67, 83 | "cp866_bin": 68, 84 | "dec8_bin": 69, 85 | "greek_bin": 70, 86 | "hebrew_bin": 71, 87 | "hp8_bin": 72, 88 | "keybcs2_bin": 73, 89 | "koi8r_bin": 74, 90 | "koi8u_bin": 75, 91 | "latin2_bin": 77, 92 | "latin5_bin": 78, 93 | "latin7_bin": 79, 94 | "cp850_bin": 80, 95 | "cp852_bin": 81, 96 | "swe7_bin": 82, 97 | "utf8_bin": 83, 98 | "big5_bin": 84, 99 | "euckr_bin": 85, 100 | "gb2312_bin": 86, 101 | "gbk_bin": 87, 102 | "sjis_bin": 88, 103 | "tis620_bin": 89, 104 | "ucs2_bin": 90, 105 | "ujis_bin": 91, 106 | "geostd8_general_ci": 92, 107 | "geostd8_bin": 93, 108 | "latin1_spanish_ci": 94, 109 | "cp932_japanese_ci": 95, 110 | "cp932_bin": 96, 111 | "eucjpms_japanese_ci": 97, 112 | "eucjpms_bin": 98, 113 | "cp1250_polish_ci": 99, 114 | "utf16_unicode_ci": 101, 115 | "utf16_icelandic_ci": 102, 116 | "utf16_latvian_ci": 103, 117 | "utf16_romanian_ci": 104, 118 | "utf16_slovenian_ci": 105, 119 | "utf16_polish_ci": 106, 120 | "utf16_estonian_ci": 107, 121 | "utf16_spanish_ci": 108, 122 | "utf16_swedish_ci": 109, 123 | "utf16_turkish_ci": 110, 124 | "utf16_czech_ci": 111, 125 | "utf16_danish_ci": 112, 126 | "utf16_lithuanian_ci": 113, 127 | "utf16_slovak_ci": 114, 128 | "utf16_spanish2_ci": 115, 129 | "utf16_roman_ci": 116, 130 | "utf16_persian_ci": 117, 131 | "utf16_esperanto_ci": 118, 132 | "utf16_hungarian_ci": 119, 133 | "utf16_sinhala_ci": 120, 134 | "utf16_german2_ci": 121, 135 | "utf16_croatian_ci": 122, 136 | "utf16_unicode_520_ci": 123, 137 | "utf16_vietnamese_ci": 124, 138 | "ucs2_unicode_ci": 128, 139 | "ucs2_icelandic_ci": 129, 140 | "ucs2_latvian_ci": 130, 141 | "ucs2_romanian_ci": 131, 142 | "ucs2_slovenian_ci": 132, 143 | "ucs2_polish_ci": 133, 144 | "ucs2_estonian_ci": 134, 145 | "ucs2_spanish_ci": 135, 146 | "ucs2_swedish_ci": 136, 147 | "ucs2_turkish_ci": 137, 148 | "ucs2_czech_ci": 138, 149 | "ucs2_danish_ci": 139, 150 | "ucs2_lithuanian_ci": 140, 151 | "ucs2_slovak_ci": 141, 152 | "ucs2_spanish2_ci": 142, 153 | "ucs2_roman_ci": 143, 154 | "ucs2_persian_ci": 144, 155 | "ucs2_esperanto_ci": 145, 156 | "ucs2_hungarian_ci": 146, 157 | "ucs2_sinhala_ci": 147, 158 | "ucs2_german2_ci": 148, 159 | "ucs2_croatian_ci": 149, 160 | "ucs2_unicode_520_ci": 150, 161 | "ucs2_vietnamese_ci": 151, 162 | "ucs2_general_mysql500_ci": 159, 163 | "utf32_unicode_ci": 160, 164 | "utf32_icelandic_ci": 161, 165 | "utf32_latvian_ci": 162, 166 | "utf32_romanian_ci": 163, 167 | "utf32_slovenian_ci": 164, 168 | "utf32_polish_ci": 165, 169 | "utf32_estonian_ci": 166, 170 | "utf32_spanish_ci": 167, 171 | "utf32_swedish_ci": 168, 172 | "utf32_turkish_ci": 169, 173 | "utf32_czech_ci": 170, 174 | "utf32_danish_ci": 171, 175 | "utf32_lithuanian_ci": 172, 176 | "utf32_slovak_ci": 173, 177 | "utf32_spanish2_ci": 174, 178 | "utf32_roman_ci": 175, 179 | "utf32_persian_ci": 176, 180 | "utf32_esperanto_ci": 177, 181 | "utf32_hungarian_ci": 178, 182 | "utf32_sinhala_ci": 179, 183 | "utf32_german2_ci": 180, 184 | "utf32_croatian_ci": 181, 185 | "utf32_unicode_520_ci": 182, 186 | "utf32_vietnamese_ci": 183, 187 | "utf8_unicode_ci": 192, 188 | "utf8_icelandic_ci": 193, 189 | "utf8_latvian_ci": 194, 190 | "utf8_romanian_ci": 195, 191 | "utf8_slovenian_ci": 196, 192 | "utf8_polish_ci": 197, 193 | "utf8_estonian_ci": 198, 194 | "utf8_spanish_ci": 199, 195 | "utf8_swedish_ci": 200, 196 | "utf8_turkish_ci": 201, 197 | "utf8_czech_ci": 202, 198 | "utf8_danish_ci": 203, 199 | "utf8_lithuanian_ci": 204, 200 | "utf8_slovak_ci": 205, 201 | "utf8_spanish2_ci": 206, 202 | "utf8_roman_ci": 207, 203 | "utf8_persian_ci": 208, 204 | "utf8_esperanto_ci": 209, 205 | "utf8_hungarian_ci": 210, 206 | "utf8_sinhala_ci": 211, 207 | "utf8_german2_ci": 212, 208 | "utf8_croatian_ci": 213, 209 | "utf8_unicode_520_ci": 214, 210 | "utf8_vietnamese_ci": 215, 211 | "utf8_general_mysql500_ci": 223, 212 | "utf8mb4_unicode_ci": 224, 213 | "utf8mb4_icelandic_ci": 225, 214 | "utf8mb4_latvian_ci": 226, 215 | "utf8mb4_romanian_ci": 227, 216 | "utf8mb4_slovenian_ci": 228, 217 | "utf8mb4_polish_ci": 229, 218 | "utf8mb4_estonian_ci": 230, 219 | "utf8mb4_spanish_ci": 231, 220 | "utf8mb4_swedish_ci": 232, 221 | "utf8mb4_turkish_ci": 233, 222 | "utf8mb4_czech_ci": 234, 223 | "utf8mb4_danish_ci": 235, 224 | "utf8mb4_lithuanian_ci": 236, 225 | "utf8mb4_slovak_ci": 237, 226 | "utf8mb4_spanish2_ci": 238, 227 | "utf8mb4_roman_ci": 239, 228 | "utf8mb4_persian_ci": 240, 229 | "utf8mb4_esperanto_ci": 241, 230 | "utf8mb4_hungarian_ci": 242, 231 | "utf8mb4_sinhala_ci": 243, 232 | "utf8mb4_german2_ci": 244, 233 | "utf8mb4_croatian_ci": 245, 234 | "utf8mb4_unicode_520_ci": 246, 235 | "utf8mb4_vietnamese_ci": 247, 236 | } 237 | 238 | // A blacklist of collations which is unsafe to interpolate parameters. 239 | // These multibyte encodings may contains 0x5c (`\`) in their trailing bytes. 240 | var unsafeCollations = map[byte]bool{ 241 | 1: true, // big5_chinese_ci 242 | 13: true, // sjis_japanese_ci 243 | 28: true, // gbk_chinese_ci 244 | 84: true, // big5_bin 245 | 86: true, // gb2312_bin 246 | 87: true, // gbk_bin 247 | 88: true, // sjis_bin 248 | 95: true, // cp932_japanese_ci 249 | 96: true, // cp932_bin 250 | } 251 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | // A Go driver for the MySQL X protocol for Go's database/sql package 2 | // Based heavily on: 3 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 4 | // 5 | // Copyright 2014 The Go-MySQL-Driver Authors. All rights reserved. 6 | // Copyright 2016 Simon J Mudd. 7 | // 8 | // This Source Code Form is subject to the terms of the Mozilla Public 9 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 10 | // You can obtain one at http://mozilla.org/MPL/2.0/. 11 | 12 | package mysql 13 | 14 | import ( 15 | "crypto/tls" 16 | "time" 17 | ) 18 | 19 | type config struct { 20 | user string 21 | passwd string 22 | net string 23 | addr string 24 | dbname string 25 | params map[string]string 26 | loc *time.Location 27 | tls *tls.Config 28 | timeout time.Duration 29 | collation uint8 30 | allowAllFiles bool 31 | allowOldPasswords bool 32 | allowCleartextPasswords bool 33 | columnsWithAlias bool 34 | interpolateParams bool 35 | useXProtocol bool // use X protocol rather than native protocol 36 | } 37 | -------------------------------------------------------------------------------- /const.go: -------------------------------------------------------------------------------- 1 | // A Go driver for the MySQL X protocol for Go's database/sql package 2 | // Based heavily on: 3 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 4 | // 5 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 6 | // Copyright 2016 Simon J Mudd. 7 | // 8 | // This Source Code Form is subject to the terms of the Mozilla Public 9 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 10 | // You can obtain one at http://mozilla.org/MPL/2.0/. 11 | 12 | package mysql 13 | 14 | const ( 15 | maxPacketSize = 1<<32 - 1 // adjusted for X protocol 16 | minPacketSize = 1 // adjusted for X protocol, see http://bugs.mysql.com/82862 17 | timeFormat = "2006-01-02 15:04:05.999999" 18 | ) 19 | 20 | // MySQL constants documentation: 21 | // http://dev.mysql.com/doc/internals/en/client-server-protocol.html 22 | 23 | // https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags 24 | type clientFlag uint32 25 | 26 | const ( 27 | clientLongPassword clientFlag = 1 << iota 28 | clientFoundRows 29 | clientLongFlag 30 | clientConnectWithDB 31 | clientNoSchema 32 | clientCompress 33 | clientODBC 34 | clientLocalFiles 35 | clientIgnoreSpace 36 | clientProtocol41 37 | clientInteractive 38 | clientSSL 39 | clientIgnoreSIGPIPE 40 | clientTransactions 41 | clientReserved 42 | clientSecureConn 43 | clientMultiStatements 44 | clientMultiResults 45 | clientPSMultiResults 46 | clientPluginAuth 47 | clientConnectAttrs 48 | clientPluginAuthLenEncClientData 49 | clientCanHandleExpiredPasswords 50 | clientSessionTrack 51 | clientDeprecateEOF 52 | ) 53 | 54 | const ( 55 | comQuit byte = iota + 1 56 | comInitDB 57 | comQuery 58 | comFieldList 59 | comCreateDB 60 | comDropDB 61 | comRefresh 62 | comShutdown 63 | comStatistics 64 | comProcessInfo 65 | comConnect 66 | comProcessKill 67 | comDebug 68 | comPing 69 | comTime 70 | comDelayedInsert 71 | comChangeUser 72 | comBinlogDump 73 | comTableDump 74 | comConnectOut 75 | comRegisterSlave 76 | comStmtPrepare 77 | comStmtExecute 78 | comStmtSendLongData 79 | comStmtClose 80 | comStmtReset 81 | comSetOption 82 | comStmtFetch 83 | ) 84 | 85 | // https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType 86 | const ( 87 | fieldTypeDecimal byte = iota 88 | fieldTypeTiny 89 | fieldTypeShort 90 | fieldTypeLong 91 | fieldTypeFloat 92 | fieldTypeDouble 93 | fieldTypeNULL 94 | fieldTypeTimestamp 95 | fieldTypeLongLong 96 | fieldTypeInt24 97 | fieldTypeDate 98 | fieldTypeTime 99 | fieldTypeDateTime 100 | fieldTypeYear 101 | fieldTypeNewDate 102 | fieldTypeVarChar 103 | fieldTypeBit 104 | ) 105 | const ( 106 | fieldTypeNewDecimal byte = iota + 0xf6 107 | fieldTypeEnum 108 | fieldTypeSet 109 | fieldTypeTinyBLOB 110 | fieldTypeMediumBLOB 111 | fieldTypeLongBLOB 112 | fieldTypeBLOB 113 | fieldTypeVarString 114 | fieldTypeString 115 | fieldTypeGeometry 116 | ) 117 | 118 | type fieldFlag uint16 119 | 120 | const ( 121 | flagNotNULL fieldFlag = 1 << iota 122 | flagPriKey 123 | flagUniqueKey 124 | flagMultipleKey 125 | flagBLOB 126 | flagUnsigned 127 | flagZeroFill 128 | flagBinary 129 | flagEnum 130 | flagAutoIncrement 131 | flagTimestamp 132 | flagSet 133 | flagUnknown1 134 | flagUnknown2 135 | flagUnknown3 136 | flagUnknown4 137 | ) 138 | 139 | // http://dev.mysql.com/doc/internals/en/status-flags.html 140 | type statusFlag uint16 141 | 142 | const ( 143 | statusInTrans statusFlag = 1 << iota 144 | statusInAutocommit 145 | statusReserved // Not in documentation 146 | statusMoreResultsExists 147 | statusNoGoodIndexUsed 148 | statusNoIndexUsed 149 | statusCursorExists 150 | statusLastRowSent 151 | statusDbDropped 152 | statusNoBackslashEscapes 153 | statusMetadataChanged 154 | statusQueryWasSlow 155 | statusPsOutParams 156 | statusInTransReadonly 157 | statusSessionStateChanged 158 | ) 159 | -------------------------------------------------------------------------------- /convert.go: -------------------------------------------------------------------------------- 1 | // Go driver for MySQL X Protocol 2 | // 3 | // Copyright 2016 Simon J Mudd. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | // 9 | // MySQL X protocol authentication using MYSQL41 method 10 | 11 | package mysql 12 | 13 | import ( 14 | "encoding/binary" 15 | "fmt" 16 | "math" 17 | 18 | "database/sql/driver" 19 | 20 | "github.com/golang/protobuf/proto" 21 | 22 | "github.com/sjmudd/go-mysqlx-driver/Mysqlx_Resultset" 23 | "github.com/sjmudd/go-mysqlx-driver/debug" 24 | ) 25 | 26 | // decodeZigzag64 reads a zigzag-encoded 64-bit integer 27 | // from the Buffer. 28 | // This is the format used for the sint64 protocol buffer type. 29 | func decodeZigzag64(x uint64) int64 { 30 | x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63) 31 | return int64(x) 32 | } 33 | 34 | // MySQL signed int to int64 35 | func mysql_sint_to_Int(data []byte) (signed int64, e error) { 36 | myint, num := proto.DecodeVarint(data) 37 | if num == 0 { 38 | e = fmt.Errorf("Unable to decode '% x' as varint...", data) 39 | } 40 | 41 | signed = decodeZigzag64(myint) 42 | debug.Msg("SINT: '% x' -> %d", data, signed) 43 | 44 | return signed, e 45 | } 46 | 47 | // MySQL unsigned signed int to uint64 48 | func mysql_uint_to_Uint(data []byte) (unsigned uint64, e error) { 49 | unsigned, num := proto.DecodeVarint(data) 50 | if num == 0 { 51 | e = fmt.Errorf("Unable to decode '% x' as varint. unsigned: %+v", data, unsigned) 52 | } 53 | debug.Msg("UINT: '% x' -> %d", data, unsigned) 54 | 55 | return unsigned, e 56 | } 57 | 58 | // MySQL float to float32 59 | func mysql_float_to_float32(data []byte) (float32, error) { 60 | f := math.Float32frombits(binary.LittleEndian.Uint32(data[:])) 61 | debug.Msg("FLOAT: '% x' -> %.3f", data, f) 62 | 63 | return f, nil 64 | } 65 | 66 | // MySQL double to float64 67 | func mysql_double_to_float64(data []byte) (float64, error) { 68 | f := math.Float64frombits(binary.LittleEndian.Uint64(data[:])) 69 | debug.Msg("DOUBLE: '% x' -> %.3f", data, f) 70 | 71 | return f, nil 72 | } 73 | 74 | // MySQL char/binary. The trailing \x00 needs to be removed. 75 | func mysql_bytes_to_bytes(data []byte) ([]byte, error) { 76 | // 012345 77 | // ABCDEF\x00 (len 7) 78 | dest := data[0 : len(data)-1] // not copying to avoid overhead (is this ok?), just using a shorter slice 79 | debug.Msg("BYTES: '% x'", dest) 80 | 81 | return dest, nil 82 | } 83 | 84 | // for handling stuff we haven't done yet. Should become obsolete as I finish the code... 85 | func no_conversion(typeName string, data []byte) ([]byte, error) { 86 | dest := data 87 | debug.Msg("no conversion yet for %s: '% x'", typeName, data, dest) 88 | 89 | // if len(data) == 0 { 90 | // return nil, nil // this is a NULL result 91 | // } 92 | 93 | return dest[0 : len(data)-1], nil // chop off last character 94 | } 95 | 96 | // Handle the conversion from the MysQL type to the driver type 97 | func convertColumnData(column *Mysqlx_Resultset.ColumnMetaData, data []byte) (dest driver.Value, e error) { 98 | debug.Msg("convertType: converting %s with bytes '% x'", column.GetType().String(), data) 99 | 100 | // We don't expect data to be nil. Probably a bug? 101 | if data == nil { 102 | return nil, fmt.Errorf("convertColumnData: data == nil. Unexpected. Returning dest = nil") 103 | } 104 | // An empty slice implies NULL 105 | if len(data) == 0 { 106 | debug.Msg("convertColumnData: len(data) == 0, so NULL: returning dest = nil") 107 | return nil, nil 108 | } 109 | 110 | // If we get this far we have non NULL values. 111 | switch column.GetType() { 112 | case Mysqlx_Resultset.ColumnMetaData_SINT: 113 | return mysql_sint_to_Int(data) 114 | case Mysqlx_Resultset.ColumnMetaData_UINT: 115 | return mysql_uint_to_Uint(data) 116 | case Mysqlx_Resultset.ColumnMetaData_DOUBLE: 117 | return mysql_double_to_float64(data) 118 | case Mysqlx_Resultset.ColumnMetaData_BYTES: 119 | return mysql_bytes_to_bytes(data) 120 | case Mysqlx_Resultset.ColumnMetaData_FLOAT: 121 | return mysql_float_to_float32(data) 122 | // ColumnMetaData_BYTES ColumnMetaData_FieldType = 7 123 | // ColumnMetaData_TIME ColumnMetaData_FieldType = 10 124 | // ColumnMetaData_DATETIME ColumnMetaData_FieldType = 12 125 | // ColumnMetaData_SET ColumnMetaData_FieldType = 15 126 | // ColumnMetaData_ENUM ColumnMetaData_FieldType = 16 127 | // ColumnMetaData_BIT ColumnMetaData_FieldType = 17 128 | // ColumnMetaData_DECIMAL ColumnMetaData_FieldType = 18 129 | default: 130 | return no_conversion("BYTES", data) 131 | } 132 | 133 | return dest, nil 134 | } 135 | -------------------------------------------------------------------------------- /datatypes.go: -------------------------------------------------------------------------------- 1 | // Go driver for MySQL X Protocol 2 | // 3 | // Copyright 2016 Simon J Mudd. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | // 9 | // MySQL X protocol authentication using MYSQL41 method 10 | 11 | package mysql 12 | 13 | // This file holds information about the XPROTOCOL datatypes 14 | 15 | import ( 16 | "fmt" 17 | "log" 18 | "strings" 19 | 20 | "github.com/sjmudd/go-mysqlx-driver/Mysqlx_Datatypes" 21 | ) 22 | 23 | func printableScalar(s *Mysqlx_Datatypes.Scalar) string { 24 | t := s.GetType() 25 | 26 | switch t { 27 | case Mysqlx_Datatypes.Scalar_V_STRING: 28 | { 29 | v := s.GetVString() 30 | 31 | return fmt.Sprintf("%s: value: %q (collation: %d)", t.String(), string(v.Value), v.GetCollation()) 32 | } 33 | case Mysqlx_Datatypes.Scalar_V_BOOL: 34 | { 35 | b := s.GetVBool() 36 | 37 | return fmt.Sprintf("%s: value: %v", t.String(), b) 38 | } 39 | } 40 | 41 | return fmt.Sprintf("UNKNOWN SCALAR: %s", t.String()) 42 | } 43 | 44 | // recursive ... 45 | func printableArray(s *Mysqlx_Datatypes.Array) string { 46 | results := []string{} 47 | for i := range s.GetValue() { 48 | results = append(results, printableDatatype(s.GetValue()[i])) 49 | } 50 | 51 | return strings.Join(results, ", ") 52 | } 53 | 54 | func printableObj(d *Mysqlx_Datatypes.Object) string { 55 | results := []string{} 56 | 57 | for i := range d.GetFld() { 58 | results = append(results, d.GetFld()[i].String()) // should later split to k/v pairs 59 | } 60 | 61 | return strings.Join(results, ", ") 62 | } 63 | 64 | func printableDatatype(d *Mysqlx_Datatypes.Any) string { 65 | // figure out the type and show it. 66 | 67 | t := d.GetType() 68 | 69 | s := fmt.Sprintf("Type: %+v", t) 70 | 71 | switch t { 72 | case Mysqlx_Datatypes.Any_SCALAR: 73 | { 74 | s = fmt.Sprintf("Scalar: %s", printableScalar(d.GetScalar())) 75 | } 76 | case Mysqlx_Datatypes.Any_OBJECT: 77 | { 78 | s = fmt.Sprintf("Object: %s", printableObj(d.GetObj())) 79 | } 80 | case Mysqlx_Datatypes.Any_ARRAY: 81 | { 82 | s = fmt.Sprintf("Array: %s", printableArray(d.GetArray())) 83 | } 84 | default: 85 | log.Fatalf("Unexpected datatype %+v", t) 86 | } 87 | 88 | return s 89 | } 90 | -------------------------------------------------------------------------------- /debug/debug.go: -------------------------------------------------------------------------------- 1 | package debug 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | /* 9 | 10 | Use various environment variables to determine verbose logging 11 | - DEBUG 12 | - DEBUG_MSG protobuf messages only 13 | */ 14 | 15 | // Msg writes a debug message to stdout iif DEBUG environment variable is set 16 | func Msg(format string, a ...interface{}) (n int, err error) { 17 | if os.Getenv("DEBUG") == "" { 18 | return 0, nil 19 | } 20 | return fmt.Printf("DEBUG: "+format+"\n", a...) 21 | } 22 | 23 | // MsgProtobuf writes a debug message iif environment variable DEBUG_MSG is set 24 | func MsgProtobuf(format string, a ...interface{}) (n int, err error) { 25 | if os.Getenv("DEBUG_MSG") == "" { 26 | return 0, nil 27 | } 28 | return fmt.Printf("MSG: "+format+"\n", a...) 29 | } 30 | -------------------------------------------------------------------------------- /driver.go: -------------------------------------------------------------------------------- 1 | // Go driver for MySQL X Protocol 2 | // 3 | // Copyright 2016 Simon J Mudd. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | // 9 | // MySQL X protocol authentication using MYSQL41 method 10 | 11 | package mysql 12 | 13 | import ( 14 | "database/sql" 15 | "database/sql/driver" 16 | "net" 17 | 18 | "github.com/sjmudd/go-mysqlx-driver/capability" 19 | ) 20 | 21 | // This struct is exported to make the driver directly accessible. 22 | // In general the driver is used via the database/sql package. 23 | type XDriver struct{} 24 | 25 | // DialFunc is a function which can be used to establish the network connection. 26 | // Custom dial functions must be registered with RegisterDial 27 | type DialFunc func(addr string) (net.Conn, error) 28 | 29 | var dials map[string]DialFunc 30 | 31 | // RegisterDial registers a custom dial function. It can then be used by the 32 | // network address mynet(addr), where mynet is the registered new network. 33 | // addr is passed as a parameter to the dial function. 34 | func RegisterDial(net string, dial DialFunc) { 35 | if dials == nil { 36 | dials = make(map[string]DialFunc) 37 | } 38 | dials[net] = dial 39 | } 40 | 41 | func (d XDriver) Open(dsn string) (driver.Conn, error) { 42 | var err error 43 | 44 | cfg, err := parseDSN(dsn) 45 | if err != nil { 46 | return nil, err 47 | } 48 | cfg.useXProtocol = true // force X protocol as this driver was called explicitly 49 | 50 | // New mysqlConn 51 | mc := &mysqlXConn{ 52 | capabilities: capability.NewServerCapabilities(), 53 | cfg: NewXconfigFromConfig(cfg), 54 | maxPacketAllowed: maxPacketSize, 55 | maxWriteSize: maxPacketSize - 1, 56 | } 57 | return mc.Open2() 58 | } 59 | 60 | func init() { 61 | sql.Register("mysql/xprotocol", &XDriver{}) 62 | } 63 | -------------------------------------------------------------------------------- /dsn_test.go: -------------------------------------------------------------------------------- 1 | // Go driver for MySQL X Protocol 2 | // 3 | // Copyright 2016 Simon J Mudd. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | // 9 | // MySQL X protocol authentication using MYSQL41 method 10 | 11 | package mysql 12 | 13 | import ( 14 | "testing" 15 | ) 16 | 17 | type testDSN struct { 18 | dsn string 19 | result bool 20 | } 21 | type testDSNs []testDSN 22 | 23 | // test that the use of xpprotocol=1 works 24 | func TestDSN(t *testing.T) { 25 | 26 | d := testDSNs{ 27 | {dsn: "user:pass@/", result: false}, 28 | {dsn: "user:pass@tcp(127.0.0.1:33060)/test?xprotocol=1", result: true}, 29 | {dsn: "user:pass@tcp(127.0.0.1)/test?xprotocol=1", result: true}, 30 | {dsn: "user:pass@tcp(127.0.0.1:33060)/test", result: false}, 31 | {dsn: "user:pass@tcp(127.0.0.1)/test", result: false}, 32 | {dsn: "user:pass@/test", result: false}, 33 | {dsn: "user:pass@/test?xprotocol=1", result: true}, 34 | } 35 | 36 | for i := range d { 37 | cfg, err := parseDSN(d[i].dsn) 38 | if err != nil { 39 | t.Errorf("TestDSN: dsn: %s, parseDSN gives error: %v", d[i].dsn, err) 40 | } 41 | if cfg.useXProtocol != d[i].result { 42 | t.Errorf("TestDSN: dsn: %s, cfg.useXprotocol: %v, expected: %v", d[i].dsn, cfg.useXProtocol, d[i].result) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | import ( 12 | // "database/sql/driver" 13 | "errors" 14 | "fmt" 15 | // "io" 16 | "log" 17 | "os" 18 | ) 19 | 20 | // Various errors the driver might return. Can change between driver versions. 21 | var ( 22 | ErrInvalidConn = errors.New("Invalid Connection") 23 | ErrMalformPkt = errors.New("Malformed Packet") 24 | ErrNoTLS = errors.New("TLS encryption requested but server does not support TLS") 25 | ErrOldPassword = errors.New("This user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords") 26 | ErrCleartextPassword = errors.New("This user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN.") 27 | ErrUnknownPlugin = errors.New("The authentication plugin is not supported.") 28 | ErrOldProtocol = errors.New("MySQL-Server does not support required Protocol 41+") 29 | ErrPktSync = errors.New("Commands out of sync. You can't run this command now") 30 | ErrPktSyncMul = errors.New("Commands out of sync. Did you run multiple statements at once?") 31 | ErrPktTooLarge = errors.New("Packet for query is too large. You can change this value on the server by adjusting the 'max_allowed_packet' variable.") 32 | ErrBusyBuffer = errors.New("Busy buffer") 33 | ) 34 | 35 | var errLog Logger = log.New(os.Stderr, "[MySQL] ", log.Ldate|log.Ltime|log.Lshortfile) 36 | 37 | // Logger is used to log critical error messages. 38 | type Logger interface { 39 | Print(v ...interface{}) 40 | } 41 | 42 | // SetLogger is used to set the logger for critical errors. 43 | // The initial logger is os.Stderr. 44 | func SetLogger(logger Logger) error { 45 | if logger == nil { 46 | return errors.New("logger is nil") 47 | } 48 | errLog = logger 49 | return nil 50 | } 51 | 52 | // MySQLWarnings is an error type which represents a group of one or more MySQL 53 | // warnings 54 | type MySQLWarnings []MySQLWarning 55 | 56 | func (mws MySQLWarnings) Error() string { 57 | var msg string 58 | for i, warning := range mws { 59 | if i > 0 { 60 | msg += "\r\n" 61 | } 62 | msg += fmt.Sprintf( 63 | "%s %s: %s", 64 | warning.Level, 65 | warning.Code, 66 | warning.Message, 67 | ) 68 | } 69 | return msg 70 | } 71 | 72 | // MySQLWarning is an error type which represents a single MySQL warning. 73 | // Warnings are returned in groups only. See MySQLWarnings 74 | type MySQLWarning struct { 75 | Level string 76 | Code string 77 | Message string 78 | } 79 | 80 | func (mc *mysqlXConn) getWarnings() (err error) { 81 | return fmt.Errorf("getWarnings() not implemented") 82 | /* 83 | rows, err := mc.Query("SHOW WARNINGS", nil) 84 | if err != nil { 85 | return 86 | } 87 | 88 | var warnings = MySQLWarnings{} 89 | var values = make([]driver.Value, 3) 90 | 91 | for { 92 | err = rows.Next(values) 93 | switch err { 94 | case nil: 95 | warning := MySQLWarning{} 96 | 97 | if raw, ok := values[0].([]byte); ok { 98 | warning.Level = string(raw) 99 | } else { 100 | warning.Level = fmt.Sprintf("%s", values[0]) 101 | } 102 | if raw, ok := values[1].([]byte); ok { 103 | warning.Code = string(raw) 104 | } else { 105 | warning.Code = fmt.Sprintf("%s", values[1]) 106 | } 107 | if raw, ok := values[2].([]byte); ok { 108 | warning.Message = string(raw) 109 | } else { 110 | warning.Message = fmt.Sprintf("%s", values[0]) 111 | } 112 | 113 | warnings = append(warnings, warning) 114 | 115 | case io.EOF: 116 | return warnings 117 | 118 | default: 119 | rows.Close() 120 | return 121 | } 122 | } 123 | */ 124 | } 125 | -------------------------------------------------------------------------------- /mysql41.go: -------------------------------------------------------------------------------- 1 | // Go driver for MySQL X Protocol 2 | // 3 | // Copyright 2016 Simon J Mudd. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | // 9 | // MySQL X protocol authentication using MYSQL41 method 10 | 11 | package mysql 12 | 13 | import ( 14 | "crypto/sha1" 15 | "fmt" 16 | "io" 17 | "log" 18 | ) 19 | 20 | // MySQL41 manages the MySQL41 authentication protocol 21 | type MySQL41 struct { 22 | dbname string 23 | name string 24 | username string 25 | password string 26 | } 27 | 28 | // NewMySQL41 returns a pointer to an initialised MySQL41 struct 29 | func NewMySQL41(dbname, username, password string) *MySQL41 { 30 | if username == "" { 31 | return nil 32 | } 33 | 34 | m := MySQL41{ 35 | name: "MYSQL41", 36 | username: username, 37 | password: password, 38 | dbname: dbname, 39 | } 40 | 41 | return &m 42 | } 43 | 44 | // generate the input of some bytes and return the SHA1 sum 45 | func mysha1(someBytes []byte) []byte { 46 | s1 := sha1.Sum(someBytes) 47 | // convert from [20]byte to slice 48 | return s1[:] 49 | } 50 | 51 | func xor(buf1, buf2 []byte) []byte { 52 | if len(buf1) != len(buf2) { 53 | log.Fatal("xor: length of both buffers has to be identical") 54 | } 55 | res := make([]byte, len(buf1)) 56 | for i := range buf1 { 57 | res[i] = buf1[i] ^ buf2[i] 58 | } 59 | return res 60 | } 61 | 62 | // Name returns the name of the authentication method 63 | func (p *MySQL41) Name() string { 64 | return p.name 65 | } 66 | 67 | // GetInitialAuthData returns any initial authentication data 68 | func (p *MySQL41) GetInitialAuthData() []byte { 69 | return nil 70 | } 71 | 72 | func (p *MySQL41) scramble(scramble []byte) []byte { 73 | buf1 := mysha1([]byte(p.password)) 74 | buf2 := mysha1(buf1) 75 | 76 | s := sha1.New() 77 | io.WriteString(s, string(scramble)) 78 | io.WriteString(s, string(buf2)) 79 | tmpBuffer := s.Sum(nil) 80 | 81 | return xor(buf1, tmpBuffer) 82 | } 83 | 84 | // GetNextAuthData returns data db + name + encrypted hash 85 | func (p *MySQL41) GetNextAuthData(serverData []byte) ([]byte, error) { 86 | if len(serverData) != 20 { 87 | return nil, fmt.Errorf("Scramble buffer had invalid length - expected 20 bytes, got %d", len(serverData)) 88 | } 89 | 90 | // docs are not clear but this is where you prepend the dbname 91 | retval := p.dbname + "\x00" + p.username + "\x00" // gives us len(username) + 2 92 | 93 | // return the string as needed (no password) 94 | if len(p.password) == 0 { 95 | return []byte(retval), nil 96 | } 97 | 98 | pass := p.scramble(serverData) 99 | 100 | retval += "*" 101 | for i := range pass { 102 | retval += fmt.Sprintf("%02x", byte(pass[i])) 103 | } 104 | 105 | return []byte(retval), nil 106 | } 107 | -------------------------------------------------------------------------------- /result.go: -------------------------------------------------------------------------------- 1 | // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 | // 3 | // Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | type mysqlResult struct { 12 | affectedRows int64 13 | insertId int64 14 | } 15 | 16 | // LastInsertId should return the last MySQL insert id 17 | func (res *mysqlResult) LastInsertId() (int64, error) { 18 | return res.insertId, nil 19 | } 20 | 21 | // RowsAffected indicate how many rows were affected by the command 22 | func (res *mysqlResult) RowsAffected() (int64, error) { 23 | return res.affectedRows, nil 24 | } 25 | -------------------------------------------------------------------------------- /state.go: -------------------------------------------------------------------------------- 1 | // Go driver for MySQL X Protocol 2 | // 3 | // Copyright 2016 Simon J Mudd. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package mysql 10 | 11 | /* 12 | 13 | states are as shown below: 14 | 15 | * if we get an error message (where we expect) we act on it and don't consider it an error 16 | * if we get another type of error we immediately abort after reporting the problem. 17 | 18 | queryStateStart 19 | | 20 | | +-------[B/N]------+ 21 | | | | 22 | V V | 23 | queryStateWaitingForColumnMetaData ------[E/*]-----+ 24 | | | 25 | [C] +-------[C/N]------+ | 26 | | | | | 27 | V V | V 28 | queryStateWaitingRow --------------------[E/*]---->| 29 | | | 30 | [F] +--------[N]-------+ | 31 | | | | | 32 | V V | V 33 | queryStateWaitingExecuteOk --------------[E/*]---->| 34 | | | 35 | V V 36 | queryStateDone queryStateError 37 | 38 | Events: 39 | [S] Write SQL_STMT_EXECUTE 40 | [B] Receive RESULTSET_COLUMN_META_DATA 41 | [C] Receive RESULTSET_ROW 42 | [E] Receive ERROR 43 | [F] Receive RESULTSET_FETCH_DONE 44 | [N] Receive NOTICE 45 | 46 | 47 | */ 48 | 49 | type queryState int 50 | 51 | const ( 52 | queryStateStart queryState = iota // not started yet 53 | queryStateWaitingColumnMetaData // query sent waiting for some data 54 | queryStateWaitingRow // query sent waiting for row data 55 | queryStateWaitingExecuteOk // query sent waiting for execute ok 56 | queryStateDone // query complete (could be error) 57 | queryStateError // error of some sort 58 | queryStateUnknown // unknown state 59 | ) 60 | 61 | var queryStateName map[queryState]string 62 | 63 | func init() { 64 | queryStateName = map[queryState]string{ 65 | queryStateStart: "Start", 66 | queryStateWaitingColumnMetaData: "Waiting for Column Metadata", 67 | queryStateWaitingRow: "Waiting for Row", 68 | queryStateWaitingExecuteOk: "Waiting for Execute Ok", 69 | queryStateDone: "Completed", 70 | queryStateError: "Error", 71 | queryStateUnknown: "Unnown", 72 | } 73 | } 74 | 75 | // return the string version of the state 76 | func (q *queryState) String() string { 77 | if q == nil { 78 | return queryStateName[queryStateUnknown] 79 | } 80 | return queryStateName[*q] 81 | } 82 | 83 | // Finished means we're not waiting for anything whether due to an error or due to completing the state changes 84 | func (q *queryState) Finished() bool { 85 | return q != nil && (*q == queryStateDone || *q == queryStateError) 86 | } 87 | 88 | // CollectingColumnMetaData returns true if we're still collecting column meta data. 89 | func (q *queryState) CollectingColumnMetaData() bool { 90 | return !q.Finished() && *q != queryStateWaitingRow 91 | } 92 | -------------------------------------------------------------------------------- /tests/charset_test.go: -------------------------------------------------------------------------------- 1 | // Go driver for MySQL X Protocol 2 | // 3 | // Copyright 2016 Simon J Mudd. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla Public 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | // You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | package test 10 | 11 | import ( 12 | "io" 13 | "testing" 14 | 15 | "github.com/sjmudd/go-mysqlx-driver/debug" 16 | ) 17 | 18 | /* 19 | output seen on my laptop 20 | 21 | root@localhost [(none)]> show global variables like '%char%'; 22 | +--------------------------+---------------------------------------------------------+ 23 | | Variable_name | Value | 24 | +--------------------------+---------------------------------------------------------+ 25 | | character_set_client | latin1 | 26 | | character_set_connection | latin1 | 27 | | character_set_database | latin1 | 28 | | character_set_filesystem | binary | 29 | | character_set_results | latin1 | 30 | | character_set_server | latin1 | 31 | | character_set_system | utf8 | 32 | | character_sets_dir | /usr/local/mysql-5.7.14-osx10.11-x86_64/share/charsets/ | 33 | +--------------------------+---------------------------------------------------------+ 34 | 8 rows in set (0.01 sec) 35 | */ 36 | 37 | // change the dsn to use ... /?charset=utf8mb4 38 | 39 | // Test04CharsetConnection 40 | func Test04CharsetConnection(t *testing.T) { 41 | const myName = "Test04CharsetConnection" 42 | var one int 43 | 44 | db, err := charsetOpen(myName) 45 | if err != nil { 46 | t.Errorf("%s: charsetOpen failed: %v", myName, err) 47 | } 48 | 49 | // Run simple SELECT query 50 | t.Logf("%s: test Query()", myName) 51 | rows, err := db.Query("SELECT 1") 52 | if err != nil { 53 | t.Fatal(err) 54 | } 55 | for rows.Next() { 56 | t.Logf("%s: read a row", myName) 57 | if err := rows.Scan(&one); err != nil { 58 | t.Fatal(err) 59 | } 60 | debug.Msg("processed row: one: %d", one) 61 | t.Logf("processed row: one: %d", one) 62 | } 63 | 64 | t.Logf("Checking for errors after reading all rows") 65 | if err := rows.Err(); err != nil && err != io.EOF { 66 | t.Fatal(err) 67 | } else { 68 | t.Logf("OK: no errors") 69 | } 70 | 71 | // close rows 72 | if err := rows.Close(); err != nil { 73 | t.Errorf(err.Error()) 74 | } 75 | 76 | // closing the connection 77 | if err = defaultClose(myName, db); err != nil { 78 | t.Errorf(err.Error()) 79 | } 80 | } 81 | 82 | // Test05CharsetConnection 83 | // 84 | // Should do something here to store the data in one character 85 | // set and then connect and get it back in another one. 86 | // That's a bit harder as we don't use/process the result set charset 87 | // data as this may need to be converted within Go to a string format 88 | // which would be UTF8 (unicode) I guess. 89 | -------------------------------------------------------------------------------- /tests/common_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "database/sql" 8 | ) 9 | 10 | const ( 11 | xprotocolDriver = "mysql/xprotocol" 12 | dsnCharsetSuffix = "?xprotocol=1&charset=utf8mb4" 13 | defaultDsnUser = "xprotocol_user" 14 | defaultDsnPass = "xprotocol_pass" 15 | defaultDsnHost = "127.0.0.1" 16 | defaultDsnPort = "33060" 17 | dsnSuffix = "?xprotocol=1" 18 | defaultDB = "xprotocol_test" 19 | ) 20 | 21 | var ( 22 | defaultDSN string 23 | charsetDSN string 24 | ) 25 | 26 | func init() { 27 | defaultDSN = dsnPrefix() + defaultDB + dsnSuffix 28 | charsetDSN = dsnPrefix() + defaultDB + dsnCharsetSuffix 29 | } 30 | 31 | // choose from the environment variable if it exists and is not empty 32 | // - was hard-coded defaultDsnPrefix = "xprotocol_user:xprotocol_pass@tcp(127.0.0.1:33060)/" 33 | func choose(envname, defaultValue string) string { 34 | if envValue := os.Getenv(envname); envValue != "" { 35 | return envValue 36 | } 37 | return defaultValue 38 | } 39 | 40 | // return the default prefix. We can now use environment variables to override the defaults. 41 | func dsnPrefix() string { 42 | return defaultDsnUser + 43 | ":" + 44 | defaultDsnPass + 45 | "@(" + 46 | choose("MYSQL_HOST", defaultDsnHost) + ":" + 47 | choose("MYSQLX_PORT", defaultDsnPort) + ")/" 48 | } 49 | 50 | type testDSN struct { 51 | dsn string 52 | result bool 53 | } 54 | type testDSNs []testDSN 55 | 56 | // open the connection to a standard port and provide the name of the test to simplify logging 57 | func defaultOpen(name string) (*sql.DB, error) { 58 | db, err := sql.Open(xprotocolDriver, defaultDSN) 59 | if err != nil { 60 | err = fmt.Errorf("connect(%q) db.Open(%q,%q) failed: %v", name, xprotocolDriver, defaultDSN, err) 61 | } 62 | return db, err 63 | } 64 | 65 | // open the connection to a standard port and provide the name of the test to simplify logging 66 | func charsetOpen(name string) (*sql.DB, error) { 67 | db, err := sql.Open(xprotocolDriver, charsetDSN) 68 | if err != nil { 69 | err = fmt.Errorf("connect(%q) db.Open(%q,%q) failed: %v", name, xprotocolDriver, charsetDSN, err) 70 | } 71 | return db, err 72 | } 73 | 74 | // closing the connection 75 | func defaultClose(name string, db *sql.DB) error { 76 | err := db.Close() 77 | if err != nil { 78 | err = fmt.Errorf("defaultClose(%q,db) db.Close() failed: %v", name, err) 79 | } 80 | return err 81 | } 82 | 83 | // close rows 84 | func defaultCloseRows(name string, rows *sql.Rows) error { 85 | err := rows.Close() 86 | if err != nil { 87 | err = fmt.Errorf("defaultCloseRows(%q,rows) rows.Close() failed: %v", name, err) 88 | } 89 | return err 90 | } 91 | -------------------------------------------------------------------------------- /tests/connect1_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "database/sql" 5 | "io" 6 | "testing" 7 | 8 | "github.com/sjmudd/go-mysqlx-driver/debug" 9 | ) 10 | 11 | // Test01ConnectToDB ensures that if we give a database name we end up in that db. 12 | func Test01ConnectToDB(t *testing.T) { 13 | var database []byte 14 | 15 | dbList := []string{defaultDB, ""} 16 | 17 | for i := range dbList { 18 | dbName := dbList[i] 19 | 20 | dsn := dsnPrefix() + dbName + dsnSuffix 21 | db, err := sql.Open(xprotocolDriver, dsn) 22 | if err != nil { 23 | t.Errorf("Test01ConnectToDB: could not connect to dsn:%s: %v", dsn, err) 24 | } else { 25 | t.Logf("OK: Open(%q,%q) succeeded", xprotocolDriver, dsn) 26 | } 27 | 28 | sql := `SELECT DATABASE()` 29 | rows, err := db.Query(sql) 30 | if err != nil { 31 | t.Fatal(err) 32 | } 33 | for rows.Next() { 34 | if err := rows.Scan(&database); err != nil { 35 | t.Fatal(err) 36 | } 37 | if string(database) != dbName { 38 | t.Errorf("Test01ConnectToDB: %q returned: %q, expected: %q", sql, database, dbName) 39 | } else { 40 | t.Logf("OK: connection to database %q matches result from SELECT DATABASE()", dbName) 41 | } 42 | } 43 | if err := rows.Err(); err != nil { 44 | t.Fatal(err.Error()) 45 | } 46 | 47 | if err = defaultClose("Test01ConnectToDB", db); err != nil { 48 | t.Errorf(err.Error()) 49 | } 50 | } 51 | } 52 | 53 | // Test02Ping checks we can connect and ping a database 54 | func Test02Ping(t *testing.T) { 55 | db, err := defaultOpen("Test02Ping") 56 | if err != nil { 57 | t.Errorf(err.Error()) 58 | } 59 | 60 | // force a connection to the server with Ping 61 | t.Logf("Test02Ping: test sql.Ping()") 62 | if err = db.Ping(); err != nil { 63 | t.Errorf("db.Ping() failed: %v", err) 64 | } else { 65 | t.Logf("OK: db.Ping() succeeded") 66 | } 67 | 68 | if err = defaultClose("Test02Ping", db); err != nil { 69 | t.Errorf(err.Error()) 70 | } 71 | } 72 | 73 | // Test03SimpleQuery checks we can do a simple query 74 | func Test03SimpleQuery(t *testing.T) { 75 | var ( 76 | one int 77 | two string 78 | three string 79 | ) 80 | db, err := defaultOpen("Test03SimpleQuery") 81 | if err != nil { 82 | t.Errorf("Test03SimpleQuery: connect() failed: %v", err) 83 | } 84 | 85 | // test simplest SELECT possible 86 | t.Logf("Test03SimpleQuery: test Query()") 87 | rows, err := db.Query("SELECT 1, DATABASE(), 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'") 88 | if err != nil { 89 | t.Fatal(err) 90 | } 91 | for rows.Next() { 92 | t.Logf("Test03SimpleQuery: read a row") 93 | if err := rows.Scan(&one, &two, &three); err != nil { 94 | t.Fatal(err) 95 | } 96 | debug.Msg("processed row: one: %d, two: %q, three: %q", one, two, three) 97 | t.Logf("processed row: one: %d, two: %q, three: %q", one, two, three) 98 | } 99 | 100 | t.Logf("Checking for errors after reading all rows") 101 | if err := rows.Err(); err != nil && err != io.EOF { 102 | t.Fatal(err) 103 | } else { 104 | t.Logf("OK: no errors") 105 | } 106 | 107 | // close rows 108 | if err := rows.Close(); err != nil { 109 | t.Errorf(err.Error()) 110 | } 111 | 112 | // closing the connection 113 | if err = defaultClose("Test03SimpleQuery", db); err != nil { 114 | t.Errorf(err.Error()) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /tests/multi_row_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/sjmudd/go-mysqlx-driver/debug" 8 | ) 9 | 10 | // genericRowsTest runs the query and checks we get back the expected number of rows 11 | func genericRowsTest(name, query string, expectedRows int) error { 12 | const myName = "genericRowsTest" 13 | 14 | db, err := defaultOpen(myName) 15 | if err != nil { 16 | return fmt.Errorf("%s: failed: %+v", myName, err) 17 | } 18 | 19 | debug.Msg("%s: %s: %q", myName, name, query) 20 | var ( 21 | collectedRows int 22 | i int // integer response from the query 23 | s string // string response from the query 24 | ) 25 | 26 | rows, err := db.Query(query) 27 | if err != nil { 28 | return fmt.Errorf("%s failed: %+v", myName, err) 29 | } 30 | defer rows.Close() 31 | for rows.Next() { 32 | if err := rows.Scan(&i, &s); err != nil { 33 | return fmt.Errorf("%s: scan failed: %+v", myName, err) 34 | } 35 | collectedRows++ 36 | debug.Msg("genericRowsTest: %s: collectedRows: %d, values: %d, %q", name, collectedRows, i, s) 37 | } 38 | if err := rows.Err(); err != nil { 39 | return fmt.Errorf("%s rows.Err() != nil: %+v", myName, err) 40 | } 41 | if collectedRows != expectedRows { 42 | return fmt.Errorf("%s: Received %d rows, exected: %d", myName, collectedRows, expectedRows) 43 | } 44 | 45 | if err = defaultClose(myName, db); err != nil { 46 | return fmt.Errorf("%s failed: %v", myName, err) 47 | } 48 | 49 | return nil // all ok 50 | } 51 | 52 | // Ensure we get no rows back 53 | func TestZeroRows(t *testing.T) { 54 | const myName = "TestZeroRows" 55 | const myQuery = `SELECT '' AS result WHERE result IS NULL` 56 | 57 | if err := genericRowsTest(myName, myQuery, 0); err != nil { 58 | t.Fatalf("%s failed: %+v", myName, err) 59 | } 60 | } 61 | 62 | // Ensure we get one row back 63 | func TestOneRow(t *testing.T) { 64 | const myName = "TestOneRow" 65 | const myQuery = `SELECT 1, 'something'` 66 | 67 | if err := genericRowsTest(myName, myQuery, 1); err != nil { 68 | t.Fatalf("%s failed: %+v", myName, err) 69 | } 70 | } 71 | 72 | // Ensure we get two rows back 73 | func TestTwoRows(t *testing.T) { 74 | const myName = "TestTwoRows" 75 | const myQuery = `SELECT * FROM ( (SELECT 1, "ONE") UNION ALL ( SELECT 2, "TWO") ) a` 76 | 77 | if err := genericRowsTest(myName, myQuery, 2); err != nil { 78 | t.Fatalf("%s failed: %+v", myName, err) 79 | } 80 | } 81 | // Ensure we get two rows back 82 | func TestThreeRows(t *testing.T) { 83 | const myName = "TestThreeRows" 84 | const myQuery = `SELECT * FROM ( (SELECT 1, "ONE") UNION ALL (SELECT 2, "TWO") UNION ALL (SELECT 3, "THREE") ) a` 85 | 86 | if err := genericRowsTest(myName, myQuery, 3); err != nil { 87 | t.Fatalf("%s failed: %+v", myName, err) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tests/mysql41_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "testing" 5 | 6 | driver "github.com/sjmudd/go-mysqlx-driver" 7 | ) 8 | 9 | func TestMySQL41(t *testing.T) { 10 | dbname := "world_x" 11 | username := "root" 12 | dbPassword := "fff" 13 | nineteenBytes := make([]byte, 19) 14 | twentyBytes := make([]byte, 20) 15 | twentytwoBytes := make([]byte, 22) 16 | 17 | // check we have a username 18 | if auth := driver.NewMySQL41(dbname, "", dbPassword); auth != nil { 19 | t.Errorf("MySQL41() with empty user should return nil, returned %+v", auth) 20 | } 21 | 22 | // throw an error if we have < 20 bytes 23 | auth := driver.NewMySQL41(dbname, username, dbPassword) 24 | if _, err := auth.GetNextAuthData(nineteenBytes); err == nil { 25 | t.Errorf("MySQL41().GetNextAuthData(<19 bytes>) did not return an error") 26 | } 27 | 28 | // throw an error if we have > 20 bytes 29 | if _, err := auth.GetNextAuthData(twentytwoBytes); err == nil { 30 | t.Errorf("MySQL41().GetNextAuthData(<22 bytes>) did not return an error") 31 | } 32 | 33 | // check length of result, should be length(usernname) + 2 x \x00 + 1 x '*' + 20-byte hash 34 | result, _ := auth.GetNextAuthData(twentyBytes) 35 | expected := len(dbname) + 2 + len(username) + 1 + 40 36 | if len(result) != expected { 37 | t.Errorf("MySQL41().GetNextAuthData(<20 bytes>) length: %d, expected: %d", 38 | len(result), 39 | expected) 40 | } 41 | 42 | // The first characters are the dbname so check \x00 after string of dbname 43 | if len(dbname) < len(result) && result[len(dbname)] != 0 && len(dbname) == 0 { 44 | t.Errorf("MySQL41().GetNextAuthData(<20 bytes>) result[0]: %d, expected: %d", 45 | result[0], 0) 46 | } 47 | 48 | // check that username is after the \x00 49 | if string(result[1+len(dbname):len(dbname)+len(username)+1]) != username { 50 | t.Errorf("TestMySQL41() username not found where expected, got %s, expected: %s", string(result[1+len(dbname):len(dbname)+len(username)+1]), dbPassword) 51 | } 52 | 53 | // check for \x00 after username 54 | if result[1+len(dbname)+len(username)] != 0 { 55 | t.Errorf("TestMySQL41() no null byte after username in result") 56 | } 57 | 58 | // check expectd hash of password (1) 59 | { 60 | buf := []byte{0xa, 0x35, 0x42, 0x1a, 0x43, 0x47, 0x6d, 0x65, 0x1, 0x4a, 0xf, 0x4c, 0x9, 0x5c, 0x32, 0x61, 0x64, 0x3c, 0x13, 0x6} 61 | result, _ := auth.GetNextAuthData(buf) 62 | 63 | exp := "*34439ed3004cf0e6030a9ec458338151bfb4e22d" 64 | if string(result[len(dbname)+len(dbPassword)+3:]) != exp { 65 | t.Errorf("hash of password %q: got %s, expected: %s", dbPassword, result, exp) 66 | } 67 | } 68 | // check expectd hash of password (2) 69 | { 70 | buf := []byte{0x41, 0x43, 0x56, 0x6e, 0x78, 0x19, 0x2c, 0x2c, 0x19, 0x6f, 0x18, 0x29, 0x05, 0x52, 0x3c, 0x62, 0x39, 0x3d, 0x5c, 0x77} 71 | result, _ := auth.GetNextAuthData(buf) 72 | 73 | exp := "*af1ef523d254181abb1155c1fbc933b80c2ec853" 74 | if string(result[len(dbname)+len(dbPassword)+3:]) != exp { 75 | t.Errorf("hash of password %q: got %s, expected: %s", dbPassword, result, exp) 76 | } 77 | } 78 | 79 | // should properly encode a result containing 0x10 and write "10" into the response buffer 80 | { 81 | buf := []byte{0x7a, 0x59, 0x6b, 0x6e, 0x19, 0x7f, 0x44, 0x1, 0x6f, 0x4a, 0xf, 0xf, 0x3e, 0x19, 0x50, 0x4c, 0x4f, 0x47, 0x53, 0x5b} 82 | result, _ := auth.GetNextAuthData(buf) 83 | 84 | exp := "*950d944626109ab5bce8bc56a4e78a296e34271d" 85 | if string(result[len(dbname)+len(dbPassword)+3:]) != exp { 86 | t.Errorf("hash of password %q: got %s, expected: %s", dbPassword, result, exp) 87 | } 88 | } 89 | 90 | // FIXME: I don't distinguish between no password and empty password. Need to fix. 91 | { 92 | auth := driver.NewMySQL41(dbname, username, "") 93 | result, _ := auth.GetNextAuthData(twentyBytes) 94 | if len(result) != len(dbname)+len(username)+2 { 95 | t.Errorf("GetNextAuthData() called with dbname %q, username %q and no password should have length %d, got %d", dbname, username, len(dbname)+len(username)+2, len(result)) 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tests/system_variable_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "database/sql" 5 | "testing" 6 | 7 | "github.com/sjmudd/go-mysqlx-driver/debug" 8 | ) 9 | 10 | // test getting back different types 11 | func Test04SystemVariables(t *testing.T) { 12 | var ( 13 | hostname string 14 | maxAllowedPacket int 15 | version string 16 | ) 17 | 18 | dsn := dsnPrefix() + defaultDB + dsnSuffix 19 | db, err := sql.Open("mysql/xprotocol", dsn) 20 | if err != nil { 21 | t.Errorf("Test04SystemVariables: could not connect to dsn:%s: %v", dsn, err) 22 | } 23 | 24 | // test a system variable (we need it later) 25 | query := `SELECT @@max_allowed_packet, @@version, @@hostname` 26 | t.Logf("Test04SystemVariables: testing: %q", query) 27 | rows, err := db.Query(query) 28 | if err != nil { 29 | t.Fatal(err) 30 | } 31 | var counter int 32 | defer rows.Close() 33 | for rows.Next() { 34 | counter++ 35 | if err := rows.Scan(&maxAllowedPacket, &version, &hostname); err != nil { 36 | t.Fatal(err) 37 | } 38 | t.Logf("processed row[%d]: max_allowed_packet: %d, version: %q, hostname: %q", counter, maxAllowedPacket, version, hostname) 39 | debug.Msg("processed row[%d]: max_allowed_packet: %d, version: %q, hostname: %q", counter, maxAllowedPacket, version, hostname) 40 | } 41 | if err := rows.Err(); err != nil { 42 | t.Fatal(err) 43 | } 44 | 45 | err = db.Close() 46 | if err != nil { 47 | t.Errorf("Test04SystemVariables: could not connect to dsn:%s: %v", dsn, err) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/tls_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | /* 4 | 5 | // test we can connect to TLS using certs in this directory 6 | func TestTLS(t *testing.T) { 7 | 8 | .....RegisterTLSConfig("testConfig", :x 9 | 10 | dsn := dsnPrefix + defaultDB + dsnSuffix 11 | const path = "./" // could be somewhere else but this will do for testing. 12 | 13 | rootCertPool := x509.NewCertPool() 14 | pem, err := ioutil.ReadFile(path + "ca-cert.pem") 15 | if err != nil { 16 | log.Fatal(err) 17 | } 18 | if ok := rootCertPool.AppendCertsFromPEM(pem); !ok { 19 | log.Fatal("Failed to append PEM.") 20 | } 21 | clientCert := make([]tls.Certificate, 0, 1) 22 | certs, err := tls.LoadX509KeyPair(path + "client-cert.pem", path + "client-key.pem") 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | clientCert = append(clientCert, certs) 27 | mysql.RegisterTLSConfig("custom", &tls.Config{ 28 | RootCAs: rootCertPool, 29 | Certificates: clientCert, 30 | }) 31 | db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom") 32 | if err != nil { 33 | } 34 | db.Close() 35 | } 36 | 37 | 38 | +// testing setting capabilities 39 | +func (mc *mysqlXConn) capabilityTestTLS() error { 40 | + // - Trigger a no-op change 41 | + // - check for 'tls' and set to the same value it has already (expected tobe false) 42 | + if mc.capabilities.Exists("tls") { 43 | + debug.Msg("Checking tls capability") 44 | + tls := mc.capabilities.Values("tls") 45 | + debug.Msg("- got back %d value(s) for tls", len(tls)) 46 | + if len(tls) == 1 { 47 | + tlsType := tls[0].Type() 48 | + debug.Msg("- tls has one value of type: %s", tlsType) 49 | + if tlsType == "bool" { 50 | + tlsValue := tls[0].Bool() 51 | + debug.Msg("- tls value: %v", tlsValue) 52 | + 53 | + // reset the value to the value it has at the moment... 54 | + debug.Msg("Setting tls to the same value it has already") 55 | + if err := mc.setScalarBoolCapability("tls", tlsValue); err != nil { 56 | + // debug.Msg("Enabling tls though the code won't handle it yet...") 57 | + // if err := mc.setScalarBoolCapability("tls", true); err != nil { 58 | + debug.Msg("capabilityTestTLS fails: %v", err) 59 | + return err 60 | + } 61 | + } 62 | + } 63 | + } 64 | + return nil 65 | +} 66 | 67 | Test05TLSTest(t *testing.T) { 68 | var ( 69 | hostname string 70 | max_allowed_packet int 71 | version string 72 | ) 73 | 74 | dsn := dsnPrefix + defaultDB + dsnSuffix 75 | db, err := sql.Open("mysql/xprotocol", dsn) 76 | if err != nil { 77 | t.Errorf("Test04SystemVariables: could not connect to dsn:%s: %v", dsn, err) 78 | } 79 | 80 | // test a system variable (we need it later) 81 | query := `SELECT @@max_allowed_packet, @@version, @@hostname` 82 | t.Logf("Test04SystemVariables: testing: %q", query) 83 | rows, err := db.Query(query) 84 | if err != nil { 85 | t.Fatal(err) 86 | } 87 | defer rows.Close() 88 | for rows.Next() { 89 | if err := rows.Scan(&max_allowed_packet,&version,&hostname); err != nil { 90 | t.Fatal(err) 91 | } 92 | t.Logf("processed row: max_allowed_packet: %d, version: %q, hostname: %q", max_allowed_packet,version,hostname) 93 | debug.Msg("processed row: max_allowed_packet: %d, version: %q, hostname: %q", max_allowed_packet,version,hostname) 94 | } 95 | if err := rows.Err(); err != nil { 96 | t.Fatal(err) 97 | } 98 | 99 | err = db.Close() 100 | if err != nil { 101 | t.Errorf("Test04SystemVariables: could not connect to dsn:%s: %v", dsn, err) 102 | } 103 | } 104 | */ 105 | -------------------------------------------------------------------------------- /tests/type_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/sjmudd/go-mysqlx-driver/debug" 8 | ) 9 | 10 | // test doing a query and returning the result 11 | func testAnyNonNullType(caller string, column string, table string, myVariable interface{}) error { 12 | db, err := defaultOpen(caller) 13 | if err != nil { 14 | return err 15 | } 16 | 17 | // test all types by collecting data 18 | query := fmt.Sprintf("SELECT %s FROM %s WHERE %s IS NOT NULL", column, table, column) 19 | debug.Msg("%s: query: %q", caller, query) 20 | rows, err := db.Query(query) 21 | if err != nil { 22 | return err 23 | } 24 | for rows.Next() { 25 | if err := rows.Scan(myVariable); err != nil { 26 | return err 27 | } 28 | debug.Msg("processed row: %s: %v", column, myVariable) 29 | } 30 | if err := rows.Err(); err != nil { 31 | return err 32 | } 33 | if err := rows.Close(); err != nil { 34 | return fmt.Errorf("%s: Unable to close rows:", caller, err) 35 | } 36 | 37 | err = defaultClose(caller, db) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | return nil 43 | } 44 | 45 | // TestTinyIntU tests MySQL tinyint unsigned, go uint8 46 | func TestTinyIntU(t *testing.T) { 47 | var myTinyintU uint8 48 | 49 | const ( 50 | caller = "TestTinyIntU" 51 | column = "my_tinyint_u" 52 | table = "xprotocol_test_tinyint_u" 53 | ) 54 | 55 | if err := testAnyNonNullType(caller, column, table, &myTinyintU); err != nil { 56 | t.Error("%s: ", caller, err) 57 | } 58 | } 59 | 60 | // TestTinyInt tests MySQL tinyint, go int8 61 | func TestTinyInt(t *testing.T) { 62 | var myTinyint int8 63 | const ( 64 | caller = "TestTinyInt" 65 | column = "my_tinyint" 66 | table = "xprotocol_test_tinyint" 67 | ) 68 | 69 | if err := testAnyNonNullType(caller, column, table, &myTinyint); err != nil { 70 | t.Error("%s: ", caller, err) 71 | } 72 | } 73 | 74 | func TestSmallintU(t *testing.T) { 75 | var mySmallintU uint16 76 | const ( 77 | caller = "TestSmallintU" 78 | column = "my_smallint_u" 79 | table = "xprotocol_test_smallint_u" 80 | ) 81 | 82 | if err := testAnyNonNullType(caller, column, table, &mySmallintU); err != nil { 83 | t.Error("%s: ", caller, err) 84 | } 85 | } 86 | 87 | // TestSmallint tests MySQL smallint, go int16 88 | func TestSmallint(t *testing.T) { 89 | var mySmallint int16 90 | const ( 91 | caller = "TestSmallint" 92 | column = "my_smallint" 93 | table = "xprotocol_test_smallint" 94 | ) 95 | 96 | if err := testAnyNonNullType(caller, column, table, &mySmallint); err != nil { 97 | t.Error("%s: ", caller, err) 98 | } 99 | } 100 | 101 | // TestMediumint tests MySQL mediumint unsigned, has no direct go type, use go uint32 102 | func TestMediumintU(t *testing.T) { 103 | var myMediumintU uint32 104 | const ( 105 | caller = "TestMediumintU" 106 | column = "my_mediumint_u" 107 | table = "xprotocol_test_mediumint_u" 108 | ) 109 | 110 | if err := testAnyNonNullType(caller, column, table, &myMediumintU); err != nil { 111 | t.Error("%s: ", caller, err) 112 | } 113 | } 114 | 115 | // TestMediumint tests MySQL mediumint, has no direct go type, use go int32 116 | func TestMediumint(t *testing.T) { 117 | var myMediumint int32 118 | const ( 119 | caller = "TestMediumint" 120 | column = "my_mediumint" 121 | table = "xprotocol_test_mediumint" 122 | ) 123 | 124 | if err := testAnyNonNullType(caller, column, table, &myMediumint); err != nil { 125 | t.Error("%s: ", caller, err) 126 | } 127 | } 128 | 129 | // TestIntU type (unsigned 32bits) 130 | func TestIntU(t *testing.T) { 131 | var myIntU uint32 132 | const ( 133 | caller = "TestInt" 134 | column = "my_int_u" 135 | table = "xprotocol_test_int_u" 136 | ) 137 | 138 | if err := testAnyNonNullType(caller, column, table, &myIntU); err != nil { 139 | t.Error("%s: ", caller, err) 140 | } 141 | } 142 | 143 | // TestInt tests MySQL int, go int32 144 | func TestInt(t *testing.T) { 145 | var myInt int32 146 | const ( 147 | caller = "TestInt" 148 | column = "my_int" 149 | table = "xprotocol_test_int" 150 | ) 151 | 152 | if err := testAnyNonNullType(caller, column, table, &myInt); err != nil { 153 | t.Error("%s: ", caller, err) 154 | } 155 | } 156 | 157 | // TestFloat tests MySQL float, go float32 158 | func TestFloat(t *testing.T) { 159 | var myFloat float32 160 | const ( 161 | caller = "TestFloat" 162 | column = "my_float" 163 | table = "xprotocol_test_float" 164 | ) 165 | 166 | if err := testAnyNonNullType(caller, column, table, &myFloat); err != nil { 167 | t.Error("%s: ", caller, err) 168 | } 169 | } 170 | 171 | // TestDouble tests MySQL double, go float64 172 | func TestDouble(t *testing.T) { 173 | var myDouble float64 174 | const ( 175 | caller = "TestDouble" 176 | column = "my_double" 177 | table = "xprotocol_test_double" 178 | ) 179 | 180 | if err := testAnyNonNullType(caller, column, table, &myDouble); err != nil { 181 | t.Error("%s: ", caller, err) 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /tests/xprotocol_test.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This script will create a database called xprotocol_test and allow a user 3 | * to access it. Minimal data will also be added to the database for 4 | * testing. 5 | * 6 | * Load in via the mysql command line using: 7 | * $ mysql -vvvt < xprotocol_test.sql 8 | */ 9 | 10 | CREATE DATABASE IF NOT EXISTS xprotocol_test; 11 | 12 | CREATE USER IF NOT EXISTS xprotocol_user@'127.0.0.1'; 13 | ALTER USER xprotocol_user@'127.0.0.1' IDENTIFIED BY 'xprotocol_pass'; 14 | GRANT ALL PRIVILEGES ON xprotocol_test.* TO xprotocol_user@'127.0.0.1'; 15 | 16 | USE xprotocol_test 17 | 18 | -- integer type 19 | DROP TABLE IF EXISTS t_int; 20 | CREATE TABLE t_int (id int NOT NULL PRIMARY KEY) ENGINE=InnoDB; 21 | INSERT INTO t_int VALUES (1), (2), (3), (4), (5); 22 | 23 | -- varchar type 24 | DROP TABLE IF EXISTS t_varchar; 25 | CREATE TABLE t_varchar (v varchar(255) NOT NULL PRIMARY KEY) ENGINE=InnoDB CHARSET=latin1; 26 | INSERT INTO t_varchar VALUES ('A'), ('B'), ('C'), ('D'), ('E'); 27 | 28 | -- table with lots of types 29 | DROP TABLE IF EXISTS field_test; 30 | CREATE TABLE `field_test` ( 31 | id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, 32 | `my_int_u` int unsigned NOT NULL, 33 | `my_int` int DEFAULT NULL, 34 | `my_tinyint_u` tinyint unsigned DEFAULT NULL, 35 | `my_tinyint` tinyint DEFAULT NULL, 36 | `my_smallint_u` smallint unsigned DEFAULT NULL, 37 | `my_smallint` smallint DEFAULT NULL, 38 | `my_mediumint_u` mediumint unsigned DEFAULT NULL, 39 | `my_mediumint` mediumint DEFAULT NULL, 40 | `my_bigint_u` bigint unsigned DEFAULT NULL, 41 | `my_bigint` bigint DEFAULT NULL, 42 | `my_double` double DEFAULT NULL, 43 | `my_float` float DEFAULT NULL, 44 | `my_decimal` decimal(10,2) DEFAULT NULL, 45 | `my_varchar` varchar(123) DEFAULT NULL, 46 | `my_char` char(5) DEFAULT NULL, 47 | `my_varbinary` varbinary(23) DEFAULT NULL, 48 | `my_binary` binary(3) DEFAULT NULL, 49 | `my_blob` tinyblob, 50 | `my_text` tinytext, 51 | `my_geometry` geometry DEFAULT NULL, 52 | `my_time` time DEFAULT NULL, 53 | `my_date` date DEFAULT NULL, 54 | `my_datetime` datetime DEFAULT NULL, 55 | `my_datetime_m` datetime(3) DEFAULT NULL, 56 | `my_year` year(4) DEFAULT NULL, 57 | `my_timestamp` timestamp NULL DEFAULT NULL, 58 | `my_timestamp_m` timestamp(6) NULL DEFAULT NULL, 59 | `my_set` set('1','2','3') DEFAULT NULL, 60 | `my_enum` enum('r','g','b') DEFAULT NULL, 61 | `my_bit` bit(17) DEFAULT NULL 62 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 63 | 64 | INSERT INTO field_test (my_int_u,my_int,my_tinyint_u,my_tinyint,my_smallint_u,my_smallint) 65 | VALUES 66 | ( 0, 0, 0,-128, 0,-32768), 67 | (999,-999, 255, 127, 65535, 32767); 68 | 69 | -- ------------------------------------------------------------------------- 70 | -- tinyint unsigned 71 | 72 | DROP TABLE IF EXISTS xprotocol_test_tinyint_u; 73 | CREATE TABLE `xprotocol_test_tinyint_u` ( 74 | id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, 75 | `my_tinyint_u` tinyint unsigned 76 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 77 | 78 | INSERT INTO xprotocol_test_tinyint_u 79 | (my_tinyint_u) 80 | VALUES 81 | -- (NULL), -- not handled yet 82 | (0), -- min 83 | (255); -- max 84 | 85 | -- ------------------------------------------------------------------------- 86 | -- tinyint 87 | 88 | DROP TABLE IF EXISTS xprotocol_test_tinyint; 89 | CREATE TABLE `xprotocol_test_tinyint` ( 90 | id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, 91 | `my_tinyint` tinyint 92 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 93 | 94 | INSERT INTO xprotocol_test_tinyint 95 | (my_tinyint) 96 | VALUES 97 | -- (NULL), -- not handled yet 98 | (-128), -- min 99 | (127); -- max 100 | 101 | -- ------------------------------------------------------------------------- 102 | -- unsigned int 103 | 104 | -- test each type in a single table 105 | DROP TABLE IF EXISTS xprotocol_test_int_u; 106 | CREATE TABLE `xprotocol_test_int_u` ( 107 | id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, 108 | `my_int_u` int unsigned 109 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 110 | 111 | INSERT INTO xprotocol_test_int_u 112 | (my_int_u) 113 | VALUES 114 | -- (NULL), -- not handled yet 115 | (0), -- min 116 | (999); -- some value 117 | 118 | -- ------------------------------------------------------------------------- 119 | -- int 120 | 121 | DROP TABLE IF EXISTS xprotocol_test_int; 122 | CREATE TABLE `xprotocol_test_int` ( 123 | id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, 124 | `my_int` int 125 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 126 | 127 | INSERT INTO xprotocol_test_int 128 | (my_int) 129 | VALUES 130 | -- (NULL), -- not handled yet 131 | (-999), -- negative value 132 | (999); -- positive value 133 | 134 | -- ------------------------------------------------------------------------- 135 | -- float 136 | 137 | DROP TABLE IF EXISTS xprotocol_test_float; 138 | CREATE TABLE `xprotocol_test_float` ( 139 | id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, 140 | `my_float` float 141 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 142 | 143 | INSERT INTO xprotocol_test_float 144 | (my_float) 145 | VALUES 146 | -- (NULL), -- not handled yet 147 | (0), -- zero 148 | (-99.9), -- negative value 149 | (99.9); -- positive value 150 | 151 | -- ------------------------------------------------------------------------- 152 | -- double 153 | 154 | DROP TABLE IF EXISTS xprotocol_test_double; 155 | CREATE TABLE `xprotocol_test_double` ( 156 | id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, 157 | `my_double` double 158 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 159 | 160 | INSERT INTO xprotocol_test_double 161 | (my_double) 162 | VALUES 163 | -- (NULL), -- not handled yet 164 | (0), -- zero 165 | (-99.9), -- negative value 166 | (99.9); -- positive value 167 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/LICENSE: -------------------------------------------------------------------------------- 1 | Go support for Protocol Buffers - Google's data interchange format 2 | 3 | Copyright 2010 The Go Authors. All rights reserved. 4 | https://github.com/golang/protobuf 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following disclaimer 14 | in the documentation and/or other materials provided with the 15 | distribution. 16 | * Neither the name of Google Inc. nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/Make.protobuf: -------------------------------------------------------------------------------- 1 | # Go support for Protocol Buffers - Google's data interchange format 2 | # 3 | # Copyright 2010 The Go Authors. All rights reserved. 4 | # https://github.com/golang/protobuf 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following disclaimer 14 | # in the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Google Inc. nor the names of its 17 | # contributors may be used to endorse or promote products derived from 18 | # this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | # Includable Makefile to add a rule for generating .pb.go files from .proto files 33 | # (Google protocol buffer descriptions). 34 | # Typical use if myproto.proto is a file in package mypackage in this directory: 35 | # 36 | # include $(GOROOT)/src/pkg/github.com/golang/protobuf/Make.protobuf 37 | 38 | %.pb.go: %.proto 39 | protoc --go_out=. $< 40 | 41 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/Makefile: -------------------------------------------------------------------------------- 1 | # Go support for Protocol Buffers - Google's data interchange format 2 | # 3 | # Copyright 2010 The Go Authors. All rights reserved. 4 | # https://github.com/golang/protobuf 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following disclaimer 14 | # in the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Google Inc. nor the names of its 17 | # contributors may be used to endorse or promote products derived from 18 | # this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | 33 | all: install 34 | 35 | install: 36 | go install ./proto ./jsonpb ./ptypes 37 | go install ./protoc-gen-go 38 | 39 | test: 40 | go test ./proto ./jsonpb ./ptypes 41 | make -C protoc-gen-go/testdata test 42 | 43 | clean: 44 | go clean ./... 45 | 46 | nuke: 47 | go clean -i ./... 48 | 49 | regenerate: 50 | make -C protoc-gen-go/descriptor regenerate 51 | make -C protoc-gen-go/plugin regenerate 52 | make -C protoc-gen-go/testdata regenerate 53 | make -C proto/testdata regenerate 54 | make -C jsonpb/jsonpb_test_proto regenerate 55 | make -C _conformance regenerate 56 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/proto/Makefile: -------------------------------------------------------------------------------- 1 | # Go support for Protocol Buffers - Google's data interchange format 2 | # 3 | # Copyright 2010 The Go Authors. All rights reserved. 4 | # https://github.com/golang/protobuf 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following disclaimer 14 | # in the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Google Inc. nor the names of its 17 | # contributors may be used to endorse or promote products derived from 18 | # this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | install: 33 | go install 34 | 35 | test: install generate-test-pbs 36 | go test 37 | 38 | 39 | generate-test-pbs: 40 | make install 41 | make -C testdata 42 | protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto 43 | make 44 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/proto/clone.go: -------------------------------------------------------------------------------- 1 | // Go support for Protocol Buffers - Google's data interchange format 2 | // 3 | // Copyright 2011 The Go Authors. All rights reserved. 4 | // https://github.com/golang/protobuf 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions are 8 | // met: 9 | // 10 | // * Redistributions of source code must retain the above copyright 11 | // notice, this list of conditions and the following disclaimer. 12 | // * Redistributions in binary form must reproduce the above 13 | // copyright notice, this list of conditions and the following disclaimer 14 | // in the documentation and/or other materials provided with the 15 | // distribution. 16 | // * Neither the name of Google Inc. nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | // Protocol buffer deep copy and merge. 33 | // TODO: RawMessage. 34 | 35 | package proto 36 | 37 | import ( 38 | "log" 39 | "reflect" 40 | "strings" 41 | ) 42 | 43 | // Clone returns a deep copy of a protocol buffer. 44 | func Clone(pb Message) Message { 45 | in := reflect.ValueOf(pb) 46 | if in.IsNil() { 47 | return pb 48 | } 49 | 50 | out := reflect.New(in.Type().Elem()) 51 | // out is empty so a merge is a deep copy. 52 | mergeStruct(out.Elem(), in.Elem()) 53 | return out.Interface().(Message) 54 | } 55 | 56 | // Merge merges src into dst. 57 | // Required and optional fields that are set in src will be set to that value in dst. 58 | // Elements of repeated fields will be appended. 59 | // Merge panics if src and dst are not the same type, or if dst is nil. 60 | func Merge(dst, src Message) { 61 | in := reflect.ValueOf(src) 62 | out := reflect.ValueOf(dst) 63 | if out.IsNil() { 64 | panic("proto: nil destination") 65 | } 66 | if in.Type() != out.Type() { 67 | // Explicit test prior to mergeStruct so that mistyped nils will fail 68 | panic("proto: type mismatch") 69 | } 70 | if in.IsNil() { 71 | // Merging nil into non-nil is a quiet no-op 72 | return 73 | } 74 | mergeStruct(out.Elem(), in.Elem()) 75 | } 76 | 77 | func mergeStruct(out, in reflect.Value) { 78 | sprop := GetProperties(in.Type()) 79 | for i := 0; i < in.NumField(); i++ { 80 | f := in.Type().Field(i) 81 | if strings.HasPrefix(f.Name, "XXX_") { 82 | continue 83 | } 84 | mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i]) 85 | } 86 | 87 | if emIn, ok := extendable(in.Addr().Interface()); ok { 88 | emOut, _ := extendable(out.Addr().Interface()) 89 | mIn, muIn := emIn.extensionsRead() 90 | if mIn != nil { 91 | mOut := emOut.extensionsWrite() 92 | muIn.Lock() 93 | mergeExtension(mOut, mIn) 94 | muIn.Unlock() 95 | } 96 | } 97 | 98 | uf := in.FieldByName("XXX_unrecognized") 99 | if !uf.IsValid() { 100 | return 101 | } 102 | uin := uf.Bytes() 103 | if len(uin) > 0 { 104 | out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...)) 105 | } 106 | } 107 | 108 | // mergeAny performs a merge between two values of the same type. 109 | // viaPtr indicates whether the values were indirected through a pointer (implying proto2). 110 | // prop is set if this is a struct field (it may be nil). 111 | func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) { 112 | if in.Type() == protoMessageType { 113 | if !in.IsNil() { 114 | if out.IsNil() { 115 | out.Set(reflect.ValueOf(Clone(in.Interface().(Message)))) 116 | } else { 117 | Merge(out.Interface().(Message), in.Interface().(Message)) 118 | } 119 | } 120 | return 121 | } 122 | switch in.Kind() { 123 | case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, 124 | reflect.String, reflect.Uint32, reflect.Uint64: 125 | if !viaPtr && isProto3Zero(in) { 126 | return 127 | } 128 | out.Set(in) 129 | case reflect.Interface: 130 | // Probably a oneof field; copy non-nil values. 131 | if in.IsNil() { 132 | return 133 | } 134 | // Allocate destination if it is not set, or set to a different type. 135 | // Otherwise we will merge as normal. 136 | if out.IsNil() || out.Elem().Type() != in.Elem().Type() { 137 | out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T) 138 | } 139 | mergeAny(out.Elem(), in.Elem(), false, nil) 140 | case reflect.Map: 141 | if in.Len() == 0 { 142 | return 143 | } 144 | if out.IsNil() { 145 | out.Set(reflect.MakeMap(in.Type())) 146 | } 147 | // For maps with value types of *T or []byte we need to deep copy each value. 148 | elemKind := in.Type().Elem().Kind() 149 | for _, key := range in.MapKeys() { 150 | var val reflect.Value 151 | switch elemKind { 152 | case reflect.Ptr: 153 | val = reflect.New(in.Type().Elem().Elem()) 154 | mergeAny(val, in.MapIndex(key), false, nil) 155 | case reflect.Slice: 156 | val = in.MapIndex(key) 157 | val = reflect.ValueOf(append([]byte{}, val.Bytes()...)) 158 | default: 159 | val = in.MapIndex(key) 160 | } 161 | out.SetMapIndex(key, val) 162 | } 163 | case reflect.Ptr: 164 | if in.IsNil() { 165 | return 166 | } 167 | if out.IsNil() { 168 | out.Set(reflect.New(in.Elem().Type())) 169 | } 170 | mergeAny(out.Elem(), in.Elem(), true, nil) 171 | case reflect.Slice: 172 | if in.IsNil() { 173 | return 174 | } 175 | if in.Type().Elem().Kind() == reflect.Uint8 { 176 | // []byte is a scalar bytes field, not a repeated field. 177 | 178 | // Edge case: if this is in a proto3 message, a zero length 179 | // bytes field is considered the zero value, and should not 180 | // be merged. 181 | if prop != nil && prop.proto3 && in.Len() == 0 { 182 | return 183 | } 184 | 185 | // Make a deep copy. 186 | // Append to []byte{} instead of []byte(nil) so that we never end up 187 | // with a nil result. 188 | out.SetBytes(append([]byte{}, in.Bytes()...)) 189 | return 190 | } 191 | n := in.Len() 192 | if out.IsNil() { 193 | out.Set(reflect.MakeSlice(in.Type(), 0, n)) 194 | } 195 | switch in.Type().Elem().Kind() { 196 | case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, 197 | reflect.String, reflect.Uint32, reflect.Uint64: 198 | out.Set(reflect.AppendSlice(out, in)) 199 | default: 200 | for i := 0; i < n; i++ { 201 | x := reflect.Indirect(reflect.New(in.Type().Elem())) 202 | mergeAny(x, in.Index(i), false, nil) 203 | out.Set(reflect.Append(out, x)) 204 | } 205 | } 206 | case reflect.Struct: 207 | mergeStruct(out, in) 208 | default: 209 | // unknown type, so not a protocol buffer 210 | log.Printf("proto: don't know how to copy %v", in) 211 | } 212 | } 213 | 214 | func mergeExtension(out, in map[int32]Extension) { 215 | for extNum, eIn := range in { 216 | eOut := Extension{desc: eIn.desc} 217 | if eIn.value != nil { 218 | v := reflect.New(reflect.TypeOf(eIn.value)).Elem() 219 | mergeAny(v, reflect.ValueOf(eIn.value), false, nil) 220 | eOut.value = v.Interface() 221 | } 222 | if eIn.enc != nil { 223 | eOut.enc = make([]byte, len(eIn.enc)) 224 | copy(eOut.enc, eIn.enc) 225 | } 226 | 227 | out[extNum] = eOut 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/proto/equal.go: -------------------------------------------------------------------------------- 1 | // Go support for Protocol Buffers - Google's data interchange format 2 | // 3 | // Copyright 2011 The Go Authors. All rights reserved. 4 | // https://github.com/golang/protobuf 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions are 8 | // met: 9 | // 10 | // * Redistributions of source code must retain the above copyright 11 | // notice, this list of conditions and the following disclaimer. 12 | // * Redistributions in binary form must reproduce the above 13 | // copyright notice, this list of conditions and the following disclaimer 14 | // in the documentation and/or other materials provided with the 15 | // distribution. 16 | // * Neither the name of Google Inc. nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | // Protocol buffer comparison. 33 | 34 | package proto 35 | 36 | import ( 37 | "bytes" 38 | "log" 39 | "reflect" 40 | "strings" 41 | ) 42 | 43 | /* 44 | Equal returns true iff protocol buffers a and b are equal. 45 | The arguments must both be pointers to protocol buffer structs. 46 | 47 | Equality is defined in this way: 48 | - Two messages are equal iff they are the same type, 49 | corresponding fields are equal, unknown field sets 50 | are equal, and extensions sets are equal. 51 | - Two set scalar fields are equal iff their values are equal. 52 | If the fields are of a floating-point type, remember that 53 | NaN != x for all x, including NaN. If the message is defined 54 | in a proto3 .proto file, fields are not "set"; specifically, 55 | zero length proto3 "bytes" fields are equal (nil == {}). 56 | - Two repeated fields are equal iff their lengths are the same, 57 | and their corresponding elements are equal (a "bytes" field, 58 | although represented by []byte, is not a repeated field) 59 | - Two unset fields are equal. 60 | - Two unknown field sets are equal if their current 61 | encoded state is equal. 62 | - Two extension sets are equal iff they have corresponding 63 | elements that are pairwise equal. 64 | - Every other combination of things are not equal. 65 | 66 | The return value is undefined if a and b are not protocol buffers. 67 | */ 68 | func Equal(a, b Message) bool { 69 | if a == nil || b == nil { 70 | return a == b 71 | } 72 | v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b) 73 | if v1.Type() != v2.Type() { 74 | return false 75 | } 76 | if v1.Kind() == reflect.Ptr { 77 | if v1.IsNil() { 78 | return v2.IsNil() 79 | } 80 | if v2.IsNil() { 81 | return false 82 | } 83 | v1, v2 = v1.Elem(), v2.Elem() 84 | } 85 | if v1.Kind() != reflect.Struct { 86 | return false 87 | } 88 | return equalStruct(v1, v2) 89 | } 90 | 91 | // v1 and v2 are known to have the same type. 92 | func equalStruct(v1, v2 reflect.Value) bool { 93 | sprop := GetProperties(v1.Type()) 94 | for i := 0; i < v1.NumField(); i++ { 95 | f := v1.Type().Field(i) 96 | if strings.HasPrefix(f.Name, "XXX_") { 97 | continue 98 | } 99 | f1, f2 := v1.Field(i), v2.Field(i) 100 | if f.Type.Kind() == reflect.Ptr { 101 | if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 { 102 | // both unset 103 | continue 104 | } else if n1 != n2 { 105 | // set/unset mismatch 106 | return false 107 | } 108 | b1, ok := f1.Interface().(raw) 109 | if ok { 110 | b2 := f2.Interface().(raw) 111 | // RawMessage 112 | if !bytes.Equal(b1.Bytes(), b2.Bytes()) { 113 | return false 114 | } 115 | continue 116 | } 117 | f1, f2 = f1.Elem(), f2.Elem() 118 | } 119 | if !equalAny(f1, f2, sprop.Prop[i]) { 120 | return false 121 | } 122 | } 123 | 124 | if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() { 125 | em2 := v2.FieldByName("XXX_InternalExtensions") 126 | if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) { 127 | return false 128 | } 129 | } 130 | 131 | if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() { 132 | em2 := v2.FieldByName("XXX_extensions") 133 | if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) { 134 | return false 135 | } 136 | } 137 | 138 | uf := v1.FieldByName("XXX_unrecognized") 139 | if !uf.IsValid() { 140 | return true 141 | } 142 | 143 | u1 := uf.Bytes() 144 | u2 := v2.FieldByName("XXX_unrecognized").Bytes() 145 | if !bytes.Equal(u1, u2) { 146 | return false 147 | } 148 | 149 | return true 150 | } 151 | 152 | // v1 and v2 are known to have the same type. 153 | // prop may be nil. 154 | func equalAny(v1, v2 reflect.Value, prop *Properties) bool { 155 | if v1.Type() == protoMessageType { 156 | m1, _ := v1.Interface().(Message) 157 | m2, _ := v2.Interface().(Message) 158 | return Equal(m1, m2) 159 | } 160 | switch v1.Kind() { 161 | case reflect.Bool: 162 | return v1.Bool() == v2.Bool() 163 | case reflect.Float32, reflect.Float64: 164 | return v1.Float() == v2.Float() 165 | case reflect.Int32, reflect.Int64: 166 | return v1.Int() == v2.Int() 167 | case reflect.Interface: 168 | // Probably a oneof field; compare the inner values. 169 | n1, n2 := v1.IsNil(), v2.IsNil() 170 | if n1 || n2 { 171 | return n1 == n2 172 | } 173 | e1, e2 := v1.Elem(), v2.Elem() 174 | if e1.Type() != e2.Type() { 175 | return false 176 | } 177 | return equalAny(e1, e2, nil) 178 | case reflect.Map: 179 | if v1.Len() != v2.Len() { 180 | return false 181 | } 182 | for _, key := range v1.MapKeys() { 183 | val2 := v2.MapIndex(key) 184 | if !val2.IsValid() { 185 | // This key was not found in the second map. 186 | return false 187 | } 188 | if !equalAny(v1.MapIndex(key), val2, nil) { 189 | return false 190 | } 191 | } 192 | return true 193 | case reflect.Ptr: 194 | // Maps may have nil values in them, so check for nil. 195 | if v1.IsNil() && v2.IsNil() { 196 | return true 197 | } 198 | if v1.IsNil() != v2.IsNil() { 199 | return false 200 | } 201 | return equalAny(v1.Elem(), v2.Elem(), prop) 202 | case reflect.Slice: 203 | if v1.Type().Elem().Kind() == reflect.Uint8 { 204 | // short circuit: []byte 205 | 206 | // Edge case: if this is in a proto3 message, a zero length 207 | // bytes field is considered the zero value. 208 | if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 { 209 | return true 210 | } 211 | if v1.IsNil() != v2.IsNil() { 212 | return false 213 | } 214 | return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte)) 215 | } 216 | 217 | if v1.Len() != v2.Len() { 218 | return false 219 | } 220 | for i := 0; i < v1.Len(); i++ { 221 | if !equalAny(v1.Index(i), v2.Index(i), prop) { 222 | return false 223 | } 224 | } 225 | return true 226 | case reflect.String: 227 | return v1.Interface().(string) == v2.Interface().(string) 228 | case reflect.Struct: 229 | return equalStruct(v1, v2) 230 | case reflect.Uint32, reflect.Uint64: 231 | return v1.Uint() == v2.Uint() 232 | } 233 | 234 | // unknown type, so not a protocol buffer 235 | log.Printf("proto: don't know how to compare %v", v1) 236 | return false 237 | } 238 | 239 | // base is the struct type that the extensions are based on. 240 | // x1 and x2 are InternalExtensions. 241 | func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool { 242 | em1, _ := x1.extensionsRead() 243 | em2, _ := x2.extensionsRead() 244 | return equalExtMap(base, em1, em2) 245 | } 246 | 247 | func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool { 248 | if len(em1) != len(em2) { 249 | return false 250 | } 251 | 252 | for extNum, e1 := range em1 { 253 | e2, ok := em2[extNum] 254 | if !ok { 255 | return false 256 | } 257 | 258 | m1, m2 := e1.value, e2.value 259 | 260 | if m1 != nil && m2 != nil { 261 | // Both are unencoded. 262 | if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { 263 | return false 264 | } 265 | continue 266 | } 267 | 268 | // At least one is encoded. To do a semantically correct comparison 269 | // we need to unmarshal them first. 270 | var desc *ExtensionDesc 271 | if m := extensionMaps[base]; m != nil { 272 | desc = m[extNum] 273 | } 274 | if desc == nil { 275 | log.Printf("proto: don't know how to compare extension %d of %v", extNum, base) 276 | continue 277 | } 278 | var err error 279 | if m1 == nil { 280 | m1, err = decodeExtension(e1.enc, desc) 281 | } 282 | if m2 == nil && err == nil { 283 | m2, err = decodeExtension(e2.enc, desc) 284 | } 285 | if err != nil { 286 | // The encoded form is invalid. 287 | log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err) 288 | return false 289 | } 290 | if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) { 291 | return false 292 | } 293 | } 294 | 295 | return true 296 | } 297 | -------------------------------------------------------------------------------- /vendor/github.com/sjmudd/mysql-server-rapid-plugin-x-protocol/README.md: -------------------------------------------------------------------------------- 1 | # mysql-server-rapid-plugin-x-protocol 2 | 3 | This is the list of protobuf files for the MySQL server's X plugin. 4 | 5 | Taken from upstream: https://github.com/mysql/mysql-server/blob/5.7/rapid/plugin/x/protocol 6 | 7 | Copyright as of upstream. These files are split out so that a MySQL X protocol specification 8 | can be made referring to these protocol files without having to refer to the rest of the 9 | MySQL server code. 10 | 11 | Initial import as of 5.7. Latest commit on mysql-server 1020e95 on Jul 12 2016. 12 | -------------------------------------------------------------------------------- /vendor/github.com/sjmudd/mysql-server-rapid-plugin-x-protocol/mysqlx.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | 20 | // tell protobuf 3.0 to use protobuf 2.x rules 21 | syntax = "proto2"; 22 | 23 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 24 | 25 | package Mysqlx; 26 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 27 | 28 | import "mysqlx_sql.proto"; 29 | import "mysqlx_resultset.proto"; 30 | import "mysqlx_crud.proto"; 31 | import "mysqlx_session.proto"; 32 | import "mysqlx_connection.proto"; 33 | import "mysqlx_expect.proto"; 34 | import "mysqlx_notice.proto"; 35 | 36 | // style-guide: 37 | // 38 | // see https://developers.google.com/protocol-buffers/docs/style 39 | // 40 | // message CamelCaseMsg { 41 | // enum CamelCaseEnum { 42 | // FIRST_VALUE = 1; 43 | // } 44 | // required CamelCaseEnum some_enum = 1; 45 | // } 46 | // 47 | 48 | 49 | // IDs of messages that can be sent from client to the server 50 | // 51 | // .. note:: 52 | // this message is never sent on the wire. It is only used to let ``protoc`` 53 | // 54 | // * generate constants 55 | // * check for uniqueness 56 | message ClientMessages { 57 | enum Type { 58 | CON_CAPABILITIES_GET = 1; 59 | CON_CAPABILITIES_SET = 2; 60 | CON_CLOSE = 3; 61 | 62 | SESS_AUTHENTICATE_START = 4; 63 | SESS_AUTHENTICATE_CONTINUE = 5; 64 | SESS_RESET = 6; 65 | SESS_CLOSE = 7; 66 | 67 | SQL_STMT_EXECUTE = 12; 68 | 69 | CRUD_FIND = 17; 70 | CRUD_INSERT = 18; 71 | CRUD_UPDATE = 19; 72 | CRUD_DELETE = 20; 73 | 74 | EXPECT_OPEN = 24; 75 | EXPECT_CLOSE = 25; 76 | } 77 | } 78 | 79 | // IDs of messages that can be sent from server to client 80 | // 81 | // .. note:: 82 | // this message is never sent on the wire. It is only used to let ``protoc`` 83 | // 84 | // * generate constants 85 | // * check for uniqueness 86 | message ServerMessages { 87 | enum Type { 88 | OK = 0; 89 | ERROR = 1; 90 | 91 | CONN_CAPABILITIES = 2; 92 | 93 | SESS_AUTHENTICATE_CONTINUE = 3; 94 | SESS_AUTHENTICATE_OK = 4; 95 | 96 | // NOTICE has to stay at 11 forever 97 | NOTICE = 11; 98 | 99 | RESULTSET_COLUMN_META_DATA = 12; 100 | RESULTSET_ROW = 13; 101 | RESULTSET_FETCH_DONE = 14; 102 | RESULTSET_FETCH_SUSPENDED = 15; 103 | RESULTSET_FETCH_DONE_MORE_RESULTSETS = 16; 104 | 105 | SQL_STMT_EXECUTE_OK = 17; 106 | RESULTSET_FETCH_DONE_MORE_OUT_PARAMS = 18; 107 | }; 108 | } 109 | 110 | 111 | // generic Ok message 112 | message Ok { 113 | optional string msg = 1; 114 | } 115 | 116 | 117 | // generic Error message 118 | // 119 | // A ``severity`` of ``ERROR`` indicates the current message sequence is 120 | // aborted for the given error and the session is ready for more. 121 | // 122 | // In case of a ``FATAL`` error message the client should not expect 123 | // the server to continue handling any further messages and should 124 | // close the connection. 125 | // 126 | // :param severity: severity of the error message 127 | // :param code: error-code 128 | // :param sql_state: SQL state 129 | // :param msg: human readable error message 130 | message Error { 131 | optional Severity severity = 1 [ default = ERROR ]; 132 | required uint32 code = 2; 133 | required string sql_state = 4; 134 | required string msg = 3; 135 | 136 | enum Severity { 137 | ERROR = 0; 138 | FATAL = 1; 139 | }; 140 | } 141 | -------------------------------------------------------------------------------- /vendor/github.com/sjmudd/mysql-server-rapid-plugin-x-protocol/mysqlx_connection.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | import "mysqlx_datatypes.proto"; 24 | 25 | package Mysqlx.Connection; 26 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 27 | 28 | // a Capability 29 | // 30 | // a tuple of a ``name`` and a :protobuf:msg:`Mysqlx.Datatypes::Any` 31 | message Capability { 32 | required string name = 1; 33 | required Mysqlx.Datatypes.Any value = 2; 34 | } 35 | 36 | // Capabilities 37 | message Capabilities { 38 | repeated Capability capabilities = 1; 39 | } 40 | 41 | // get supported connection capabilities and their current state 42 | // 43 | // :returns: :protobuf:msg:`Mysqlx.Connection::Capabilities` or :protobuf:msg:`Mysqlx::Error` 44 | // 45 | message CapabilitiesGet { 46 | }; 47 | 48 | // sets connection capabilities atomically 49 | // 50 | // only provided values are changed, other values are left unchanged. 51 | // If any of the changes fails, all changes are discarded. 52 | // 53 | // :precond: active sessions == 0 54 | // :returns: :protobuf:msg:`Mysqlx::Ok` or :protobuf:msg:`Mysqlx::Error` 55 | message CapabilitiesSet { 56 | required Capabilities capabilities = 1; 57 | }; 58 | 59 | // announce to the server that the client wants to close the connection 60 | // 61 | // it discards any session state of the server 62 | // 63 | // :Returns: :protobuf:msg:`Mysqlx::Ok` 64 | message Close { 65 | }; 66 | 67 | -------------------------------------------------------------------------------- /vendor/github.com/sjmudd/mysql-server-rapid-plugin-x-protocol/mysqlx_crud.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | // Basic CRUD operations 24 | package Mysqlx.Crud; 25 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 26 | 27 | import "mysqlx_expr.proto"; 28 | import "mysqlx_datatypes.proto"; 29 | 30 | // column definition 31 | message Column { 32 | optional string name = 1; 33 | optional string alias = 2; 34 | repeated Mysqlx.Expr.DocumentPathItem document_path = 3; 35 | } 36 | 37 | // a projection 38 | // 39 | // :param source: the expression identifying an element from the source data 40 | // which can include a column identifier or any expression 41 | // :param alias: optional alias. Required for DOCUMENTs (clients may use 42 | // the source string as default) 43 | message Projection { 44 | required Mysqlx.Expr.Expr source = 1; 45 | optional string alias = 2; 46 | } 47 | 48 | // DataModel to use for filters, names, ... 49 | enum DataModel { 50 | DOCUMENT = 1; 51 | TABLE = 2; 52 | }; 53 | 54 | // collection 55 | message Collection { 56 | required string name = 1; 57 | optional string schema = 2; 58 | } 59 | 60 | // limit 61 | // 62 | // :param row_count: maximum rows to filter 63 | // :param offset: maximum rows to skip before applying the row_count 64 | message Limit { 65 | required uint64 row_count = 1; 66 | optional uint64 offset = 2; 67 | } 68 | 69 | // sort order 70 | message Order { 71 | enum Direction { 72 | ASC = 1; 73 | DESC = 2; 74 | }; 75 | 76 | required Mysqlx.Expr.Expr expr = 1; 77 | optional Direction direction = 2 [ default=ASC ]; 78 | } 79 | 80 | // update operations 81 | // 82 | // :param source: specification of the value to be updated 83 | // if data_model is TABLE, a column name may be specified and also a document path, if the column has type JSON 84 | // if data_model is DOCUMENT, only document paths are allowed 85 | // in both cases, schema and table must be not set 86 | // :param operation: the type of operation to be performed 87 | // :param value: an expression to be computed as the new value for the operation 88 | message UpdateOperation { 89 | enum UpdateType { 90 | SET = 1; // only allowed for TABLE 91 | ITEM_REMOVE = 2; // no value (removes the identified path from a object or array) 92 | ITEM_SET = 3; // sets the new value on the identified path 93 | ITEM_REPLACE = 4; // replaces a value if the path exists 94 | ITEM_MERGE = 5; // source and value must be documents 95 | ARRAY_INSERT = 6; // insert the value in the array at the index identified in the source path 96 | ARRAY_APPEND = 7; // append the value on the array at the identified path 97 | } 98 | required Mysqlx.Expr.ColumnIdentifier source = 1; 99 | required UpdateType operation = 2; 100 | optional Mysqlx.Expr.Expr value = 3; 101 | } 102 | 103 | // Find Documents/Rows in a Collection/Table 104 | // 105 | // .. uml:: 106 | // 107 | // client -> server: Find 108 | // ... one or more Resultset ... 109 | // 110 | // :param collection: collection to insert into 111 | // :param data_model: datamodel that the operations refer to 112 | // :param projection: list of column projections that shall be returned 113 | // :param args: values for parameters used in filter expression 114 | // :param criteria: filter criteria 115 | // :param limit: numbers of rows that shall be skipped and returned 116 | // :param order: sort-order in which the rows/document shall be returned in 117 | // :param grouping: column expression list for aggregation (GROUP BY) 118 | // :param grouping_criteria: filter criteria for aggregated groups 119 | // :Returns: :protobuf:msg:`Mysqlx.Resultset::` 120 | message Find { 121 | required Collection collection = 2; 122 | 123 | optional DataModel data_model = 3; 124 | repeated Projection projection = 4; 125 | optional Mysqlx.Expr.Expr criteria = 5; 126 | repeated Mysqlx.Datatypes.Scalar args = 11; 127 | optional Limit limit = 6; 128 | repeated Order order = 7; 129 | repeated Mysqlx.Expr.Expr grouping = 8; 130 | optional Mysqlx.Expr.Expr grouping_criteria = 9; 131 | }; 132 | 133 | // Insert documents/rows into a collection/table 134 | // 135 | // :param collection: collection to insert into 136 | // :param data_model: datamodel that the operations refer to 137 | // :param projection: name of the columns to insert data into (empty if data_model is DOCUMENT) 138 | // :param row: set of rows to insert into the collection/table (a single expression with a JSON document literal or an OBJECT expression) 139 | // :param args: values for parameters used in row expressions 140 | // :Returns: :protobuf:msg:`Mysqlx.Resultset::` 141 | message Insert { 142 | required Collection collection = 1; 143 | 144 | optional DataModel data_model = 2; 145 | repeated Column projection = 3; 146 | 147 | message TypedRow { 148 | repeated Mysqlx.Expr.Expr field = 1; 149 | }; 150 | repeated TypedRow row = 4; 151 | repeated Mysqlx.Datatypes.Scalar args = 5; 152 | }; 153 | 154 | // Update documents/rows in a collection/table 155 | // 156 | // :param collection: collection to change 157 | // :param data_model: datamodel that the operations refer to 158 | // :param criteria: filter expression to match rows that the operations will apply on 159 | // :param args: values for parameters used in filter expression 160 | // :param limit: limits the number of rows to match 161 | // :param order: specifies order of matched rows 162 | // :param operation: list of operations to be applied. Valid operations will depend on the data_model. 163 | // :Returns: :protobuf:msg:`Mysqlx.Resultset::` 164 | message Update { 165 | required Collection collection = 2; 166 | 167 | optional DataModel data_model = 3; 168 | optional Mysqlx.Expr.Expr criteria = 4; 169 | repeated Mysqlx.Datatypes.Scalar args = 8; 170 | optional Limit limit = 5; 171 | repeated Order order = 6; 172 | 173 | repeated UpdateOperation operation = 7; 174 | }; 175 | 176 | // Delete documents/rows from a Collection/Table 177 | // 178 | // :param collection: collection to change 179 | // :param data_model: datamodel that the operations refer to 180 | // :param criteria: filter expression to match rows that the operations will apply on 181 | // :param args: values for parameters used in filter expression 182 | // :param limit: limits the number of rows to match 183 | // :param order: specifies order of matched rows 184 | // :Returns: :protobuf:msg:`Mysqlx.Resultset::` 185 | message Delete { 186 | required Collection collection = 1; 187 | 188 | optional DataModel data_model = 2; 189 | optional Mysqlx.Expr.Expr criteria = 3; 190 | repeated Mysqlx.Datatypes.Scalar args = 6; 191 | optional Limit limit = 4; 192 | repeated Order order = 5; 193 | }; 194 | 195 | -------------------------------------------------------------------------------- /vendor/github.com/sjmudd/mysql-server-rapid-plugin-x-protocol/mysqlx_datatypes.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | package Mysqlx.Datatypes; 24 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 25 | 26 | 27 | // a scalar 28 | message Scalar { 29 | // a string with a charset/collation 30 | message String { 31 | required bytes value = 1; 32 | optional uint64 collation = 2; 33 | }; 34 | 35 | // an opaque octet sequence, with an optional content_type 36 | // See ``Mysqlx.Resultset.ColumnMetadata`` for list of known values. 37 | message Octets { 38 | required bytes value = 1; 39 | optional uint32 content_type = 2; 40 | }; 41 | 42 | enum Type { 43 | V_SINT = 1; 44 | V_UINT = 2; 45 | V_NULL = 3; 46 | V_OCTETS = 4; 47 | V_DOUBLE = 5; 48 | V_FLOAT = 6; 49 | V_BOOL = 7; 50 | V_STRING = 8; 51 | }; 52 | 53 | required Type type = 1; 54 | 55 | optional sint64 v_signed_int = 2; 56 | optional uint64 v_unsigned_int = 3; 57 | // 4 is unused, was Null which doesn't have a storage anymore 58 | optional Octets v_octets = 5; 59 | optional double v_double = 6; 60 | optional float v_float = 7; 61 | optional bool v_bool = 8; 62 | optional String v_string = 9; 63 | } 64 | 65 | // a object 66 | message Object { 67 | message ObjectField { 68 | required string key = 1; 69 | required Any value = 2; 70 | } 71 | 72 | repeated ObjectField fld = 1; 73 | } 74 | 75 | // a Array 76 | message Array { 77 | repeated Any value = 1; 78 | } 79 | 80 | // a helper to allow all field types 81 | message Any { 82 | enum Type { 83 | SCALAR = 1; 84 | OBJECT = 2; 85 | ARRAY = 3; 86 | }; 87 | 88 | required Type type = 1; 89 | 90 | optional Scalar scalar = 2; 91 | optional Object obj = 3; 92 | optional Array array = 4; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /vendor/github.com/sjmudd/mysql-server-rapid-plugin-x-protocol/mysqlx_expect.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | // Expect operations 24 | package Mysqlx.Expect; 25 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 26 | 27 | // Pipelining messages is a core feature of the Mysqlx Protocol. It 28 | // sends messages to the server without waiting for a response to 29 | // save latency. 30 | // 31 | // * in case of success the time to wait and check the result as been saved 32 | // and the latency is reduced. 33 | // 34 | // * in the case of an error a mechanism is need to ensure that the following 35 | // messages are not executed, but skipped with an error instead. 36 | // 37 | // :: 38 | // 39 | // Mysqlx.Crud::PrepareFind(stmt_id=1,...) 40 | // Mysqlx.Expect::Open([no_error]) // if a execute fails 41 | // Mysqlx.PreparedStmt::Execute(stmt_id=1,...) 42 | // Mysqlx.PreparedStmt::Execute(stmt_id=1,...) 43 | // Mysqlx.Expect::Close() 44 | // Mysqlx.PreparedStmt::Close(stmt_id=1,...) 45 | // 46 | // This basic mechanism is extended to carry a arbitrary set of conditions that are 47 | // checked before executing message: 48 | // 49 | // :: 50 | // 51 | // Mysqlx.Expect::Open([+no_error, +gtid_executed_contains = "...", +max_stmt_exec_time_ms = 10]) 52 | // 53 | // Mysqlx.Expect::Close() 54 | // 55 | // Expect blocks can be nested to increase/change the restrictions for a subset of the 56 | // messages. At the end of the Expect block the previous restrictions are restored. 57 | // 58 | // :: 59 | // 60 | // Mysqlx.Expect::Open([+no_error]) // if preparing the Find fails, don't try to close it 61 | // Mysqlx.Crud::PrepareFind(stmt_id=1,...) 62 | // Mysqlx.Expect::Open([+no_error]) // if a Execute fails, skip the rest of them and continue with Close 63 | // Mysqlx.PreparedStmt::Execute(stmt_id=1,...) 64 | // Mysqlx.PreparedStmt::Execute(stmt_id=1,...) 65 | // Mysqlx.Expect::Close() 66 | // Mysqlx.PreparedStmt::Close(stmt_id=1,...) 67 | // Mysqlx.Expect::Close() 68 | 69 | // open an Expect block and set/unset the conditions that have to be fulfilled 70 | // 71 | // if any of the conditions fail, all enclosed messages will fail with 72 | // a Mysqlx.Error message. 73 | // 74 | // :returns: :protobuf:msg:`Mysqlx::Ok` on success, :protobuf:msg:`Mysqlx::Error` on error 75 | // 76 | message Open { 77 | message Condition { 78 | enum ConditionOperation { 79 | // set the condition 80 | // 81 | // set, if not set 82 | // overwrite, if set 83 | EXPECT_OP_SET = 0; 84 | // unset the condition 85 | EXPECT_OP_UNSET = 1; 86 | }; 87 | required uint32 condition_key = 1; 88 | optional bytes condition_value = 2; 89 | optional ConditionOperation op = 3 [ default = EXPECT_OP_SET ]; 90 | }; 91 | enum CtxOperation { 92 | // copy the operations from the parent Expect-block 93 | EXPECT_CTX_COPY_PREV = 0; 94 | // start with a empty set of operations 95 | EXPECT_CTX_EMPTY = 1; 96 | }; 97 | optional CtxOperation op = 1 [ default = EXPECT_CTX_COPY_PREV ]; 98 | repeated Condition cond = 2; 99 | } 100 | 101 | // close a Expect block 102 | // 103 | // closing a Expect block restores the state of the previous Expect block 104 | // for the following messages 105 | // 106 | // :returns: :protobuf:msg:`Mysqlx::Ok` on success, :protobuf:msg:`Mysqlx::Error` on error 107 | message Close { 108 | } 109 | 110 | -------------------------------------------------------------------------------- /vendor/github.com/sjmudd/mysql-server-rapid-plugin-x-protocol/mysqlx_expr.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | // Expression syntax 24 | // 25 | // expr is the fundamental structure in various places 26 | // of the SQL language: 27 | // 28 | // * ``SELECT AS ...`` 29 | // * ``WHERE `` 30 | // 31 | // The structures can be used to: 32 | // 33 | // * build an Item-tree in the MySQL Server 34 | // * generate SQL from it 35 | // * use as filter condition in CRUD's Find(), Update() and Delete() calls. 36 | package Mysqlx.Expr; 37 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 38 | 39 | import "mysqlx_datatypes.proto"; 40 | 41 | // Expressions 42 | // 43 | // the "root" of the expression tree 44 | // 45 | // .. productionlist:: 46 | // expr: `operator` | 47 | // : `identifier` | 48 | // : `function_call` | 49 | // : variable | 50 | // : `literal` | 51 | // : placeholder 52 | // 53 | // If expression type is PLACEHOLDER then it refers to the value of a parameter 54 | // specified when executing a statement (see `args` field of `StmtExecute` command). 55 | // Field `position` (which must be present for such an expression) gives 0-based 56 | // position of the parameter in the parameter list. 57 | // 58 | message Expr { 59 | enum Type { 60 | IDENT = 1; 61 | LITERAL = 2; 62 | VARIABLE = 3; 63 | FUNC_CALL = 4; 64 | OPERATOR = 5; 65 | PLACEHOLDER = 6; 66 | OBJECT = 7; 67 | ARRAY = 8; 68 | }; 69 | 70 | required Type type = 1; 71 | 72 | optional ColumnIdentifier identifier = 2; 73 | optional string variable = 3; 74 | optional Mysqlx.Datatypes.Scalar literal = 4; 75 | optional FunctionCall function_call = 5; 76 | optional Operator operator = 6; 77 | optional uint32 position = 7; 78 | optional Object object = 8; 79 | optional Array array = 9; 80 | } 81 | 82 | // identifier: name, schame.name 83 | // 84 | // .. productionlist:: 85 | // identifier: string "." string | 86 | // : string 87 | message Identifier { 88 | required string name = 1; 89 | optional string schema_name = 2; 90 | } 91 | 92 | // DocumentPathItem 93 | // 94 | // .. productionlist:: 95 | // document_path: path_item | path_item document_path 96 | // path_item : member | array_index | "**" 97 | // member : "." string | "." "*" 98 | // array_index : "[" number "]" | "[" "*" "]" 99 | // 100 | message DocumentPathItem { 101 | enum Type { 102 | MEMBER = 1; // .member 103 | MEMBER_ASTERISK = 2; // .* 104 | ARRAY_INDEX = 3; // [index] 105 | ARRAY_INDEX_ASTERISK = 4; // [*] 106 | DOUBLE_ASTERISK = 5; // ** 107 | }; 108 | required Type type = 1; 109 | optional string value = 2; 110 | optional uint32 index = 3; 111 | } 112 | 113 | 114 | // col_identifier (table): col@doc_path, tbl.col@doc_path col, tbl.col, schema.tbl.col 115 | // col_identifier (document): doc_path 116 | // 117 | // .. productionlist:: 118 | // col_identifier: string "." string "." string | 119 | // : string "." string | 120 | // : string | 121 | // : string "." string "." string "@" document_path | 122 | // : string "." string "@" document_path | 123 | // : string "@" document_path | 124 | // : document_path 125 | // document_path: member | arrayLocation | doubleAsterisk 126 | // member = "." string | "." "*" 127 | // arrayLocation = "[" index "]" | "[" "*" "]" 128 | // doubleAsterisk = "**" 129 | // 130 | message ColumnIdentifier { 131 | repeated Mysqlx.Expr.DocumentPathItem document_path = 1; 132 | optional string name = 2; 133 | optional string table_name = 3; 134 | optional string schema_name = 4; 135 | } 136 | 137 | // function call: ``func(a, b, "1", 3)`` 138 | // 139 | // .. productionlist:: 140 | // function_call: `identifier` "(" [ `expr` ["," `expr` ]* ] ")" 141 | message FunctionCall { 142 | required Identifier name = 1; 143 | repeated Expr param = 2; 144 | } 145 | 146 | // operator: ``<<(a, b)`` 147 | // 148 | // .. note:: 149 | // 150 | // Non-authoritative list of operators implemented (case sensitive): 151 | // 152 | // Nullary 153 | // * ``*`` 154 | // * ``default`` 155 | // 156 | // Unary 157 | // * ``!`` 158 | // * ``sign_plus`` 159 | // * ``sign_minus`` 160 | // * ``~`` 161 | // 162 | // Binary 163 | // * ``&&`` 164 | // * ``||`` 165 | // * ``xor`` 166 | // * ``==`` 167 | // * ``!=`` 168 | // * ``>`` 169 | // * ``>=`` 170 | // * ``<`` 171 | // * ``<=`` 172 | // * ``&`` 173 | // * ``|`` 174 | // * ``^`` 175 | // * ``<<`` 176 | // * ``>>`` 177 | // * ``+`` 178 | // * ``-`` 179 | // * ``*`` 180 | // * ``/`` 181 | // * ``div`` 182 | // * ``%`` 183 | // * ``is`` 184 | // * ``is_not`` 185 | // * ``regexp`` 186 | // * ``not_regexp`` 187 | // * ``like`` 188 | // * ``not_like`` 189 | // * ``cast`` 190 | // 191 | // Using special representation, with more than 2 params 192 | // * ``in`` (param[0] IN (param[1], param[2], ...)) 193 | // * ``not_in`` (param[0] NOT IN (param[1], param[2], ...)) 194 | // 195 | // Ternary 196 | // * ``between`` 197 | // * ``between_not`` 198 | // * ``date_add`` 199 | // * ``date_sub`` 200 | // 201 | // Units for date_add/date_sub 202 | // * ``MICROSECOND`` 203 | // * ``SECOND`` 204 | // * ``MINUTE`` 205 | // * ``HOUR`` 206 | // * ``DAY`` 207 | // * ``WEEK`` 208 | // * ``MONTH`` 209 | // * ``QUARTER`` 210 | // * ``YEAR`` 211 | // * ``SECOND_MICROSECOND`` 212 | // * ``MINUTE_MICROSECOND`` 213 | // * ``MINUTE_SECOND`` 214 | // * ``HOUR_MICROSECOND`` 215 | // * ``HOUR_SECOND`` 216 | // * ``HOUR_MINUTE`` 217 | // * ``DAY_MICROSECOND`` 218 | // * ``DAY_SECOND`` 219 | // * ``DAY_MINUTE`` 220 | // * ``DAY_HOUR`` 221 | // 222 | // Types for cast 223 | // * ``BINARY[(N)]`` 224 | // * ``CHAR[(N)]`` 225 | // * ``DATE`` 226 | // * ``DATETIME`` 227 | // * ``DECIMAL[(M[,D])]`` 228 | // * ``JSON`` 229 | // * ``SIGNED [INTEGER]`` 230 | // * ``TIME`` 231 | // * ``UNSIGNED [INTEGER]`` 232 | // 233 | // .. productionlist:: 234 | // operator: `name` "(" [ `expr` ["," `expr` ]* ] ")" 235 | message Operator { 236 | required string name = 1; 237 | repeated Expr param = 2; 238 | } 239 | 240 | // an object (with expression values) 241 | message Object { 242 | message ObjectField { 243 | required string key = 1; 244 | required Expr value = 2; 245 | } 246 | 247 | repeated ObjectField fld = 1; 248 | } 249 | 250 | // a Array of expressions 251 | message Array { 252 | repeated Expr value = 1; 253 | } 254 | -------------------------------------------------------------------------------- /vendor/github.com/sjmudd/mysql-server-rapid-plugin-x-protocol/mysqlx_notice.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | 20 | // tell protobuf 3.0 to use protobuf 2.x rules 21 | syntax = "proto2"; 22 | 23 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 24 | 25 | // Notices 26 | // 27 | // A notice 28 | // 29 | // * is sent from the server to the client 30 | // * may be global or relate to the current message sequence 31 | package Mysqlx.Notice; 32 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 33 | 34 | import "mysqlx_datatypes.proto"; 35 | 36 | // Common Frame for all Notices 37 | // 38 | // ===================================================== ===== 39 | // .type value 40 | // ===================================================== ===== 41 | // :protobuf:msg:`Mysqlx.Notice::Warning` 1 42 | // :protobuf:msg:`Mysqlx.Notice::SessionVariableChanged` 2 43 | // :protobuf:msg:`Mysqlx.Notice::SessionStateChanged` 3 44 | // ===================================================== ===== 45 | // 46 | // :param type: the type of the payload 47 | // :param payload: the payload of the notification 48 | // :param scope: global or local notification 49 | // 50 | message Frame { 51 | enum Scope { 52 | GLOBAL = 1; 53 | LOCAL = 2; 54 | }; 55 | required uint32 type = 1; 56 | optional Scope scope = 2 [ default = GLOBAL ]; 57 | optional bytes payload = 3; 58 | } 59 | 60 | // Server-side warnings and notes 61 | // 62 | // ``.scope`` == ``local`` 63 | // ``.level``, ``.code`` and ``.msg`` map the content of 64 | // 65 | // .. code-block:: sql 66 | // 67 | // SHOW WARNINGS 68 | // 69 | // ``.scope`` == ``global`` 70 | // (undefined) will be used for global, unstructured messages like: 71 | // 72 | // * server is shutting down 73 | // * a node disconnected from group 74 | // * schema or table dropped 75 | // 76 | // ========================================== ======================= 77 | // :protobuf:msg:`Mysqlx.Notice::Frame` field value 78 | // ========================================== ======================= 79 | // ``.type`` 1 80 | // ``.scope`` ``local`` or ``global`` 81 | // ========================================== ======================= 82 | // 83 | // :param level: warning level: Note or Warning 84 | // :param code: warning code 85 | // :param msg: warning message 86 | message Warning { 87 | enum Level { 88 | NOTE = 1; 89 | WARNING = 2; 90 | ERROR = 3; 91 | }; 92 | optional Level level = 1 [ default = WARNING ]; 93 | required uint32 code = 2; 94 | required string msg = 3; 95 | } 96 | 97 | // Notify clients about changes to the current session variables 98 | // 99 | // Every change to a variable that is accessable through: 100 | // 101 | // .. code-block:: sql 102 | // 103 | // SHOW SESSION VARIABLES 104 | // 105 | // ========================================== ========= 106 | // :protobuf:msg:`Mysqlx.Notice::Frame` field value 107 | // ========================================== ========= 108 | // ``.type`` 2 109 | // ``.scope`` ``local`` 110 | // ========================================== ========= 111 | // 112 | // :param namespace: namespace that param belongs to 113 | // :param param: name of the variable 114 | // :param value: the changed value of param 115 | message SessionVariableChanged { 116 | required string param = 1; 117 | optional Mysqlx.Datatypes.Scalar value = 2; 118 | } 119 | 120 | 121 | // Notify clients about changes to the internal session state 122 | // 123 | // ========================================== ========= 124 | // :protobuf:msg:`Mysqlx.Notice::Frame` field value 125 | // ========================================== ========= 126 | // ``.type`` 3 127 | // ``.scope`` ``local`` 128 | // ========================================== ========= 129 | // 130 | // :param param: parameter key 131 | // :param value: updated value 132 | message SessionStateChanged { 133 | enum Parameter { 134 | CURRENT_SCHEMA = 1; 135 | ACCOUNT_EXPIRED = 2; 136 | GENERATED_INSERT_ID = 3; 137 | ROWS_AFFECTED = 4; 138 | ROWS_FOUND = 5; 139 | ROWS_MATCHED = 6; 140 | TRX_COMMITTED = 7; 141 | TRX_ROLLEDBACK = 9; 142 | PRODUCED_MESSAGE = 10; 143 | CLIENT_ID_ASSIGNED = 11; 144 | // .. more to be added 145 | } 146 | required Parameter param = 1; 147 | optional Mysqlx.Datatypes.Scalar value = 2; 148 | } 149 | 150 | -------------------------------------------------------------------------------- /vendor/github.com/sjmudd/mysql-server-rapid-plugin-x-protocol/mysqlx_session.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | // Messages to manage Sessions 24 | // 25 | // .. uml:: 26 | // 27 | // == session start == 28 | // Client -> Server: AuthenticateStart 29 | // opt 30 | // Server --> Client: AuthenticateContinue 31 | // Client --> Server: AuthenticateContinue 32 | // end 33 | // alt 34 | // Server --> Client: AuthenticateOk 35 | // else 36 | // Server --> Client: Error 37 | // end 38 | // ... 39 | // == session reset == 40 | // Client -> Server: Reset 41 | // Server --> Client: Ok 42 | // == session end == 43 | // Client -> Server: Close 44 | // Server --> Client: Ok 45 | // 46 | package Mysqlx.Session; 47 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 48 | 49 | // the initial message send from the client to the server to start the 50 | // authentication proccess 51 | // 52 | // :param mech_name: authentication mechanism name 53 | // :param auth_data: authentication data 54 | // :param initial_response: initial response 55 | // :Returns: :protobuf:msg:`Mysqlx.Session::AuthenticateContinue` 56 | message AuthenticateStart { 57 | required string mech_name = 1; 58 | optional bytes auth_data = 2; 59 | optional bytes initial_response = 3; 60 | } 61 | 62 | // send by client or server after a :protobuf:msg:`Mysqlx.Session::AuthenticateStart` to 63 | // exchange more auth data 64 | // 65 | // :param auth_data: authentication data 66 | // :Returns: :protobuf:msg:`Mysqlx.Session::AuthenticateContinue` 67 | message AuthenticateContinue { 68 | required bytes auth_data = 1; 69 | } 70 | 71 | // sent by the server after successful authentication 72 | // 73 | // :param auth_data: authentication data 74 | message AuthenticateOk { 75 | optional bytes auth_data = 1; 76 | } 77 | 78 | // reset the current session 79 | // 80 | // :Returns: :protobuf:msg:`Mysqlx::Ok` 81 | message Reset { 82 | } 83 | 84 | // close the current session 85 | // 86 | // :Returns: :protobuf:msg:`Mysqlx::Ok` 87 | message Close { 88 | } 89 | 90 | -------------------------------------------------------------------------------- /vendor/github.com/sjmudd/mysql-server-rapid-plugin-x-protocol/mysqlx_sql.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; version 2 of the 7 | * License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17 | * 02110-1301 USA 18 | */ 19 | syntax = "proto2"; 20 | 21 | // ifdef PROTOBUF_LITE: option optimize_for = LITE_RUNTIME; 22 | 23 | // Messages of the MySQL Package 24 | package Mysqlx.Sql; 25 | option java_package = "com.mysql.cj.mysqlx.protobuf"; 26 | 27 | import "mysqlx_datatypes.proto"; 28 | 29 | // execute a statement in the given namespace 30 | // 31 | // .. uml:: 32 | // 33 | // client -> server: StmtExecute 34 | // ... zero or more Resultsets ... 35 | // server --> client: StmtExecuteOk 36 | // 37 | // Notices: 38 | // This message may generate a notice containing WARNINGs generated by its execution. 39 | // This message may generate a notice containing INFO messages generated by its execution. 40 | // 41 | // :param namespace: namespace of the statement to be executed 42 | // :param stmt: statement that shall be executed. 43 | // :param args: values for wildcard replacements 44 | // :param compact_metadata: send only type information for :protobuf:msg:`Mysqlx.Resultset::ColumnMetadata`, skipping names and others 45 | // :returns: 46 | // * zero or one :protobuf:msg:`Mysqlx.Resultset::` followed by :protobuf:msg:`Mysqlx.Sql::StmtExecuteOk` 47 | message StmtExecute { 48 | optional string namespace = 3 [ default = "sql" ]; 49 | required bytes stmt = 1; 50 | repeated Mysqlx.Datatypes.Any args = 2; 51 | optional bool compact_metadata = 4 [ default = false ]; 52 | } 53 | 54 | // statement executed successful 55 | message StmtExecuteOk { 56 | } 57 | 58 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "ignore": "test", 4 | "package": [ 5 | { 6 | "checksumSHA1": "G5qBL33D1rgCxlVq9btzXFMRRm8=", 7 | "path": "github.com/golang/protobuf", 8 | "revision": "888eb0692c857ec880338addf316bd662d5e630e", 9 | "revisionTime": "2016-08-23T21:25:17Z" 10 | }, 11 | { 12 | "checksumSHA1": "XnbEHQRzINRKXKmu9GcaqGkK4Lg=", 13 | "path": "github.com/golang/protobuf/proto", 14 | "revision": "888eb0692c857ec880338addf316bd662d5e630e", 15 | "revisionTime": "2016-08-23T21:25:17Z" 16 | }, 17 | { 18 | "checksumSHA1": "MYj5RnaTJH89MPyOklmZp+2ECPI=", 19 | "path": "github.com/sjmudd/mysql-server-rapid-plugin-x-protocol", 20 | "revision": "e29a1a9d0942fd53f9401a132837c18073c40018", 21 | "revisionTime": "2016-09-09T11:50:57Z" 22 | } 23 | ], 24 | "rootPath": "bitbucket.org/sjmudd/go-mysqlx-driver" 25 | } 26 | -------------------------------------------------------------------------------- /xconfig.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "crypto/tls" 5 | "time" 6 | ) 7 | 8 | type xconfig struct { 9 | user string 10 | passwd string 11 | net string 12 | addr string 13 | dbname string 14 | params map[string]string 15 | loc *time.Location 16 | tls *tls.Config 17 | timeout time.Duration 18 | collation uint8 19 | allowAllFiles bool 20 | allowCleartextPasswords bool 21 | columnsWithAlias bool 22 | interpolateParams bool 23 | useXProtocol bool // use X protocol rather than native protocol 24 | useGetCapabilities bool // for X protocol, do we send a GetCapabilities message to query server capabilities? default: true 25 | } 26 | 27 | func NewXconfigFromConfig(cfg *config) *xconfig { 28 | return &xconfig{ 29 | user: cfg.user, 30 | passwd: cfg.passwd, 31 | net: cfg.net, 32 | addr: cfg.addr, 33 | dbname: cfg.dbname, 34 | params: cfg.params, 35 | loc: cfg.loc, 36 | tls: cfg.tls, 37 | timeout: cfg.timeout, 38 | collation: cfg.collation, 39 | allowAllFiles: cfg.allowAllFiles, 40 | allowCleartextPasswords: cfg.allowCleartextPasswords, 41 | columnsWithAlias: cfg.columnsWithAlias, 42 | interpolateParams: cfg.interpolateParams, 43 | useXProtocol: true, 44 | } 45 | } 46 | --------------------------------------------------------------------------------