Conversation
ea33064 to
39a70af
Compare
Implement MySQL REGEXP_LIKE(expr, pattern [, match_type]) with explicit supported arities and shared helpers for UTF-8 validation, PCRE compilation, and MySQL-style error translation. Translate the c, i, m, n, and u flags with MySQL newline semantics; preserve numeric SQL operands; and validate arguments in MySQL order. Document the remaining ICU multi-code-point case-folding limitation. Cover arity and error precedence, flags and newlines, delimiter and quoted-literal escaping, invalid UTF-8, numeric operands, resource errors, and coexistence with the legacy REGEXP operator.
Implement MySQL REGEXP_REPLACE(expr, pattern, replacement [, pos [, occurrence [, match_type]]]) with character-based positions, MySQL replacement-template expansion, and exact argument-count validation. Stream matches instead of retaining the complete match list, preserve numeric capture indexes and unmatched groups, and handle empty subjects, zero-width matches, lookbehind, full-subject UTF-8 validation, and MySQL numeric coercion and 32-bit narrowing. Cover replacement grammar and errors, named and optional captures, numeric operands, NULL and validation precedence, multibyte offsets, invalid prefixes, position boundaries, and empty-subject behavior.
Implement MySQL REGEXP_SUBSTR(expr, pattern [, pos [, occurrence [, match_type]]]) by returning the requested streamed match at a character position, or NULL when no such match exists. Match MySQL argument validation and numeric coercion, validate the complete UTF-8 subject before applying a nonzero position, preserve lookbehind context, and allow a zero-width match when pos is one character past the end. Cover NULL and error precedence, occurrence clamping, numeric and multibyte inputs, invalid UTF-8 prefixes, position boundaries, anchors, zero-width matches, and lookbehind across pos.
Implement MySQL REGEXP_INSTR(expr, pattern [, pos [, occurrence [, return_option [, match_type]]]]) with 1-based character positions and start-or-end result selection. Evaluate anchors and lookbehind against the region beginning at pos, matching MySQL semantics. Validate return_option before nullable pattern and flag arguments, apply MySQL numeric coercion, and reject positions beyond the subject. Cover validation precedence, rounded and wrapped numeric controls, multibyte results, invalid UTF-8 prefixes, occurrence clamping, region-relative anchors and lookbehind, and return-option errors.
Adds a final layer of tests that exercise behaviors which involve more than one of REGEXP_LIKE / _REPLACE / _SUBSTR / _INSTR at once and only become testable once all four functions are available: - Empty pattern raises "Illegal argument to a regular expression." uniformly (MySQL ERROR 3685). - Empty subject with a zero-width-matching pattern still produces a match (LIKE = 1, SUBSTR = "", INSTR = 1). - Zero-width anchors ^ / $ report sensible 1-based positions and an empty-string match for SUBSTR rather than NULL. - Astral-plane (4-byte UTF-8) characters are counted as one code point by both SUBSTR and INSTR. - Negative pos rejects consistently across REPLACE / SUBSTR / INSTR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the four MySQL 8.0 regular-expression functions on top of SQLite by registering PHP UDFs that translate MySQL/ICU semantics onto PCRE.
regexp_compile()that maps MySQL match-type flags (c/i/m/n/u) onto PCRE modifiers with UTF-8 mode always on, plusregexp_run()/regexp_fail()that distinguish compile errors from backtrack-limit and invalid-UTF-8 failures.preg_matchwith its offset argument so lookbehind assertions retain context acrosspos. Implements MySQL/ICU replacement grammar:$Nbackreferences (with$0= full match and longest-valid-prefix wins),\Xdrops the backslash,${N}is rejected, trailing\is dropped.occurrence = 0replaces all; negatives clamp to 1.pos. Acceptspos = char_count + 1(returns NULL); clampsoccurrence <= 0to 1.return_optionstrictly 0 or 1; rejectspos > char_counteven where SUBSTR/REPLACE allow it.MySQL fidelity
Behavior was verified against MySQL 8.0.45 in Docker across ~100 SQL cases. Error texts mirror MySQL's ICU wording where practical:
Illegal argument to a regular expression.(empty pattern, ERROR 3685)A capture group has an invalid name.(invalid `$` in replacement, ERROR 3887)Index out of bounds in regular expression search.(ERROR 3686)Incorrect arguments to regexp_instr: return_option must be 1 or 0.Known limitations
Documented in `regexp_compile()`:
Test plan
Addresses #47.