Skip to content

Commit 14ad7f8

Browse files
committed
Pin down REGEXP_* edge cases shared across functions
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.
1 parent beb1aa5 commit 14ad7f8

1 file changed

Lines changed: 67 additions & 0 deletions

File tree

packages/mysql-on-sqlite/tests/WP_SQLite_Driver_Tests.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,73 @@ public function testRegexpInstrLookbehindAcrossPos() {
612612
$this->assertSame( '2', $this->engine->get_query_results()[0]->r );
613613
}
614614

615+
public function testRegexpEmptyPatternRejected() {
616+
// MySQL rejects the empty pattern with ERROR 3685.
617+
$this->assertQueryError(
618+
"SELECT REGEXP_LIKE('abc', '')",
619+
'Illegal argument to a regular expression.'
620+
);
621+
$this->assertQueryError(
622+
"SELECT REGEXP_REPLACE('abc', '', 'x')",
623+
'Illegal argument to a regular expression.'
624+
);
625+
$this->assertQueryError(
626+
"SELECT REGEXP_SUBSTR('abc', '')",
627+
'Illegal argument to a regular expression.'
628+
);
629+
$this->assertQueryError(
630+
"SELECT REGEXP_INSTR('abc', '')",
631+
'Illegal argument to a regular expression.'
632+
);
633+
}
634+
635+
public function testRegexpEmptySubject() {
636+
// A pattern that matches empty string still matches against an empty subject.
637+
$this->assertQuery( "SELECT REGEXP_LIKE('', 'a*') AS r" );
638+
$this->assertSame( '1', $this->engine->get_query_results()[0]->r );
639+
$this->assertQuery( "SELECT REGEXP_SUBSTR('', 'a*') AS r" );
640+
$this->assertSame( '', $this->engine->get_query_results()[0]->r );
641+
$this->assertQuery( "SELECT REGEXP_INSTR('', 'a*') AS r" );
642+
$this->assertSame( '1', $this->engine->get_query_results()[0]->r );
643+
}
644+
645+
public function testRegexpZeroWidthAnchors() {
646+
// ^ matches at position 1 (length 0).
647+
$this->assertQuery( "SELECT REGEXP_INSTR('abc', '^') AS r" );
648+
$this->assertSame( '1', $this->engine->get_query_results()[0]->r );
649+
// $ matches one past the last character.
650+
$this->assertQuery( "SELECT REGEXP_INSTR('abc', '\$') AS r" );
651+
$this->assertSame( '4', $this->engine->get_query_results()[0]->r );
652+
// SUBSTR of a zero-width anchor is the empty string, not NULL.
653+
$this->assertQuery( "SELECT REGEXP_SUBSTR('abc', '^') AS r" );
654+
$this->assertSame( '', $this->engine->get_query_results()[0]->r );
655+
}
656+
657+
public function testRegexpAstralPlaneCharacter() {
658+
// 4-byte UTF-8 encodes as one code point; char offsets should reflect that.
659+
// "x😀y" has three characters (x at 1, 😀 at 2, y at 3).
660+
$this->assertQuery( "SELECT REGEXP_SUBSTR('x😀y', '.', 2) AS r" );
661+
$this->assertSame( '😀', $this->engine->get_query_results()[0]->r );
662+
$this->assertQuery( "SELECT REGEXP_INSTR('😀z', 'z', 1, 1, 1) AS r" );
663+
$this->assertSame( '3', $this->engine->get_query_results()[0]->r );
664+
}
665+
666+
public function testRegexpNegativePosErrors() {
667+
// REGEXP_LIKE has no pos argument. The other three reject negative pos.
668+
$this->assertQueryError(
669+
"SELECT REGEXP_REPLACE('abc', 'a', 'X', -1)",
670+
'Index out of bounds in regular expression search.'
671+
);
672+
$this->assertQueryError(
673+
"SELECT REGEXP_SUBSTR('abc', 'a', -1)",
674+
'Index out of bounds in regular expression search.'
675+
);
676+
$this->assertQueryError(
677+
"SELECT REGEXP_INSTR('abc', 'a', -1)",
678+
'Index out of bounds in regular expression search.'
679+
);
680+
}
681+
615682
public function testInsertDateNow() {
616683
$this->assertQuery(
617684
"INSERT INTO _dates (option_name, option_value) VALUES ('first', now());"

0 commit comments

Comments
 (0)