| /* | 
 |  * 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 |