提交 4a2eb9f4 authored 作者: Andrew Brock's avatar Andrew Brock

Move documentation, add tests, refactor change logic

Add boolean flag to makeRegexpFlags that indicates whether the presence of a global flag should simply be ignored (i.e. when in PostreSQL mode) or whether it should throw an exception.

If the database is in PostgreSQL mode and the 'g' flag is not present, use the String.replaceFirst method instead of the H2 default String.replaceAll method when doing the regex replace.
上级 91b9987c
......@@ -4296,7 +4296,7 @@ Replaces each substring that matches a regular expression.
For details, see the Java ""String.replaceAll()"" method.
If any parameter is null (except optional flagsString parameter), the result is null.
Flags values limited to 'i', 'c', 'n', 'm'. Other symbols causes exception (except for 'g' which is ignored when running in PostgreSQL mode).
Flags values limited to 'i', 'c', 'n', 'm'. Other symbols causes exception.
Multiple symbols could be uses in one flagsString parameter (like 'im').
Later flags overrides first ones, for example 'ic' equivalent to case sensitive matching 'c'.
......
......@@ -950,7 +950,12 @@ or the SQL statement <code>SET MODE PostgreSQL</code>.
</li><li>The system columns <code>CTID</code> and
<code>OID</code> are supported.
</li><li>LOG(x) is base 10 in this mode.
</li><li>REGEXP_REPLACE() uses \ for back-references.
</li><li>REGEXP_REPLACE():
<ul>
<li>Uses \ for back-references</li>
<li>Will not throw an exception when the <code>flagsString</code> parameter contains a 'g'</li>
<li>Will use Java's <code>String.replaceFirst()</code> method (instead of <code>String.replaceAll()</code>) if the 'g' flag is not present in the <code>flagsString</code> parameter.</li>
</ul>
</li><li>Fixed-width strings are padded with spaces.
</li><li>MONEY data type is treated like NUMERIC(19, 2) data type.
</li><li>Datetime value functions return the same value within a transaction.
......
......@@ -1370,16 +1370,19 @@ public class Function extends Expression implements FunctionCall {
}
String regexpMode = v3 == null || v3.getString() == null ? "" :
v3.getString();
if(database.getMode().getEnum().equals(Mode.ModeEnum.PostgreSQL)) {
// PostgreSQL doesn't do global replaces without a 'g' flag, but H2 does
regexpMode = regexpMode.replaceAll("g", "");
}
int flags = makeRegexpFlags(regexpMode);
int flags = makeRegexpFlags(regexpMode, Mode.ModeEnum.PostgreSQL.equals(database.getMode().getEnum()));
try {
if(Mode.ModeEnum.PostgreSQL.equals(database.getMode().getEnum()) && !regexpMode.contains("g")) {
result = ValueString.get(
Pattern.compile(regexp, flags).matcher(v0.getString())
.replaceFirst(replacement),
database.getMode().treatEmptyStringsAsNull);
} else {
result = ValueString.get(
Pattern.compile(regexp, flags).matcher(v0.getString())
.replaceAll(replacement),
database.getMode().treatEmptyStringsAsNull);
}
} catch (StringIndexOutOfBoundsException e) {
throw DbException.get(
ErrorCode.LIKE_ESCAPE_ERROR_1, e, replacement);
......@@ -1654,7 +1657,7 @@ public class Function extends Expression implements FunctionCall {
String regexp = v1.getString();
String regexpMode = v2 == null || v2.getString() == null ? "" :
v2.getString();
int flags = makeRegexpFlags(regexpMode);
int flags = makeRegexpFlags(regexpMode, false);
try {
result = ValueBoolean.get(Pattern.compile(regexp, flags)
.matcher(v0.getString()).find());
......@@ -2036,7 +2039,7 @@ public class Function extends Expression implements FunctionCall {
return md;
}
private static int makeRegexpFlags(String stringFlags) {
private static int makeRegexpFlags(String stringFlags, boolean ignoreGlobalFlag) {
int flags = Pattern.UNICODE_CASE;
if (stringFlags != null) {
for (int i = 0; i < stringFlags.length(); ++i) {
......@@ -2053,6 +2056,10 @@ public class Function extends Expression implements FunctionCall {
case 'm':
flags |= Pattern.MULTILINE;
break;
case 'g':
if (ignoreGlobalFlag) {
break;
}
default:
throw DbException.get(ErrorCode.INVALID_VALUE_2, stringFlags);
}
......
......@@ -35,3 +35,21 @@ select regexp_replace('first last', '(\w+) (\w+)', '\2 \1');
select regexp_replace('first last', '(\w+) (\w+)', '$2 $1');
>> last first
select regexp_replace('AbcDef', '[^a-z]', '', 'g');
> exception INVALID_VALUE_2
select regexp_replace('First and Second', '[A-Z]', '');
>> irst and econd
set mode PostgreSQL;
> ok
select regexp_replace('AbcDef', '[^a-z]', '', 'g');
>> bcef
select regexp_replace('AbcDef123', '[a-z]', '!', 'gi');
>> !!!!!!123
select regexp_replace('First Only', '[A-Z]', '');
>> irst Only
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论