Skip to content

Commit ccf3f4c

Browse files
authored
Merge pull request #368 from Thorium/master
Exposed MySqlDbType #362 and initial version of GetSchema() #361
2 parents ad6b637 + d6008e7 commit ccf3f4c

File tree

5 files changed

+261
-2
lines changed

5 files changed

+261
-2
lines changed

src/MySqlConnector/MySqlClient/MySqlConnection.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Data;
44
using System.Data.Common;
5+
using System.Linq;
56
using System.Net.Sockets;
67
using System.Threading;
78
using System.Threading.Tasks;
@@ -215,6 +216,97 @@ private static async Task ClearPoolAsync(MySqlConnection connection, IOBehavior
215216

216217
#if !NETSTANDARD1_3
217218
protected override DbProviderFactory DbProviderFactory => MySqlClientFactory.Instance;
219+
220+
/// <summary>
221+
/// System.Data.Common, initial implementation of API DBConnection.GetSchema(String)
222+
/// Returns schema information for the data source of this DbConnection using the specified string for the schema name.
223+
/// </summary>
224+
/// <param name="collectionName">Specifies the name of the schema to return.</param>
225+
/// <returns>A DataTable that contains schema information.</returns>
226+
public override System.Data.DataTable GetSchema(string collectionName)
227+
{
228+
return GetSchema(collectionName, null);
229+
}
230+
231+
232+
/// <summary>
233+
/// System.Data.Common, initial implementation of API DBConnection.GetSchema(String)
234+
/// Returns schema information for the data source of this DbConnection using the specified string for the schema name.
235+
/// </summary>
236+
/// <param name="collectionName">Specifies the name of the schema to return.</param>
237+
/// <param name="restrictions">Restrictions not supported yet.</param>
238+
/// <returns>A DataTable that contains schema information.</returns>
239+
public override System.Data.DataTable GetSchema(string collectionName, string[] restrictions)
240+
{
241+
var dt = new DataTable(collectionName);
242+
switch (collectionName)
243+
{
244+
case "DataTypes":
245+
dt.Columns.AddRange(new[] { // The names come from DbMetaDataColumnNames
246+
new DataColumn("DataType", typeof(string)),
247+
new DataColumn("TypeName", typeof(string)),
248+
new DataColumn("ProviderDbType", typeof(int)),
249+
new DataColumn("IsUnsigned", typeof(bool))
250+
});
251+
252+
// Column type mappings:
253+
var colTypes = Types.TypeMapper.Mapper.GetColumnMappings();
254+
foreach (var map in colTypes)
255+
{
256+
var dbTypeMap = map.DbTypeMapping;
257+
var dbType = dbTypeMap.DbTypes.FirstOrDefault();
258+
dt.Rows.Add(new object[] {
259+
dbTypeMap.ClrType.FullName,
260+
map.ColumnTypeName,
261+
(int)dbType,
262+
map.Unsigned
263+
});
264+
}
265+
266+
// Data type mappings:
267+
foreach (MySqlDbType mapItem in Enum.GetValues(typeof(MySqlDbType)))
268+
{
269+
var typeName = Enum.GetName(typeof(MySqlDbType), mapItem);
270+
var dbType = Types.TypeMapper.ConvertFromMySqlDbType(mapItem);
271+
var map = Types.TypeMapper.Mapper.GetDbTypeMapping(dbType);
272+
if (map != null) // MySqlDbType.Set is not supported by the mapper.
273+
{
274+
dt.Rows.Add(new object[] {
275+
map.ClrType.FullName,
276+
Enum.GetName(typeof(MySqlDbType), mapItem).ToLower(),
277+
(int)dbType,
278+
typeName.Contains("UInt") || typeName.Contains("UByte")
279+
});
280+
}
281+
}
282+
return dt;
283+
284+
case "Procedures":
285+
dt.Columns.AddRange(new[] {
286+
new DataColumn("ROUTINE_TYPE"),
287+
new DataColumn("ROUTINE_SCHEMA"),
288+
new DataColumn("SPECIFIC_NAME")
289+
});
290+
var procsQuery = "SELECT ROUTINE_TYPE, ROUTINE_SCHEMA, SPECIFIC_NAME FROM INFORMATION_SCHEMA.ROUTINES;";
291+
if (m_connectionState != ConnectionState.Open)
292+
{
293+
Open();
294+
}
295+
using (var com = new MySqlCommand(procsQuery, this))
296+
using (var reader = com.ExecuteReader())
297+
{
298+
while (reader.Read())
299+
{
300+
dt.Rows.Add(new object[] { reader.GetString(0), reader.GetString(1), reader.GetString(2) });
301+
}
302+
}
303+
return dt;
304+
305+
default:
306+
throw new NotImplementedException("Not yet supported: GetSchema(\"" + collectionName + "\"). Please send a PR.");
307+
}
308+
}
309+
218310
#endif
219311

220312
public override int ConnectionTimeout => m_connectionSettings.ConnectionTimeout;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
3+
namespace MySql.Data.MySqlClient
4+
{
5+
public enum MySqlDbType
6+
{
7+
Decimal,
8+
Byte,
9+
Int16,
10+
Int24 = 9,
11+
Int32 = 3,
12+
Int64 = 8,
13+
Float = 4,
14+
Double,
15+
Timestamp = 7,
16+
Date = 10,
17+
Time,
18+
DateTime,
19+
[Obsolete("The Datetime enum value is obsolete. Please use DateTime.")]
20+
Datetime = 12,
21+
Year,
22+
Newdate,
23+
VarString,
24+
Bit,
25+
JSON = 245,
26+
NewDecimal,
27+
Enum,
28+
Set,
29+
TinyBlob,
30+
MediumBlob,
31+
LongBlob,
32+
Blob,
33+
VarChar,
34+
String,
35+
Geometry,
36+
UByte = 501,
37+
UInt16,
38+
UInt24 = 509,
39+
UInt32 = 503,
40+
UInt64 = 508,
41+
Binary = 600,
42+
VarBinary,
43+
TinyText = 749,
44+
MediumText,
45+
LongText,
46+
Text,
47+
Guid = 800
48+
}
49+
}

src/MySqlConnector/MySqlClient/MySqlParameter.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Data;
33
using System.Data.Common;
44
using System.IO;
@@ -11,6 +11,12 @@ public MySqlParameter()
1111
{
1212
}
1313

14+
public MySqlParameter(string name, object objValue)
15+
{
16+
ParameterName = name;
17+
Value = objValue;
18+
}
19+
1420
public override DbType DbType { get; set; }
1521

1622
public override ParameterDirection Direction
@@ -71,6 +77,16 @@ public override void ResetDbType()
7177
DbType = default(DbType);
7278
}
7379

80+
public MySqlDbType MySqlDbType {
81+
get {
82+
return Types.TypeMapper.ConverToMySqlDbType(DbType);
83+
}
84+
set {
85+
DbType = Types.TypeMapper.ConvertFromMySqlDbType(MySqlDbType);
86+
}
87+
}
88+
89+
7490
internal MySqlParameter WithParameterName(string parameterName) => new MySqlParameter(this, parameterName);
7591

7692
private MySqlParameter(MySqlParameter other, string parameterName)

src/MySqlConnector/MySqlClient/Types/TypeMapper.cs

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Data;
4+
using System.Data.Common;
45
using System.Linq;
56
using MySql.Data.Serialization;
67

@@ -131,6 +132,92 @@ internal ColumnTypeMapping GetColumnTypeMapping(string columnTypeName, bool unsi
131132
return columnTypeMapping;
132133
}
133134

135+
internal static MySqlDbType ConverToMySqlDbType(DbType dbtype)
136+
{
137+
switch (dbtype)
138+
{
139+
case DbType.AnsiString: return MySqlDbType.String;
140+
case DbType.Binary: return MySqlDbType.Binary;
141+
case DbType.Byte: return MySqlDbType.Byte;
142+
case DbType.Boolean: return MySqlDbType.Bit;
143+
case DbType.Currency: return MySqlDbType.Decimal;
144+
case DbType.Date: return MySqlDbType.Date;
145+
case DbType.DateTime: return MySqlDbType.DateTime;
146+
case DbType.Decimal: return MySqlDbType.Decimal;
147+
case DbType.Double: return MySqlDbType.Double;
148+
case DbType.Guid: return MySqlDbType.Guid;
149+
case DbType.Int16: return MySqlDbType.Int16;
150+
case DbType.Int32: return MySqlDbType.Int32;
151+
case DbType.Int64: return MySqlDbType.Int64;
152+
case DbType.Object: return MySqlDbType.Text;
153+
case DbType.SByte: return MySqlDbType.UByte;
154+
case DbType.Single: return MySqlDbType.Float;
155+
case DbType.String: return MySqlDbType.String;
156+
case DbType.Time: return MySqlDbType.Time;
157+
case DbType.UInt16: return MySqlDbType.UInt16;
158+
case DbType.UInt32: return MySqlDbType.UInt32;
159+
case DbType.UInt64: return MySqlDbType.UInt64;
160+
case DbType.VarNumeric: return MySqlDbType.Decimal;
161+
case DbType.AnsiStringFixedLength: return MySqlDbType.String;
162+
case DbType.StringFixedLength: return MySqlDbType.VarChar;
163+
case DbType.Xml: return MySqlDbType.Text;
164+
case DbType.DateTime2: return MySqlDbType.Newdate;
165+
case DbType.DateTimeOffset: return MySqlDbType.Timestamp;
166+
}
167+
throw new InvalidCastException("Never reached. " + dbtype.ToString());
168+
}
169+
internal static DbType ConvertFromMySqlDbType(MySqlDbType dbtype)
170+
{
171+
switch (dbtype)
172+
{
173+
case MySqlDbType.Decimal: return DbType.Decimal;
174+
case MySqlDbType.Byte: return DbType.Byte;
175+
case MySqlDbType.Int16: return DbType.Int16;
176+
case MySqlDbType.Int24: return DbType.Int32;
177+
case MySqlDbType.Int32: return DbType.Int32;
178+
case MySqlDbType.Int64: return DbType.Int64;
179+
case MySqlDbType.Float: return DbType.Single;
180+
case MySqlDbType.Double: return DbType.Double;
181+
case MySqlDbType.Timestamp: return DbType.DateTimeOffset;
182+
case MySqlDbType.Date: return DbType.Date;
183+
case MySqlDbType.Time: return DbType.Time;
184+
case MySqlDbType.DateTime: return DbType.DateTime;
185+
case MySqlDbType.Year: return DbType.Int16;
186+
case MySqlDbType.Newdate: return DbType.DateTime2;
187+
case MySqlDbType.VarString: return DbType.String;
188+
case MySqlDbType.Bit: return DbType.Boolean;
189+
case MySqlDbType.JSON: return DbType.String;
190+
case MySqlDbType.NewDecimal: return DbType.Decimal;
191+
case MySqlDbType.Enum: return DbType.Int16;
192+
case MySqlDbType.Set: return DbType.Object;
193+
case MySqlDbType.TinyBlob: return DbType.Binary;
194+
case MySqlDbType.MediumBlob: return DbType.Binary;
195+
case MySqlDbType.LongBlob: return DbType.Binary;
196+
case MySqlDbType.Blob: return DbType.Binary;
197+
case MySqlDbType.VarChar: return DbType.StringFixedLength;
198+
case MySqlDbType.String: return DbType.String;
199+
case MySqlDbType.Geometry: return DbType.Binary;
200+
case MySqlDbType.UByte: return DbType.SByte;
201+
case MySqlDbType.UInt16: return DbType.UInt16;
202+
case MySqlDbType.UInt24: return DbType.UInt32;
203+
case MySqlDbType.UInt32: return DbType.UInt32;
204+
case MySqlDbType.UInt64: return DbType.UInt64;
205+
case MySqlDbType.Binary: return DbType.Binary;
206+
case MySqlDbType.VarBinary: return DbType.Binary;
207+
case MySqlDbType.TinyText: return DbType.String;
208+
case MySqlDbType.MediumText: return DbType.String;
209+
case MySqlDbType.LongText: return DbType.String;
210+
case MySqlDbType.Text: return DbType.String;
211+
case MySqlDbType.Guid: return DbType.Guid;
212+
}
213+
throw new InvalidCastException("Never reached. " + dbtype.ToString());
214+
}
215+
216+
internal IEnumerable<ColumnTypeMapping> GetColumnMappings()
217+
{
218+
return m_columnTypeMappingLookup.Values.AsEnumerable();
219+
}
220+
134221
private Dictionary<Type, DbTypeMapping> m_dbTypeMappingsByClrType = new Dictionary<Type, DbTypeMapping>();
135222
private Dictionary<DbType, DbTypeMapping> m_dbTypeMappingsByDbType = new Dictionary<DbType, DbTypeMapping>();
136223
private Dictionary<string, ColumnTypeMapping> m_columnTypeMappingLookup = new Dictionary<string, ColumnTypeMapping>();

tests/MySqlConnector.Tests/ConnectionTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,21 @@ public void AuthPluginNameNotNullTerminated()
129129
}
130130
}
131131

132+
[Fact]
133+
public void GetSchemaHasDataTypesCollection()
134+
{
135+
using (var connection = new MySqlConnection(m_csb.ConnectionString))
136+
{
137+
var dataTypes = connection.GetSchema("DataTypes");
138+
Assert.Equal("DataType", dataTypes.Columns[0].ColumnName);
139+
Assert.True(dataTypes.Rows != null);
140+
Assert.True(dataTypes.Rows.Count > 15);
141+
var row1 = String.Join(",", dataTypes.Rows[0].ItemArray);
142+
Assert.Equal("System.Boolean,bit,3,False", row1);
143+
}
144+
}
145+
146+
132147
private static async Task WaitForConditionAsync<T>(T expected, Func<T> getValue)
133148
{
134149
var sw = Stopwatch.StartNew();

0 commit comments

Comments
 (0)