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/perfetto_sql/intrinsics/functions/sqlite3_str_split.h"
18 
19 #include "src/trace_processor/sqlite/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 
sqlite_str_split(sqlite3_context * context,int argc,sqlite3_value ** argv)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     sqlite::result::Error(context, kDelimiterError);
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     sqlite::result::Error(context, kDelimiterError);
43     return;
44   }
45   if (sqlite3_value_type(argv[2]) != SQLITE_INTEGER) {
46     sqlite::result::Error(context, kSplitFieldIndexError);
47     return;
48   }
49   int fld = sqlite3_value_int(argv[2]);
50   if (fld < 0) {
51     sqlite::result::Error(context, kSplitFieldIndexError);
52     return;
53   }
54   if (sqlite3_value_type(argv[0]) != SQLITE_TEXT) {
55     sqlite::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       sqlite::result::RawString(context, in, size,
66                                 sqlite::utils::kSqliteTransient);
67       return;
68     } else if (next == nullptr) {
69       break;
70     }
71     in = next + delimiter_len;
72     --fld;
73   } while (fld >= 0);
74   sqlite::result::Null(context);
75 }
76 }  // namespace
77 
sqlite3_str_split_init(sqlite3 * db)78 void sqlite3_str_split_init(sqlite3* db) {
79   PERFETTO_CHECK(sqlite3_create_function(db, "str_split", 3,
80                                          SQLITE_UTF8 | SQLITE_DETERMINISTIC,
81                                          nullptr, &sqlite_str_split, nullptr,
82                                          nullptr) == SQLITE_OK);
83 }
84 
85 }  // namespace trace_processor
86 }  // namespace perfetto
87