6
6
#include < V8/ConvertDataTypes.h>
7
7
#include < V8/Utils.h>
8
8
#include < Common/logger_useful.h>
9
+ #include < span>
9
10
10
11
namespace DB
11
12
{
@@ -86,10 +87,12 @@ JavaScriptBlueprint::JavaScriptBlueprint(const String & name, const String & sou
86
87
87
88
{
88
89
v8::Local<v8::Value> val;
89
- if (! obj->Get (local_ctx, V8::to_v8 (isolate_, " has_customized_emit" )).ToLocal (&val) || !val->IsUndefined ())
90
+ if (obj->Get (local_ctx, V8::to_v8 (isolate_, " has_customized_emit" )).ToLocal (&val) && !val->IsUndefined ())
90
91
{
91
- LOG_INFO (&Poco::Logger::get (" JavaScriptAggregateFunction" ), " JavaScript UDA '{}' has defined its own emit strategy" , name);
92
- has_user_defined_emit_strategy = true ;
92
+ has_user_defined_emit_strategy = V8::from_v8<bool >(isolate_, val);
93
+ if (has_user_defined_emit_strategy)
94
+ LOG_INFO (
95
+ &Poco::Logger::get (" JavaScriptAggregateFunction" ), " JavaScript UDA '{}' has defined its own emit strategy" , name);
93
96
}
94
97
}
95
98
@@ -110,9 +113,19 @@ JavaScriptBlueprint::~JavaScriptBlueprint() noexcept
110
113
}
111
114
112
115
JavaScriptAggrFunctionState::JavaScriptAggrFunctionState (
113
- const JavaScriptBlueprint & blueprint, const std::vector<UserDefinedFunctionConfiguration::Argument> & arguments)
116
+ const JavaScriptBlueprint & blueprint,
117
+ const std::vector<UserDefinedFunctionConfiguration::Argument> & arguments,
118
+ const bool is_changelog_input_)
119
+ : is_changelog_input(is_changelog_input_)
114
120
{
115
121
columns.reserve (arguments.size ());
122
+
123
+ // / check _tp_delta column
124
+ if (unlikely (arguments.back ().type ->getTypeId () != TypeIndex::Int8))
125
+ throw Exception (
126
+ ErrorCodes::NOT_IMPLEMENTED,
127
+ " Tha last argument of JavaScript UDA is '_tp_delta' column, which should be 'int8'. Invalid type." );
128
+
116
129
for (const auto & arg : arguments)
117
130
{
118
131
auto col = arg.type ->createColumn ();
@@ -206,11 +219,28 @@ JavaScriptAggrFunctionState::~JavaScriptAggrFunctionState()
206
219
207
220
void JavaScriptAggrFunctionState::add (const IColumn ** src_columns, size_t row_num)
208
221
{
209
- for (size_t i = 0 ; auto & col : columns)
210
- {
211
- col->insertFrom (*src_columns[i], row_num);
212
- i++;
213
- }
222
+ assert (columns.size () >= 1 );
223
+ size_t num_of_input_columns = columns.size () - 1 ;
224
+
225
+ for (size_t i = 0 ; i < num_of_input_columns; i++)
226
+ columns[i]->insertFrom (*src_columns[i], row_num);
227
+
228
+ // / _tp_delta column
229
+ if (is_changelog_input)
230
+ columns.back ()->insert (1 );
231
+ }
232
+
233
+ void JavaScriptAggrFunctionState::negate (const IColumn ** src_columns, size_t row_num)
234
+ {
235
+ assert (columns.size () >= 1 );
236
+ size_t num_of_input_columns = columns.size () - 1 ;
237
+
238
+ for (size_t i = 0 ; i < num_of_input_columns; i++)
239
+ columns[i]->insertFrom (*src_columns[i], row_num);
240
+
241
+ // / _tp_delta column
242
+ if (is_changelog_input)
243
+ columns.back ()->insert (-1 );
214
244
}
215
245
216
246
void JavaScriptAggrFunctionState::reinitCache ()
@@ -237,10 +267,12 @@ AggregateFunctionJavaScriptAdapter::AggregateFunctionJavaScriptAdapter(
237
267
JavaScriptUserDefinedFunctionConfigurationPtr config_,
238
268
const DataTypes & types,
239
269
const Array & params_,
270
+ bool is_changelog_input_,
240
271
size_t max_v8_heap_size_in_bytes_)
241
272
: IAggregateFunctionHelper<AggregateFunctionJavaScriptAdapter>(types, params_)
242
273
, config(config_)
243
274
, num_arguments(types.size())
275
+ , is_changelog_input(is_changelog_input_)
244
276
, max_v8_heap_size_in_bytes(max_v8_heap_size_in_bytes_)
245
277
, blueprint(config->name, config->source)
246
278
{
@@ -260,7 +292,7 @@ DataTypePtr AggregateFunctionJavaScriptAdapter::getReturnType() const
260
292
void AggregateFunctionJavaScriptAdapter::create (AggregateDataPtr __restrict place) const
261
293
{
262
294
V8::checkHeapLimit (blueprint.isolate .get (), max_v8_heap_size_in_bytes);
263
- new (place) Data (blueprint, config->arguments );
295
+ new (place) Data (blueprint, config->arguments , is_changelog_input );
264
296
}
265
297
266
298
// / destroy instance of UDF
@@ -307,6 +339,11 @@ void AggregateFunctionJavaScriptAdapter::add(AggregateDataPtr __restrict place,
307
339
this ->data (place).add (columns, row_num);
308
340
}
309
341
342
+ void AggregateFunctionJavaScriptAdapter::negate (AggregateDataPtr __restrict place, const IColumn ** columns, size_t row_num, Arena *) const
343
+ {
344
+ this ->data (place).negate (columns, row_num);
345
+ }
346
+
310
347
void AggregateFunctionJavaScriptAdapter::merge (AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, Arena *) const
311
348
{
312
349
auto & data = this ->data (place);
@@ -376,11 +413,13 @@ size_t AggregateFunctionJavaScriptAdapter::flush(AggregateDataPtr __restrict pla
376
413
v8::Local<v8::Function> local_func = v8::Local<v8::Function>::New (isolate_, data.process_func );
377
414
378
415
// / Second, convert the input column into the corresponding object used by UDF
379
- auto argv = V8::prepareArguments (isolate_, config->arguments , data.columns );
416
+ // / remove the _tp_delta column if the input stream is not changelog
417
+ auto column_size = is_changelog_input ? config->arguments .size () : config->arguments .size () - 1 ;
418
+ auto argv = V8::prepareArguments (isolate_, std::span (config->arguments .begin (), column_size), data.columns );
380
419
381
420
// / Third, execute the UDF and get aggregate state (only support the final state now, intermediate state is not supported
382
421
v8::Local<v8::Value> res;
383
- if (!local_func->Call (ctx, local_obj, static_cast <int >(config-> arguments . size () ), argv.data ()).ToLocal (&res))
422
+ if (!local_func->Call (ctx, local_obj, static_cast <int >(column_size ), argv.data ()).ToLocal (&res))
384
423
V8::throwException (
385
424
isolate_,
386
425
try_catch,
0 commit comments