Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FetchSize global setting #1946

Merged
merged 4 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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