Skip to content

Commit 54797eb

Browse files
committed
basic classes
1 parent 9ddbed5 commit 54797eb

13 files changed

Lines changed: 565 additions & 6 deletions

README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
# SuperSocket.MySQL
22

3-
[![Join the chat at https://gitter.im/supersocket/community](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/supersocket/community)
4-
[![Build Status](https://travis-ci.org/supersocket/SuperSocket.MySQL.svg?branch=master)](https://travis-ci.org/supersocket/SuperSocket.MySQL)
5-
6-
73
The MySQL driver base on SuperSocket
84

95
###### MySQL Protocol Specs
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
3+
namespace SuperSocket.MySQL
4+
{
5+
[Flags]
6+
public enum ClientCapabilities : uint
7+
{
8+
CLIENT_LONG_PASSWORD = 0x00000001,
9+
CLIENT_FOUND_ROWS = 0x00000002,
10+
CLIENT_LONG_FLAG = 0x00000004,
11+
CLIENT_CONNECT_WITH_DB = 0x00000008,
12+
CLIENT_NO_SCHEMA = 0x00000010,
13+
CLIENT_COMPRESS = 0x00000020,
14+
CLIENT_ODBC = 0x00000040,
15+
CLIENT_LOCAL_FILES = 0x00000080,
16+
CLIENT_IGNORE_SPACE = 0x00000100,
17+
CLIENT_PROTOCOL_41 = 0x00000200,
18+
CLIENT_INTERACTIVE = 0x00000400,
19+
CLIENT_SSL = 0x00000800,
20+
CLIENT_IGNORE_SIGPIPE = 0x00001000,
21+
CLIENT_TRANSACTIONS = 0x00002000,
22+
CLIENT_RESERVED = 0x00004000,
23+
CLIENT_SECURE_CONNECTION = 0x00008000,
24+
CLIENT_MULTI_STATEMENTS = 0x00010000,
25+
CLIENT_MULTI_RESULTS = 0x00020000,
26+
CLIENT_PS_MULTI_RESULTS = 0x00040000,
27+
CLIENT_PLUGIN_AUTH = 0x00080000,
28+
CLIENT_CONNECT_ATTRS = 0x00100000,
29+
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA = 0x00200000,
30+
CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS = 0x00400000,
31+
CLIENT_SESSION_TRACK = 0x00800000,
32+
CLIENT_DEPRECATE_EOF = 0x01000000,
33+
CLIENT_OPTIONAL_RESULTSET_METADATA = 0x02000000,
34+
CLIENT_ZSTD_COMPRESSION_ALGORITHM = 0x04000000,
35+
CLIENT_QUERY_ATTRIBUTES = 0x08000000,
36+
MULTI_FACTOR_AUTHENTICATION = 0x10000000,
37+
CLIENT_CAPABILITY_EXTENSION = 0x20000000,
38+
CLIENT_SSL_VERIFY_SERVER_CERT = 0x40000000,
39+
CLIENT_REMEMBER_OPTIONS = 0x80000000
40+
}
41+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
using System;
2+
using System.Buffers;
3+
using System.Text;
4+
5+
namespace SuperSocket.MySQL
6+
{
7+
public static class IBufferWriterExtensions
8+
{
9+
public static int WriteUInt8(this IBufferWriter<byte> writer, byte value)
10+
{
11+
var span = writer.GetSpan(1);
12+
span[0] = value;
13+
writer.Advance(1);
14+
return 1;
15+
}
16+
17+
public static int WriteUInt16(this IBufferWriter<byte> writer, ushort value)
18+
{
19+
var span = writer.GetSpan(2);
20+
span[0] = (byte)value;
21+
span[1] = (byte)(value >> 8);
22+
writer.Advance(2);
23+
return 2;
24+
}
25+
26+
public static int WriteUInt24(this IBufferWriter<byte> writer, uint value)
27+
{
28+
var span = writer.GetSpan(3);
29+
span[0] = (byte)value;
30+
span[1] = (byte)(value >> 8);
31+
span[2] = (byte)(value >> 16);
32+
writer.Advance(3);
33+
return 3;
34+
}
35+
36+
public static int WriteUInt32(this IBufferWriter<byte> writer, uint value)
37+
{
38+
var span = writer.GetSpan(4);
39+
span[0] = (byte)value;
40+
span[1] = (byte)(value >> 8);
41+
span[2] = (byte)(value >> 16);
42+
span[3] = (byte)(value >> 24);
43+
writer.Advance(4);
44+
return 4;
45+
}
46+
47+
public static int WriteUInt64(this IBufferWriter<byte> writer, ulong value)
48+
{
49+
var span = writer.GetSpan(8);
50+
span[0] = (byte)value;
51+
span[1] = (byte)(value >> 8);
52+
span[2] = (byte)(value >> 16);
53+
span[3] = (byte)(value >> 24);
54+
span[4] = (byte)(value >> 32);
55+
span[5] = (byte)(value >> 40);
56+
span[6] = (byte)(value >> 48);
57+
span[7] = (byte)(value >> 56);
58+
writer.Advance(8);
59+
return 8;
60+
}
61+
62+
public static int WriteLengthEncodedInteger(this IBufferWriter<byte> writer, ulong value)
63+
{
64+
if (value < 251)
65+
{
66+
writer.WriteUInt8((byte)value);
67+
return 1;
68+
}
69+
else if (value < 65536)
70+
{
71+
writer.WriteUInt8(0xFC);
72+
writer.WriteUInt16((ushort)value);
73+
return 3;
74+
}
75+
else if (value < 16777216)
76+
{
77+
writer.WriteUInt8(0xFD);
78+
writer.WriteUInt24((uint)value);
79+
return 4;
80+
}
81+
else
82+
{
83+
writer.WriteUInt8(0xFE);
84+
writer.WriteUInt64(value);
85+
return 9;
86+
}
87+
}
88+
89+
public static int WriteFixedString(this IBufferWriter<byte> writer, string value)
90+
{
91+
if (string.IsNullOrEmpty(value))
92+
return 0;
93+
94+
var maxByteCount = Encoding.UTF8.GetMaxByteCount(value.Length);
95+
var span = writer.GetSpan(maxByteCount);
96+
var bytesWritten = Encoding.UTF8.GetBytes(value, span);
97+
writer.Advance(bytesWritten);
98+
return bytesWritten;
99+
}
100+
101+
public static int WriteNullTerminatedString(this IBufferWriter<byte> writer, string value)
102+
{
103+
var bytesWritten = 0;
104+
105+
if (!string.IsNullOrEmpty(value))
106+
{
107+
var bytes = System.Text.Encoding.UTF8.GetBytes(value);
108+
var span = writer.GetSpan(bytes.Length + 1);
109+
bytes.CopyTo(span);
110+
span[bytes.Length] = 0; // null terminator
111+
writer.Advance(bytes.Length + 1);
112+
bytesWritten = bytes.Length + 1;
113+
}
114+
else
115+
{
116+
var span = writer.GetSpan(1);
117+
span[0] = 0; // null terminator
118+
writer.Advance(1);
119+
bytesWritten = 1;
120+
}
121+
122+
return bytesWritten;
123+
}
124+
125+
public static void WriteLengthEncodedString(this IBufferWriter<byte> writer, string value)
126+
{
127+
writer.WriteLengthEncodedInteger((ulong)value.Length);
128+
writer.WriteFixedString(value);
129+
}
130+
}
131+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System;
2+
3+
namespace SuperSocket.MySQL
4+
{
5+
public interface IMySQLPacketFactory
6+
{
7+
MySQLPacket Create(int packageType);
8+
}
9+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System;
2+
3+
namespace SuperSocket.MySQL
4+
{
5+
/// <summary>
6+
/// MySQL command types.
7+
/// Reference: https://dev.mysql.com/doc/internals/en/command-phase.html
8+
/// </summary>
9+
internal enum MySQLCommand : byte
10+
{
11+
COM_SLEEP = 0x00,
12+
COM_QUIT = 0x01,
13+
COM_INIT_DB = 0x02,
14+
COM_QUERY = 0x03,
15+
COM_FIELD_LIST = 0x04,
16+
COM_CREATE_DB = 0x05,
17+
COM_DROP_DB = 0x06,
18+
COM_REFRESH = 0x07,
19+
COM_SHUTDOWN = 0x08,
20+
COM_STATISTICS = 0x09,
21+
COM_PROCESS_INFO = 0x0A,
22+
COM_CONNECT = 0x0B,
23+
COM_PROCESS_KILL = 0x0C,
24+
COM_DEBUG = 0x0D,
25+
COM_PING = 0x0E,
26+
COM_TIME = 0x0F,
27+
COM_DELAYED_INSERT = 0x10,
28+
COM_CHANGE_USER = 0x11,
29+
COM_BINLOG_DUMP = 0x12,
30+
COM_TABLE_DUMP = 0x13,
31+
COM_CONNECT_OUT = 0x14,
32+
COM_REGISTER_SLAVE = 0x15,
33+
COM_STMT_PREPARE = 0x16,
34+
COM_STMT_EXECUTE = 0x17,
35+
COM_STMT_SEND_LONG_DATA = 0x18,
36+
COM_STMT_CLOSE = 0x19,
37+
COM_STMT_RESET = 0x1A,
38+
COM_SET_OPTION = 0x1B,
39+
COM_STMT_FETCH = 0x1C,
40+
COM_DAEMON = 0x1D,
41+
COM_BINLOG_DUMP_GTID = 0x1E,
42+
COM_RESET_CONNECTION = 0x1F
43+
}
44+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
using System.Buffers;
3+
using SuperSocket.ProtoBase;
4+
5+
namespace SuperSocket.MySQL
6+
{
7+
public class MySQLPacketDecoder : IPackageDecoder<MySQLPacket>
8+
{
9+
private readonly IMySQLPacketFactory _packetFactory;
10+
11+
public MySQLPacketDecoder(IMySQLPacketFactory packetFactory)
12+
{
13+
_packetFactory = packetFactory ?? throw new ArgumentNullException(nameof(packetFactory));
14+
}
15+
16+
public MySQLPacket Decode(ref ReadOnlySequence<byte> buffer, object context)
17+
{
18+
var package = _packetFactory.Create(0);
19+
var reader = new SequenceReader<byte>(buffer);
20+
package.Decode(ref reader, context);
21+
return package;
22+
}
23+
}
24+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Buffers;
3+
using SuperSocket.ProtoBase;
4+
5+
namespace SuperSocket.MySQL
6+
{
7+
internal class MySQLPacketEncoder : IPackageEncoder<MySQLPacket>
8+
{
9+
public int Encode(IBufferWriter<byte> bufferWriter, MySQLPacket package)
10+
{
11+
return package.Encode(bufferWriter);
12+
}
13+
}
14+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Buffers;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
6+
namespace SuperSocket.MySQL
7+
{
8+
internal class MySQLPacketFactory : IMySQLPacketFactory
9+
{
10+
private readonly Dictionary<int, Func<MySQLPacket>> _packetCreators = new ();
11+
12+
public void RegisterPacketType<TMySQLPacket>(int packageType)
13+
where TMySQLPacket : MySQLPacket, new()
14+
{
15+
_packetCreators[packageType] = () => new TMySQLPacket();
16+
}
17+
18+
public MySQLPacket Create(int packageType)
19+
{
20+
if (!_packetCreators.TryGetValue(packageType, out var creator))
21+
{
22+
throw new InvalidDataException($"No packet registered for package type {packageType}");
23+
}
24+
25+
return creator();
26+
}
27+
}
28+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Buffers;
3+
using SuperSocket.ProtoBase;
4+
5+
namespace SuperSocket.MySQL
6+
{
7+
public class MySQLPacketFilter : FixedHeaderPipelineFilter<MySQLPacket>
8+
{
9+
private const int headerSize = 4; // MySQL package header size is 4 bytes
10+
11+
public MySQLPacketFilter()
12+
: base(headerSize)
13+
{
14+
}
15+
16+
protected override int GetBodyLengthFromHeader(ref ReadOnlySequence<byte> buffer)
17+
{
18+
var reader = new SequenceReader<byte>(buffer);
19+
20+
reader.TryRead(out byte byte0);
21+
reader.TryRead(out byte byte1);
22+
reader.TryRead(out byte byte2);
23+
24+
return byte2 * 256 * 256 + byte1 * 256 + byte0;
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)