| 1181 | } |
| 1182 | |
| 1183 | IntVal StringFunctions::RegexpMatchCount4Args(FunctionContext* context, |
| 1184 | const StringVal& str, const StringVal& pattern, const IntVal& start_pos, |
| 1185 | const StringVal& match_parameter) { |
| 1186 | if (str.is_null || pattern.is_null) return IntVal::null(); |
| 1187 | |
| 1188 | int offset = 0; |
| 1189 | DCHECK_GE(str.len, 0); |
| 1190 | // The parameter "start_pos" starts counting at 1 instead of 0. If "start_pos" is |
| 1191 | // beyond the end of the string, "str" will be considered an empty string. |
| 1192 | if (!start_pos.is_null) offset = min(start_pos.val - 1, str.len); |
| 1193 | if (offset < 0) { |
| 1194 | stringstream error; |
| 1195 | error << "Illegal starting position " << start_pos.val << endl; |
| 1196 | context->SetError(error.str().c_str()); |
| 1197 | return IntVal::null(); |
| 1198 | } |
| 1199 | |
| 1200 | re2::RE2* re = reinterpret_cast<re2::RE2*>( |
| 1201 | context->GetFunctionState(FunctionContext::THREAD_LOCAL)); |
| 1202 | // Destroys re if we have to locally compile it. |
| 1203 | scoped_ptr<re2::RE2> scoped_re; |
| 1204 | if (re == NULL) { |
| 1205 | DCHECK(!context->IsArgConstant(1) || (context->GetNumArgs() == 4 && |
| 1206 | !context->IsArgConstant(3))); |
| 1207 | string error_str; |
| 1208 | re = CompileRegex(pattern, &error_str, match_parameter); |
| 1209 | if (re == NULL) { |
| 1210 | context->SetError(error_str.c_str()); |
| 1211 | return IntVal::null(); |
| 1212 | } |
| 1213 | scoped_re.reset(re); |
| 1214 | } |
| 1215 | |
| 1216 | DCHECK_GE(str.len, offset); |
| 1217 | re2::StringPiece str_sp(reinterpret_cast<char*>(str.ptr), str.len); |
| 1218 | int count = 0; |
| 1219 | re2::StringPiece match; |
| 1220 | while (offset <= str.len && |
| 1221 | re->Match(str_sp, offset, str.len, re2::RE2::UNANCHORED, &match, 1)) { |
| 1222 | // Empty string is a valid match for pattern with '*'. Start matching at the next |
| 1223 | // character until we reach the end of the string. |
| 1224 | count++; |
| 1225 | if (match.size() == 0) { |
| 1226 | if (offset == str.len) { |
| 1227 | break; |
| 1228 | } |
| 1229 | offset++; |
| 1230 | } else { |
| 1231 | // Make sure forward progress is being made or we will be in an infinite loop. |
| 1232 | DCHECK_GT(match.data() - str_sp.data() + match.size(), offset); |
| 1233 | offset = match.data() - str_sp.data() + match.size(); |
| 1234 | } |
| 1235 | } |
| 1236 | return IntVal(count); |
| 1237 | } |
| 1238 | |
| 1239 | // NULL handling of function Concat and ConcatWs are different. |
| 1240 | // Function concat was reimplemented to keep the original |
nothing calls this directly
no test coverage detected