diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java index 478547b02..957e403a8 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java @@ -60,6 +60,7 @@ import java.util.Map; import java.util.Set; import javax.sql.DataSource; +import org.apache.commons.lang.CharUtils; import org.apache.commons.lang.StringUtils; import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; @@ -318,6 +319,9 @@ public class DBDictionary protected final Set systemTableSet = new HashSet(); protected final Set fixedSizeTypeNameSet = new HashSet(); + public String leadingDelimiter = "\""; + public String trailingDelimiter = "\""; + /** * Some JDBC drivers - ie DB2 type 2 on Z/OS throw exceptions on * setQueryTimeout when provided specific input values. @@ -3502,7 +3506,7 @@ public class DBDictionary Column c = new Column(); c.setSchemaName(colMeta.getString("TABLE_SCHEM")); c.setTableName(colMeta.getString("TABLE_NAME")); - c.setName(colMeta.getString("COLUMN_NAME")); + c.setName(delimit(colMeta.getString("COLUMN_NAME"))); c.setType(colMeta.getInt("DATA_TYPE")); c.setTypeName(colMeta.getString("TYPE_NAME")); c.setSize(colMeta.getInt("COLUMN_SIZE")); @@ -4089,4 +4093,29 @@ public class DBDictionary public void setTrimSchemaName(boolean trimSchemaName) { this.trimSchemaName = trimSchemaName; } + + public String getLeadingDelimiter() { + return leadingDelimiter; + } + + public void setLeadingDelimiter(String delim) { + leadingDelimiter = delim; + } + + public String getTrailingDelimiter() { + return trailingDelimiter; + } + + public void setTrailingDelimiter(String delim) { + trailingDelimiter = delim; + } + + public String delimit(String name) { + char[] chars = name.toCharArray(); + if (!CharUtils.isAsciiAlpha(chars[0])) { + return getLeadingDelimiter() + name + getTrailingDelimiter(); + } + + return name; + } } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java index 2db1537f4..b3a7ef86e 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java @@ -472,8 +472,21 @@ public class ResultSetResult throws SQLException { if (obj instanceof Number) return obj; + // If an object is manually delimited, the delimiters need to be stripped in order for this to work + if (obj instanceof String) + return Numbers.valueOf(findObject(stripDelimiters((String)obj), joins)); + return Numbers.valueOf(findObject(obj, joins)); } + + protected String stripDelimiters(String str) { + String leadingDelim = _dict.getLeadingDelimiter(); + String trailingDelim = _dict.getTrailingDelimiter(); + if (str.startsWith(leadingDelim) && str.endsWith(trailingDelim)) { + return str.substring(leadingDelim.length(), str.lastIndexOf(trailingDelim)); + } + return str; + } /** * Return the 1-based result set index for the given column or id, or a diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/ResultClsAnnotation.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/ResultClsAnnotation.java new file mode 100644 index 000000000..b6f55805c --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/ResultClsAnnotation.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.results.cls; + +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EntityResult; +import javax.persistence.FieldResult; +import javax.persistence.Id; +import javax.persistence.NamedNativeQueries; +import javax.persistence.NamedNativeQuery; +import javax.persistence.SqlResultSetMapping; + +@NamedNativeQueries({ +@NamedNativeQuery(name = "ResultClsQueryDoubleQuotes", + query = "select \"1\",\"2\" FROM ResultClsAnnoEntity", + resultSetMapping = "ResultClsRSMapping", + resultClass = ResultClsAnnotation.class) +}) + +@SqlResultSetMapping(name = "ResultClsRSMapping", + entities = @EntityResult(entityClass = ResultClsAnnotation.class, fields = { + @FieldResult(name = "id", column = "\"1\""), + @FieldResult(name = "description", column = "\"2\"") })) +@Entity(name = "ResultClsAnnoEntity") +public class ResultClsAnnotation { + public ResultClsAnnotation() { + } + + @Id + @Column(name = "\"1\"") + public String id; + @Basic + @Column(name = "\"2\"") + public String description; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/ResultClsXml.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/ResultClsXml.java new file mode 100644 index 000000000..25dc3dc77 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/ResultClsXml.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.results.cls; + +public class ResultClsXml { + public ResultClsXml() { + } + + public String id; + public String description; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/TestResultClsAnnotation.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/TestResultClsAnnotation.java new file mode 100644 index 000000000..0da12655f --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/TestResultClsAnnotation.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.results.cls; + +import java.util.Iterator; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.Query; + +import org.apache.openjpa.jdbc.sql.DBDictionary; +import org.apache.openjpa.persistence.test.SQLListenerTestCase; + +public class TestResultClsAnnotation extends SQLListenerTestCase { + private boolean supportedDB = false; + + public void setUp() { + setUp(ResultClsAnnotation.class, CLEAR_TABLES); + assertNotNull(emf); + + DBDictionary dict = getDBDictionary(); + if (dict.getLeadingDelimiter().equals("\"") && dict.getTrailingDelimiter().equals("\"")) { + supportedDB = true; + populate(); + } + } + + public void testIt() { + if (!supportedDB) + return; + + EntityManager em = emf.createEntityManager(); + + try { + Query q = em.createNamedQuery("ResultClsQueryDoubleQuotes"); + List result = q.getResultList(); + assertEquals(1, result.size()); + + for (Iterator it = result.iterator(); it.hasNext();) { + Object obj = (Object) it.next(); + ResultClsAnnotation ct = (ResultClsAnnotation) obj; + assertEquals("id1", ct.getId()); + assertEquals("description1", ct.getDescription()); + } + } finally { + em.close(); + } + } + + private void populate() { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + + ResultClsAnnotation ct = new ResultClsAnnotation(); + ct.setId("id1"); + ct.setDescription("description1"); + em.persist(ct); + + em.getTransaction().commit(); + em.close(); + } + +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/TestResultClsXml.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/TestResultClsXml.java new file mode 100644 index 000000000..9fdd0d281 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/results/cls/TestResultClsXml.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.results.cls; + +import java.util.Iterator; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.Query; + +import org.apache.openjpa.jdbc.sql.DBDictionary; +import org.apache.openjpa.persistence.test.SQLListenerTestCase; + +public class TestResultClsXml extends SQLListenerTestCase { + private boolean supportedDB = false; + + public void setUp() { + setUp(ResultClsXml.class, CLEAR_TABLES); + assertNotNull(emf); + + DBDictionary dict = getDBDictionary(); + if (dict.getLeadingDelimiter().equals("\"") && dict.getTrailingDelimiter().equals("\"")) { + supportedDB = true; + populate(); + } + } + + public void testIt() { + if (!supportedDB) + return; + + EntityManager em = emf.createEntityManager(); + + try { + Query q = getQuery(em); + + List result = q.getResultList(); + assertEquals(1, result.size()); + + for (Iterator it = result.iterator(); it.hasNext();) { + Object obj = (Object) it.next(); + ResultClsXml ct = (ResultClsXml) obj; + assertEquals("id1", ct.getId()); + assertEquals("description1", ct.getDescription()); + } + + } catch (Exception ex) { + fail("unexpected exception: " + ex.getMessage()); + ex.printStackTrace(); + + } finally { + em.close(); + } + } + + protected String getPersistenceUnitName() { + return "query-result"; + } + + private void populate() { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + + ResultClsXml ct = new ResultClsXml(); + ct.setId("id1"); + ct.setDescription("description1"); + em.persist(ct); + + em.getTransaction().commit(); + em.close(); + } + + private Query getQuery(EntityManager em) { + // TODO: temp + Query query = em.createNamedQuery("ResultClsQueryDoubleQuotes"); +// DBDictionary dict = getDBDictionary(); +// Query query = null; +// if (dict.getLeadingDelimiter().equals("\"") && dict.getTrailingDelimiter().equals("\"")) { +// query = em.createNamedQuery("ResultClsQueryDoubleQuotes"); +// } else if (dict.getLeadingDelimiter().equals("`") && dict.getTrailingDelimiter().equals("`")) { +// query = em.createNamedQuery("ResultClsQueryBackTicks"); +// } else if (dict.getLeadingDelimiter().equals("[") && dict.getTrailingDelimiter().equals("]")) { +// query = em.createNamedQuery("ResultClsQueryBrackets"); +// } else { +// query = em.createNamedQuery("ResultClsQueryDefault"); +// } + return query; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTestCase.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTestCase.java index 4dc8b9b6e..e57bad0cf 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTestCase.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTestCase.java @@ -18,7 +18,9 @@ */ package org.apache.openjpa.persistence.test; +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; import org.apache.openjpa.jdbc.meta.ClassMapping; +import org.apache.openjpa.jdbc.sql.DBDictionary; import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; import org.apache.openjpa.lib.log.Log; @@ -78,4 +80,8 @@ public abstract class SingleEMFTestCase protected Log getLog() { return emf.getConfiguration().getLog("Tests"); } + + protected DBDictionary getDBDictionary() { + return ((JDBCConfiguration) emf.getConfiguration()).getDBDictionaryInstance(); + } } diff --git a/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml b/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml index f0b185d22..a71005af3 100644 --- a/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml +++ b/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml @@ -74,4 +74,22 @@ value="buildSchema(ForeignKeys=true)"/> + + + META-INF/query-result-orm.xml + org.apache.openjpa.persistence.results.cls.ResultClsXml + + + + + + + + org.apache.openjpa.persistence.results.cls.ResultClsAnnotation + + + + diff --git a/openjpa-persistence-jdbc/src/test/resources/META-INF/query-result-orm.xml b/openjpa-persistence-jdbc/src/test/resources/META-INF/query-result-orm.xml new file mode 100644 index 000000000..ce15c414f --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/resources/META-INF/query-result-orm.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + ResultQueryDesc + + select "1","2" FROM ResultClsXmlEntity + + + + + + + + + + + + \ No newline at end of file