Commit 7deb1bd8 authored by Jan Varga's avatar Jan Varga
Browse files

Bug 1676969 - Add escapeUTF8StringForLIKE; r=asuth,dom-workers-and-storage-reviewers

parent b538315d
Loading
Loading
Loading
Loading
+26 −9
Original line number Diff line number Diff line
@@ -184,22 +184,39 @@ StorageBaseStatementInternal::ExecuteAsync(
                                         mNativeConnection, aCallback, _stmt);
}

NS_IMETHODIMP
StorageBaseStatementInternal::EscapeStringForLIKE(const nsAString& aValue,
                                                  const char16_t aEscapeChar,
                                                  nsAString& _escapedString) {
  const char16_t MATCH_ALL('%');
  const char16_t MATCH_ONE('_');
template <typename T>
void EscapeStringForLIKEInternal(const T& aValue,
                                 const typename T::char_type aEscapeChar,
                                 T& aResult) {
  const typename T::char_type MATCH_ALL('%');
  const typename T::char_type MATCH_ONE('_');

  _escapedString.Truncate(0);
  aResult.Truncate(0);

  for (uint32_t i = 0; i < aValue.Length(); i++) {
    if (aValue[i] == aEscapeChar || aValue[i] == MATCH_ALL ||
        aValue[i] == MATCH_ONE) {
      _escapedString += aEscapeChar;
      aResult += aEscapeChar;
    }
    _escapedString += aValue[i];
    aResult += aValue[i];
  }
}

NS_IMETHODIMP
StorageBaseStatementInternal::EscapeStringForLIKE(const nsAString& aValue,
                                                  const char16_t aEscapeChar,
                                                  nsAString& _escapedString) {
  EscapeStringForLIKEInternal(aValue, aEscapeChar, _escapedString);

  return NS_OK;
}

NS_IMETHODIMP
StorageBaseStatementInternal::EscapeUTF8StringForLIKE(
    const nsACString& aValue, const char aEscapeChar,
    nsACString& _escapedString) {
  EscapeStringForLIKEInternal(aValue, aEscapeChar, _escapedString);

  return NS_OK;
}

+6 −0
Original line number Diff line number Diff line
@@ -140,6 +140,8 @@ class StorageBaseStatementInternal : public nsISupports {
                          mozIStoragePendingStatement** _stmt);
  NS_IMETHOD EscapeStringForLIKE(const nsAString& aValue, char16_t aEscapeChar,
                                 nsAString& _escapedString);
  NS_IMETHOD EscapeUTF8StringForLIKE(const nsACString& aValue, char aEscapeChar,
                                     nsACString& _escapedString);

  // Needs access to internalAsyncFinalize
  friend class AsyncStatementFinalizer;
@@ -182,6 +184,10 @@ NS_DEFINE_STATIC_IID_ACCESSOR(StorageBaseStatementInternal,
  MIX_IMPL(_class, _optionalGuard, EscapeStringForLIKE,                 \
           (const nsAString& aValue, char16_t aEscapeChar,              \
            nsAString& _escapedString),                                 \
           (aValue, aEscapeChar, _escapedString))                       \
  MIX_IMPL(_class, _optionalGuard, EscapeUTF8StringForLIKE,             \
           (const nsACString& aValue, char aEscapeChar,                 \
            nsACString& _escapedString),                                \
           (aValue, aEscapeChar, _escapedString))

/**
+6 −0
Original line number Diff line number Diff line
@@ -116,4 +116,10 @@ interface mozIStorageBaseStatement : mozIStorageBindingParams {
   *         into "foo//bar/_baz/%20cheese" (if the escape char is '/').
   */
  AString escapeStringForLIKE(in AString aValue, in wchar aEscapeChar);

  /**
   * The same as above, but for UTF8 strings.
   */
  AUTF8String escapeUTF8StringForLIKE(in AUTF8String aValue,
                                      in char aEscapeChar);
};
+32 −21
Original line number Diff line number Diff line
@@ -22,31 +22,42 @@ function setup() {
}

function test_escape_for_like_ascii() {
  const paramForLike = "oo/bar_baz%20chees";
  const escapeChar = "/";

  for (const utf8 of [false, true]) {
    var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?1 ESCAPE '/'");
  var paramForLike = stmt.escapeStringForLIKE("oo/bar_baz%20chees", "/");
    var paramForLikeEscaped = utf8
      ? stmt.escapeUTF8StringForLIKE(paramForLike, escapeChar)
      : stmt.escapeStringForLIKE(paramForLike, escapeChar);
    // verify that we escaped / _ and %
  Assert.equal(paramForLike, "oo//bar/_baz/%20chees");
    Assert.equal(paramForLikeEscaped, "oo//bar/_baz/%20chees");
    // prepend and append with % for "contains"
  stmt.bindByIndex(0, "%" + paramForLike + "%");
    stmt.bindByIndex(0, "%" + paramForLikeEscaped + "%");
    stmt.executeStep();
    Assert.equal("foo/bar_baz%20cheese", stmt.getString(0));
    stmt.finalize();
  }
}

function test_escape_for_like_non_ascii() {
  const paramForLike = "oo%20" + LATIN1_AE + "/_ba";
  const escapeChar = "/";

  for (const utf8 of [false, true]) {
    var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?1 ESCAPE '/'");
  var paramForLike = stmt.escapeStringForLIKE(
    "oo%20" + LATIN1_AE + "/_ba",
    "/"
  );
    var paramForLikeEscaped = utf8
      ? stmt.escapeUTF8StringForLIKE(paramForLike, escapeChar)
      : stmt.escapeStringForLIKE(paramForLike, escapeChar);
    // verify that we escaped / _ and %
  Assert.equal(paramForLike, "oo/%20" + LATIN1_AE + "///_ba");
    Assert.equal(paramForLikeEscaped, "oo/%20" + LATIN1_AE + "///_ba");
    // prepend and append with % for "contains"
  stmt.bindByIndex(0, "%" + paramForLike + "%");
    stmt.bindByIndex(0, "%" + paramForLikeEscaped + "%");
    stmt.executeStep();
    Assert.equal("foo%20" + LATIN1_ae + "/_bar", stmt.getString(0));
    stmt.finalize();
  }
}

var tests = [test_escape_for_like_ascii, test_escape_for_like_non_ascii];