Loading storage/StorageBaseStatementInternal.cpp +26 −9 Original line number Diff line number Diff line Loading @@ -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; } Loading storage/StorageBaseStatementInternal.h +6 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)) /** Loading storage/mozIStorageBaseStatement.idl +6 −0 Original line number Diff line number Diff line Loading @@ -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); }; storage/test/unit/test_like_escape.js +32 −21 Original line number Diff line number Diff line Loading @@ -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]; Loading Loading
storage/StorageBaseStatementInternal.cpp +26 −9 Original line number Diff line number Diff line Loading @@ -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; } Loading
storage/StorageBaseStatementInternal.h +6 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)) /** Loading
storage/mozIStorageBaseStatement.idl +6 −0 Original line number Diff line number Diff line Loading @@ -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); };
storage/test/unit/test_like_escape.js +32 −21 Original line number Diff line number Diff line Loading @@ -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]; Loading