/* * Copyright (C) 2019 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/sqlite3_str_split.h" #include "src/trace_processor/sqlite_utils.h" namespace perfetto { namespace trace_processor { namespace { constexpr char kDelimiterError[] = "str_split: delimiter must be a non-empty string"; constexpr char kSplitFieldIndexError[] = "str_split: field number must be a non-negative integer"; void sqlite_str_split(sqlite3_context* context, int argc, sqlite3_value** argv) { PERFETTO_DCHECK(argc == 3); if (sqlite3_value_type(argv[1]) != SQLITE_TEXT) { sqlite3_result_error(context, kDelimiterError, -1); return; } const char* delimiter = reinterpret_cast<const char*>(sqlite3_value_text(argv[1])); const size_t delimiter_len = strlen(delimiter); if (delimiter_len == 0) { sqlite3_result_error(context, kDelimiterError, -1); return; } if (sqlite3_value_type(argv[2]) != SQLITE_INTEGER) { sqlite3_result_error(context, kSplitFieldIndexError, -1); return; } int fld = sqlite3_value_int(argv[2]); if (fld < 0) { sqlite3_result_error(context, kSplitFieldIndexError, -1); return; } if (sqlite3_value_type(argv[0]) != SQLITE_TEXT) { sqlite3_result_null(context); return; } const char* in = reinterpret_cast<const char*>(sqlite3_value_text(argv[0])); const char* next; do { next = strstr(in, delimiter); if (fld == 0) { int size = next != nullptr ? static_cast<int>(next - in) : static_cast<int>(strlen(in)); sqlite3_result_text(context, in, size, sqlite_utils::kSqliteTransient); return; } else if (next == nullptr) { break; } in = next + delimiter_len; --fld; } while (fld >= 0); sqlite3_result_null(context); } } // namespace void sqlite3_str_split_init(sqlite3* db) { PERFETTO_CHECK(sqlite3_create_function(db, "str_split", 3, SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0, &sqlite_str_split, 0, 0) == SQLITE_OK); } } // namespace trace_processor } // namespace perfetto