Skip to content

Commit 8c9b4bd

Browse files
authored
Add FetchSize global setting (#1946)
* fix #1945 * PR number * docs
1 parent 33090c0 commit 8c9b4bd

File tree

4 files changed

+47
-4
lines changed

4 files changed

+47
-4
lines changed

Dapper/CommandDefinition.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ internal IDbCommand SetupCommand(IDbConnection cnn, Action<IDbCommand, object> p
131131

132132
private static SqlMapper.Link<Type, Action<IDbCommand>> commandInitCache;
133133

134+
internal static void ResetCommandInitCache()
135+
=> SqlMapper.Link<Type, Action<IDbCommand>>.Clear(ref commandInitCache);
136+
134137
private static Action<IDbCommand> GetInit(Type commandType)
135138
{
136139
if (commandType == null)
@@ -141,29 +144,42 @@ private static Action<IDbCommand> GetInit(Type commandType)
141144
}
142145
var bindByName = GetBasicPropertySetter(commandType, "BindByName", typeof(bool));
143146
var initialLongFetchSize = GetBasicPropertySetter(commandType, "InitialLONGFetchSize", typeof(int));
147+
var fetchSize = GetBasicPropertySetter(commandType, "FetchSize", typeof(long));
144148

145149
action = null;
146-
if (bindByName != null || initialLongFetchSize != null)
150+
if (bindByName is not null || initialLongFetchSize is not null || fetchSize is not null)
147151
{
148152
var method = new DynamicMethod(commandType.Name + "_init", null, new Type[] { typeof(IDbCommand) });
149153
var il = method.GetILGenerator();
150154

151-
if (bindByName != null)
155+
if (bindByName is not null)
152156
{
153157
// .BindByName = true
154158
il.Emit(OpCodes.Ldarg_0);
155159
il.Emit(OpCodes.Castclass, commandType);
156160
il.Emit(OpCodes.Ldc_I4_1);
157161
il.EmitCall(OpCodes.Callvirt, bindByName, null);
158162
}
159-
if (initialLongFetchSize != null)
163+
if (initialLongFetchSize is not null)
160164
{
161165
// .InitialLONGFetchSize = -1
162166
il.Emit(OpCodes.Ldarg_0);
163167
il.Emit(OpCodes.Castclass, commandType);
164168
il.Emit(OpCodes.Ldc_I4_M1);
165169
il.EmitCall(OpCodes.Callvirt, initialLongFetchSize, null);
166170
}
171+
if (fetchSize is not null)
172+
{
173+
var snapshot = SqlMapper.Settings.FetchSize;
174+
if (snapshot >= 0)
175+
{
176+
// .FetchSize = {withValue}
177+
il.Emit(OpCodes.Ldarg_0);
178+
il.Emit(OpCodes.Castclass, commandType);
179+
il.Emit(OpCodes.Ldc_I8, snapshot); // bake it as a constant
180+
il.EmitCall(OpCodes.Callvirt, fetchSize, null);
181+
}
182+
}
167183
il.Emit(OpCodes.Ret);
168184
action = (Action<IDbCommand>)method.CreateDelegate(typeof(Action<IDbCommand>));
169185
}

Dapper/SqlMapper.Link.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public static partial class SqlMapper
1313
/// <typeparam name="TValue">The value type of the cache.</typeparam>
1414
internal class Link<TKey, TValue> where TKey : class
1515
{
16+
public static void Clear(ref Link<TKey, TValue> head) => Interlocked.Exchange(ref head, null);
17+
1618
public static bool TryGet(Link<TKey, TValue> link, TKey key, out TValue value)
1719
{
1820
while (link != null)

Dapper/SqlMapper.Settings.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Data;
3+
using System.Threading;
34

45
namespace Dapper
56
{
@@ -63,7 +64,9 @@ static Settings()
6364
public static void SetDefaults()
6465
{
6566
CommandTimeout = null;
66-
ApplyNullValues = false;
67+
ApplyNullValues = PadListExpansions = UseIncrementalPseudoPositionalParameterNames = false;
68+
AllowedCommandBehaviors = DefaultAllowedCommandBehaviors;
69+
FetchSize = InListStringSplitCount = -1;
6770
}
6871

6972
/// <summary>
@@ -99,6 +102,26 @@ public static void SetDefaults()
99102
/// instead of the original name; for most scenarios, this is ignored since the name is redundant, but "snowflake" requires this.
100103
/// </summary>
101104
public static bool UseIncrementalPseudoPositionalParameterNames { get; set; }
105+
106+
/// <summary>
107+
/// If assigned a non-negative value, then that value is applied to any commands <c>FetchSize</c> property, if it exists;
108+
/// see https://docs.oracle.com/en/database/oracle/oracle-database/18/odpnt/CommandFetchSize.html; note that this value
109+
/// can only be set globally - it is not intended for frequent/contextual changing.
110+
/// </summary>
111+
public static long FetchSize
112+
{
113+
get => Volatile.Read(ref s_FetchSize);
114+
set
115+
{
116+
if (Volatile.Read(ref s_FetchSize) != value)
117+
{
118+
Volatile.Write(ref s_FetchSize, value);
119+
CommandDefinition.ResetCommandInitCache(); // if this setting is useful: we've invalidated things
120+
}
121+
}
122+
}
123+
124+
private static long s_FetchSize = -1;
102125
}
103126
}
104127
}

docs/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Note: to get the latest pre-release build, add ` -Pre` to the end of the command
2222

2323
### unreleased
2424

25+
26+
- add global `FetchSize` setting for use with Oracle (#1946 via mgravell, fixes #1945) (also add some missing logic in `Settings.Reset()`)
2527
- add underscore handling with constructors (#1786 via @jo-goro, fixes #818; also #1947 via mgravell)
2628

2729
(note: new PRs will not be merged until they add release note wording here)

0 commit comments

Comments
 (0)