fix(oracle): honour the n and m match parameters in REGEXP_LIKE - #2045
fix(oracle): honour the n and m match parameters in REGEXP_LIKE#2045btlqql wants to merge 1 commit into
Conversation
sys.regexp_like() parsed its match_parameter argument with a hand-rolled
switch (contrib/ivorysql_ora/src/builtin_functions/character_datatype_functions.c,
ora_regexp_like()) that had drifted away from ora_parse_re_flags(), the
helper the other five REGEXP_* functions in the same file already use:
- 'm' was not handled at all, so the documented Oracle option raised
ERROR: invalid option of regexp_like: m
- 'n' set REG_NEWLINE, i.e. PostgreSQL's newline-sensitive mode, which
excludes a newline from "." and turns on the multiline anchors. That
is the opposite of Oracle's 'n', which *allows* "." to match a
newline, and it also silently enabled an option that only 'm' may turn
on.
- with no match_parameter at all "." matched a newline, although Oracle
only permits that with 'n' (ora_regexp_like_no_flags() had the same
problem, so the two-argument form was wrong as well).
The same switch is also the reason REGEXP_LIKE behaved unlike REGEXP_COUNT,
REGEXP_INSTR, REGEXP_SUBSTR and REGEXP_REPLACE, whose 'n'/'m' matrix is
already pinned by ora_character_datatype_functions.
Fix: parse the flags the way ora_parse_re_flags() does. 'n' now clears
REG_NLDOT, 'm' now sets REG_NLANCH, and both entry points start from
REG_ADVANCED | REG_NLDOT (Oracle's default: "." does not match a newline).
The unknown-option error message is unchanged.
Trigger (before the fix, sys.regexp_like is the C function behind the
package's REGEXP_LIKE and is reachable both qualified and, in Oracle mode,
unqualified):
select sys.regexp_like('X' || chr(10), 'X.', 'm') from dual;
ERROR: invalid option of regexp_like: m
select sys.regexp_like('X' || chr(10), 'X.'); -- Oracle: false
select sys.regexp_like('X' || chr(10), 'X.', 'n'); -- Oracle: true
Regression test: extend the existing n/m matrix in
contrib/ivorysql_ora/sql/ora_character_datatype_functions.sql (and the
matching expected file) with the REGEXP_LIKE rows. The expected values
(0|0|1|0 and 0|0|0|1) are the same ones the neighbouring REGEXP_COUNT and
REGEXP_SUBSTR cases produce for the identical expressions.
Signed-off-by: btlqql <2977859784@qq.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
Included review availability: Your plan provides up to 4 included reviews per hour; 1 remains after this review. 📝 WalkthroughWalkthrough
ChangesREGEXP_LIKE flag behavior
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix · Severity of issue fixed: Medium Suggested reviewers: Merge Risk: ⚪ Minimal · up to The updated REGEXP_LIKE behavior is covered for newline and multiline-anchor handling, with no actionable merge risk identified. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Defect
REGEXP_LIKEis implemented bysys.regexp_like(...)->ora_regexp_like()incontrib/ivorysql_ora/src/builtin_functions/character_datatype_functions.c. It parses thematch_parameterargument with its ownswitch, while the other fiveREGEXP_*functions in thesame file go through
ora_parse_re_flags()(src/backend/utils/adt/regexp.c). The two have driftedapart, so the Oracle option letters do not mean what Oracle documents:
(
ora_regexp_like()lines 791-816 before the patch;ora_regexp_like_no_flags()had the sameout_flag = REG_ADVANCED;two lines below.)Three consequences:
'm'falls intodefault:-> the documented Oracle option raises an error.'n'sets PostgreSQL'sREG_NEWLINE(REG_NLSTOP | REG_NLANCH), which excludes a newlinefrom
"."and turns on the multiline anchors. Oracle's'n'is the opposite: it allows"."to match a newline, and only
'm'may turn on the anchors.match_parameter,"."matches a newline; Oracle only permits that with'n'.ora_regexp_like_no_flags()(the two-argument registration) is wrong for the same reason.How I triggered it
sys.regexp_likeis the C function behind the package'sREGEXP_LIKE; in Oracle-compatible mode theunqualified name reaches it too (that is what the neighbouring
REGEXP_COUNT/REGEXP_SUBSTRcasesin the same regression file rely on), and the qualified form is unambiguous either way:
The expected values are not invented: the same file already pins the identical n/m matrix for
REGEXP_COUNT,REGEXP_INSTR,REGEXP_SUBSTRandREGEXP_REPLACEat0|0|1|0(dot vs. newline)and
0|0|0|1(multiline anchors), and the test below reproduces exactly those two rows forREGEXP_LIKE.Fix
Parse the flags the way the rest of the family does (
character_datatype_functions.c, 2 hunks, 19lines): both entry points start from
REG_ADVANCED | REG_NLDOT(Oracle's default:"."does notmatch a newline),
'n'clearsREG_NLDOTand'm'setsREG_NLANCH. The unknown-option errormessage is unchanged, so the existing
ERROR: invalid option of regexp_like: pexpectation staysvalid.
Regression test
contrib/ivorysql_ora/sql/ora_character_datatype_functions.sql+ the matchingexpectedfile: twostatements appended to the existing match-parameter matrix, using the same
chr(10)idiom and thesame column aliases as the neighbouring cases (so the expected table widths are identical to rows
that are already in the file).
What I could not verify
There is no C toolchain,
make,bison/flex,perlor container in my environment, so I couldnot build IvorySQL or run
oracle_regression/contrib_regressionlocally. The patch and theexpected output are unverified by execution - CI must run
contrib/ivorysql_ora'sora_regression(theora_character_datatype_functionstest) to confirm. Everything else waschecked statically against this tree:
REG_NLDOT/REG_NLANCHcome fromsrc/include/regex/regex.h(already included by the file, and
REG_NLANCHis already used inora_regexp_count),ora_parse_re_flags()insrc/backend/utils/adt/regexp.cis the intended semantics(
'n'-> clearREG_NLDOT,'m'-> setREG_NLANCH), and the expected numbers were taken from theverified
REGEXP_COUNTblock for the same expressions.Fixes #2044
Summary by CodeRabbit
sys.regexp_likeconsistently handles newline and multiline options.noption allows dots to match newline characters, whilemenables multiline^and$anchors.