From cb0264c3cac00c288f9a0b4614f203d1c4b157ab Mon Sep 17 00:00:00 2001
From: Ilya Verbin <iverbin@tarantool.org>
Date: Tue, 6 Feb 2024 18:25:18 +0300
Subject: [PATCH] key_def: ignore json path in key_def_find_by_fieldno

This function returns a key_def part by a field number. However, currently
it returns NULL for parts that contain a JSON path to indexed data. Fix it.

Needed for tarantool/tarantool-ee#671

NO_DOC=bugfix
NO_CHANGELOG=not visible in CE
---
 src/box/key_def.c    | 10 ++++++----
 src/box/key_def.h    |  4 +++-
 test/unit/key_def.cc | 31 ++++++++++++++++++++++++++++++-
 3 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/src/box/key_def.c b/src/box/key_def.c
index bdd6561d5e..8097cf3036 100644
--- a/src/box/key_def.c
+++ b/src/box/key_def.c
@@ -1016,10 +1016,12 @@ key_def_decode_parts(struct key_part_def *parts, uint32_t part_count,
 const struct key_part *
 key_def_find_by_fieldno(const struct key_def *key_def, uint32_t fieldno)
 {
-	struct key_part part;
-	memset(&part, 0, sizeof(struct key_part));
-	part.fieldno = fieldno;
-	return key_def_find(key_def, &part);
+	const struct key_part *part = key_def->parts;
+	const struct key_part *end = part + key_def->part_count;
+	for (; part != end; part++)
+		if (part->fieldno == fieldno)
+			return part;
+	return NULL;
 }
 
 const struct key_part *
diff --git a/src/box/key_def.h b/src/box/key_def.h
index 4d90a0a000..1170399542 100644
--- a/src/box/key_def.h
+++ b/src/box/key_def.h
@@ -730,7 +730,9 @@ key_def_decode_parts(struct key_part_def *parts, uint32_t part_count,
 		     uint32_t field_count, struct region *region);
 
 /**
- * Returns the part in index_def->parts for the specified fieldno.
+ * Returns the first part in index_def->parts for the specified fieldno.
+ * The part is returned regardless of whether it is indexed by JSON path or not.
+ *
  * If fieldno is not in index_def->parts returns NULL.
  */
 const struct key_part *
diff --git a/test/unit/key_def.cc b/test/unit/key_def.cc
index 7f1d4fc96e..e96c2b9946 100644
--- a/test/unit/key_def.cc
+++ b/test/unit/key_def.cc
@@ -1367,10 +1367,38 @@ test_tuple_compare_sequential_no_optional_parts_unique(bool ascending_key,
 	check_plan();
 }
 
+static void
+test_key_def_find_by_fieldno(void)
+{
+	plan(3);
+	header();
+
+	const struct key_part *key_part;
+	struct key_def *key_def = test_key_def_new(
+		"[{%s%u%s%s}{%s%u%s%s}{%s%u%s%s%s%s}]",
+		"field", 1, "type", "unsigned",
+		"field", 2, "type", "string",
+		"field", 3, "type", "string", "path", "foo");
+
+	key_part = key_def_find_by_fieldno(key_def, 2);
+	isnt(key_part, NULL, "field 2 (no path) found");
+
+	key_part = key_def_find_by_fieldno(key_def, 3);
+	isnt(key_part, NULL, "field 3 (with path) found");
+
+	key_part = key_def_find_by_fieldno(key_def, 100);
+	is(key_part, NULL, "field 100 not found");
+
+	key_def_delete(key_def);
+
+	footer();
+	check_plan();
+}
+
 static int
 test_main(void)
 {
-	plan(50);
+	plan(51);
 	header();
 
 	test_func_compare();
@@ -1423,6 +1451,7 @@ test_main(void)
 	test_key_compare_singlepart(true, false);
 	test_key_compare_singlepart(false, true);
 	test_key_compare_singlepart(false, false);
+	test_key_def_find_by_fieldno();
 
 	footer();
 	return check_plan();
-- 
GitLab