<HTML><BODY><div>Hi!</div><div>I was wrong about indentation: in C code it should be 8-symbol wide tabs.</div><div>Sorry, my bad.</div><div> </div><div>Best regards,</div><div>Maxim Kokryashkin</div><blockquote style="border-left:1px solid #0857A6; margin:10px; padding:0 0 0 10px;">Среда, 20 октября 2021, 14:47 +03:00 от Максим Корякшин via Tarantool-patches <tarantool-patches@dev.tarantool.org>:<br> <div id=""><div class="js-helper js-readmsg-msg"><div><div id="style_16347304261045157924_BODY"><div class="cl_736561"><div>Hi! Thanks for the patch!</div><div>Please consider my comments below.</div><div> </div><div><div style="box-sizing:border-box; padding:0px 0px 0.4em">Use the imperative mood in the subject line as it is stated in the developer</div><div style="box-sizing:border-box; padding:0px 0px 0.4em">guideline[1]. A properly formed Git commit subject line should always be</div><div style="box-sizing:border-box; padding:0px 0px 0.4em">able to complete the following sentence: “If applied, this commit will<span> </span></div><div style="box-sizing:border-box; padding:0px 0px 0.4em"><em style="box-sizing: border-box;">/your subject line here/</em>”.</div></div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;">Среда, 20 октября 2021, 11:37 +03:00 от Lord via Tarantool-patches <<a href="/compose?To=tarantool%2dpatches@dev.tarantool.org">tarantool-patches@dev.tarantool.org</a>>:<br> <div id=""><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div id="style_16347190431874040412_BODY_mr_css_attr">From: Gleb <<a>kashkin.nsaa@gmail.com</a>><br><br>Replaced positioning logic in POSITION() and REPLACE() sql functions</div></div></div></div></blockquote><div>Typo: s/sql/SQL</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>with Knuth-Morris-Pratt algorithm by adding two different versions<br>of latter for STRING and VARBINARY arguments and corresponding<br>prefix table generators.<br>Slightly adapted tests to fit new collation rules that differ<br>decorated letters.<br><br>Improved asymptotics of positioning logic to:<br>time O(haystack_len + needle_len), mem O(needle_len)<br>As one of collating types is a unicode string,</div></div></div></div></blockquote><div>Typo: s/unicode/Unicode</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>ICU UCharIterators had to be used and thus unicode</div></div></div></div></blockquote><div>Typo: s/unicode/Unicode</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>letters are compared as UChar32 values and normalization<br>is not done ('a' and 'ä' are treated as different)<br><br>Closes #6492<br>---</div></div></div></div></blockquote><div>Here is your notes section, where you can provide any additional</div><div>information such as the link to the issue, the link to the</div><div>GitHub branch, or any other additional comments. It would be</div><div>much more convinient if you could provide that information here.</div><div>Check this[2] as an example.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div> src/box/sql/func.c | 402 ++++++++++++++++++++++++++-------<br> test/sql-tap/position.test.lua | 9 +-<br> 2 files changed, 321 insertions(+), 90 deletions(-)<br><br>diff --git a/src/box/sql/func.c b/src/box/sql/func.c<br>index 29d713fd0..fe3c16828 100644<br>--- a/src/box/sql/func.c<br>+++ b/src/box/sql/func.c<br>@@ -291,6 +291,147 @@ absFunc(sql_context * context, int argc, sql_value ** argv)<br>  }<br> }<br> <br>+/**<br>+ * Implementation of prefix table generator<br>+ * prefix_table_gen() is a part of Knuth-Morris-Pratt algorithm<br>+ * that is used in position() and replaceFunc() to find<br>+ * instances of `needle` in `haystack` bin data<br>+ */<br>+inline static void<br>+prefix_table_gen_bin(const unsigned char * needle,<br>+ const size_t n_needle_bytes,<br>+ size_t * table)</div></div></div></div></blockquote><div>When declaring pointer data or a function that returns a pointer</div><div>type, the preferred use of * is adjacent to the data name or function name.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+{</div></div></div></div></blockquote><div>The indentation step should be four whitespaces, so please fix the</div><div>indentation here and below.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ size_t i = 1, j = 0;<br>+ table[0] = 0;<br>+ while (i < n_needle_bytes) {<br>+ if (needle[i] != needle[j]) {<br>+ if (j == 0) {<br>+ table[i] = 0;<br>+ ++i;<br>+ } else<br>+ j = table[j - 1];<br>+ }<br>+ else {<br>+ table[i] = j + 1;<br>+ ++i;<br>+ ++j;<br>+ }<br>+ }<br>+}</div></div></div></div></blockquote><div>Use braces in both branches if only one branch of a conditional</div><div>statement is a single statement. Also, the braces code style</div><div>should be the following[3].</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+<br>+/**<br>+ * Implementation of prefix table generator using UCharIterators<br>+ * prefix_table_gen() is a part of Knuth-Morris-Pratt algorithm<br>+ * that is used in position() to find instances of `needle`<br>+ * in `haystack` unicode string<br>+ */<br>+inline static void<br>+prefix_table_gen_ustr(const UCharIterator * needle_begin,<br>+ const unsigned char * needle_str,</div></div></div></div></blockquote><div>See the comment about the pointer declaration above.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ size_t n_needle_bytes,<br>+ size_t n_needle_chars,<br>+ size_t table[])<br>+{<br>+ table[0] = 0;<br>+ UCharIterator needle_iter;<br>+ UCharIterator second_iter;<br>+ uiter_setUTF8(&needle_iter, needle_str, n_needle_bytes);<br>+ uiter_setUTF8(&second_iter, needle_str, n_needle_bytes);<br>+ needle_iter.next(&needle_iter);<br>+ while (needle_iter.getIndex(&needle_iter, UITER_CURRENT) < n_needle_chars) {</div></div></div></div></blockquote><div>Please, follow the indentation rules here and below. A loop’s body should be indented.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ if (needle_iter.current(&needle_iter) != second_iter.current(&second_iter)) {<br>+ if (second_iter.getIndex(&second_iter, UITER_CURRENT) == 0) {<br>+ table[needle_iter.getIndex(&needle_iter, UITER_CURRENT)] = 0;<br>+ needle_iter.next(&needle_iter);<br>+ } else<br>+ second_iter.move(&second_iter, table[second_iter.getIndex(&second_iter, UITER_CURRENT) - 1], UITER_START);<br>+ }</div></div></div></div></blockquote><div>See the comment about braces above.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ else {<br>+ table[needle_iter.getIndex(&needle_iter, UITER_CURRENT)] = second_iter.getIndex(&second_iter, UITER_CURRENT) + 1;<br>+ needle_iter.next(&needle_iter);<br>+ second_iter.next(&second_iter);<br>+ }<br>+ }<br>+}<br>+<br>+/**<br>+ * Implementation of KMP algorithm to find substring<br>+ * in a bin array starting from given position.<br>+ *<br>+ * Requieres index for starting position in `haystack`.<br>+ *</div></div></div></div></blockquote><div>Type: s/Requieres/Requires</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ * Returns found substring position + 1 or 0 if none.</div></div></div></div></blockquote><div>Minor: I guess, it should be ‘Returns found substring position + 1 or 0</div><div>if there is no such substring.’</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ */<br>+static int<br>+kmp_bin(const unsigned char * haystack_str,<br>+ const unsigned char * needle_str,<br>+ size_t n_haystack_bytes,<br>+ size_t n_needle_bytes,</div></div></div></div></blockquote><div>As I see no changes to these args in the function body, I think they</div><div>should be declared as a constant.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ size_t i,<br>+ const size_t * prefix_table)</div></div></div></div></blockquote><div>See the comment about the pointer declaration above.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+{<br>+ size_t j = 0;<br>+ int position = 0;<br>+ while (i < n_haystack_bytes) {<br>+ if (needle_str[j] == haystack_str[i]) {<br>+ ++i;<br>+ ++j;<br>+ }<br>+ else {<br>+ if (j == 0) {<br>+ ++i;<br>+ } else {<br>+ j = prefix_table[j - 1];<br>+ }<br>+ }<br>+ if (j >= n_needle_bytes) {<br>+ position = i - j + 1;<br>+ return position;<br>+ }<br>+ }<br>+ return position;<br>+}</div></div></div></div></blockquote><div>See the comment about the indentation above. </div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+<br>+/**<br>+ * Implementation of KMP algorithm to find substring<br>+ * in an array of unicode chars starting from given iterator.<br>+ *<br>+ * Requieres UCharIterator [haystack_iter] of starting position<br>+ * in `haystack`, iterator gets set to the first item after found<br>+ * `needle` or reaches the end of haystack if none.<br>+ *<br>+ * Returns found substring position + 1 or 0 if none.<br>+ */<br>+inline static int<br>+kmp_ustr(struct sql_context * context,<br>+ UCharIterator * haystack_iter,<br>+ UCharIterator * needle_iter,<br>+ size_t n_haystack_chars,</div></div></div></div></blockquote><div>I think that arg should be declared as a const.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ const size_t * prefix_table)</div></div></div></div></blockquote><div>See the comment about the pointer declaration above.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+{<br>+ struct coll *coll = sqlGetFuncCollSeq(context);<br>+ int position = 0;<br>+ while (haystack_iter->getIndex(haystack_iter, UITER_CURRENT) < n_haystack_chars) {<br>+ if (needle_iter->current(needle_iter) == haystack_iter->current(haystack_iter)) {<br>+ needle_iter->next(needle_iter);<br>+ haystack_iter->next(haystack_iter);<br>+ } else {<br>+ if (needle_iter->getIndex(needle_iter, UITER_CURRENT) == 0) {<br>+ haystack_iter->next(haystack_iter);<br>+ } else {<br>+ needle_iter->move(needle_iter, prefix_table[needle_iter->getIndex(needle_iter, UITER_CURRENT) - 1], UITER_START);<br>+ }<br>+ }<br>+ if (!needle_iter->hasNext(needle_iter)) {<br>+ position = haystack_iter->getIndex(haystack_iter, UITER_CURRENT) - needle_iter->getIndex(needle_iter, UITER_CURRENT) + 1;<br>+ haystack_iter->next(haystack_iter);<br>+ return position;<br>+ }<br>+ }<br>+ return position;<br>+}<br>+</div></div></div></div></blockquote><div>See the comment about the indentation above.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div> /**<br>  * Implementation of the position() function.<br>  *<br>@@ -303,7 +444,7 @@ absFunc(sql_context * context, int argc, sql_value ** argv)<br>  * occurrence of needle, or 0 if needle never occurs in haystack.<br>  */<br> static void<br>-position_func(struct sql_context *context, int argc, struct Mem **argv)<br>+position_func(struct sql_context * context, int argc, struct Mem ** argv)<br> {<br>  UNUSED_PARAMETER(argc);<br>  struct Mem *needle = argv[0];<br>@@ -339,9 +480,10 @@ position_func(struct sql_context *context, int argc, struct Mem **argv)<br>  return;<br>  }<br> <br>- int n_needle_bytes = mem_len_unsafe(needle);<br>- int n_haystack_bytes = mem_len_unsafe(haystack);<br>+ size_t n_needle_bytes = mem_len_unsafe(needle);<br>+ size_t n_haystack_bytes = mem_len_unsafe(haystack);<br>  int position = 1;<br>+ size_t *prefix_table = NULL;<br>  if (n_needle_bytes > 0) {<br>  const unsigned char *haystack_str;<br>  const unsigned char *needle_str;<br>@@ -351,18 +493,25 @@ position_func(struct sql_context *context, int argc, struct Mem **argv)<br>  assert(needle_str != NULL);<br>  assert(haystack_str != NULL || n_haystack_bytes == 0);<br>  /*<br>- * Naive implementation of substring<br>- * searching: matching time O(n * m).<br>+ * Basic version of KMP alg</div></div></div></div></blockquote><div>Typo: s/of KMP/of the KMP</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ * searching: matching time O(n + m), requires mem O(m).<br>  * Can be improved.</div></div></div></div></blockquote><div>That comment about improvement can be</div><div>removed because it relates to the original naive</div><div>implementation.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>  */<br>- while (n_needle_bytes <= n_haystack_bytes &&<br>- memcmp(haystack_str, needle_str, n_needle_bytes) != 0) {<br>- position++;<br>- n_haystack_bytes--;<br>- haystack_str++;<br>+ prefix_table = calloc(n_needle_bytes, sizeof(size_t));<br>+<br>+ if (prefix_table != NULL) {<br>+ prefix_table_gen_bin(needle_str, n_needle_bytes, prefix_table);<br>+ position = kmp_bin(haystack_str, needle_str, n_haystack_bytes, n_needle_bytes, 0, prefix_table);<br>+ } else {<br>+ while (n_needle_bytes <= n_haystack_bytes &&<br>+ memcmp(haystack_str, needle_str, n_needle_bytes) != 0) {<br>+ position++;<br>+ n_haystack_bytes--;<br>+ haystack_str++;<br>+ }<br>+ if (n_needle_bytes > n_haystack_bytes)<br>+ position = 0;<br>  }</div></div></div></div></blockquote><div>See the comment about the indentation above.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ /*<br>+ * KMP algorithm with unicode support</div></div></div></div></blockquote><div>Type s/unicode/Unicode.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div> /*<br>- * The replace() function. Three arguments are all strings: call<br>+ * The replace() function. Three arguments are all strings: call</div></div></div></div></blockquote><div>This change is excess.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>@@ -1309,7 +1487,7 @@ replaceFunc(sql_context * context, int argc, sql_value ** argv)<br>  zPattern = mem_as_ustr(argv[1]);<br>  if (zPattern == 0) {<br>  assert(mem_is_null(argv[1])<br>- || sql_context_db_handle(context)->mallocFailed);<br>+ || sql_context_db_handle(context)->mallocFailed);</div></div></div></div></blockquote><div>This change is excess.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>  return;<br>  }<br>  nPattern = mem_len_unsafe(argv[1]);<br>@@ -1331,40 +1509,90 @@ replaceFunc(sql_context * context, int argc, sql_value ** argv)<br>  return;<br>  }<br>  loopLimit = nStr - nPattern;<br>- for (i = j = 0; i <= loopLimit; i++) {<br>- if (zStr[i] != zPattern[0]<br>- || memcmp(&zStr[i], zPattern, nPattern)) {<br>- zOut[j++] = zStr[i];<br>- } else {<br>- u8 *zOld;<br>- sql *db = sql_context_db_handle(context);<br>- nOut += nRep - nPattern;<br>- testcase(nOut - 1 == db->aLimit[SQL_LIMIT_LENGTH]);<br>- testcase(nOut - 2 == db->aLimit[SQL_LIMIT_LENGTH]);<br>- if (nOut - 1 > db->aLimit[SQL_LIMIT_LENGTH]) {<br>- diag_set(ClientError, ER_SQL_EXECUTE, "string "\<br>- "or binary string is too big");<br>- context->is_aborted = true;<br>- sql_free(zOut);<br>- return;<br>- }<br>- zOld = zOut;<br>- zOut = sql_realloc64(zOut, (int)nOut);<br>- if (zOut == 0) {<br>- context->is_aborted = true;<br>- sql_free(zOld);<br>- return;<br>+<br>+ if (prefix_table != NULL) {<br>+ /**<br>+ * optimized replacement logic using KMP algorithm<br>+ * requires additional O(nPattern) memory for prefix table<br>+ * replacing: time O(n + m)<br>+ */</div></div></div></div></blockquote><div>In C comments out of functions and inside of functions should</div><div>be different in how they are started. Everything else is wrong.</div><div>Below are correct examples:</div><div>  /** comes for documentation comments</div><div>  /* for local not documented comments.</div><div> </div><div>However the difference is vague already, so the rule is simple —</div><div>out of function = /**, inside = /*. </div><div> </div><div>This is described in more detail here[4].</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+<br>+ /* precalculating prefix table */<br>+ prefix_table = calloc(nPattern, sizeof(size_t));<br>+ prefix_table_gen_bin(zPattern, nPattern, prefix_table);<br>+ /* counting the number of Pattern occurrences */<br>+ for (nCnt = iStr = nPatternPos = 0;;) {<br>+ nPatternPos = kmp_bin(zStr, zPattern, nStr, nPattern, iStr, prefix_table);<br>+ iStr = nPatternPos + nPattern;<br>+ if (nPatternPos == 0)<br>+ break;<br>+ ++nCnt;<br>+ }<br>+ /* reallocationg mem for zOut */<br>+ nOut += (nRep - nPattern) * nCnt;<br>+ assert(nOut < SQL_MAX_LENGTH);<br>+ zOut = contextMalloc(context, (i64) nOut);<br>+ if (zOut == 0) {<br>+ return;<br>+ }</div></div></div></div></blockquote><div>Brackets are excess.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>+ /* coping and replacing in-place */<br>+ for (iStr = nCopiedStr = nCopiedOut = nPatternPos = 0;;) {<br>+ nPatternPos = kmp_bin(zStr, zPattern, nStr, nPattern, iStr, prefix_table);<br>+ iStr = nPatternPos + nPattern;<br>+ if (nPatternPos == 0)<br>+ break;<br>+ assert(nPatternPos >= nCopiedStr);<br>+ memcpy(zOut + nCopiedOut, zStr + nCopiedStr, nPatternPos - nCopiedStr);<br>+ nCopiedOut += nPatternPos - nCopiedStr;<br>+ memcpy(zOut + nCopiedOut, zRep, nRep);<br>+ nCopiedOut += nRep;<br>+ nCopiedStr = nPatternPos + nPattern;<br>+ }<br>+ memcpy(zOut + nCopiedOut, zStr + nCopiedStr, nStr - nCopiedStr);<br>+ zOut[nOut - 1] = 0;<br>+ free(prefix_table);<br>+ }<br>+ else {<br>+ /**<br>+ * Naive replacing substring algorithm<br>+ * replacing: time O(n * m), mem O(1)<br>+ * used if cannot allocate mem for prefix table<br>+ */</div></div></div></div></blockquote><div>See the comment about in-function comments above.</div><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px;"><div><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div><div>diff --git a/test/sql-tap/position.test.lua b/test/sql-tap/position.test.lua<br>index 6a96ed9bc..b9244baf6 100755<br>--- a/test/sql-tap/position.test.lua<br>+++ b/test/sql-tap/position.test.lua<br>@@ -679,12 +679,15 @@ test:do_execsql_test(<br> <br> -- Collation is set in space format.<br> <br>+-- Tests 63-65 are altered because new version of position() that uses KMP alg<br>+-- intentionally does not normalize given strings (in which case 'a' differs from 'à' etc.)<br>+<br> test:do_execsql_test(<br>     "position-1.63",<br>     [[<br>         CREATE TABLE test1 (s1 VARCHAR(5) PRIMARY KEY COLLATE "unicode_ci");<br>         INSERT INTO test1 VALUES('à');<br>- SELECT POSITION('a', s1) FROM test1;<br>+ SELECT POSITION('à', s1) FROM test1;<br>         DELETE FROM test1;<br>     ]], {<br>         1<br>@@ -695,7 +698,7 @@ test:do_execsql_test(<br>     "position-1.64",<br>     [[<br>         INSERT INTO test1 VALUES('qwèrty');<br>- SELECT POSITION('er', s1) FROM test1;<br>+ SELECT POSITION('èr', s1) FROM test1;<br>         DELETE FROM test1;<br>     ]], {<br>         3<br>@@ -706,7 +709,7 @@ test:do_execsql_test(<br>     "position-1.65",<br>     [[<br>         INSERT INTO test1 VALUES('qwèrtÿ');<br>- SELECT POSITION('y', s1) FROM test1;<br>+ SELECT POSITION('ÿ', s1) FROM test1;<br>         DELETE FROM test1;<br>     ]], {<br>         6<br>--<br>2.33.0</div></div></div></div></blockquote><div>I propose to introduce a separate patch for tests modification.</div><div>Changes in tests have nothing to do with the KMP algorithm</div><div>implementation itself. </div><div> </div><div>You can read a guide on how to send a patch set here[5].</div><div> </div><div>[1]: <a href="https://www.tarantool.io/en/doc/latest/dev_guide/developer_guidelines/" target="_blank">https://www.tarantool.io/en/doc/latest/dev_guide/developer_guidelines/</a></div><div>[2]: <a href="https://lists.tarantool.org/tarantool-patches/20210731133648.25660-1-m.kokryashkin@tarantool.org/" target="_blank">https://lists.tarantool.org/tarantool-patches/20210731133648.25660-1-m.kokryashkin@tarantool.org/</a></div><div>[3]: <a href="https://www.tarantool.io/en/doc/latest/dev_guide/c_style_guide/#chapter-3-placing-braces-and-spaces" target="_blank">https://www.tarantool.io/en/doc/latest/dev_guide/c_style_guide/#chapter-3-placing-braces-and-spaces</a></div><div>[4]: <a href="https://www.tarantool.io/en/doc/latest/dev_guide/c_style_guide/#chapter-8-commenting" target="_blank">https://www.tarantool.io/en/doc/latest/dev_guide/c_style_guide/#chapter-8-commenting</a></div><div>[5]: <a href="https://www.tarantool.io/en/doc/latest/dev_guide/developer_guidelines/#how-to-submit-a-patch-for-review" target="_blank">https://www.tarantool.io/en/doc/latest/dev_guide/developer_guidelines/#how-to-submit-a-patch-for-review</a></div><div> </div><div>Best regards,</div><div>Maxim Kokryashkin</div></div></div></div></div></div></blockquote><div> </div></BODY></HTML>