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