Skip to content

Commit

Permalink
Add FetchSize global setting (#1946)
Browse files Browse the repository at this point in the history
* fix #1945

* PR number

* docs
  • Loading branch information
mgravell committed Aug 17, 2023
1 parent 33090c0 commit 8c9b4bd
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 4 deletions.
22 changes: 19 additions & 3 deletions Dapper/CommandDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ internal IDbCommand SetupCommand(IDbConnection cnn, Action<IDbCommand, object> p

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

internal static void ResetCommandInitCache()
=> SqlMapper.Link<Type, Action<IDbCommand>>.Clear(ref commandInitCache);

private static Action<IDbCommand> GetInit(Type commandType)
{
if (commandType == null)
Expand All @@ -141,29 +144,42 @@ private static Action<IDbCommand> GetInit(Type commandType)
}
var bindByName = GetBasicPropertySetter(commandType, "BindByName", typeof(bool));
var initialLongFetchSize = GetBasicPropertySetter(commandType, "InitialLONGFetchSize", typeof(int));
var fetchSize = GetBasicPropertySetter(commandType, "FetchSize", typeof(long));

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

if (bindByName != null)
if (bindByName is not null)
{
// .BindByName = true
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, commandType);
il.Emit(OpCodes.Ldc_I4_1);
il.EmitCall(OpCodes.Callvirt, bindByName, null);
}
if (initialLongFetchSize != null)
if (initialLongFetchSize is not null)
{
// .InitialLONGFetchSize = -1
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, commandType);
il.Emit(OpCodes.Ldc_I4_M1);
il.EmitCall(OpCodes.Callvirt, initialLongFetchSize, null);
}
if (fetchSize is not null)
{
var snapshot = SqlMapper.Settings.FetchSize;
if (snapshot >= 0)
{
// .FetchSize = {withValue}
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, commandType);
il.Emit(OpCodes.Ldc_I8, snapshot); // bake it as a constant
il.EmitCall(OpCodes.Callvirt, fetchSize, null);
}
}
il.Emit(OpCodes.Ret);
action = (Action<IDbCommand>)method.CreateDelegate(typeof(Action<IDbCommand>));
}
Expand Down
2 changes: 2 additions & 0 deletions Dapper/SqlMapper.Link.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public static partial class SqlMapper
/// <typeparam name="TValue">The value type of the cache.</typeparam>
internal class Link<TKey, TValue> where TKey : class
{
public static void Clear(ref Link<TKey, TValue> head) => Interlocked.Exchange(ref head, null);

public static bool TryGet(Link<TKey, TValue> link, TKey key, out TValue value)
{
while (link != null)
Expand Down
25 changes: 24 additions & 1 deletion Dapper/SqlMapper.Settings.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Data;
using System.Threading;

namespace Dapper
{
Expand Down Expand Up @@ -63,7 +64,9 @@ static Settings()
public static void SetDefaults()
{
CommandTimeout = null;
ApplyNullValues = false;
ApplyNullValues = PadListExpansions = UseIncrementalPseudoPositionalParameterNames = false;
AllowedCommandBehaviors = DefaultAllowedCommandBehaviors;
FetchSize = InListStringSplitCount = -1;
}

/// <summary>
Expand Down Expand Up @@ -99,6 +102,26 @@ public static void SetDefaults()
/// instead of the original name; for most scenarios, this is ignored since the name is redundant, but "snowflake" requires this.
/// </summary>
public static bool UseIncrementalPseudoPositionalParameterNames { get; set; }

/// <summary>
/// If assigned a non-negative value, then that value is applied to any commands <c>FetchSize</c> property, if it exists;
/// see https://docs.oracle.com/en/database/oracle/oracle-database/18/odpnt/CommandFetchSize.html; note that this value
/// can only be set globally - it is not intended for frequent/contextual changing.
/// </summary>
public static long FetchSize
{
get => Volatile.Read(ref s_FetchSize);
set
{
if (Volatile.Read(ref s_FetchSize) != value)
{
Volatile.Write(ref s_FetchSize, value);
CommandDefinition.ResetCommandInitCache(); // if this setting is useful: we've invalidated things
}
}
}

private static long s_FetchSize = -1;
}
}
}
2 changes: 2 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Note: to get the latest pre-release build, add ` -Pre` to the end of the command

### unreleased


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

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

0 comments on commit 8c9b4bd

Please sign in to comment.