(ctx context.Context, arg funcArgs)
| 1238 | } |
| 1239 | |
| 1240 | func (qs *queryState) handleRegexFunction(ctx context.Context, arg funcArgs) error { |
| 1241 | span := trace.SpanFromContext(ctx) |
| 1242 | stop := x.SpanTimer(span, "handleRegexFunction") |
| 1243 | defer stop() |
| 1244 | if span != nil { |
| 1245 | span.AddEvent("Processing UIDs", trace.WithAttributes( |
| 1246 | attribute.Int64("uid_count", int64(arg.srcFn.n)), |
| 1247 | attribute.String("srcFn", x.SafeUTF8(fmt.Sprintf("%+v", arg.srcFn))))) |
| 1248 | } |
| 1249 | |
| 1250 | attr := arg.q.Attr |
| 1251 | typ, err := schema.State().TypeOf(attr) |
| 1252 | span.AddEvent("Attribute information", trace.WithAttributes( |
| 1253 | attribute.String("attr", attr), |
| 1254 | attribute.String("type", typ.Name()))) |
| 1255 | if err != nil || !typ.IsScalar() { |
| 1256 | return errors.Errorf("Attribute not scalar: %s %v", x.ParseAttr(attr), typ) |
| 1257 | } |
| 1258 | if typ != types.StringID { |
| 1259 | return errors.Errorf("Got non-string type. Regex match is allowed only on string type.") |
| 1260 | } |
| 1261 | useIndex := schema.State().HasTokenizer(ctx, tok.IdentTrigram, attr) |
| 1262 | span.AddEvent("Trigram index information", trace.WithAttributes( |
| 1263 | attribute.Bool("trigram_index_found", useIndex), |
| 1264 | attribute.Bool("func_at_root", arg.srcFn.isFuncAtRoot))) |
| 1265 | |
| 1266 | query := cindex.RegexpQuery(arg.srcFn.regex.Syntax) |
| 1267 | empty := pb.List{} |
| 1268 | var uids *pb.List |
| 1269 | |
| 1270 | // Here we determine the list of uids to match. |
| 1271 | switch { |
| 1272 | // If this is a filter eval, use the given uid list (good) |
| 1273 | case arg.q.UidList != nil: |
| 1274 | // These UIDs are copied into arg.out.UidMatrix which is later updated while |
| 1275 | // processing the query. The below trick makes a copy of the list to avoid the |
| 1276 | // race conditions later. I (Aman) did a race condition tests to ensure that we |
| 1277 | // do not have more race condition in similar code in the rest of the file. |
| 1278 | // The race condition was found only here because in filter condition, even when |
| 1279 | // predicates do not have indexes, we allow regexp queries (for example, we do |
| 1280 | // not support eq/gt/lt/le in @filter, see #4077), and this was new code that |
| 1281 | // was added just to support the aforementioned case, the race condition is only |
| 1282 | // in this part of the code. |
| 1283 | uids = &pb.List{} |
| 1284 | uids.Uids = append(arg.q.UidList.Uids[:0:0], arg.q.UidList.Uids...) |
| 1285 | |
| 1286 | // Prefer to use an index (fast) |
| 1287 | case useIndex: |
| 1288 | uids, err = uidsForRegex(attr, arg, query, &empty) |
| 1289 | if err != nil { |
| 1290 | return err |
| 1291 | } |
| 1292 | |
| 1293 | // No index and at root, return error instructing user to use `has` or index. |
| 1294 | default: |
| 1295 | return errors.Errorf( |
| 1296 | "Attribute %v does not have trigram index for regex matching. "+ |
| 1297 | "Please add a trigram index or use has/uid function with regexp() as filter.", |
no test coverage detected