xref: /aosp_15_r20/external/perfetto/src/trace_processor/sqlite/bindings/sqlite_aggregate_function.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_AGGREGATE_FUNCTION_H_
18 #define SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_AGGREGATE_FUNCTION_H_
19 
20 #include <sqlite3.h>
21 
22 #include "perfetto/ext/base/scoped_file.h"
23 
24 namespace perfetto::trace_processor {
25 
26 // Prototype for an aggregate context which can be fetched from an aggregate
27 // function in SQLite.
28 template <typename Impl>
29 struct SqliteAggregateContext {
ScopedDestructorSqliteAggregateContext30   static int ScopedDestructor(Impl* impl) {
31     if (impl) {
32       impl->~Impl();
33     }
34     return 0;
35   }
36   using ScopedContext = base::ScopedResource<Impl*, ScopedDestructor, nullptr>;
37 
38   // Function which should be called from |Step| to retrieve the context.
GetOrCreateContextForStepSqliteAggregateContext39   static Impl& GetOrCreateContextForStep(sqlite3_context* ctx) {
40     // Fast path: the context is already allocated and initialized. Just fetch
41     // it (by passing 0 to SQLite to supress any allocations) and return it.
42     if (auto* ptr = sqlite3_aggregate_context(ctx, 0); ptr) {
43       return *static_cast<Impl*>(ptr);
44     }
45 
46     // Slow path: we need to actually allocate the memory and then initialize
47     // it.
48     auto* raw_ptr = sqlite3_aggregate_context(ctx, sizeof(Impl));
49     new (raw_ptr) Impl();
50     return *static_cast<Impl*>(raw_ptr);
51   }
52 
53   // Function which should be called from |Final| to retrieve the context.
54   // Returns null if no previous call to |Step| was made.
GetContextOrNullForFinalSqliteAggregateContext55   static ScopedContext GetContextOrNullForFinal(sqlite3_context* ctx) {
56     return ScopedContext(static_cast<Impl*>(sqlite3_aggregate_context(ctx, 0)));
57   }
58 };
59 
60 // Prototype for a aggregate function which can be registered with SQLite.
61 //
62 // See https://www.sqlite.org/c3ref/create_function.html for details on how to
63 // implement the methods of this class.
64 template <typename Impl>
65 struct SqliteAggregateFunction {
66   // The type of the context object which will be passed to the function.
67   // Can be redefined in any sub-classes to override the context.
68   using UserDataContext = void;
69 
70   // The xStep function which will be executed by SQLite to add a row of values
71   // to the aggregate.
72   //
73   // Implementations MUST define this function themselves; this function is
74   // declared but *not* defined so linker errors will be thrown if not defined.
75   static void Step(sqlite3_context*, int argc, sqlite3_value** argv);
76 
77   // The xFinal function which will be executed by SQLite to obtain the current
78   // value of the aggregate *and* free all resources allocated by previous calls
79   // to Step.
80   //
81   // Implementations MUST define this function themselves; this function is
82   // declared but *not* defined so linker errors will be thrown if not defined.
83   static void Final(sqlite3_context* ctx);
84 
85   // Returns the pointer to the user data structure which is passed when
86   // creating the function.
GetUserDataSqliteAggregateFunction87   static auto GetUserData(sqlite3_context* ctx) {
88     return static_cast<typename Impl::UserDataContext*>(sqlite3_user_data(ctx));
89   }
90 };
91 
92 }  // namespace perfetto::trace_processor
93 
94 #endif  // SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_AGGREGATE_FUNCTION_H_
95