Merge "Fix segfault in trace processor" into main
diff --git a/src/trace_processor/db/column/dense_null_overlay.cc b/src/trace_processor/db/column/dense_null_overlay.cc
index e171ec0..55003fa 100644
--- a/src/trace_processor/db/column/dense_null_overlay.cc
+++ b/src/trace_processor/db/column/dense_null_overlay.cc
@@ -82,10 +82,10 @@
       case SearchValidationResult::kNoData: {
         // There is no need to search in underlying storage. It's enough to
         // intersect the |non_null_|.
-        BitVector res = non_null_->IntersectRange(in.start, in.end);
-        res.Not();
+        BitVector res = non_null_->Copy();
         res.Resize(in.end, false);
-        return RangeOrBitVector(std::move(res));
+        res.Not();
+        return RangeOrBitVector(res.IntersectRange(in.start, in.end));
       }
       case SearchValidationResult::kAllData:
         return RangeOrBitVector(in);
diff --git a/src/trace_processor/db/column/null_overlay.cc b/src/trace_processor/db/column/null_overlay.cc
index fa1e679..b1f8f45 100644
--- a/src/trace_processor/db/column/null_overlay.cc
+++ b/src/trace_processor/db/column/null_overlay.cc
@@ -129,10 +129,10 @@
       case SearchValidationResult::kNoData: {
         // There is no need to search in underlying storage. It's enough to
         // intersect the |non_null_|.
-        BitVector res = non_null_->IntersectRange(in.start, in.end);
-        res.Not();
+        BitVector res = non_null_->Copy();
         res.Resize(in.end, false);
-        return RangeOrBitVector(std::move(res));
+        res.Not();
+        return RangeOrBitVector(res.IntersectRange(in.start, in.end));
       }
       case SearchValidationResult::kAllData:
         return RangeOrBitVector(in);
diff --git a/src/trace_processor/db/column/numeric_storage.h b/src/trace_processor/db/column/numeric_storage.h
index f7cb51c..821fd40 100644
--- a/src/trace_processor/db/column/numeric_storage.h
+++ b/src/trace_processor/db/column/numeric_storage.h
@@ -100,21 +100,7 @@
     SingleSearchResult SingleSearch(FilterOp op,
                                     SqlValue sql_val,
                                     uint32_t i) const override {
-      if constexpr (std::is_same_v<T, double>) {
-        if (sql_val.type != SqlValue::kDouble) {
-          return SingleSearchResult::kNeedsFullSearch;
-        }
-        return utils::SingleSearchNumeric(op, (*vector_)[i],
-                                          sql_val.double_value);
-      } else {
-        if (sql_val.type != SqlValue::kLong ||
-            sql_val.long_value > std::numeric_limits<T>::max() ||
-            sql_val.long_value < std::numeric_limits<T>::min()) {
-          return SingleSearchResult::kNeedsFullSearch;
-        }
-        return utils::SingleSearchNumeric(op, (*vector_)[i],
-                                          static_cast<T>(sql_val.long_value));
-      }
+      return utils::SingleSearchNumeric(op, (*vector_)[i], sql_val);
     }
 
     void StableSort(SortToken* start,
diff --git a/src/trace_processor/db/column/numeric_storage_unittest.cc b/src/trace_processor/db/column/numeric_storage_unittest.cc
index 2b20306..46ef920 100644
--- a/src/trace_processor/db/column/numeric_storage_unittest.cc
+++ b/src/trace_processor/db/column/numeric_storage_unittest.cc
@@ -187,6 +187,11 @@
             SingleSearchResult::kMatch);
   ASSERT_EQ(chain->SingleSearch(FilterOp::kGe, SqlValue::Long(0), 5),
             SingleSearchResult::kNoMatch);
+
+  ASSERT_EQ(chain->SingleSearch(FilterOp::kIsNull, SqlValue(), 0),
+            SingleSearchResult::kNoMatch);
+  ASSERT_EQ(chain->SingleSearch(FilterOp::kIsNotNull, SqlValue(), 0),
+            SingleSearchResult::kMatch);
 }
 
 TEST(NumericStorage, Search) {
diff --git a/src/trace_processor/db/column/set_id_storage.cc b/src/trace_processor/db/column/set_id_storage.cc
index 6e4719f..ae1c167 100644
--- a/src/trace_processor/db/column/set_id_storage.cc
+++ b/src/trace_processor/db/column/set_id_storage.cc
@@ -72,15 +72,7 @@
 SingleSearchResult SetIdStorage::ChainImpl::SingleSearch(FilterOp op,
                                                          SqlValue sql_val,
                                                          uint32_t i) const {
-  if (sql_val.type != SqlValue::kLong ||
-      sql_val.long_value > std::numeric_limits<uint32_t>::max() ||
-      sql_val.long_value < std::numeric_limits<uint32_t>::min()) {
-    // Because of the large amount of code needing for handling comparisions
-    // with doubles or out of range values, just defer to the full search.
-    return SingleSearchResult::kNeedsFullSearch;
-  }
-  return utils::SingleSearchNumeric(op, (*values_)[i],
-                                    static_cast<uint32_t>(sql_val.long_value));
+  return utils::SingleSearchNumeric(op, (*values_)[i], sql_val);
 }
 
 SearchValidationResult SetIdStorage::ChainImpl::ValidateSearchConstraints(
diff --git a/src/trace_processor/db/column/utils.h b/src/trace_processor/db/column/utils.h
index 14c6456..9533d8cd 100644
--- a/src/trace_processor/db/column/utils.h
+++ b/src/trace_processor/db/column/utils.h
@@ -19,7 +19,9 @@
 #include <algorithm>
 #include <cstdint>
 #include <functional>
+#include <limits>
 #include <optional>
+#include <type_traits>
 #include <vector>
 
 #include "perfetto/base/logging.h"
@@ -29,6 +31,36 @@
 #include "src/trace_processor/db/column/types.h"
 
 namespace perfetto::trace_processor::column::utils {
+namespace internal {
+
+template <typename T, typename Comparator>
+SingleSearchResult SingleSearchNumeric(T left, const SqlValue& right_v) {
+  if constexpr (std::is_same_v<T, double>) {
+    if (right_v.type != SqlValue::kDouble) {
+      // Because of the large amount of code needing for handling comparisons
+      // with integers, just defer to the full search.
+      return SingleSearchResult::kNeedsFullSearch;
+    }
+    return Comparator()(left, right_v.double_value)
+               ? SingleSearchResult::kMatch
+               : SingleSearchResult::kNoMatch;
+  } else if constexpr (std::is_integral_v<T>) {
+    if (right_v.type != SqlValue::kLong ||
+        right_v.long_value > std::numeric_limits<T>::max() ||
+        right_v.long_value < std::numeric_limits<T>::min()) {
+      // Because of the large amount of code needing for handling comparisons
+      // with doubles or out of range values, just defer to the full search.
+      return SingleSearchResult::kNeedsFullSearch;
+    }
+    return Comparator()(left, static_cast<T>(right_v.long_value))
+               ? SingleSearchResult::kMatch
+               : SingleSearchResult::kNoMatch;
+  } else {
+    static_assert(std::is_same_v<T, void>, "Illegal type");
+  }
+}
+
+}  // namespace internal
 
 template <typename Comparator, typename ValType, typename DataType>
 void LinearSearchWithComparator(ValType val,
@@ -77,27 +109,25 @@
 }
 
 template <typename T>
-SingleSearchResult SingleSearchNumeric(FilterOp op, T left, T right) {
+SingleSearchResult SingleSearchNumeric(FilterOp op,
+                                       T left,
+                                       const SqlValue& right_v) {
   switch (op) {
     case FilterOp::kEq:
-      return std::equal_to<T>()(left, right) ? SingleSearchResult::kMatch
-                                             : SingleSearchResult::kNoMatch;
+      return internal::SingleSearchNumeric<T, std::equal_to<T>>(left, right_v);
     case FilterOp::kNe:
-      return std::not_equal_to<T>()(left, right) ? SingleSearchResult::kMatch
-                                                 : SingleSearchResult::kNoMatch;
+      return internal::SingleSearchNumeric<T, std::not_equal_to<T>>(left,
+                                                                    right_v);
     case FilterOp::kGe:
-      return std::greater_equal<T>()(left, right)
-                 ? SingleSearchResult::kMatch
-                 : SingleSearchResult::kNoMatch;
+      return internal::SingleSearchNumeric<T, std::greater_equal<T>>(left,
+                                                                     right_v);
     case FilterOp::kGt:
-      return std::greater<T>()(left, right) ? SingleSearchResult::kMatch
-                                            : SingleSearchResult::kNoMatch;
+      return internal::SingleSearchNumeric<T, std::greater<T>>(left, right_v);
     case FilterOp::kLe:
-      return std::less_equal<T>()(left, right) ? SingleSearchResult::kMatch
-                                               : SingleSearchResult::kNoMatch;
+      return internal::SingleSearchNumeric<T, std::less_equal<T>>(left,
+                                                                  right_v);
     case FilterOp::kLt:
-      return std::less<T>()(left, right) ? SingleSearchResult::kMatch
-                                         : SingleSearchResult::kNoMatch;
+      return internal::SingleSearchNumeric<T, std::less<T>>(left, right_v);
     case FilterOp::kIsNotNull:
       return SingleSearchResult::kMatch;
     case FilterOp::kGlob:
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index 4910cbd..92cad97 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -1162,13 +1162,6 @@
       );
   },
 
-  setPivotTableArgumentNames(
-    state: StateDraft,
-    args: {argumentNames: string[]},
-  ) {
-    state.nonSerializableState.pivotTable.argumentNames = args.argumentNames;
-  },
-
   changePivotTablePivotOrder(
     state: StateDraft,
     args: {from: number; to: number; direction: DropDirection},
diff --git a/ui/src/common/empty_state.ts b/ui/src/common/empty_state.ts
index 5bf1f5a..f866914 100644
--- a/ui/src/common/empty_state.ts
+++ b/ui/src/common/empty_state.ts
@@ -83,7 +83,6 @@
       ],
       constrainToArea: true,
       queryRequested: false,
-      argumentNames: [],
     },
   };
 }
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 3b27e16..d0af73b 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -424,9 +424,6 @@
   // Set to true by frontend to request controller to perform the query to
   // acquire the necessary data from the engine.
   queryRequested: boolean;
-
-  // Argument names in the current trace, used for autocompletion purposes.
-  argumentNames: string[];
 }
 
 export interface LoadedConfigNone {
diff --git a/ui/src/controller/pivot_table_controller.ts b/ui/src/controller/pivot_table_controller.ts
index b1eb386..663fdf4 100644
--- a/ui/src/controller/pivot_table_controller.ts
+++ b/ui/src/controller/pivot_table_controller.ts
@@ -31,7 +31,7 @@
 } from '../frontend/pivot_table_query_generator';
 import {Aggregation, PivotTree} from '../frontend/pivot_table_types';
 import {Engine} from '../trace_processor/engine';
-import {ColumnType, STR} from '../trace_processor/query_result';
+import {ColumnType} from '../trace_processor/query_result';
 
 import {Controller} from './controller';
 
@@ -189,7 +189,6 @@
   engine: Engine;
   lastQueryAreaId = '';
   lastQueryAreaTracks = new Set<string>();
-  requestedArgumentNames = false;
 
   constructor(args: {engine: Engine}) {
     super({});
@@ -272,31 +271,11 @@
     );
   }
 
-  async requestArgumentNames() {
-    this.requestedArgumentNames = true;
-    const result = await this.engine.query(`
-      select distinct flat_key from args
-    `);
-    const it = result.iter({flat_key: STR});
-
-    const argumentNames = [];
-    while (it.valid()) {
-      argumentNames.push(it.flat_key);
-      it.next();
-    }
-
-    globals.dispatch(Actions.setPivotTableArgumentNames({argumentNames}));
-  }
-
   run() {
     if (!PIVOT_TABLE_REDUX_FLAG.get()) {
       return;
     }
 
-    if (!this.requestedArgumentNames) {
-      this.requestArgumentNames();
-    }
-
     const pivotTableState = globals.state.nonSerializableState.pivotTable;
     const selection = getLegacySelection(globals.state);
 
diff --git a/ui/src/frontend/pivot_table_argument_popup.ts b/ui/src/frontend/pivot_table_argument_popup.ts
index faa1579..949200e 100644
--- a/ui/src/frontend/pivot_table_argument_popup.ts
+++ b/ui/src/frontend/pivot_table_argument_popup.ts
@@ -20,21 +20,6 @@
 
 interface ArgumentPopupArgs {
   onArgumentChange: (arg: string) => void;
-  knownArguments: string[];
-}
-
-function longestString(array: string[]): string {
-  if (array.length === 0) {
-    return '';
-  }
-
-  let answer = array[0];
-  for (let i = 1; i < array.length; i++) {
-    if (array[i].length > answer.length) {
-      answer = array[i];
-    }
-  }
-  return answer;
 }
 
 // Component rendering popup for entering an argument name to use as a pivot.
@@ -47,41 +32,6 @@
     raf.scheduleFullRedraw();
   }
 
-  renderMatches(attrs: ArgumentPopupArgs): m.Child[] {
-    const result: m.Child[] = [];
-
-    for (const option of attrs.knownArguments) {
-      // Would be great to have smarter fuzzy matching, but in the meantime
-      // simple substring check should work fine.
-      const index = option.indexOf(this.argument);
-
-      if (index === -1) {
-        continue;
-      }
-
-      if (result.length === 10) {
-        break;
-      }
-
-      result.push(
-        m(
-          'div',
-          {
-            onclick: () => {
-              this.setArgument(attrs, option);
-            },
-          },
-          option.substring(0, index),
-          // Highlight the matching part with bold font
-          m('strong', this.argument),
-          option.substring(index + this.argument.length),
-        ),
-      );
-    }
-
-    return result;
-  }
-
   view({attrs}: m.Vnode<ArgumentPopupArgs>): m.Child {
     return m(
       '.name-completion',
@@ -94,8 +44,6 @@
         },
         value: this.argument,
       }),
-      m('.arguments-popup-sizer', longestString(attrs.knownArguments)),
-      this.renderMatches(attrs),
     );
   }
 }
diff --git a/ui/src/frontend/tables/attribute_modal_holder.ts b/ui/src/frontend/tables/attribute_modal_holder.ts
index 562a922..d154ab1 100644
--- a/ui/src/frontend/tables/attribute_modal_holder.ts
+++ b/ui/src/frontend/tables/attribute_modal_holder.ts
@@ -15,7 +15,6 @@
 import m from 'mithril';
 
 import {showModal} from '../../widgets/modal';
-import {globals} from '../globals';
 import {ArgumentPopup} from '../pivot_table_argument_popup';
 
 export class AttributeModalHolder {
@@ -45,8 +44,6 @@
 
   private renderModalContents() {
     return m(ArgumentPopup, {
-      knownArguments:
-        globals.state.nonSerializableState.pivotTable.argumentNames,
       onArgumentChange: (arg) => {
         this.typedArgument = arg;
       },