@@ -65,7 +65,26 @@ public override ExtensionMethodDelegate TryGetExtensionMethod(string name)
65
65
66
66
private static PhpValue sqliteCreateAggregate ( Context ctx , PDO pdo , PhpArray arguments )
67
67
{
68
- return PhpValue . False ;
68
+ if ( pdo . GetCurrentConnection < SqliteConnection > ( ) is not { } connection )
69
+ return PhpValue . False ;
70
+
71
+ var name = arguments [ 0 ] . String ;
72
+ var step = arguments [ 1 ] . AsCallable ( ) ;
73
+ var finalize = arguments [ 2 ] . AsCallable ( ) ;
74
+ var numberOfArguments = - 1 ;
75
+ if ( arguments . TryGetValue ( 3 , out var args ) && args . IsInteger ( ) )
76
+ numberOfArguments = args . ToInt ( ) ;
77
+
78
+ var handle = connection . Handle ;
79
+
80
+ raw . sqlite3_create_function (
81
+ handle ,
82
+ name ,
83
+ numberOfArguments ,
84
+ null ,
85
+ CreateAggregateStep ( ctx , step ) ,
86
+ CreateAggregateFinalize ( ctx , finalize ) ) ;
87
+ return PhpValue . True ;
69
88
}
70
89
private static PhpValue sqliteCreateCollation ( Context ctx , PDO pdo , PhpArray arguments )
71
90
{
@@ -126,39 +145,83 @@ public override string GetLastInsertId(PDO pdo, string name)
126
145
}
127
146
}
128
147
129
- private static delegate_function_scalar CreateScalarFunction ( Context ctx , IPhpCallable callback )
148
+ private static delegate_function_aggregate_step CreateAggregateStep ( Context ctx , IPhpCallable callback )
130
149
{
131
150
return ( sqliteContext , data , args ) =>
132
151
{
152
+ if ( sqliteContext . state is not StepFunctionState state )
153
+ {
154
+ sqliteContext . state = state = new StepFunctionState ( ) ;
155
+ }
156
+ var rowIndex = state . RowIndex ++ ;
157
+
133
158
var phpArgs = args
134
159
. Select ( AsPhp )
160
+ . Prepend ( PhpValue . FromClr ( rowIndex ) )
161
+ . Prepend ( state . Value )
135
162
. ToArray ( ) ;
136
- var ret = callback . Invoke ( ctx , phpArgs ) ;
137
-
138
163
139
- if ( ret . IsLong ( out var longValue ) )
140
- {
141
- raw . sqlite3_result_int64 ( sqliteContext , longValue ) ;
142
- }
143
- else if ( ret . IsInteger ( ) )
144
- {
145
- raw . sqlite3_result_int ( sqliteContext , ret . ToInt ( ) ) ;
146
- }
147
- else if ( ret . IsDouble ( out var doubleValue ) )
148
- {
149
- raw . sqlite3_result_double ( sqliteContext , doubleValue ) ;
150
- }
151
- else if ( ret . IsString ( out var stringValue ) )
152
- {
153
- var foo = stringValue ;
154
- raw . sqlite3_result_text ( sqliteContext , foo ) ;
155
- }
156
- else
164
+ var ret = callback . Invoke ( ctx , phpArgs ) ;
165
+ state . Value = ret ;
166
+ } ;
167
+ }
168
+
169
+ private static delegate_function_aggregate_final CreateAggregateFinalize ( Context ctx , IPhpCallable callback )
170
+ {
171
+ return ( sqliteContext , data ) =>
172
+ {
173
+ if ( sqliteContext . state is not StepFunctionState state )
157
174
{
158
- raw . sqlite3_result_null ( sqliteContext ) ;
175
+ sqliteContext . state = state = new StepFunctionState ( ) ;
159
176
}
177
+
178
+ var ret = callback . Invoke ( ctx , state . Value , state . RowIndex ) ;
179
+ SetSqliteReturnValue ( ret , sqliteContext ) ;
180
+ } ;
181
+ }
182
+
183
+ private static delegate_function_scalar CreateScalarFunction ( Context ctx , IPhpCallable callback )
184
+ {
185
+ return ( sqliteContext , data , args ) =>
186
+ {
187
+ var phpArgs = args
188
+ . Select ( AsPhp )
189
+ . ToArray ( ) ;
190
+ var ret = callback . Invoke ( ctx , phpArgs ) ;
191
+ SetSqliteReturnValue ( ret , sqliteContext ) ;
160
192
} ;
161
193
}
194
+
195
+ private static void SetSqliteReturnValue ( PhpValue ret , sqlite3_context sqliteContext )
196
+ {
197
+ if ( ret . IsLong ( out var longValue ) )
198
+ {
199
+ raw . sqlite3_result_int64 ( sqliteContext , longValue ) ;
200
+ }
201
+ else if ( ret . IsInteger ( ) )
202
+ {
203
+ raw . sqlite3_result_int ( sqliteContext , ret . ToInt ( ) ) ;
204
+ }
205
+ else if ( ret . IsDouble ( out var doubleValue ) )
206
+ {
207
+ raw . sqlite3_result_double ( sqliteContext , doubleValue ) ;
208
+ }
209
+ else if ( ret . IsString ( out var stringValue ) )
210
+ {
211
+ var foo = stringValue ;
212
+ raw . sqlite3_result_text ( sqliteContext , foo ) ;
213
+ }
214
+ else
215
+ {
216
+ raw . sqlite3_result_null ( sqliteContext ) ;
217
+ }
218
+ }
219
+
220
+ private class StepFunctionState
221
+ {
222
+ public int RowIndex { get ; set ; }
223
+ public PhpValue Value { get ; set ; } = PhpValue . Null ;
224
+ }
162
225
163
226
private static PhpValue AsPhp ( sqlite3_value value )
164
227
{
0 commit comments