Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd7177e9

Browse files
authored
Microsoft.Data.Sqlite: Use aggregate_context instead of user_state in CreateAggregate
Fixes#26070
1 parent6a9f143 commitd7177e9

File tree

2 files changed

+89
-10
lines changed

2 files changed

+89
-10
lines changed

‎src/Microsoft.Data.Sqlite.Core/SqliteConnection.cs‎

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -821,22 +821,24 @@ private void CreateAggregateCore<TAccumulate, TResult>(
821821
delegate_function_aggregate_step?func_step=null;
822822
if(func!=null)
823823
{
824-
func_step=(ctx,user_data,args)=>
824+
func_step=static(ctx,user_data,args)=>
825825
{
826-
varcontext=(AggregateContext<TAccumulate>)user_data;
826+
vardefinition=(AggregateDefinition<TAccumulate,TResult>)user_data;
827+
ctx.state??=newAggregateContext<TAccumulate>(definition.Seed);
828+
829+
varcontext=(AggregateContext<TAccumulate>)ctx.state;
827830
if(context.Exception!=null)
828831
{
829832
return;
830833
}
831834

832835
// TODO: Avoid allocation when niladic
833-
varreader=newSqliteParameterReader(name,args);
836+
varreader=newSqliteParameterReader(definition.Name,args);
834837

835838
try
836839
{
837-
// TODO: Avoid closure by passing func via user_data
838840
// NB: No need to set ctx.state since we just mutate the instance
839-
context.Accumulate=func(context.Accumulate,reader);
841+
context.Accumulate=definition.Func!(context.Accumulate,reader);
840842
}
841843
catch(Exceptionex)
842844
{
@@ -848,16 +850,18 @@ private void CreateAggregateCore<TAccumulate, TResult>(
848850
delegate_function_aggregate_final?func_final=null;
849851
if(resultSelector!=null)
850852
{
851-
func_final=(ctx,user_data)=>
853+
func_final=static(ctx,user_data)=>
852854
{
853-
varcontext=(AggregateContext<TAccumulate>)user_data;
855+
vardefinition=(AggregateDefinition<TAccumulate,TResult>)user_data;
856+
ctx.state??=newAggregateContext<TAccumulate>(definition.Seed);
857+
858+
varcontext=(AggregateContext<TAccumulate>)ctx.state;
854859

855860
if(context.Exception==null)
856861
{
857862
try
858863
{
859-
// TODO: Avoid closure by passing resultSelector via user_data
860-
varresult=resultSelector(context.Accumulate);
864+
varresult=definition.ResultSelector!(context.Accumulate);
861865

862866
newSqliteResultBinder(ctx,result).Bind();
863867
}
@@ -881,7 +885,7 @@ private void CreateAggregateCore<TAccumulate, TResult>(
881885
}
882886

883887
varflags=isDeterministic?SQLITE_DETERMINISTIC:0;
884-
varstate=newAggregateContext<TAccumulate>(seed);
888+
varstate=newAggregateDefinition<TAccumulate,TResult>(name,seed,func,resultSelector);
885889

886890
if(State==ConnectionState.Open)
887891
{
@@ -915,6 +919,22 @@ private void CreateAggregateCore<TAccumulate, TResult>(
915919
returnvalues;
916920
}
917921

922+
privatesealedclassAggregateDefinition<TAccumulate,TResult>
923+
{
924+
publicAggregateDefinition(stringname,TAccumulateseed,Func<TAccumulate,SqliteValueReader,TAccumulate>?func,Func<TAccumulate,TResult>?resultSelector)
925+
{
926+
Name=name;
927+
Seed=seed;
928+
Func=func;
929+
ResultSelector=resultSelector;
930+
}
931+
932+
publicstringName{get;}
933+
publicTAccumulateSeed{get;}
934+
publicFunc<TAccumulate,SqliteValueReader,TAccumulate>?Func{get;}
935+
publicFunc<TAccumulate,TResult>?ResultSelector{get;}
936+
}
937+
918938
privatesealedclassAggregateContext<T>
919939
{
920940
publicAggregateContext(Tseed)

‎test/Microsoft.Data.Sqlite.Tests/SqliteConnectionTest.cs‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,65 @@ public void CreateAggregate_works()
850850
Assert.Equal("AX1Z",result);
851851
}
852852

853+
[Fact]
854+
publicvoidCreateAggregate_works_called_twice()
855+
{
856+
usingvarconnection=newSqliteConnection("Data Source=:memory:");
857+
connection.Open();
858+
connection.ExecuteNonQuery("CREATE TABLE dual2 (dummy1, dummy2); INSERT INTO dual2 (dummy1, dummy2) VALUES ('X', 'Y');");
859+
connection.CreateAggregate(
860+
"test",
861+
"A",
862+
(stringa,stringx,stringy)=>a+x+y,
863+
a=>a+"Z");
864+
865+
varresult=connection.ExecuteScalar<string>("SELECT test(dummy1, dummy2) FROM dual2;");
866+
Assert.Equal("AXYZ",result);
867+
868+
result=connection.ExecuteScalar<string>("SELECT test(dummy1, dummy2) FROM dual2;");
869+
Assert.Equal("AXYZ",result);
870+
}
871+
872+
[Fact]
873+
publicvoidCreateAggregate_works_called_twice_in_same_query()
874+
{
875+
usingvarconnection=newSqliteConnection("Data Source=:memory:");
876+
connection.Open();
877+
connection.ExecuteNonQuery("CREATE TABLE dual2 (dummy1, dummy2); INSERT INTO dual2 (dummy1, dummy2) VALUES ('X', 'Y');");
878+
connection.CreateAggregate(
879+
"test",
880+
"A",
881+
(stringa,stringx,stringy)=>a+x+y,
882+
a=>a+"Z");
883+
884+
using(varreader=connection.ExecuteReader("SELECT test(dummy1, dummy2), test(dummy2, dummy1) FROM dual2;"))
885+
{
886+
Assert.True(reader.Read());
887+
888+
Assert.Equal("AXYZ",reader.GetString(0));
889+
Assert.Equal("AYXZ",reader.GetString(1));
890+
891+
Assert.False(reader.Read());
892+
}
893+
}
894+
895+
[Fact]
896+
publicvoidCreateAggregate_works_when_no_rows()
897+
{
898+
usingvarconnection=newSqliteConnection("Data Source=:memory:");
899+
connection.Open();
900+
connection.ExecuteNonQuery("CREATE TABLE dual2 (dummy1, dummy2);");
901+
connection.CreateAggregate(
902+
"test",
903+
"A",
904+
(stringa,stringx,stringy)=>a+x+y,
905+
a=>a+"Z");
906+
907+
varresult=connection.ExecuteScalar<string>("SELECT test(dummy1, dummy2) FROM dual2;");
908+
909+
Assert.Equal("AZ",result);
910+
}
911+
853912
[Fact]
854913
publicvoidCreateAggregate_works_when_params()
855914
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp