Parses FTS options from the create statement of an FTS table. This method assumes the given create statement is a valid well-formed SQLite statement as defined in the CREATE VIRTUAL TABLE syntax diagram . @param createStatement the "CREATE V
(String createStatement)
| 126 | * @return the set of FTS option key and values in the create statement. |
| 127 | */ |
| 128 | @VisibleForTesting |
| 129 | @SuppressWarnings("WeakerAccess") /* synthetic access */ |
| 130 | static Set<String> parseOptions(String createStatement) { |
| 131 | if (createStatement.isEmpty()) { |
| 132 | return new HashSet<>(); |
| 133 | } |
| 134 | |
| 135 | // Module arguments are within the parenthesis followed by the module name. |
| 136 | String argsString = createStatement.substring( |
| 137 | createStatement.indexOf('(') + 1, |
| 138 | createStatement.lastIndexOf(')')); |
| 139 | |
| 140 | // Split the module argument string by the comma delimiter, keeping track of quotation so |
| 141 | // so that if the delimiter is found within a string literal we don't substring at the wrong |
| 142 | // index. SQLite supports four ways of quoting keywords, see: |
| 143 | // https://www.sqlite.org/lang_keywords.html |
| 144 | List<String> args = new ArrayList<>(); |
| 145 | ArrayDeque<Character> quoteStack = new ArrayDeque<>(); |
| 146 | int lastDelimiterIndex = -1; |
| 147 | for (int i = 0; i < argsString.length(); i++) { |
| 148 | char c = argsString.charAt(i); |
| 149 | switch (c) { |
| 150 | case '\'': |
| 151 | case '"': |
| 152 | case '`': |
| 153 | if (quoteStack.isEmpty()) { |
| 154 | quoteStack.push(c); |
| 155 | } else if (quoteStack.peek() == c) { |
| 156 | quoteStack.pop(); |
| 157 | } |
| 158 | break; |
| 159 | case '[': |
| 160 | if (quoteStack.isEmpty()) { |
| 161 | quoteStack.push(c); |
| 162 | } |
| 163 | break; |
| 164 | case ']': |
| 165 | if (!quoteStack.isEmpty() && quoteStack.peek() == '[') { |
| 166 | quoteStack.pop(); |
| 167 | } |
| 168 | break; |
| 169 | case ',': |
| 170 | if (quoteStack.isEmpty()) { |
| 171 | args.add(argsString.substring(lastDelimiterIndex + 1, i).trim()); |
| 172 | lastDelimiterIndex = i; |
| 173 | } |
| 174 | break; |
| 175 | } |
| 176 | } |
| 177 | args.add(argsString.substring(lastDelimiterIndex + 1).trim()); // Add final argument. |
| 178 | |
| 179 | // Match args against valid options, otherwise they are column definitions. |
| 180 | HashSet<String> options = new HashSet<>(); |
| 181 | for (String arg : args) { |
| 182 | for (String validOption : FTS_OPTIONS) { |
| 183 | if (arg.startsWith(validOption)) { |
| 184 | options.add(arg); |
| 185 | } |