MaxFreedomPollard opened a new pull request, #24991:
URL: https://github.com/apache/datafusion/pull/24991

   ## Which issue does this PR close?
   
   - No issue filed. I hit this reading `get_index` in `regexpinstr.rs` to work 
out how `N` and `subexpr` are meant to combine. Happy to file one if the 
changelog needs the link.
   
   ## Rationale for this change
   
   `regexp_instr` ignores `N` whenever `subexpr` is greater than zero. It 
always reports a position inside the first match, whichever occurrence you 
asked for.
   
   ```sql
   > SELECT regexp_instr('12 abc def ghi 34 abc def ghi 56', '(abc) (def) 
(ghi)', 1, 2, 'i', 2);
   8   -- the 'def' in the first match. Should be 23, the 'def' in the second.
   
   > SELECT regexp_instr('12 abc def ghi 34 abc def ghi 56', '(abc) (def) 
(ghi)', 1, 3, 'i', 1);
   4   -- there is no third match. Should be 0.
   ```
   
   The second one is the worse shape: a query that asks for an occurrence which 
does not exist gets a real position back, so nothing in the result says the 
match was missing.
   
   PostgreSQL, which this function follows, defines `regexp_instr` as returning 
"the starting or ending position of the N'th match", and `subexpr` as "an 
integer indicating which subexpression is of interest: the result identifies 
the position of the substring matching that subexpression" of that match. 
DataFusion's own doc string promises the two things independently: "N: Optional 
The N-th occurrence of pattern to find" and "subexpr: Optional Specifies which 
capture group (subexpression) to return the position for".
   
   ## What changes are included in this PR?
   
   `get_index` in `datafusion/functions/src/regex/regexpinstr.rs` picked the 
match with `Regex::captures`, which only ever returns the first match, and 
dropped `n` on that branch. It now uses `Regex::captures_iter(...).nth(n - 1)`, 
the capture-group counterpart of the `find_iter(...).nth(n - 1)` the `subexpr 
== 0` branch already used, so both branches count occurrences the same way. The 
comment claiming subexpr took precedence over N goes with it.
   
   `N = 1` is unchanged, because `captures_iter(...).nth(0)` and 
`captures(...)` are the same match. That is why no existing test or `.slt` 
expectation moves.
   
   ## What is the testing strategy for this PR?
   
   Every existing test of `subexpr`, in `regexpinstr.rs` and in 
`regexp/regexp_instr.slt` alike, used `N = 1`, which is how this survived.
   
   `test_case_sensitive_regexp_instr_scalar_subexp` gains `N = 2` for each of 
the three capture groups, `N = 3` where no such match exists, and a `start = 
18` row so `start` and `subexpr` are exercised together. The harness already 
runs every row through `Utf8`, `LargeUtf8` and `Utf8View`. 
`regexp/regexp_instr.slt` gains the two queries above.
   
   Reverting only `regexpinstr.rs` to `main` and keeping the new tests, both 
fail:
   
   ```
   $ cargo test --profile ci -p datafusion-functions --lib regexp_instr
   panicked at datafusion/functions/src/regex/regexpinstr.rs:740:21:
   assertion `left == right` failed: regexp_instr scalar test failed
     left: Some(4)
    right: Some(19)
   
   $ cargo test --profile ci -p datafusion-sqllogictest --test sqllogictests -- 
regexp/regexp_instr
   1. query result mismatch:
   [SQL] SELECT regexp_instr('12 abc def ghi 34 abc def ghi 56', '(abc) (def) 
(ghi)', 1, 2, 'i', 2);
   [Diff] (-expected|+actual)
   -   23
   +   8
   2. query result mismatch:
   [SQL] SELECT regexp_instr('12 abc def ghi 34 abc def ghi 56', '(abc) (def) 
(ghi)', 1, 3, 'i', 1);
   [Diff] (-expected|+actual)
   -   0
   +   4
   ```
   
   With the fix, on aarch64-apple-darwin, rustc 1.97.0:
   
   ```
   $ cargo test --profile ci -p datafusion-functions --lib
   test result: ok. 341 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
   
   $ cargo test --profile ci -p datafusion-sqllogictest --test sqllogictests -- 
regexp
   Progress: 5/5 files completed (100%)
   
   $ cargo fmt --all -- --check
   $ cargo clippy --profile ci -p datafusion-functions --all-targets -- -D 
warnings
   ```
   
   ## Are there any user-facing changes?
   
   Yes. `regexp_instr(str, regexp, start, N, flags, subexpr)` with `N` greater 
than 1 and `subexpr` greater than 0 now returns a position in the N'th match, 
and 0 when there is no N'th match. No API change.
   
   One thing I did not touch: `expr_fn::regexp_instr` in 
`datafusion/functions/src/regex/mod.rs` takes an `endoption` argument and 
pushes it as the fifth positional argument. PostgreSQL has that parameter, but 
this UDF does not, so its fifth argument is `flags`. Any caller passing 
`Some(endoption)` builds a seven-argument call that no signature accepts. That 
looked like a separate change to me, and possibly an API break, so I left it 
alone.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to