diff options
author | Stefan Winkler | 2008-12-01 13:35:29 +0000 |
---|---|---|
committer | Stefan Winkler | 2008-12-01 13:35:29 +0000 |
commit | 02cc960c39a9b50c5c70f797eb3759b9148a5639 (patch) | |
tree | 7cbc9d3bc4a6b9c7a0a272c18a11a8b571985718 | |
parent | fd25da3564204637c89de2dd122c25a2514cde7c (diff) | |
download | cdo-02cc960c39a9b50c5c70f797eb3759b9148a5639.tar.gz cdo-02cc960c39a9b50c5c70f797eb3759b9148a5639.tar.xz cdo-02cc960c39a9b50c5c70f797eb3759b9148a5639.zip |
[244290] [DB] Trailing backslash is not escaped
https://bugs.eclipse.org/bugs/show_bug.cgi?id=244290
6 files changed, 223 insertions, 22 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/StatementJDBCDelegate.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/StatementJDBCDelegate.java index ec175f7be0..28b11a8baf 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/StatementJDBCDelegate.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/StatementJDBCDelegate.java @@ -74,8 +74,7 @@ public class StatementJDBCDelegate extends AbstractJDBCDelegate for (IAttributeMapping attributeMapping : attributeMappings) { builder.append(", "); - Object value = attributeMapping.getRevisionValue(revision); - attributeMapping.getField().appendValue(builder, value); + attributeMapping.appendValue(builder, revision); } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/DBStoreTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/DBStoreTest.java index 98e782b644..f25e7db848 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/DBStoreTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/DBStoreTest.java @@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.tests; import org.eclipse.emf.cdo.CDOSession; import org.eclipse.emf.cdo.CDOTransaction; +import org.eclipse.emf.cdo.CDOView; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.tests.model1.Company; import org.eclipse.emf.cdo.tests.model1.Model1Factory; @@ -34,4 +35,71 @@ public class DBStoreTest extends AbstractCDOTest t.commit(); } + + public void testStoreStringTrailingBackslash() + { + storeRetrieve("foobar\\"); + } + + public void testStoreStringContainingBackslash() + { + storeRetrieve("foo\\bar"); + } + + public void testStoreStringTrailingSingleQuote() + { + storeRetrieve("foobar'"); + } + + public void testStoreStringContainingSingleQuote() + { + storeRetrieve("foo'bar"); + } + + public void testStoreStringTrailingDoubleQuote() + { + storeRetrieve("foobar\""); + } + + public void testStoreStringContainingDoubleQuote() + { + storeRetrieve("foo\"bar"); + } + + public void testStoreStringTrailingTwoSingleQuote() + { + storeRetrieve("foobar''"); + } + + public void testStoreStringContainingTwoSingleQuote() + { + storeRetrieve("foo''bar"); + } + + private void storeRetrieve(String s) + { + CDOSession session = openModel1Session(); + CDOTransaction transaction = session.openTransaction(); + CDOResource resource = transaction.getOrCreateResource("/test"); + + Company e = Model1Factory.eINSTANCE.createCompany(); + e.setName(s); + // this escapes only the string! + // resulting string only contains one backslash + + resource.getContents().add(e); + transaction.commit(); + + transaction.close(); + session.close(); + clearCache(getRepository().getRevisionManager()); + + session = openModel1Session(); + CDOView view = session.openView(); + resource = view.getResource("/test"); + + assertEquals(1, resource.getContents().size()); + e = (Company)resource.getContents().get(0); + assertEquals(s, e.getName()); + } } diff --git a/plugins/org.eclipse.net4j.db.derby/src/org/eclipse/net4j/db/derby/DerbyAdapter.java b/plugins/org.eclipse.net4j.db.derby/src/org/eclipse/net4j/db/derby/DerbyAdapter.java index bf902aa969..9b6d773517 100644 --- a/plugins/org.eclipse.net4j.db.derby/src/org/eclipse/net4j/db/derby/DerbyAdapter.java +++ b/plugins/org.eclipse.net4j.db.derby/src/org/eclipse/net4j/db/derby/DerbyAdapter.java @@ -14,6 +14,8 @@ import org.eclipse.net4j.db.DBType; import org.eclipse.net4j.db.ddl.IDBField; import org.eclipse.net4j.spi.db.DBAdapter; +import java.util.StringTokenizer; + /** * @author Eike Stepper * @since 2.0 @@ -71,16 +73,58 @@ public abstract class DerbyAdapter extends DBAdapter @Override public void appendValue(StringBuilder builder, IDBField field, Object value) { + Object newValue = value; if (value instanceof Boolean) { - value = (Boolean)value ? 1 : 0; + newValue = (Boolean)value ? 1 : 0; + } + else if (value instanceof String) + { + // Derby just adds one additional single quote for a single quote + String str = (String)value; + StringTokenizer tokenizer = new StringTokenizer(str, "\'", true); // split on single quote + StringBuilder newValueBuilder = new StringBuilder(); + + while (tokenizer.hasMoreTokens()) + { + String current = tokenizer.nextToken(); + if (current.length() == 0) + { + continue; + } + + if (current.length() > 1) // >1 -> can not be token -> normal string + { + newValueBuilder.append(current); + } + else + { // length == 1 + newValueBuilder.append(processEscape(current.charAt(0))); + } + } + + newValue = newValueBuilder.toString(); + } + else if (value instanceof Character) + { + newValue = processEscape((Character)value); } - super.appendValue(builder, field, value); + super.appendValue(builder, field, newValue); } public String[] getReservedWords() { return RESERVED_WORDS; } + + private Object processEscape(char c) + { + if (c == '\'') // one single quote --> + { + return "\'\'"; // results two single quotes + } + + return c; // no escape character --> return as is + } } diff --git a/plugins/org.eclipse.net4j.db.hsqldb/src/org/eclipse/net4j/db/hsqldb/HSQLDBAdapter.java b/plugins/org.eclipse.net4j.db.hsqldb/src/org/eclipse/net4j/db/hsqldb/HSQLDBAdapter.java index 5788945801..fdda6df586 100644 --- a/plugins/org.eclipse.net4j.db.hsqldb/src/org/eclipse/net4j/db/hsqldb/HSQLDBAdapter.java +++ b/plugins/org.eclipse.net4j.db.hsqldb/src/org/eclipse/net4j/db/hsqldb/HSQLDBAdapter.java @@ -19,6 +19,7 @@ import org.hsqldb.jdbcDriver; import javax.sql.DataSource; import java.sql.Driver; +import java.util.StringTokenizer; /** * @author Eike Stepper @@ -95,4 +96,54 @@ public class HSQLDBAdapter extends DBAdapter { return getSQL92ReservedWords(); } + + @Override + public void appendValue(StringBuilder builder, IDBField field, Object value) + { + Object newValue = value; + + if (value instanceof String) + { + // HSQLDB just adds one additional single quote for a single quote + String str = (String)value; + StringTokenizer tokenizer = new StringTokenizer(str, "\'", true); // split on single quote + StringBuilder newValueBuilder = new StringBuilder(); + + while (tokenizer.hasMoreTokens()) + { + String current = tokenizer.nextToken(); + if (current.length() == 0) + { + continue; + } + + if (current.length() > 1) // >1 -> can not be token -> normal string + { + newValueBuilder.append(current); + } + else + { // length == 1 + newValueBuilder.append(processEscape(current.charAt(0))); + } + } + + newValue = newValueBuilder.toString(); + } + else if (value instanceof Character) + { + newValue = processEscape((Character)value); + } + + super.appendValue(builder, field, newValue); + } + + private Object processEscape(char c) + { + if (c == '\'') // one single quote --> + { + return "\'\'"; // results two single quotes + } + + return c; // no escape character --> return as is + } } diff --git a/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java b/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java index 33e7b4602a..07e2983d87 100644 --- a/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java +++ b/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java @@ -21,6 +21,7 @@ import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; import javax.sql.DataSource; import java.sql.SQLException; +import java.util.StringTokenizer; /** * @author Eike Stepper @@ -137,4 +138,59 @@ public class MYSQLAdapter extends DBAdapter return super.isTypeIndexable(type); } } + + @Override + public void appendValue(StringBuilder builder, IDBField field, Object value) + { + Object newValue = value; + + if (value instanceof String) + { + // MySQL does Java-Style backslash-escaping + String str = (String)value; + StringTokenizer st = new StringTokenizer(str, "\\\'", true); // split on backslash or single quote + StringBuilder newValueBuilder = new StringBuilder(); + + while (st.hasMoreTokens()) + { + String current = st.nextToken(); + if (current.length() == 0) + { + continue; + } + + if (current.length() > 1) // >1 -> can not be token -> normal string + { + newValueBuilder.append(current); + } + else + { // length == 1 + newValueBuilder.append(processEscape(current.charAt(0))); + } + } + + newValue = newValueBuilder.toString(); + } + else if (value instanceof Character) + { + newValue = processEscape((Character)value); + } + + super.appendValue(builder, field, newValue); + } + + private Object processEscape(char c) + { + if (c == '\\') // one backslash --> + { + return "\\\\"; // results in two backslashes + } + + if (c == '\'') // one single quote --> + { + return "\\'"; // results in backslash+single quote + } + + return c; // no escape character --> return as is + } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java index 730dffc8b4..0c45c7ada6 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java @@ -115,24 +115,7 @@ public enum DBType if (value instanceof String || value instanceof Character) { builder.append("'"); - if (value instanceof String) - { - String str = (String)value; - for (int i = 0; i < str.length(); i++) - { - char c = str.charAt(i); - builder.append(c); - if (c == '\'') - { - builder.append(c); - } - } - } - else - { - builder.append(value); - } - + builder.append(value); builder.append("'"); } else |