trace_processor: add support for filtering on nullable types
This CL adds support for filtering using IS NULL and IS NOT NULL which
was previously causing CHECKs.
Change-Id: I6533c3f24a48cd1d52f78500ba4d2ec283eee8d1
diff --git a/src/trace_processor/args_table.cc b/src/trace_processor/args_table.cc
index 2a0f9d1..cd2756d 100644
--- a/src/trace_processor/args_table.cc
+++ b/src/trace_processor/args_table.cc
@@ -141,31 +141,40 @@
FilteredRowIndex* index) const {
switch (type_) {
case VarardicType::kInt: {
- auto binary_op = sqlite_utils::GetPredicateForOp<int64_t>(op);
+ auto binary_op = sqlite_utils::GetOptionalPredicateForOp<int64_t>(op);
int64_t extracted = sqlite_utils::ExtractSqliteValue<int64_t>(value);
index->FilterRows([this, &binary_op, extracted](uint32_t row) {
const auto& arg = storage_->args().arg_values()[row];
- return arg.type == type_ && binary_op(arg.int_value, extracted);
+ if (arg.type == type_) {
+ return binary_op(arg.int_value, extracted);
+ }
+ return binary_op(base::nullopt, extracted);
});
break;
}
case VarardicType::kReal: {
- auto binary_op = sqlite_utils::GetPredicateForOp<double>(op);
+ auto binary_op = sqlite_utils::GetOptionalPredicateForOp<double>(op);
double extracted = sqlite_utils::ExtractSqliteValue<double>(value);
index->FilterRows([this, &binary_op, extracted](uint32_t row) {
const auto& arg = storage_->args().arg_values()[row];
- return arg.type == type_ && binary_op(arg.real_value, extracted);
+ if (arg.type == type_) {
+ return binary_op(arg.real_value, extracted);
+ }
+ return binary_op(base::nullopt, extracted);
});
break;
}
case VarardicType::kString: {
- auto binary_op = sqlite_utils::GetPredicateForOp<std::string>(op);
+ auto binary_op = sqlite_utils::GetOptionalPredicateForOp<std::string>(op);
const auto* extracted =
reinterpret_cast<const char*>(sqlite3_value_text(value));
index->FilterRows([this, &binary_op, extracted](uint32_t row) {
const auto& arg = storage_->args().arg_values()[row];
const auto& str = storage_->GetString(arg.string_value);
- return arg.type == type_ && binary_op(str, extracted);
+ if (arg.type == type_) {
+ return binary_op(str, extracted);
+ }
+ return binary_op(base::nullopt, extracted);
});
break;
}
diff --git a/src/trace_processor/counters_table.cc b/src/trace_processor/counters_table.cc
index 8edeaca..9bb8d6d 100644
--- a/src/trace_processor/counters_table.cc
+++ b/src/trace_processor/counters_table.cc
@@ -114,7 +114,7 @@
void CountersTable::RefColumn::Filter(int op,
sqlite3_value* value,
FilteredRowIndex* index) const {
- auto binary_op = sqlite_utils::GetPredicateForOp<int64_t>(op);
+ auto binary_op = sqlite_utils::GetOptionalPredicateForOp<int64_t>(op);
int64_t extracted = sqlite_utils::ExtractSqliteValue<int64_t>(value);
index->FilterRows([this, &binary_op, extracted](uint32_t row) {
auto ref = storage_->counters().refs()[row];
@@ -123,7 +123,7 @@
auto upid = storage_->GetThread(static_cast<uint32_t>(ref)).upid;
// Trying to filter null with any operation we currently handle
// should return false.
- return upid.has_value() && binary_op(upid.value(), extracted);
+ return binary_op(upid, extracted);
}
return binary_op(ref, extracted);
});
diff --git a/src/trace_processor/sqlite_utils.h b/src/trace_processor/sqlite_utils.h
index fe0f0d4..285b6e5 100644
--- a/src/trace_processor/sqlite_utils.h
+++ b/src/trace_processor/sqlite_utils.h
@@ -25,6 +25,7 @@
#include <string>
#include "perfetto/base/logging.h"
+#include "perfetto/base/optional.h"
#include "src/trace_processor/scoped_db.h"
#include "src/trace_processor/table.h"
@@ -77,6 +78,7 @@
std::function<bool(T, T)> GetPredicateForOp(int op) {
switch (op) {
case SQLITE_INDEX_CONSTRAINT_EQ:
+ case SQLITE_INDEX_CONSTRAINT_IS:
return std::equal_to<T>();
case SQLITE_INDEX_CONSTRAINT_GE:
return std::greater_equal<T>();
@@ -87,12 +89,28 @@
case SQLITE_INDEX_CONSTRAINT_LT:
return std::less<T>();
case SQLITE_INDEX_CONSTRAINT_NE:
+ case SQLITE_INDEX_CONSTRAINT_ISNOT:
return std::not_equal_to<T>();
default:
PERFETTO_CHECK(false);
}
}
+template <class T>
+std::function<bool(base::Optional<T>, T)> GetOptionalPredicateForOp(int op) {
+ switch (op) {
+ case SQLITE_INDEX_CONSTRAINT_ISNULL:
+ return [](base::Optional<T> f, T) { return !f.has_value(); };
+ case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
+ return [](base::Optional<T> f, T) { return f.has_value(); };
+ default:
+ auto fn = GetPredicateForOp<T>(op);
+ return [fn](base::Optional<T> f, T s) {
+ return f.has_value() && fn(f.value(), s);
+ };
+ }
+}
+
template <typename T>
T ExtractSqliteValue(sqlite3_value* value);