7
7
using System . Data . Common ;
8
8
using System . Diagnostics ;
9
9
using System . Diagnostics . CodeAnalysis ;
10
+ using System . IO ;
10
11
using System . Reflection ;
12
+ using System . Runtime . InteropServices ;
11
13
using Microsoft . Data . Sqlite . Properties ;
12
14
using SQLitePCL ;
13
15
using static SQLitePCL . raw ;
@@ -52,38 +54,50 @@ static SqliteConnection()
52
54
? . GetRuntimeMethod ( "Init" , Type . EmptyTypes )
53
55
? . Invoke ( null , null ) ;
54
56
55
- var appDataType = Type . GetType ( "Windows.Storage.ApplicationData, Windows, ContentType=WindowsRuntime" )
56
- ?? Type . GetType ( "Windows.Storage.ApplicationData, Microsoft.Windows.SDK.NET" ) ;
57
-
58
- var storageFolderType = Type . GetType ( "Windows.Storage.StorageFolder, Windows, ContentType=WindowsRuntime" )
59
- ?? Type . GetType ( "Windows.Storage.StorageFolder, Microsoft.Windows.SDK.NET" ) ;
60
-
61
- object ? currentAppData = null ;
62
- try
57
+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
63
58
{
64
- currentAppData = appDataType ? . GetRuntimeProperty ( "Current" ) ? . GetValue ( null ) ;
65
- }
66
- catch ( TargetInvocationException )
67
- {
68
- // Ignore "The process has no package identity."
69
- }
59
+ Type ? appDataType = null ;
60
+ Type ? storageFolderType = null ;
61
+ try
62
+ {
63
+ appDataType = Type . GetType ( "Windows.Storage.ApplicationData, Windows, ContentType=WindowsRuntime" )
64
+ ?? Type . GetType ( "Windows.Storage.ApplicationData, Microsoft.Windows.SDK.NET" ) ;
70
65
71
- if ( currentAppData != null )
72
- {
73
- var localFolder = appDataType ? . GetRuntimeProperty ( "LocalFolder" ) ? . GetValue ( currentAppData ) ;
74
- var localFolderPath = ( string ? ) storageFolderType ? . GetRuntimeProperty ( "Path" ) ? . GetValue ( localFolder ) ;
75
- if ( localFolderPath != null )
66
+ storageFolderType = Type . GetType ( "Windows.Storage.StorageFolder, Windows, ContentType=WindowsRuntime" )
67
+ ?? Type . GetType ( "Windows.Storage.StorageFolder, Microsoft.Windows.SDK.NET" ) ;
68
+ }
69
+ catch ( FileLoadException )
76
70
{
77
- var rc = sqlite3_win32_set_directory ( SQLITE_WIN32_DATA_DIRECTORY_TYPE , localFolderPath ) ;
78
- Debug . Assert ( rc == SQLITE_OK ) ;
71
+ // Ignore "Could not load assembly."
79
72
}
80
73
81
- var tempFolder = appDataType ? . GetRuntimeProperty ( "TemporaryFolder" ) ? . GetValue ( currentAppData ) ;
82
- var tempFolderPath = ( string ? ) storageFolderType ? . GetRuntimeProperty ( "Path" ) ? . GetValue ( tempFolder ) ;
83
- if ( tempFolderPath != null )
74
+ object ? currentAppData = null ;
75
+ try
76
+ {
77
+ currentAppData = appDataType ? . GetRuntimeProperty ( "Current" ) ? . GetValue ( null ) ;
78
+ }
79
+ catch ( TargetInvocationException )
84
80
{
85
- var rc = sqlite3_win32_set_directory ( SQLITE_WIN32_TEMP_DIRECTORY_TYPE , tempFolderPath ) ;
86
- Debug . Assert ( rc == SQLITE_OK ) ;
81
+ // Ignore "The process has no package identity."
82
+ }
83
+
84
+ if ( currentAppData != null )
85
+ {
86
+ var localFolder = appDataType ? . GetRuntimeProperty ( "LocalFolder" ) ? . GetValue ( currentAppData ) ;
87
+ var localFolderPath = ( string ? ) storageFolderType ? . GetRuntimeProperty ( "Path" ) ? . GetValue ( localFolder ) ;
88
+ if ( localFolderPath != null )
89
+ {
90
+ var rc = sqlite3_win32_set_directory ( SQLITE_WIN32_DATA_DIRECTORY_TYPE , localFolderPath ) ;
91
+ Debug . Assert ( rc == SQLITE_OK ) ;
92
+ }
93
+
94
+ var tempFolder = appDataType ? . GetRuntimeProperty ( "TemporaryFolder" ) ? . GetValue ( currentAppData ) ;
95
+ var tempFolderPath = ( string ? ) storageFolderType ? . GetRuntimeProperty ( "Path" ) ? . GetValue ( tempFolder ) ;
96
+ if ( tempFolderPath != null )
97
+ {
98
+ var rc = sqlite3_win32_set_directory ( SQLITE_WIN32_TEMP_DIRECTORY_TYPE , tempFolderPath ) ;
99
+ Debug . Assert ( rc == SQLITE_OK ) ;
100
+ }
87
101
}
88
102
}
89
103
}
@@ -821,22 +835,24 @@ private void CreateAggregateCore<TAccumulate, TResult>(
821
835
delegate_function_aggregate_step ? func_step = null ;
822
836
if ( func != null )
823
837
{
824
- func_step = ( ctx , user_data , args ) =>
838
+ func_step = static ( ctx , user_data , args ) =>
825
839
{
826
- var context = ( AggregateContext < TAccumulate > ) user_data ;
840
+ var definition = ( AggregateDefinition < TAccumulate , TResult > ) user_data ;
841
+ ctx . state ??= new AggregateContext < TAccumulate > ( definition . Seed ) ;
842
+
843
+ var context = ( AggregateContext < TAccumulate > ) ctx . state ;
827
844
if ( context . Exception != null )
828
845
{
829
846
return ;
830
847
}
831
848
832
849
// TODO: Avoid allocation when niladic
833
- var reader = new SqliteParameterReader ( name , args ) ;
850
+ var reader = new SqliteParameterReader ( definition . Name , args ) ;
834
851
835
852
try
836
853
{
837
- // TODO: Avoid closure by passing func via user_data
838
854
// NB: No need to set ctx.state since we just mutate the instance
839
- context . Accumulate = func ( context . Accumulate , reader ) ;
855
+ context . Accumulate = definition . Func ! ( context . Accumulate , reader ) ;
840
856
}
841
857
catch ( Exception ex )
842
858
{
@@ -848,16 +864,18 @@ private void CreateAggregateCore<TAccumulate, TResult>(
848
864
delegate_function_aggregate_final ? func_final = null ;
849
865
if ( resultSelector != null )
850
866
{
851
- func_final = ( ctx , user_data ) =>
867
+ func_final = static ( ctx , user_data ) =>
852
868
{
853
- var context = ( AggregateContext < TAccumulate > ) user_data ;
869
+ var definition = ( AggregateDefinition < TAccumulate , TResult > ) user_data ;
870
+ ctx . state ??= new AggregateContext < TAccumulate > ( definition . Seed ) ;
871
+
872
+ var context = ( AggregateContext < TAccumulate > ) ctx . state ;
854
873
855
874
if ( context . Exception == null )
856
875
{
857
876
try
858
877
{
859
- // TODO: Avoid closure by passing resultSelector via user_data
860
- var result = resultSelector ( context . Accumulate ) ;
878
+ var result = definition . ResultSelector ! ( context . Accumulate ) ;
861
879
862
880
new SqliteResultBinder ( ctx , result ) . Bind ( ) ;
863
881
}
@@ -881,7 +899,7 @@ private void CreateAggregateCore<TAccumulate, TResult>(
881
899
}
882
900
883
901
var flags = isDeterministic ? SQLITE_DETERMINISTIC : 0 ;
884
- var state = new AggregateContext < TAccumulate > ( seed ) ;
902
+ var state = new AggregateDefinition < TAccumulate , TResult > ( name , seed , func , resultSelector ) ;
885
903
886
904
if ( State == ConnectionState . Open )
887
905
{
@@ -915,6 +933,22 @@ private void CreateAggregateCore<TAccumulate, TResult>(
915
933
return values ;
916
934
}
917
935
936
+ private sealed class AggregateDefinition < TAccumulate , TResult >
937
+ {
938
+ public AggregateDefinition ( string name , TAccumulate seed , Func < TAccumulate , SqliteValueReader , TAccumulate > ? func , Func < TAccumulate , TResult > ? resultSelector )
939
+ {
940
+ Name = name ;
941
+ Seed = seed ;
942
+ Func = func ;
943
+ ResultSelector = resultSelector ;
944
+ }
945
+
946
+ public string Name { get ; }
947
+ public TAccumulate Seed { get ; }
948
+ public Func < TAccumulate , SqliteValueReader , TAccumulate > ? Func { get ; }
949
+ public Func < TAccumulate , TResult > ? ResultSelector { get ; }
950
+ }
951
+
918
952
private sealed class AggregateContext < T >
919
953
{
920
954
public AggregateContext ( T seed )
0 commit comments