Merge changes I729e7762,I9ac46f5f into main

* changes:
  tp: implement structs in trace processor
  tp: implement array_agg aggregate function
diff --git a/Android.bp b/Android.bp
index 3a57165..7c6d340 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2436,6 +2436,7 @@
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_operators_operators",
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_table_functions_interface",
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_table_functions_table_functions",
+        ":perfetto_src_trace_processor_perfetto_sql_intrinsics_types_types",
         ":perfetto_src_trace_processor_sorter_sorter",
         ":perfetto_src_trace_processor_sqlite_bindings_bindings",
         ":perfetto_src_trace_processor_sqlite_sqlite",
@@ -12908,6 +12909,7 @@
 filegroup {
     name: "perfetto_src_trace_processor_perfetto_sql_intrinsics_functions_functions",
     srcs: [
+        "src/trace_processor/perfetto_sql/intrinsics/functions/array.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/base64.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/create_function.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/create_view_function.cc",
@@ -12919,6 +12921,7 @@
         "src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.cc",
+        "src/trace_processor/perfetto_sql/intrinsics/functions/struct.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/to_ftrace.cc",
     ],
@@ -13070,6 +13073,11 @@
     ],
 }
 
+// GN: //src/trace_processor/perfetto_sql/intrinsics/types:types
+filegroup {
+    name: "perfetto_src_trace_processor_perfetto_sql_intrinsics_types_types",
+}
+
 // GN: //src/trace_processor/perfetto_sql/prelude:prelude
 genrule {
     name: "perfetto_src_trace_processor_perfetto_sql_prelude_prelude",
@@ -15167,6 +15175,7 @@
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_table_functions_interface",
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_table_functions_table_functions",
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_table_functions_unittests",
+        ":perfetto_src_trace_processor_perfetto_sql_intrinsics_types_types",
         ":perfetto_src_trace_processor_rpc_rpc",
         ":perfetto_src_trace_processor_rpc_unittests",
         ":perfetto_src_trace_processor_sorter_sorter",
@@ -16194,6 +16203,7 @@
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_operators_operators",
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_table_functions_interface",
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_table_functions_table_functions",
+        ":perfetto_src_trace_processor_perfetto_sql_intrinsics_types_types",
         ":perfetto_src_trace_processor_rpc_httpd",
         ":perfetto_src_trace_processor_rpc_rpc",
         ":perfetto_src_trace_processor_rpc_stdiod",
@@ -16592,6 +16602,7 @@
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_operators_operators",
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_table_functions_interface",
         ":perfetto_src_trace_processor_perfetto_sql_intrinsics_table_functions_table_functions",
+        ":perfetto_src_trace_processor_perfetto_sql_intrinsics_types_types",
         ":perfetto_src_trace_processor_sorter_sorter",
         ":perfetto_src_trace_processor_sqlite_bindings_bindings",
         ":perfetto_src_trace_processor_sqlite_sqlite",
diff --git a/BUILD b/BUILD
index 132487e..52bb806 100644
--- a/BUILD
+++ b/BUILD
@@ -263,6 +263,7 @@
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_interface",
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_table_functions",
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_tables",
+        ":src_trace_processor_perfetto_sql_intrinsics_types_types",
         ":src_trace_processor_rpc_rpc",
         ":src_trace_processor_sorter_sorter",
         ":src_trace_processor_sqlite_bindings_bindings",
@@ -2334,6 +2335,8 @@
 perfetto_filegroup(
     name = "src_trace_processor_perfetto_sql_intrinsics_functions_functions",
     srcs = [
+        "src/trace_processor/perfetto_sql/intrinsics/functions/array.cc",
+        "src/trace_processor/perfetto_sql/intrinsics/functions/array.h",
         "src/trace_processor/perfetto_sql/intrinsics/functions/base64.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/base64.h",
         "src/trace_processor/perfetto_sql/intrinsics/functions/clock_functions.h",
@@ -2357,6 +2360,8 @@
         "src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.h",
         "src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.h",
+        "src/trace_processor/perfetto_sql/intrinsics/functions/struct.cc",
+        "src/trace_processor/perfetto_sql/intrinsics/functions/struct.h",
         "src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.h",
         "src/trace_processor/perfetto_sql/intrinsics/functions/to_ftrace.cc",
@@ -2459,6 +2464,15 @@
     ],
 )
 
+# GN target: //src/trace_processor/perfetto_sql/intrinsics/types:types
+perfetto_filegroup(
+    name = "src_trace_processor_perfetto_sql_intrinsics_types_types",
+    srcs = [
+        "src/trace_processor/perfetto_sql/intrinsics/types/struct.h",
+        "src/trace_processor/perfetto_sql/intrinsics/types/value.h",
+    ],
+)
+
 # GN target: //src/trace_processor/perfetto_sql/prelude:prelude
 perfetto_cc_amalgamated_sql(
     name = "src_trace_processor_perfetto_sql_prelude_prelude",
@@ -2866,8 +2880,11 @@
     name = "src_trace_processor_sqlite_bindings_bindings",
     srcs = [
         "src/trace_processor/sqlite/bindings/sqlite_aggregate_function.h",
+        "src/trace_processor/sqlite/bindings/sqlite_function.h",
         "src/trace_processor/sqlite/bindings/sqlite_module.h",
         "src/trace_processor/sqlite/bindings/sqlite_result.h",
+        "src/trace_processor/sqlite/bindings/sqlite_type.h",
+        "src/trace_processor/sqlite/bindings/sqlite_value.h",
         "src/trace_processor/sqlite/bindings/sqlite_window_function.h",
     ],
 )
@@ -2890,7 +2907,6 @@
         "src/trace_processor/sqlite/sqlite_tokenizer.h",
         "src/trace_processor/sqlite/sqlite_utils.cc",
         "src/trace_processor/sqlite/sqlite_utils.h",
-        "src/trace_processor/sqlite/sqlite_value.h",
         "src/trace_processor/sqlite/stats_table.cc",
         "src/trace_processor/sqlite/stats_table.h",
     ],
@@ -6078,6 +6094,7 @@
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_interface",
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_table_functions",
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_tables",
+        ":src_trace_processor_perfetto_sql_intrinsics_types_types",
         ":src_trace_processor_sorter_sorter",
         ":src_trace_processor_sqlite_bindings_bindings",
         ":src_trace_processor_sqlite_sqlite",
@@ -6258,6 +6275,7 @@
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_interface",
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_table_functions",
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_tables",
+        ":src_trace_processor_perfetto_sql_intrinsics_types_types",
         ":src_trace_processor_rpc_httpd",
         ":src_trace_processor_rpc_rpc",
         ":src_trace_processor_rpc_stdiod",
@@ -6498,6 +6516,7 @@
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_interface",
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_table_functions",
         ":src_trace_processor_perfetto_sql_intrinsics_table_functions_tables",
+        ":src_trace_processor_perfetto_sql_intrinsics_types_types",
         ":src_trace_processor_sorter_sorter",
         ":src_trace_processor_sqlite_bindings_bindings",
         ":src_trace_processor_sqlite_sqlite",
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
index a98ab99..f04a57a 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
@@ -115,6 +115,19 @@
       std::unique_ptr<typename Function::Context> ctx,
       bool deterministic = true);
 
+  // Registers a trace processor C++ function to be runnable from SQL.
+  //
+  // The format of the function is given by the |SqliteFunction|.
+  //
+  // |ctx|:           context object for the function; this object *must*
+  //                  outlive the function so should likely be either static or
+  //                  scoped to the lifetime of TraceProcessor.
+  // |deterministic|: whether this function has deterministic output given the
+  //                  same set of arguments.
+  template <typename Function>
+  base::Status RegisterSqliteFunction(typename Function::UserDataContext* ctx,
+                                      bool deterministic = true);
+
   // Registers a trace processor C++ aggregate function to be runnable from SQL.
   //
   // The format of the function is given by the |SqliteAggregateFunction|.
@@ -353,6 +366,15 @@
 }
 
 template <typename Function>
+base::Status PerfettoSqlEngine::RegisterSqliteFunction(
+    typename Function::UserDataContext* ctx,
+    bool deterministic) {
+  static_function_count_++;
+  return engine_->RegisterFunction(Function::kName, Function::kArgCount,
+                                   Function::Step, ctx, nullptr, deterministic);
+}
+
+template <typename Function>
 base::Status PerfettoSqlEngine::RegisterSqliteAggregateFunction(
     typename Function::UserDataContext* ctx,
     bool deterministic) {
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn b/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
index b749026..04b3aa5 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
@@ -19,6 +19,8 @@
 
 source_set("functions") {
   sources = [
+    "array.cc",
+    "array.h",
     "base64.cc",
     "base64.h",
     "clock_functions.h",
@@ -42,6 +44,8 @@
     "sqlite3_str_split.h",
     "stack_functions.cc",
     "stack_functions.h",
+    "struct.cc",
+    "struct.h",
     "structural_tree_partition.cc",
     "structural_tree_partition.h",
     "to_ftrace.cc",
@@ -77,6 +81,7 @@
     "../../../util:sql_argument",
     "../../../util:stdlib",
     "../../engine",
+    "../types",
   ]
   public_deps = [ ":interface" ]
 }
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/array.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/array.cc
new file mode 100644
index 0000000..d5c0315
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/array.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/perfetto_sql/intrinsics/functions/array.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+#include <variant>
+#include <vector>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/status.h"
+#include "perfetto/public/compiler.h"
+#include "src/trace_processor/perfetto_sql/engine/function_util.h"
+#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
+#include "src/trace_processor/sqlite/bindings/sqlite_aggregate_function.h"
+#include "src/trace_processor/sqlite/bindings/sqlite_result.h"
+#include "src/trace_processor/sqlite/bindings/sqlite_type.h"
+#include "src/trace_processor/sqlite/bindings/sqlite_value.h"
+
+namespace perfetto::trace_processor {
+namespace {
+
+using ArrayVariant = std::variant<std::vector<int64_t>,
+                                  std::vector<double>,
+                                  std::vector<std::string>>;
+
+struct AggCtx : SqliteAggregateContext<AggCtx> {
+  template <typename T>
+  void Push(sqlite3_context* ctx, T value) {
+    if (PERFETTO_UNLIKELY(!array)) {
+      array = std::vector<T>{std::move(value)};
+      return;
+    }
+    auto* a = std::get_if<std::vector<T>>(&*array);
+    if (!a) {
+      return sqlite::result::Error(
+          ctx, "ARRAY_AGG: all values must have the same type");
+    }
+    a->emplace_back(std::move(value));
+  }
+  template <typename T>
+  void Result(sqlite3_context* ctx, const char* type) {
+    auto res = std::make_unique<std::vector<T>>(
+        std::get<std::vector<T>>(std::move(*array)));
+    return sqlite::result::RawPointer(ctx, res.release(), type, [](void* ptr) {
+      std::unique_ptr<std::vector<T>>(static_cast<std::vector<T>*>(ptr));
+    });
+  }
+
+  std::optional<ArrayVariant> array;
+};
+
+// An SQL aggregate-function which creates an array.
+struct ArrayAgg : public SqliteAggregateFunction<ArrayAgg> {
+  static constexpr char kName[] = "__intrinsic_array_agg";
+  static constexpr int kArgCount = 1;
+
+  static void Step(sqlite3_context*, int argc, sqlite3_value** argv);
+  static void Final(sqlite3_context* ctx);
+};
+
+void ArrayAgg::Step(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
+  PERFETTO_DCHECK(argc == kArgCount);
+
+  auto& agg_ctx = AggCtx::GetOrCreateContextForStep(ctx);
+  switch (sqlite::value::Type(argv[0])) {
+    case sqlite::Type::kInteger:
+      return agg_ctx.Push(ctx, sqlite::value::Int64(argv[0]));
+    case sqlite::Type::kText:
+      return agg_ctx.Push<std::string>(ctx, sqlite::value::Text(argv[0]));
+    case sqlite::Type::kFloat:
+      return agg_ctx.Push(ctx, sqlite::value::Double(argv[0]));
+    case sqlite::Type::kNull:
+      return sqlite::result::Error(
+          ctx,
+          "ARRAY_AGG: nulls are not supported. They should be filtered out "
+          "before calling ARRAY_AGG.");
+    case sqlite::Type::kBlob:
+      return sqlite::result::Error(ctx, "ARRAY_AGG: blobs are not supported.");
+  }
+}
+
+void ArrayAgg::Final(sqlite3_context* ctx) {
+  auto raw_agg_ctx = AggCtx::GetContextOrNullForFinal(ctx);
+  if (!raw_agg_ctx) {
+    return sqlite::result::Null(ctx);
+  }
+
+  auto& array = *raw_agg_ctx.get()->array;
+  switch (array.index()) {
+    case 0 /* int64_t */:
+      return raw_agg_ctx.get()->Result<int64_t>(ctx, "ARRAY<INT64>");
+    case 1 /* double */:
+      return raw_agg_ctx.get()->Result<double>(ctx, "ARRAY<DOUBLE>");
+    case 2 /* std::string */:
+      return raw_agg_ctx.get()->Result<std::string>(ctx, "ARRAY<STRING>");
+  }
+}
+
+}  // namespace
+
+base::Status RegisterArrayFunctions(PerfettoSqlEngine& engine) {
+  return engine.RegisterSqliteAggregateFunction<ArrayAgg>(nullptr);
+}
+
+}  // namespace perfetto::trace_processor
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/array.h b/src/trace_processor/perfetto_sql/intrinsics/functions/array.h
new file mode 100644
index 0000000..8afc13d
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/array.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_ARRAY_H_
+#define SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_ARRAY_H_
+
+#include "perfetto/base/status.h"
+
+namespace perfetto::trace_processor {
+
+class PerfettoSqlEngine;
+
+// Registers the following array related functions with SQLite:
+//  * __intrinsic_array_agg: an aggregate function which allows building
+//    arrays from a table.
+// TODO(lalitm): once we have some stability here, expand the comments
+// here.
+base::Status RegisterArrayFunctions(PerfettoSqlEngine& engine);
+
+}  // namespace perfetto::trace_processor
+
+#endif  // SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_ARRAY_H_
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/struct.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/struct.cc
new file mode 100644
index 0000000..33dcde3
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/struct.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/perfetto_sql/intrinsics/functions/struct.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+#include <variant>
+
+#include "perfetto/base/status.h"
+#include "src/trace_processor/perfetto_sql/engine/function_util.h"
+#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
+#include "src/trace_processor/perfetto_sql/intrinsics/types/struct.h"
+#include "src/trace_processor/sqlite/bindings/sqlite_function.h"
+#include "src/trace_processor/sqlite/bindings/sqlite_result.h"
+#include "src/trace_processor/sqlite/bindings/sqlite_type.h"
+#include "src/trace_processor/sqlite/bindings/sqlite_value.h"
+#include "src/trace_processor/sqlite/sqlite_utils.h"
+
+namespace perfetto::trace_processor {
+namespace {
+
+// An SQL scalar function which creates an struct.
+// TODO(lalitm): once we have some stability here, expand the comments
+// here.
+struct Struct : public SqliteFunction<Struct> {
+  static constexpr char kName[] = "__intrinsic_struct";
+  static constexpr int kArgCount = -1;
+
+  static void Step(sqlite3_context*, int argc, sqlite3_value** argv);
+};
+
+void Struct::Step(sqlite3_context* ctx, int rargc, sqlite3_value** argv) {
+  auto argc = static_cast<uint32_t>(rargc);
+  if (argc % 2 != 0) {
+    return sqlite::result::Error(
+        ctx, "STRUCT: must have an even number of arguments");
+  }
+  if (argc / 2 > perfetto_sql::Struct::kMaxFields) {
+    return sqlite::utils::SetError(
+        ctx, base::ErrStatus("STRUCT: only at most %d fields are supported",
+                             perfetto_sql::Struct::kMaxFields));
+  }
+
+  auto s = std::make_unique<perfetto_sql::Struct>();
+  s->field_count = argc / 2;
+  for (uint32_t i = 0; i < s->field_count; ++i) {
+    if (sqlite::value::Type(argv[i]) != sqlite::Type::kText) {
+      return sqlite::result::Error(ctx, "STRUCT: field names must be strings");
+    }
+    auto& field = s->fields[i];
+    field.first = sqlite::value::Text(argv[i]);
+    switch (sqlite::value::Type(argv[s->field_count + i])) {
+      case sqlite::Type::kText:
+        field.second = sqlite::value::Text(argv[s->field_count + i]);
+        break;
+      case sqlite::Type::kInteger:
+        field.second = sqlite::value::Int64(argv[s->field_count + i]);
+        break;
+      case sqlite::Type::kFloat:
+        field.second = sqlite::value::Double(argv[s->field_count + i]);
+        break;
+      case sqlite::Type::kNull:
+        field.second = std::monostate();
+        break;
+      case sqlite::Type::kBlob:
+        return sqlite::result::Error(ctx, "STRUCT: blob fields not supported");
+    }
+  }
+  sqlite::result::RawPointer(ctx, s.release(), "STRUCT", [](void* ptr) {
+    std::unique_ptr<perfetto_sql::Struct>(
+        static_cast<perfetto_sql::Struct*>(ptr));
+  });
+}
+
+}  // namespace
+
+base::Status RegisterStructFunctions(PerfettoSqlEngine& engine) {
+  return engine.RegisterSqliteFunction<Struct>(nullptr);
+}
+
+}  // namespace perfetto::trace_processor
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/struct.h b/src/trace_processor/perfetto_sql/intrinsics/functions/struct.h
new file mode 100644
index 0000000..0c5f49d
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/struct.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_STRUCT_H_
+#define SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_STRUCT_H_
+
+#include "perfetto/base/status.h"
+
+namespace perfetto::trace_processor {
+
+class PerfettoSqlEngine;
+
+// Registers the following struct related functions with SQLite:
+//  * __intrinsic_struct: a scalar function which allows creating a
+//    struct from its component fields.
+// TODO(lalitm): once we have some stability here, expand the comments
+// here.
+base::Status RegisterStructFunctions(PerfettoSqlEngine& engine);
+
+}  // namespace perfetto::trace_processor
+
+#endif  // SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_STRUCT_H_
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.cc
index 2d68548..05c44c2 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.cc
@@ -29,7 +29,7 @@
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/tables_py.h"
 #include "src/trace_processor/sqlite/bindings/sqlite_aggregate_function.h"
 #include "src/trace_processor/sqlite/bindings/sqlite_result.h"
-#include "src/trace_processor/sqlite/sqlite_value.h"
+#include "src/trace_processor/sqlite/bindings/sqlite_value.h"
 
 namespace perfetto::trace_processor {
 namespace tables {
@@ -81,8 +81,8 @@
 
   // For performance reasons, we don't typecheck the arguments and assume they
   // are longs.
-  auto id = static_cast<uint32_t>(sqlite::value::Long(argv[0]));
-  auto group = static_cast<uint32_t>(sqlite::value::Long(argv[2]));
+  auto id = static_cast<uint32_t>(sqlite::value::Int64(argv[0]));
+  auto group = static_cast<uint32_t>(sqlite::value::Int64(argv[2]));
 
   // Keep track of the maximum group seen.
   agg_ctx.max_group = std::max(agg_ctx.max_group, group);
@@ -101,7 +101,7 @@
   }
 
   // Otherwise, this is a non-root. Increment the child count of its parent.
-  auto parent_id = static_cast<uint32_t>(sqlite::value::Long(parent_id_value));
+  auto parent_id = static_cast<uint32_t>(sqlite::value::Int64(parent_id_value));
   uint32_t max_id = std::max(id, parent_id);
   if (max_id >= agg_ctx.child_count_by_id.size()) {
     agg_ctx.child_count_by_id.resize(max_id + 1);
diff --git a/src/trace_processor/perfetto_sql/intrinsics/types/BUILD.gn b/src/trace_processor/perfetto_sql/intrinsics/types/BUILD.gn
new file mode 100644
index 0000000..230dc71
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/types/BUILD.gn
@@ -0,0 +1,26 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../../../../../gn/perfetto_tp_tables.gni")
+import("../../../../../gn/test.gni")
+
+assert(enable_perfetto_trace_processor_sqlite)
+
+source_set("types") {
+  sources = [
+    "struct.h",
+    "value.h",
+  ]
+  deps = [ "../../../../../gn:default_deps" ]
+}
diff --git a/src/trace_processor/perfetto_sql/intrinsics/types/struct.h b/src/trace_processor/perfetto_sql/intrinsics/types/struct.h
new file mode 100644
index 0000000..00011ed
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/types/struct.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_TYPES_STRUCT_H_
+#define SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_TYPES_STRUCT_H_
+
+#include <array>
+#include <cstdint>
+#include <string>
+#include <utility>
+
+#include "src/trace_processor/perfetto_sql/intrinsics/types/value.h"
+
+namespace perfetto::trace_processor::perfetto_sql {
+
+struct Struct {
+  static constexpr uint32_t kMaxFields = 8;
+  std::array<std::pair<std::string, Value>, kMaxFields> fields;
+  uint32_t field_count = 0;
+};
+
+}  // namespace perfetto::trace_processor::perfetto_sql
+
+#endif  // SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_TYPES_STRUCT_H_
diff --git a/src/trace_processor/perfetto_sql/intrinsics/types/value.h b/src/trace_processor/perfetto_sql/intrinsics/types/value.h
new file mode 100644
index 0000000..6c541d1
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/types/value.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_TYPES_VALUE_H_
+#define SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_TYPES_VALUE_H_
+
+#include <cstdint>
+#include <string>
+#include <variant>
+
+namespace perfetto::trace_processor::perfetto_sql {
+
+using Value = std::variant<std::monostate, int64_t, double, std::string>;
+
+}  // namespace perfetto::trace_processor::perfetto_sql
+
+#endif  // SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_TYPES_VALUE_H_
diff --git a/src/trace_processor/sqlite/BUILD.gn b/src/trace_processor/sqlite/BUILD.gn
index 902c9d8..fda30ba 100644
--- a/src/trace_processor/sqlite/BUILD.gn
+++ b/src/trace_processor/sqlite/BUILD.gn
@@ -32,7 +32,6 @@
     "sqlite_tokenizer.h",
     "sqlite_utils.cc",
     "sqlite_utils.h",
-    "sqlite_value.h",
     "stats_table.cc",
     "stats_table.h",
   ]
diff --git a/src/trace_processor/sqlite/bindings/BUILD.gn b/src/trace_processor/sqlite/bindings/BUILD.gn
index 07922a7..9205585 100644
--- a/src/trace_processor/sqlite/bindings/BUILD.gn
+++ b/src/trace_processor/sqlite/bindings/BUILD.gn
@@ -19,8 +19,11 @@
 source_set("bindings") {
   sources = [
     "sqlite_aggregate_function.h",
+    "sqlite_function.h",
     "sqlite_module.h",
     "sqlite_result.h",
+    "sqlite_type.h",
+    "sqlite_value.h",
     "sqlite_window_function.h",
   ]
   deps = [
diff --git a/src/trace_processor/sqlite/bindings/sqlite_function.h b/src/trace_processor/sqlite/bindings/sqlite_function.h
new file mode 100644
index 0000000..a97541f
--- /dev/null
+++ b/src/trace_processor/sqlite/bindings/sqlite_function.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_FUNCTION_H_
+#define SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_FUNCTION_H_
+
+#include <sqlite3.h>  // IWYU pragma: export
+
+namespace perfetto::trace_processor {
+
+// Prototype for a function which can be registered with SQLite.
+//
+// See https://www.sqlite.org/c3ref/create_function.html for details on how
+// to implement the methods of this class.
+template <typename Impl>
+class SqliteFunction {
+ public:
+  // The type of the context object which will be passed to the function.
+  // Can be redefined in any sub-classes to override the context.
+  using UserDataContext = void;
+
+  // The xStep function which will be executed by SQLite to add a row of values
+  // to the current window.
+  //
+  // Implementations MUST define this function themselves; this function is
+  // declared but *not* defined so linker errors will be thrown if not defined.
+  static void Step(sqlite3_context*, int argc, sqlite3_value** argv);
+
+  // Returns the pointer to the user data structure which is passed when
+  // creating the function.
+  static auto GetUserData(sqlite3_context* ctx) {
+    return static_cast<typename Impl::UserDataContext*>(sqlite3_user_data(ctx));
+  }
+};
+
+}  // namespace perfetto::trace_processor
+
+#endif  // SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_FUNCTION_H_
diff --git a/src/trace_processor/sqlite/bindings/sqlite_result.h b/src/trace_processor/sqlite/bindings/sqlite_result.h
index 5c1fb21..fe548b4 100644
--- a/src/trace_processor/sqlite/bindings/sqlite_result.h
+++ b/src/trace_processor/sqlite/bindings/sqlite_result.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@
 #ifndef SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_RESULT_H_
 #define SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_RESULT_H_
 
-#include <sqlite3.h>
+#include <sqlite3.h>  // IWYU pragma: export
 #include <cstdint>
 
 namespace perfetto::trace_processor::sqlite::result {
diff --git a/src/trace_processor/sqlite/bindings/sqlite_type.h b/src/trace_processor/sqlite/bindings/sqlite_type.h
new file mode 100644
index 0000000..9b07009
--- /dev/null
+++ b/src/trace_processor/sqlite/bindings/sqlite_type.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_TYPE_H_
+#define SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_TYPE_H_
+
+#include <sqlite3.h>  // IWYU pragma: export
+
+namespace perfetto::trace_processor::sqlite {
+
+enum class Type : int {
+  kNull = SQLITE_NULL,
+  kInteger = SQLITE_INTEGER,
+  kText = SQLITE_TEXT,
+  kFloat = SQLITE_FLOAT,
+  kBlob = SQLITE_BLOB,
+};
+
+}  // namespace perfetto::trace_processor::sqlite
+
+#endif  // SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_TYPE_H_
diff --git a/src/trace_processor/sqlite/bindings/sqlite_value.h b/src/trace_processor/sqlite/bindings/sqlite_value.h
new file mode 100644
index 0000000..a935acf
--- /dev/null
+++ b/src/trace_processor/sqlite/bindings/sqlite_value.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_VALUE_H_
+#define SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_VALUE_H_
+
+#include <sqlite3.h>  // IWYU pragma: export
+#include <cstdint>
+
+#include "src/trace_processor/sqlite/bindings/sqlite_type.h"
+
+namespace perfetto::trace_processor::sqlite::value {
+
+// This file contains wraps the sqlite3_value_* functions which extract values
+// from sqlite3_value structs.
+
+inline Type Type(sqlite3_value* value) {
+  return static_cast<enum Type>(sqlite3_value_type(value));
+}
+
+inline bool IsNull(sqlite3_value* value) {
+  return Type(value) == Type::kNull;
+}
+
+inline int64_t Int64(sqlite3_value* value) {
+  return sqlite3_value_int64(value);
+}
+
+inline double Double(sqlite3_value* value) {
+  return sqlite3_value_double(value);
+}
+
+inline const char* Text(sqlite3_value* value) {
+  return reinterpret_cast<const char*>(sqlite3_value_text(value));
+}
+
+template <typename T>
+inline T* Pointer(sqlite3_value* value, const char* type) {
+  return static_cast<T*>(sqlite3_value_pointer(value, type));
+}
+
+}  // namespace perfetto::trace_processor::sqlite::value
+
+#endif  // SRC_TRACE_PROCESSOR_SQLITE_BINDINGS_SQLITE_VALUE_H_
diff --git a/src/trace_processor/sqlite/sqlite_value.h b/src/trace_processor/sqlite/sqlite_value.h
deleted file mode 100644
index 7f447a2..0000000
--- a/src/trace_processor/sqlite/sqlite_value.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_SQLITE_SQLITE_VALUE_H_
-#define SRC_TRACE_PROCESSOR_SQLITE_SQLITE_VALUE_H_
-
-#include <sqlite3.h>
-#include <cstdint>
-
-struct sqlite_value;
-
-namespace perfetto::trace_processor::sqlite::value {
-
-// This file contains thin wrappers around the sqlite3_value_* functions which
-// fetches data from SQLite in fuction definitions, virtual table filter clauses
-// etc.
-
-inline int64_t Long(sqlite3_value* value) {
-  return sqlite3_value_int64(value);
-}
-
-inline bool IsNull(sqlite3_value* value) {
-  return sqlite3_value_type(value) == SQLITE_NULL;
-}
-
-}  // namespace perfetto::trace_processor::sqlite::value
-
-#endif  // SRC_TRACE_PROCESSOR_SQLITE_SQLITE_VALUE_H_
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index c3af18d..e58696e 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -68,6 +68,7 @@
 #include "src/trace_processor/metrics/sql/amalgamated_sql_metrics.h"
 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
 #include "src/trace_processor/perfetto_sql/engine/table_pointer_module.h"
+#include "src/trace_processor/perfetto_sql/intrinsics/functions/array.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/base64.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/clock_functions.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/create_function.h"
@@ -80,6 +81,7 @@
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.h"
+#include "src/trace_processor/perfetto_sql/intrinsics/functions/struct.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/to_ftrace.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/utils.h"
@@ -720,32 +722,42 @@
   {
     base::Status status = RegisterLastNonNullFunction(*engine_);
     if (!status.ok())
-      PERFETTO_ELOG("%s", status.c_message());
+      PERFETTO_FATAL("%s", status.c_message());
   }
   {
     base::Status status = RegisterStackFunctions(engine_.get(), &context_);
     if (!status.ok())
-      PERFETTO_ELOG("%s", status.c_message());
+      PERFETTO_FATAL("%s", status.c_message());
   }
   {
     base::Status status = PprofFunctions::Register(*engine_, &context_);
     if (!status.ok())
-      PERFETTO_ELOG("%s", status.c_message());
+      PERFETTO_FATAL("%s", status.c_message());
   }
   {
     base::Status status = RegisterLayoutFunctions(*engine_);
     if (!status.ok())
-      PERFETTO_ELOG("%s", status.c_message());
+      PERFETTO_FATAL("%s", status.c_message());
   }
   {
     base::Status status = RegisterMathFunctions(*engine_);
     if (!status.ok())
-      PERFETTO_ELOG("%s", status.c_message());
+      PERFETTO_FATAL("%s", status.c_message());
   }
   {
     base::Status status = RegisterBase64Functions(*engine_);
     if (!status.ok())
-      PERFETTO_ELOG("%s", status.c_message());
+      PERFETTO_FATAL("%s", status.c_message());
+  }
+  {
+    base::Status status = RegisterArrayFunctions(*engine_);
+    if (!status.ok())
+      PERFETTO_FATAL("%s", status.c_message());
+  }
+  {
+    base::Status status = RegisterStructFunctions(*engine_);
+    if (!status.ok())
+      PERFETTO_FATAL("%s", status.c_message());
   }
 
   TraceStorage* storage = context_.storage.get();