This is an automated email from the ASF dual-hosted git repository.

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 4208d0ba6f2a749692fe64181a1373af07d55db5
Author: Julian Hyde <jh...@apache.org>
AuthorDate: Wed Feb 26 12:26:07 2020 -0800

    [CALCITE-3823] Do not use String.replaceAll
    
    String.replaceAll uses regex, which is inefficient, and may not be
    what we want. For strings, use either String.replace; for regex use
    Pattern.compile().matcher().replaceAll(), being sure to store the
    pattern for future use.
    
    Add entries to forbidden-apis/signatures.txt to prevent people
    using String.replaceAll in future.
---
 .../org/apache/calcite/runtime/SqlFunctions.java   | 14 +++++++----
 .../java/org/apache/calcite/sql/SqlDialect.java    | 15 ++---------
 .../calcite/sql/dialect/BigQuerySqlDialect.java    |  4 ---
 .../apache/calcite/sql/parser/SqlParserUtil.java   | 12 ++++-----
 .../apache/calcite/sql/pretty/SqlPrettyWriter.java |  8 +++---
 .../calcite/sql/validate/SqlValidatorImpl.java     |  2 +-
 .../java/org/apache/calcite/util/BitString.java    |  2 +-
 .../main/java/org/apache/calcite/util/Util.java    |  2 +-
 .../org/apache/calcite/profile/ProfilerTest.java   |  5 ++--
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java |  2 +-
 .../apache/calcite/sql/parser/SqlParserTest.java   |  2 +-
 .../calcite/sql/test/SqlPrettyWriterTest.java      |  2 +-
 .../org/apache/calcite/test/CalciteAssert.java     |  9 +++----
 .../java/org/apache/calcite/test/DiffTestCase.java | 10 +++++---
 .../java/org/apache/calcite/test/JdbcTest.java     |  4 +--
 .../java/org/apache/calcite/test/Matchers.java     |  6 ++++-
 .../apache/calcite/test/MaterializationTest.java   |  2 +-
 .../java/org/apache/calcite/test/QuidemTest.java   | 10 +++++---
 .../org/apache/calcite/test/SqlFunctionsTest.java  | 29 ++++++++++++++++++++++
 .../java/org/apache/calcite/util/TestUtil.java     | 26 +++++++++----------
 .../elasticsearch/ElasticsearchProject.java        |  2 +-
 .../elasticsearch/ElasticSearchAdapterTest.java    |  2 +-
 .../calcite/adapter/elasticsearch/MatchTest.java   |  2 +-
 .../apache/calcite/adapter/mongodb/MongoTable.java |  8 ------
 .../org/apache/calcite/test/MongoAssertions.java   |  8 ++++--
 .../org/apache/calcite/adapter/os/SqlShell.java    |  6 ++---
 .../apache/calcite/adapter/tpcds/TpcdsTest.java    |  2 +-
 .../org/apache/calcite/adapter/tpch/TpchTest.java  |  2 +-
 .../materialize/TpcdsLatticeSuggesterTest.java     | 17 +++++++------
 .../calcite/adapter/splunk/SplunkPushDownRule.java |  2 +-
 src/main/config/forbidden-apis/signatures.txt      |  7 ++++++
 31 files changed, 129 insertions(+), 95 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java 
b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index 3f390a5..be5e8c3 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -141,6 +141,8 @@ public class SqlFunctions {
   private static final ThreadLocal<Map<String, AtomicLong>> THREAD_SEQUENCES =
       ThreadLocal.withInitial(HashMap::new);
 
+  private static final Pattern PATTERN_0_STAR_E = Pattern.compile("0*E");
+
   private SqlFunctions() {
   }
 
@@ -599,7 +601,7 @@ public class SqlFunctions {
     String[] existingExpressions = Arrays.stream(POSIX_CHARACTER_CLASSES)
         .filter(v -> 
originalRegex.contains(v.toLowerCase(Locale.ROOT))).toArray(String[]::new);
     for (String v : existingExpressions) {
-      regex = regex.replaceAll(v.toLowerCase(Locale.ROOT), "\\\\p{" + v + "}");
+      regex = regex.replace(v.toLowerCase(Locale.ROOT), "\\p{" + v + "}");
     }
 
     int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE;
@@ -1683,7 +1685,7 @@ public class SqlFunctions {
     BigDecimal bigDecimal =
         new BigDecimal(x, MathContext.DECIMAL32).stripTrailingZeros();
     final String s = bigDecimal.toString();
-    return s.replaceAll("0*E", "E").replace("E+", "E");
+    return PATTERN_0_STAR_E.matcher(s).replaceAll("E").replace("E+", "E");
   }
 
   /** CAST(DOUBLE AS VARCHAR). */
@@ -1694,16 +1696,18 @@ public class SqlFunctions {
     BigDecimal bigDecimal =
         new BigDecimal(x, MathContext.DECIMAL64).stripTrailingZeros();
     final String s = bigDecimal.toString();
-    return s.replaceAll("0*E", "E").replace("E+", "E");
+    return PATTERN_0_STAR_E.matcher(s).replaceAll("E").replace("E+", "E");
   }
 
   /** CAST(DECIMAL AS VARCHAR). */
   public static String toString(BigDecimal x) {
     final String s = x.toString();
-    if (s.startsWith("0")) {
+    if (s.equals("0")) {
+      return s;
+    } else if (s.startsWith("0.")) {
       // we want ".1" not "0.1"
       return s.substring(1);
-    } else if (s.startsWith("-0")) {
+    } else if (s.startsWith("-0.")) {
       // we want "-.1" not "-0.1"
       return "-" + s.substring(2);
     } else {
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java 
b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
index 2eef2dc..07f82c6 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java
@@ -346,14 +346,7 @@ public class SqlDialect {
    * @return Quoted identifier
    */
   public String quoteIdentifier(String val) {
-    if (identifierQuoteString == null) {
-      return val; // quoting is not supported
-    }
-    String val2 =
-        val.replaceAll(
-            identifierEndQuoteString,
-            identifierEscapedQuote);
-    return identifierQuoteString + val2 + identifierEndQuoteString;
+    return quoteIdentifier(new StringBuilder(), val).toString();
   }
 
   /**
@@ -375,12 +368,8 @@ public class SqlDialect {
         || !identifierNeedsQuote(val)) {
       buf.append(val);
     } else {
-      String val2 =
-          val.replaceAll(
-              identifierEndQuoteString,
-              identifierEscapedQuote);
       buf.append(identifierQuoteString);
-      buf.append(val2);
+      buf.append(val.replace(identifierEndQuoteString, 
identifierEscapedQuote));
       buf.append(identifierEndQuoteString);
     }
     return buf;
diff --git 
a/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java 
b/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java
index eaa6ebf..7451215 100644
--- a/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java
@@ -94,10 +94,6 @@ public class BigQuerySqlDialect extends SqlDialect {
     super(context);
   }
 
-  @Override public String quoteIdentifier(String val) {
-    return quoteIdentifier(new StringBuilder(), val).toString();
-  }
-
   @Override protected boolean identifierNeedsQuote(String val) {
     return !IDENTIFIER_REGEX.matcher(val).matches()
         || RESERVED_KEYWORDS.contains(val.toUpperCase(Locale.ROOT));
diff --git 
a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java 
b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java
index dc48389..4f309d7 100644
--- a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java
@@ -315,12 +315,12 @@ public final class SqlParserUtil {
    */
   @Deprecated // to be removed before 2.0
   public static byte[] parseBinaryString(String s) {
-    s = s.replaceAll(" ", "");
-    s = s.replaceAll("\n", "");
-    s = s.replaceAll("\t", "");
-    s = s.replaceAll("\r", "");
-    s = s.replaceAll("\f", "");
-    s = s.replaceAll("'", "");
+    s = s.replace(" ", "");
+    s = s.replace("\n", "");
+    s = s.replace("\t", "");
+    s = s.replace("\r", "");
+    s = s.replace("\f", "");
+    s = s.replace("'", "");
 
     if (s.length() == 0) {
       return new byte[0];
diff --git 
a/core/src/main/java/org/apache/calcite/sql/pretty/SqlPrettyWriter.java 
b/core/src/main/java/org/apache/calcite/sql/pretty/SqlPrettyWriter.java
index e29d2ef..244199e 100644
--- a/core/src/main/java/org/apache/calcite/sql/pretty/SqlPrettyWriter.java
+++ b/core/src/main/java/org/apache/calcite/sql/pretty/SqlPrettyWriter.java
@@ -995,14 +995,14 @@ public class SqlPrettyWriter implements SqlWriter {
   }
 
   public void identifier(String name, boolean quoted) {
-    String qName = name;
     // If configured globally or the original identifier is quoted,
     // then quotes the identifier.
+    maybeWhitespace(name);
     if (isQuoteAllIdentifiers() || quoted) {
-      qName = dialect.quoteIdentifier(name);
+      dialect.quoteIdentifier(buf, name);
+    } else {
+      buf.append(name);
     }
-    maybeWhitespace(qName);
-    buf.append(qName);
     setNeedWhitespace(true);
   }
 
diff --git 
a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java 
b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index d80e16d..358050b 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -1023,7 +1023,7 @@ public class SqlValidatorImpl implements 
SqlValidatorWithHints {
             || (op.getSyntax() == SqlSyntax.PREFIX)) {
           if (op.getOperandTypeChecker() != null) {
             String sig = op.getAllowedSignatures();
-            sig = sig.replaceAll("'", "");
+            sig = sig.replace("'", "");
             result.add(
                 new SqlMonikerImpl(
                     sig,
diff --git a/core/src/main/java/org/apache/calcite/util/BitString.java 
b/core/src/main/java/org/apache/calcite/util/BitString.java
index f523826..eb0caf7 100644
--- a/core/src/main/java/org/apache/calcite/util/BitString.java
+++ b/core/src/main/java/org/apache/calcite/util/BitString.java
@@ -49,7 +49,7 @@ public class BitString {
   protected BitString(
       String bits,
       int bitCount) {
-    assert bits.replaceAll("1", "").replaceAll("0", "").length() == 0
+    assert bits.replace("1", "").replace("0", "").length() == 0
         : "bit string '" + bits + "' contains digits other than {0, 1}";
     this.bits = bits;
     this.bitCount = bitCount;
diff --git a/core/src/main/java/org/apache/calcite/util/Util.java 
b/core/src/main/java/org/apache/calcite/util/Util.java
index db64509..8b59a88 100644
--- a/core/src/main/java/org/apache/calcite/util/Util.java
+++ b/core/src/main/java/org/apache/calcite/util/Util.java
@@ -741,7 +741,7 @@ public class Util {
   }
 
   public static String toLinux(String s) {
-    return s.replaceAll("\r\n", "\n");
+    return s.replace("\r\n", "\n");
   }
 
   /**
diff --git a/core/src/test/java/org/apache/calcite/profile/ProfilerTest.java 
b/core/src/test/java/org/apache/calcite/profile/ProfilerTest.java
index b957476..37faa577 100644
--- a/core/src/test/java/org/apache/calcite/profile/ProfilerTest.java
+++ b/core/src/test/java/org/apache/calcite/profile/ProfilerTest.java
@@ -629,8 +629,9 @@ public class ProfilerTest {
           map1.keySet().retainAll(Fluid.this.columns);
         }
         final String json = jb.toJsonString(map);
-        return json.replaceAll("\n", "").replaceAll(" ", "")
-            .replaceAll("\"", "");
+        return json.replace("\n", "")
+            .replace(" ", "")
+            .replace("\"", "");
       }
     }
   }
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index de0f2b7..490bfa1 100644
--- 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -1345,7 +1345,7 @@ public class RelToSqlConverterTest {
         + " 4 AS \"fo$ur\", 5 AS \"ignore\"\n"
         + "FROM \"foodmart\".\"days\") AS \"t\"\n"
         + "WHERE \"one\" < \"tWo\" AND \"THREE\" < \"fo$ur\"";
-    final String expectedOracle = expectedPostgresql.replaceAll(" AS ", " ");
+    final String expectedOracle = expectedPostgresql.replace(" AS ", " ");
     sql(query)
         .withBigQuery().ok(expectedBigQuery)
         .withMysql().ok(expectedMysql)
diff --git 
a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java 
b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
index 546e6bb..ac67a31 100644
--- a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
@@ -7451,7 +7451,7 @@ public class SqlParserTest {
     sql(in).ok(out);
 
     // Verify that we can override with an explicit escape character
-    sql(in.replaceAll("\\\\", "!") + "UESCAPE '!'").ok(out);
+    sql(in.replace("\\", "!") + "UESCAPE '!'").ok(out);
   }
 
   @Test public void testIllegalUnicodeEscape() {
diff --git 
a/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java 
b/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java
index ebe61b2..f4aff8b 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlPrettyWriterTest.java
@@ -134,7 +134,7 @@ public class SqlPrettyWriterTest {
 
       // Now parse the result, and make sure it is structurally equivalent
       // to the original.
-      final String actual2 = formatted.replaceAll("`", "\"");
+      final String actual2 = formatted.replace("`", "\"");
       final SqlNode node2;
       if (expr) {
         final SqlCall valuesCall =
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java 
b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
index 64da551..a6cb7b1 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -457,8 +457,7 @@ public class CalciteAssert {
     return s -> {
       try {
         final String actual = Util.toLinux(toString(s));
-        final String maskedActual =
-            actual.replaceAll(", id = [0-9]+", "");
+        final String maskedActual = Matchers.trimNodeIds(actual);
         assertThat(maskedActual, containsString(expected));
       } catch (SQLException e) {
         throw TestUtil.rethrow(e);
@@ -1130,7 +1129,7 @@ public class CalciteAssert {
             map.put("view", table + "v");
           }
           String sql = materializations[i];
-          final String sql2 = sql.replaceAll("`", "\"");
+          final String sql2 = sql.replace("`", "\"");
           map.put("sql", sql2);
           list.add(map);
         }
@@ -1737,7 +1736,7 @@ public class CalciteAssert {
       } else {
         final String message =
             "Plan [" + plan + "] contains [" + expected.java + "]";
-        final String actualJava = toLinux(plan).replaceAll("\\\\r\\\\n", 
"\\\\n");
+        final String actualJava = toLinux(plan);
         assertTrue(actualJava.contains(expected.java), message);
       }
       return this;
@@ -2172,7 +2171,7 @@ public class CalciteAssert {
       return START
           + sql.replace("\\", "\\\\")
               .replace("\"", "\\\"")
-              .replaceAll("\n", "\\\\n")
+              .replace("\n", "\\\\n")
           + END;
     }
 
diff --git a/core/src/test/java/org/apache/calcite/test/DiffTestCase.java 
b/core/src/test/java/org/apache/calcite/test/DiffTestCase.java
index cb34b5d..4b4551e 100644
--- a/core/src/test/java/org/apache/calcite/test/DiffTestCase.java
+++ b/core/src/test/java/org/apache/calcite/test/DiffTestCase.java
@@ -74,8 +74,10 @@ public abstract class DiffTestCase {
    */
   // private List diffMasks;
   private String diffMasks;
+  Pattern compiledDiffPattern;
   Matcher compiledDiffMatcher;
   private String ignorePatterns;
+  Pattern compiledIgnorePattern;
   Matcher compiledIgnoreMatcher;
 
   /**
@@ -285,7 +287,7 @@ public abstract class DiffTestCase {
     } else {
       diffMasks = diffMasks + "|" + mask;
     }
-    Pattern compiledDiffPattern = Pattern.compile(diffMasks);
+    compiledDiffPattern = Pattern.compile(diffMasks);
     compiledDiffMatcher = compiledDiffPattern.matcher("");
   }
 
@@ -295,7 +297,7 @@ public abstract class DiffTestCase {
     } else {
       ignorePatterns = ignorePatterns + "|" + javaPattern;
     }
-    Pattern compiledIgnorePattern = Pattern.compile(ignorePatterns);
+    compiledIgnorePattern = Pattern.compile(ignorePatterns);
     compiledIgnoreMatcher = compiledIgnorePattern.matcher("");
   }
 
@@ -306,7 +308,7 @@ public abstract class DiffTestCase {
       // we assume most of lines do not match
       // so compiled matches will be faster than replaceAll.
       if (compiledDiffMatcher.find()) {
-        return s.replaceAll(diffMasks, "XYZZY");
+        return compiledDiffPattern.matcher(s).replaceAll("XYZZY");
       }
     }
     return s;
@@ -328,7 +330,7 @@ public abstract class DiffTestCase {
     if (verbose) {
       if (inIde()) {
         // If we're in IntelliJ, it's worth printing the 'expected
-        // <...> actual <...>' string, becauase IntelliJ can format
+        // <...> actual <...>' string, because IntelliJ can format
         // this intelligently. Otherwise, use the more concise
         // diff format.
         assertEquals(fileContents(refFile), fileContents(logFile), message);
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java 
b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index af92927..43eefdc 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -3694,7 +3694,7 @@ public class JdbcTest {
     String planLine =
         "a0s0w0 = org.apache.calcite.runtime.SqlFunctions.lesser(a0s0w0, 
org.apache.calcite.runtime.SqlFunctions.toFloat(_rows[j]));";
     if (CalciteSystemProperty.DEBUG.value()) {
-      planLine = planLine.replaceAll("a0s0w0", "MINa0s0w0");
+      planLine = planLine.replace("a0s0w0", "MINa0s0w0");
     }
     CalciteAssert.hr()
         .query("select min(\"salary\"+1) over w as m\n"
@@ -3719,7 +3719,7 @@ public class JdbcTest {
     String planLine =
         "a0s0w0 = org.apache.calcite.runtime.SqlFunctions.lesser(a0s0w0, 
org.apache.calcite.runtime.SqlFunctions.toFloat(_rows[j]));";
     if (CalciteSystemProperty.DEBUG.value()) {
-      planLine = planLine.replaceAll("a0s0w0", "MINa0s0w0");
+      planLine = planLine.replace("a0s0w0", "MINa0s0w0");
     }
     CalciteAssert.hr()
         .query("select 1+min(\"salary\"+1) over w as m\n"
diff --git a/core/src/test/java/org/apache/calcite/test/Matchers.java 
b/core/src/test/java/org/apache/calcite/test/Matchers.java
index 2acd22a..48ca5e3 100644
--- a/core/src/test/java/org/apache/calcite/test/Matchers.java
+++ b/core/src/test/java/org/apache/calcite/test/Matchers.java
@@ -43,12 +43,16 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.function.Function;
+import java.util.regex.Pattern;
 import java.util.stream.StreamSupport;
 
 /**
  * Matchers for testing SQL queries.
  */
 public class Matchers {
+
+  private static final Pattern PATTERN = Pattern.compile(", id = [0-9]+");
+
   private Matchers() {}
 
   /** Allows passing the actual result from the {@code matchesSafely} method to
@@ -248,7 +252,7 @@ public class Matchers {
   }
 
   public static String trimNodeIds(String s) {
-    return s.replaceAll(", id = [0-9]+", "");
+    return PATTERN.matcher(s).replaceAll("");
   }
 
   /**
diff --git 
a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java 
b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
index 5db1113..e28959c 100644
--- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
+++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
@@ -2580,7 +2580,7 @@ public class MaterializationTest {
                 map.put("table", "locations");
                 String sql = "select distinct `deptno` as `empid`, '' as 
`name`\n"
                     + "from `emps`";
-                final String sql2 = sql.replaceAll("`", "\"");
+                final String sql2 = sql.replace("`", "\"");
                 map.put("sql", sql2);
                 return ImmutableList.of(map);
               })
diff --git a/core/src/test/java/org/apache/calcite/test/QuidemTest.java 
b/core/src/test/java/org/apache/calcite/test/QuidemTest.java
index 5e502ec..800173d 100644
--- a/core/src/test/java/org/apache/calcite/test/QuidemTest.java
+++ b/core/src/test/java/org/apache/calcite/test/QuidemTest.java
@@ -55,6 +55,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.function.Function;
+import java.util.regex.Pattern;
 
 import static org.junit.jupiter.api.Assertions.fail;
 
@@ -62,6 +63,9 @@ import static org.junit.jupiter.api.Assertions.fail;
  * Test that runs every Quidem file as a test.
  */
 public abstract class QuidemTest {
+
+  private static final Pattern PATTERN = Pattern.compile("\\.iq$");
+
   private static Object getEnv(String varName) {
     switch (varName) {
     case "jdk18":
@@ -84,9 +88,9 @@ public abstract class QuidemTest {
 
   private Method findMethod(String path) {
     // E.g. path "sql/agg.iq" gives method "testSqlAgg"
-    String methodName =
-        AvaticaUtils.toCamelCase(
-            "test_" + path.replace(File.separatorChar, 
'_').replaceAll("\\.iq$", ""));
+    final String path1 = path.replace(File.separatorChar, '_');
+    final String path2 = PATTERN.matcher(path1).replaceAll("");
+    String methodName = AvaticaUtils.toCamelCase("test_" + path2);
     Method m;
     try {
       m = getClass().getMethod(methodName, String.class);
diff --git a/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
index dd9e4a2..fb14007 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlFunctionsTest.java
@@ -73,6 +73,35 @@ public class SqlFunctionsTest {
     assertThat(charLength("xyz"), is(3));
   }
 
+  @Test public void testToString() {
+    assertThat(SqlFunctions.toString(0f), is("0E0"));
+    assertThat(SqlFunctions.toString(1f), is("1"));
+    assertThat(SqlFunctions.toString(1.5f), is("1.5"));
+    assertThat(SqlFunctions.toString(-1.5f), is("-1.5"));
+    assertThat(SqlFunctions.toString(1.5e8f), is("1.5E8"));
+    assertThat(SqlFunctions.toString(-0.0625f), is("-0.0625"));
+    assertThat(SqlFunctions.toString(0.0625f), is("0.0625"));
+    assertThat(SqlFunctions.toString(-5e-12f), is("-5E-12"));
+
+    assertThat(SqlFunctions.toString(0d), is("0E0"));
+    assertThat(SqlFunctions.toString(1d), is("1"));
+    assertThat(SqlFunctions.toString(1.5d), is("1.5"));
+    assertThat(SqlFunctions.toString(-1.5d), is("-1.5"));
+    assertThat(SqlFunctions.toString(1.5e8d), is("1.5E8"));
+    assertThat(SqlFunctions.toString(-0.0625d), is("-0.0625"));
+    assertThat(SqlFunctions.toString(0.0625d), is("0.0625"));
+    assertThat(SqlFunctions.toString(-5e-12d), is("-5E-12"));
+
+    assertThat(SqlFunctions.toString(new BigDecimal("0")), is("0"));
+    assertThat(SqlFunctions.toString(new BigDecimal("1")), is("1"));
+    assertThat(SqlFunctions.toString(new BigDecimal("1.5")), is("1.5"));
+    assertThat(SqlFunctions.toString(new BigDecimal("-1.5")), is("-1.5"));
+    assertThat(SqlFunctions.toString(new BigDecimal("1.5e8")), is("1.5E+8"));
+    assertThat(SqlFunctions.toString(new BigDecimal("-0.0625")), is("-.0625"));
+    assertThat(SqlFunctions.toString(new BigDecimal("0.0625")), is(".0625"));
+    assertThat(SqlFunctions.toString(new BigDecimal("-5e-12")), is("-5E-12"));
+  }
+
   @Test public void testConcat() {
     assertThat(concat("a b", "cd"), is("a bcd"));
     // The code generator will ensure that nulls are never passed in. If we
diff --git a/core/src/test/java/org/apache/calcite/util/TestUtil.java 
b/core/src/test/java/org/apache/calcite/util/TestUtil.java
index 5d69e16..b67d98f 100644
--- a/core/src/test/java/org/apache/calcite/util/TestUtil.java
+++ b/core/src/test/java/org/apache/calcite/util/TestUtil.java
@@ -178,19 +178,19 @@ public abstract class TestUtil {
    * Quotes a pattern.
    */
   public static String quotePattern(String s) {
-    return s.replaceAll("\\\\", "\\\\")
-        .replaceAll("\\.", "\\\\.")
-        .replaceAll("\\+", "\\\\+")
-        .replaceAll("\\{", "\\\\{")
-        .replaceAll("\\}", "\\\\}")
-        .replaceAll("\\|", "\\\\||")
-        .replaceAll("[$]", "\\\\\\$")
-        .replaceAll("\\?", "\\\\?")
-        .replaceAll("\\*", "\\\\*")
-        .replaceAll("\\(", "\\\\(")
-        .replaceAll("\\)", "\\\\)")
-        .replaceAll("\\[", "\\\\[")
-        .replaceAll("\\]", "\\\\]");
+    return s.replace("\\", "\\\\")
+        .replace(".", "\\.")
+        .replace("+", "\\+")
+        .replace("{", "\\{")
+        .replace("}", "\\}")
+        .replace("|", "\\||")
+        .replace("$", "\\$")
+        .replace("?", "\\?")
+        .replace("*", "\\*")
+        .replace("(", "\\(")
+        .replace(")", "\\)")
+        .replace("[", "\\[")
+        .replace("]", "\\]");
   }
 
   /**
diff --git 
a/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchProject.java
 
b/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchProject.java
index ff723f6..fe9ddbd 100644
--- 
a/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchProject.java
+++ 
b/elasticsearch/src/main/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchProject.java
@@ -89,7 +89,7 @@ public class ElasticsearchProject extends Project implements 
ElasticsearchRel {
                 + ":{\"script\":"
                 // _source (ES2) vs params._source (ES5)
                 + "\"" + implementor.elasticsearchTable.scriptedFieldPrefix() 
+ "."
-                + expr.replaceAll("\"", "") + "\"}");
+                + expr.replace("\"", "") + "\"}");
       }
     }
 
diff --git 
a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java
 
b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java
index dc74ee5..3cd8704 100644
--- 
a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java
+++ 
b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java
@@ -79,7 +79,7 @@ public class ElasticSearchAdapterTest {
     
Resources.readLines(ElasticSearchAdapterTest.class.getResource("/zips-mini.json"),
         StandardCharsets.UTF_8, new LineProcessor<Void>() {
           @Override public boolean processLine(String line) throws IOException 
{
-            line = line.replaceAll("_id", "id"); // _id is a reserved 
attribute in ES
+            line = line.replace("_id", "id"); // _id is a reserved attribute 
in ES
             bulk.add((ObjectNode) NODE.mapper().readTree(line));
             return true;
           }
diff --git 
a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/MatchTest.java
 
b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/MatchTest.java
index 56d94aa..1f02812 100644
--- 
a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/MatchTest.java
+++ 
b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/MatchTest.java
@@ -95,7 +95,7 @@ public class MatchTest {
     
Resources.readLines(ElasticSearchAdapterTest.class.getResource("/zips-mini.json"),
         StandardCharsets.UTF_8, new LineProcessor<Void>() {
           @Override public boolean processLine(String line) throws IOException 
{
-            line = line.replaceAll("_id", "id"); // _id is a reserved 
attribute in ES
+            line = line.replace("_id", "id"); // _id is a reserved attribute 
in ES
             bulk.add((ObjectNode) NODE.mapper().readTree(line));
             return true;
           }
diff --git 
a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoTable.java 
b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoTable.java
index a9a0a07..c78d537 100644
--- a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoTable.java
+++ b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoTable.java
@@ -152,14 +152,6 @@ public class MongoTable extends AbstractQueryableTable
     };
   }
 
-  /** Helper method to strip non-numerics from a string.
-   *
-   * <p>Currently used to determine mongod versioning numbers
-   * from buildInfo.versionArray for use in aggregate method logic. */
-  private static Integer parseIntString(String valueString) {
-    return Integer.parseInt(valueString.replaceAll("[^0-9]", ""));
-  }
-
   /** Implementation of {@link org.apache.calcite.linq4j.Queryable} based on
    * a {@link org.apache.calcite.adapter.mongodb.MongoTable}.
    *
diff --git a/mongodb/src/test/java/org/apache/calcite/test/MongoAssertions.java 
b/mongodb/src/test/java/org/apache/calcite/test/MongoAssertions.java
index 288ee3f..d1307aa 100644
--- a/mongodb/src/test/java/org/apache/calcite/test/MongoAssertions.java
+++ b/mongodb/src/test/java/org/apache/calcite/test/MongoAssertions.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.function.Consumer;
+import java.util.regex.Pattern;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -40,6 +41,8 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
  */
 public class MongoAssertions {
 
+  private static final Pattern PATTERN = Pattern.compile("\\.0$");
+
   private MongoAssertions() {}
 
   /**
@@ -60,8 +63,9 @@ public class MongoAssertions {
         CalciteAssert.toStringList(resultSet, actualList);
         for (int i = 0; i < actualList.size(); i++) {
           String s = actualList.get(i);
-          actualList.set(i,
-              s.replaceAll("\\.0;", ";").replaceAll("\\.0$", ""));
+          s = s.replace(".0;", ";");
+          s = PATTERN.matcher(s).replaceAll("");
+          actualList.set(i, s);
         }
         Collections.sort(actualList);
 
diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/SqlShell.java 
b/plus/src/main/java/org/apache/calcite/adapter/os/SqlShell.java
index 435cb21..6370c67 100644
--- a/plus/src/main/java/org/apache/calcite/adapter/os/SqlShell.java
+++ b/plus/src/main/java/org/apache/calcite/adapter/os/SqlShell.java
@@ -172,8 +172,8 @@ public class SqlShell {
         .append("\",\n")
         .append("         \"type\": \"view\",\n")
         .append("         \"sql\": \"")
-        .append(sql.replaceAll("\"", "\\\\\"")
-            .replaceAll("\n", ""))
+        .append(sql.replace("\"", "\\\"")
+            .replace("\n", ""))
         .append("\"\n");
   }
 
@@ -256,7 +256,7 @@ public class SqlShell {
           // do nothing - unfortunately same as empty string
         } else if (s.contains("\"")) {
           b.append('"')
-              .append(s.replaceAll("\"", "\"\""))
+              .append(s.replace("\"", "\"\""))
               .append('"');
         } else if (s.indexOf(',') >= 0
             || s.indexOf('\n') >= 0
diff --git a/plus/src/test/java/org/apache/calcite/adapter/tpcds/TpcdsTest.java 
b/plus/src/test/java/org/apache/calcite/adapter/tpcds/TpcdsTest.java
index 804377c..3bdc2db 100644
--- a/plus/src/test/java/org/apache/calcite/adapter/tpcds/TpcdsTest.java
+++ b/plus/src/test/java/org/apache/calcite/adapter/tpcds/TpcdsTest.java
@@ -297,7 +297,7 @@ public class TpcdsTest {
       break;
     }
     return with()
-        .query(sql.replaceAll("tpcds\\.", "tpcds_01."));
+        .query(sql.replace("tpcds.", "tpcds_01."));
   }
 
   public Frameworks.ConfigBuilder config() throws Exception {
diff --git a/plus/src/test/java/org/apache/calcite/adapter/tpch/TpchTest.java 
b/plus/src/test/java/org/apache/calcite/adapter/tpch/TpchTest.java
index 8e65312..66f3b18 100644
--- a/plus/src/test/java/org/apache/calcite/adapter/tpch/TpchTest.java
+++ b/plus/src/test/java/org/apache/calcite/adapter/tpch/TpchTest.java
@@ -933,6 +933,6 @@ public class TpchTest {
    * @param i Ordinal of query, per the benchmark, 1-based */
   private CalciteAssert.AssertQuery query(int i) {
     return with()
-        .query(QUERIES.get(i - 1).replaceAll("tpch\\.", "tpch_01."));
+        .query(QUERIES.get(i - 1).replace("tpch.", "tpch_01."));
   }
 }
diff --git 
a/plus/src/test/java/org/apache/calcite/materialize/TpcdsLatticeSuggesterTest.java
 
b/plus/src/test/java/org/apache/calcite/materialize/TpcdsLatticeSuggesterTest.java
index 825766b..aa78c80 100644
--- 
a/plus/src/test/java/org/apache/calcite/materialize/TpcdsLatticeSuggesterTest.java
+++ 
b/plus/src/test/java/org/apache/calcite/materialize/TpcdsLatticeSuggesterTest.java
@@ -43,6 +43,7 @@ import org.junit.jupiter.api.Test;
 import java.util.List;
 import java.util.Properties;
 import java.util.Random;
+import java.util.regex.Pattern;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -63,14 +64,16 @@ public class TpcdsLatticeSuggesterTest {
 
   private void checkFoodMartAll(boolean evolve) throws Exception {
     final Tester t = new Tester().tpcds().withEvolve(evolve);
+    final Pattern pattern =
+        Pattern.compile("substr\\(([^,]*),([^,]*),([^)]*)\\)");
     for (Query query : Query.values()) {
-      final String sql = query.sql(new Random(0))
-          .replaceAll("as returns", "as \"returns\"")
-          .replaceAll("sum\\(returns\\)", "sum(\"returns\")")
-          .replaceAll(", returns", ", \"returns\"")
-          .replaceAll("14 days", "interval '14' day")
-          .replaceAll("substr\\(([^,]*),([^,]*),([^)]*)\\)",
-              "substring($1 from $2 for $3)");
+      final String sql0 = query.sql(new Random(0))
+          .replace("as returns", "as \"returns\"")
+          .replace("sum(returns)", "sum(\"returns\")")
+          .replace(", returns", ", \"returns\"")
+          .replace("14 days", "interval '14' day");
+      final String sql =
+          pattern.matcher(sql0).replaceAll("substring($1 from $2 for $3)");
       if (CalciteSystemProperty.DEBUG.value()) {
         System.out.println("Query #" + query.id + "\n"
             + number(sql));
diff --git 
a/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
 
b/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
index 10ca4f8..8c0271f 100644
--- 
a/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
+++ 
b/splunk/src/main/java/org/apache/calcite/adapter/splunk/SplunkPushDownRule.java
@@ -398,7 +398,7 @@ public class SplunkPushDownRule
     } else if (litSqlType == SqlTypeName.CHAR) {
       value = ((NlsString) literal.getValue()).getValue();
       if (like) {
-        value = value.replaceAll("%", "*");
+        value = value.replace("%", "*");
       }
       value = searchEscape(value);
     }
diff --git a/src/main/config/forbidden-apis/signatures.txt 
b/src/main/config/forbidden-apis/signatures.txt
index 343fa38..9b40bb8 100644
--- a/src/main/config/forbidden-apis/signatures.txt
+++ b/src/main/config/forbidden-apis/signatures.txt
@@ -26,6 +26,13 @@ java.lang.Object#wait(long,int)
 java.lang.Object#notify()
 java.lang.Object#notifyAll()
 
+@defaultMessage If you want regex use Pattern.compile; otherwise 
String.replace is faster
+java.lang.String#replaceAll(java.lang.String, java.lang.String)
+
+@defaultMessage Use toLowerCase(Locale.ROOT) and toUpperCase(Locale.ROOT)
+java.lang.String#toUpperCase()
+java.lang.String#toLowerCase()
+
 @defaultMessage Use StringBuilder; it is more efficient
 java.lang.StringBuffer
 

Reply via email to