1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "src/trace_processor/sqlite3_str_split.h" 18 19 #include "src/trace_processor/sqlite_utils.h" 20 21 namespace perfetto { 22 namespace trace_processor { 23 24 namespace { 25 constexpr char kDelimiterError[] = 26 "str_split: delimiter must be a non-empty string"; 27 constexpr char kSplitFieldIndexError[] = 28 "str_split: field number must be a non-negative integer"; 29 30 void sqlite_str_split(sqlite3_context* context, 31 int argc, 32 sqlite3_value** argv) { 33 PERFETTO_DCHECK(argc == 3); 34 if (sqlite3_value_type(argv[1]) != SQLITE_TEXT) { 35 sqlite3_result_error(context, kDelimiterError, -1); 36 return; 37 } 38 const char* delimiter = 39 reinterpret_cast<const char*>(sqlite3_value_text(argv[1])); 40 const size_t delimiter_len = strlen(delimiter); 41 if (delimiter_len == 0) { 42 sqlite3_result_error(context, kDelimiterError, -1); 43 return; 44 } 45 if (sqlite3_value_type(argv[2]) != SQLITE_INTEGER) { 46 sqlite3_result_error(context, kSplitFieldIndexError, -1); 47 return; 48 } 49 int fld = sqlite3_value_int(argv[2]); 50 if (fld < 0) { 51 sqlite3_result_error(context, kSplitFieldIndexError, -1); 52 return; 53 } 54 if (sqlite3_value_type(argv[0]) != SQLITE_TEXT) { 55 sqlite3_result_null(context); 56 return; 57 } 58 const char* in = reinterpret_cast<const char*>(sqlite3_value_text(argv[0])); 59 const char* next; 60 do { 61 next = strstr(in, delimiter); 62 if (fld == 0) { 63 int size = next != nullptr ? static_cast<int>(next - in) 64 : static_cast<int>(strlen(in)); 65 sqlite3_result_text(context, in, size, sqlite_utils::kSqliteTransient); 66 return; 67 } else if (next == nullptr) { 68 break; 69 } 70 in = next + delimiter_len; 71 --fld; 72 } while (fld >= 0); 73 sqlite3_result_null(context); 74 } 75 } // namespace 76 77 void sqlite3_str_split_init(sqlite3* db) { 78 PERFETTO_CHECK(sqlite3_create_function(db, "str_split", 3, 79 SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0, 80 &sqlite_str_split, 0, 0) == SQLITE_OK); 81 } 82 83 } // namespace trace_processor 84 } // namespace perfetto 85