Skip to content

Commit b26876f

Browse files
committed
Merge pull request #235 from bgrainger/parameter-direction
Add better exception for unsupported ParameterDirection.
2 parents aeb9ead + 9c02738 commit b26876f

File tree

7 files changed

+81
-7
lines changed

7 files changed

+81
-7
lines changed

src/MySqlConnector/MySqlClient/Caches/CachedProcedure.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ internal MySqlParameterCollection AlignParamsWithDb(MySqlParameterCollection par
7575
alignParam = index >= 0 ? parameterCollection[index] : throw new ArgumentException($"Parameter '{cachedParam.Name}' not found in the collection.");
7676
}
7777

78-
if (alignParam.Direction == default(ParameterDirection))
78+
if (!alignParam.HasSetDirection)
7979
alignParam.Direction = cachedParam.Direction;
8080
if (alignParam.DbType == default(DbType))
8181
alignParam.DbType = cachedParam.DbType;
@@ -93,4 +93,4 @@ internal MySqlParameterCollection AlignParamsWithDb(MySqlParameterCollection par
9393
readonly string m_component;
9494
readonly ReadOnlyCollection<CachedParameter> m_parameters;
9595
}
96-
}
96+
}

src/MySqlConnector/MySqlClient/CommandExecutors/StoredProcedureCommandExecutor.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ public override async Task<DbDataReader> ExecuteReaderAsync(string commandText,
3737
var outName = "@outParam" + i;
3838
switch (param.Direction)
3939
{
40-
case 0:
4140
case ParameterDirection.Input:
4241
case ParameterDirection.InputOutput:
4342
var inParam = param.WithParameterName(inName);
@@ -79,7 +78,7 @@ public override async Task<DbDataReader> ExecuteReaderAsync(string commandText,
7978
var reader = (MySqlDataReader) await base.ExecuteReaderAsync(commandText, inParams, behavior, ioBehavior, cancellationToken).ConfigureAwait(false);
8079
if (returnParam != null && await reader.ReadAsync(ioBehavior, cancellationToken).ConfigureAwait(false))
8180
returnParam.Value = reader.GetValue(0);
82-
81+
8382
return reader;
8483
}
8584

@@ -115,4 +114,4 @@ internal void SetParams()
115114
List<string> m_outParamNames;
116115
private CancellationToken m_cancellationToken;
117116
}
118-
}
117+
}

src/MySqlConnector/MySqlClient/CommandExecutors/TextCommandExecutor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ public virtual async Task<DbDataReader> ExecuteReaderAsync(string commandText, M
6060
statementPreparerOptions |= StatementPreparerOptions.AllowUserVariables;
6161
if (m_command.Connection.OldGuids)
6262
statementPreparerOptions |= StatementPreparerOptions.OldGuids;
63+
if (m_command.CommandType == CommandType.StoredProcedure)
64+
statementPreparerOptions |= StatementPreparerOptions.AllowOutputParameters;
6365
var preparer = new MySqlStatementPreparer(commandText, parameterCollection, statementPreparerOptions);
6466
var payload = new PayloadData(preparer.ParseAndBindParameters());
6567
try

src/MySqlConnector/MySqlClient/MySqlParameter.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,19 @@ public MySqlParameter()
1313

1414
public override DbType DbType { get; set; }
1515

16-
public override ParameterDirection Direction { get; set; }
16+
public override ParameterDirection Direction
17+
{
18+
get => m_direction.GetValueOrDefault(ParameterDirection.Input);
19+
set
20+
{
21+
if (value != ParameterDirection.Input && value != ParameterDirection.Output &&
22+
value != ParameterDirection.InputOutput && value != ParameterDirection.ReturnValue)
23+
{
24+
throw new ArgumentOutOfRangeException(nameof(value), "{0} is not a supported value for ParameterDirection".FormatInvariant(value));
25+
}
26+
m_direction = value;
27+
}
28+
}
1729

1830
public override bool IsNullable { get; set; }
1931

@@ -64,7 +76,7 @@ public override void ResetDbType()
6476
private MySqlParameter(MySqlParameter other, string parameterName)
6577
{
6678
DbType = other.DbType;
67-
Direction = other.Direction;
79+
m_direction = other.m_direction;
6880
IsNullable = other.IsNullable;
6981
Size = other.Size;
7082
ParameterName = parameterName ?? other.ParameterName;
@@ -75,6 +87,8 @@ private MySqlParameter(MySqlParameter other, string parameterName)
7587
#endif
7688
}
7789

90+
internal bool HasSetDirection => m_direction.HasValue;
91+
7892
internal string NormalizedParameterName { get; private set; }
7993

8094
internal void AppendSqlString(BinaryWriter writer, StatementPreparerOptions options)
@@ -200,5 +214,6 @@ internal static string NormalizeParameterName(string name)
200214
}
201215

202216
string m_name;
217+
ParameterDirection? m_direction;
203218
}
204219
}

src/MySqlConnector/MySqlClient/MySqlStatementPreparer.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Data;
23
using System.IO;
34
using System.Text;
45
using MySql.Data.Serialization;
@@ -67,6 +68,9 @@ protected override void OnPositionalParameter(int index)
6768
private void DoAppendParameter(int parameterIndex, int textIndex, int textLength)
6869
{
6970
AppendString(m_preparer.m_commandText, m_lastIndex, textIndex - m_lastIndex);
71+
var parameter = m_preparer.m_parameters[parameterIndex];
72+
if (parameter.Direction != ParameterDirection.Input && (m_preparer.m_options & StatementPreparerOptions.AllowOutputParameters) == 0)
73+
throw new MySqlException("Only ParameterDirection.Input is supported when CommandType is Text (parameter name: {0})".FormatInvariant(parameter.ParameterName));
7074
m_preparer.m_parameters[parameterIndex].AppendSqlString(m_writer, m_preparer.m_options);
7175
m_lastIndex = textIndex + textLength;
7276
}

src/MySqlConnector/MySqlClient/StatementPreparerOptions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ internal enum StatementPreparerOptions
88
None = 0,
99
AllowUserVariables = 1,
1010
OldGuids = 2,
11+
AllowOutputParameters = 4,
1112
}
1213
}

tests/SideBySide/QueryTests.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,59 @@ private void UseReaderWithoutDisposingThread(object obj)
609609
}
610610
}
611611

612+
[Fact]
613+
public void ParameterDefaults()
614+
{
615+
var parameter = new MySqlParameter();
616+
Assert.Equal(DbType.AnsiString, parameter.DbType);
617+
Assert.Equal(ParameterDirection.Input, parameter.Direction);
618+
Assert.False(parameter.IsNullable);
619+
Assert.Null(parameter.ParameterName);
620+
Assert.Equal(0, parameter.Precision);
621+
Assert.Equal(0, parameter.Scale);
622+
Assert.Equal(0, parameter.Size);
623+
Assert.Null(parameter.Value);
624+
}
625+
626+
[Fact]
627+
public void InputOutputParameter()
628+
{
629+
using (var cmd = m_database.Connection.CreateCommand())
630+
{
631+
cmd.CommandText = "set @param = 1234";
632+
633+
cmd.Parameters.Add(new MySqlParameter
634+
{
635+
ParameterName = "@param",
636+
Direction = ParameterDirection.InputOutput,
637+
Value = 123,
638+
});
639+
640+
Assert.Throws<MySqlException>(() => cmd.ExecuteNonQuery());
641+
642+
// Issue #231: Assert.Equal(1234, cmd.Parameters["@param"].Value);
643+
}
644+
}
645+
646+
[Fact]
647+
public void OutputParameter()
648+
{
649+
using (var cmd = m_database.Connection.CreateCommand())
650+
{
651+
cmd.CommandText = "set @param = 1234";
652+
653+
cmd.Parameters.Add(new MySqlParameter
654+
{
655+
ParameterName = "@param",
656+
Direction = ParameterDirection.Output,
657+
});
658+
659+
Assert.Throws<MySqlException>(() => cmd.ExecuteNonQuery());
660+
661+
// Issue #231: Assert.Equal(1234, cmd.Parameters["@param"].Value);
662+
}
663+
}
664+
612665
class BoolTest
613666
{
614667
public int Id { get; set; }

0 commit comments

Comments
 (0)