| /* |
| * 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/sqlite/sqlite3_str_split.h" |
| |
| #include "src/trace_processor/sqlite/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, |
| nullptr, &sqlite_str_split, nullptr, |
| nullptr) == SQLITE_OK); |
| } |
| |
| } // namespace trace_processor |
| } // namespace perfetto |