From 3041959320a36f1b3166e2bf24fd1d2dac1cea1d Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Wed, 16 Aug 2023 21:05:51 +0100 Subject: [PATCH 1/3] fix #1945 --- Dapper/CommandDefinition.cs | 22 +++++++++++++++++++--- Dapper/SqlMapper.Link.cs | 2 ++ Dapper/SqlMapper.Settings.cs | 24 +++++++++++++++++++++++- docs/index.md | 2 ++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/Dapper/CommandDefinition.cs b/Dapper/CommandDefinition.cs index 5860cd461..87d0d7119 100644 --- a/Dapper/CommandDefinition.cs +++ b/Dapper/CommandDefinition.cs @@ -131,6 +131,9 @@ internal IDbCommand SetupCommand(IDbConnection cnn, Action p private static SqlMapper.Link> commandInitCache; + internal static void ResetCommandInitCache() + => SqlMapper.Link>.Clear(ref commandInitCache); + private static Action GetInit(Type commandType) { if (commandType == null) @@ -141,14 +144,15 @@ private static Action 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); @@ -156,7 +160,7 @@ private static Action GetInit(Type 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); @@ -164,6 +168,18 @@ private static Action GetInit(Type 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)method.CreateDelegate(typeof(Action)); } diff --git a/Dapper/SqlMapper.Link.cs b/Dapper/SqlMapper.Link.cs index 277f2a9e9..fe6de9226 100644 --- a/Dapper/SqlMapper.Link.cs +++ b/Dapper/SqlMapper.Link.cs @@ -13,6 +13,8 @@ public static partial class SqlMapper /// The value type of the cache. internal class Link where TKey : class { + public static void Clear(ref Link head) => Interlocked.Exchange(ref head, null); + public static bool TryGet(Link link, TKey key, out TValue value) { while (link != null) diff --git a/Dapper/SqlMapper.Settings.cs b/Dapper/SqlMapper.Settings.cs index cc71238b2..2167fcbf9 100644 --- a/Dapper/SqlMapper.Settings.cs +++ b/Dapper/SqlMapper.Settings.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using System.Threading; namespace Dapper { @@ -63,7 +64,9 @@ static Settings() public static void SetDefaults() { CommandTimeout = null; - ApplyNullValues = false; + ApplyNullValues = PadListExpansions = UseIncrementalPseudoPositionalParameterNames = false; + AllowedCommandBehaviors = DefaultAllowedCommandBehaviors; + FetchSize = InListStringSplitCount = -1; } /// @@ -99,6 +102,25 @@ public static void SetDefaults() /// instead of the original name; for most scenarios, this is ignored since the name is redundant, but "snowflake" requires this. /// public static bool UseIncrementalPseudoPositionalParameterNames { get; set; } + + /// + /// If assigned a non-negative value, then that value is applied to any commands FetchSize property, if it exists; + /// see https://docs.oracle.com/en/database/oracle/oracle-database/18/odpnt/CommandFetchSize.html + /// + 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; } } } diff --git a/docs/index.md b/docs/index.md index e2092effc..7cae6517a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -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 (#XXXX via mgravell, fixes #1945) + (note: new PRs will not be merged until they add release note wording here) ### 2.0.143 From acc47c35558d2a803bcdc3f866bbf8f1e0f9b96d Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Wed, 16 Aug 2023 21:06:44 +0100 Subject: [PATCH 2/3] PR number --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 7cae6517a..f2c3a2498 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,7 +22,7 @@ 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 (#XXXX via mgravell, fixes #1945) +- add global `FetchSize` setting for use with Oracle (#1946 via mgravell, fixes #1945) (note: new PRs will not be merged until they add release note wording here) From 9e1e94a14b19ce62016da5db1032845ca1cc4b23 Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Wed, 16 Aug 2023 21:10:38 +0100 Subject: [PATCH 3/3] docs --- Dapper/SqlMapper.Settings.cs | 3 ++- docs/index.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Dapper/SqlMapper.Settings.cs b/Dapper/SqlMapper.Settings.cs index 2167fcbf9..192cd893d 100644 --- a/Dapper/SqlMapper.Settings.cs +++ b/Dapper/SqlMapper.Settings.cs @@ -105,7 +105,8 @@ public static void SetDefaults() /// /// If assigned a non-negative value, then that value is applied to any commands FetchSize property, if it exists; - /// see https://docs.oracle.com/en/database/oracle/oracle-database/18/odpnt/CommandFetchSize.html + /// 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. /// public static long FetchSize { diff --git a/docs/index.md b/docs/index.md index f2c3a2498..f1765c18e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,7 +22,7 @@ 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) +- add global `FetchSize` setting for use with Oracle (#1946 via mgravell, fixes #1945) (also add some missing logic in `Settings.Reset()`) (note: new PRs will not be merged until they add release note wording here)