/* * Copyright 2009-2016 Tilmann Zaeschke. All rights reserved. * * This file is part of ZooDB. * * ZooDB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ZooDB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ZooDB. If not, see <http://www.gnu.org/licenses/>. * * See the README and COPYING files for further information. */ package org.zoodb.test.jdo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Collection; import java.util.Iterator; import javax.jdo.JDOUserException; import javax.jdo.PersistenceManager; import javax.jdo.Query; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.zoodb.test.testutil.TestTools; /** * Tests for query setResult(). * * @author ztilmann * */ public class Test_122_QueryBugs { @BeforeClass public static void setUp() { TestTools.removeDb(); TestTools.createDb(); } @Before public void before() { TestTools.defineSchema(TestClass.class); PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); pm.newQuery(TestClass.class).deletePersistentAll(); TestClass tc1 = new TestClass(); tc1.setData(1, false, 'c', (byte)127, (short)32001, 1234567890L, "xyz1", new byte[]{1,2}, -1.1f, 35); pm.makePersistent(tc1); tc1 = new TestClass(); tc1.setData(12, false, 'd', (byte)126, (short)32002, 1234567890L, "xyz2", new byte[]{1,2}, -0.1f, 34); pm.makePersistent(tc1); tc1 = new TestClass(); tc1.setData(123, false, 'e', (byte)125, (short)32003, 1234567890L, null, new byte[]{1,2}, 0.1f, 3.0); pm.makePersistent(tc1); tc1 = new TestClass(); tc1.setData(1234, false, 'f', (byte)124, (short)32004, 1234567890L, "xyz", new byte[]{1,2}, 1.1f, -0.01); pm.makePersistent(tc1); tc1 = new TestClass(); tc1.setData(12345, false, 'g', (byte)123, (short)32005, 1234567890L, "xyz", new byte[]{1,2}, 11.1f, -35); pm.makePersistent(tc1); pm.currentTransaction().commit(); TestTools.closePM();; } @After public void afterTest() { TestTools.closePM(); //also removes indexes and objects TestTools.removeSchema(TestClass.class); } @AfterClass public static void tearDown() { TestTools.removeDb(); } /** * See issue #20. */ @Test public void testStringIndex() { TestTools.defineIndex(TestClass.class, "_string", false); testStringQuery(); } /** * See issue #20. */ @Test public void testStringQuery() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); //System.out.println(ZooSchema.locateClass(pm, TestClass.class).hasIndex("_string")); Query q = null; Collection<?> r; q = pm.newQuery(TestClass.class, "_string != 'xyz'"); r = (Collection<?>)q.execute(); assertEquals(3, r.size()); q = pm.newQuery(TestClass.class, "_string == null"); r = (Collection<?>)q.execute(); assertEquals(1, r.size()); q = pm.newQuery(TestClass.class, "_string != null"); r = (Collection<?>)q.execute(); assertEquals(4, r.size()); } /** * See issue #21. */ @Test public void testSetFilterForParameters() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); Query q = null; Collection<?> r; q = pm.newQuery(TestClass.class, "_int == :x"); q.setFilter("_int == 123"); r = (Collection<?>)q.execute(); assertEquals(1, r.size()); } @Test public void testQueryString_Issue26() { //also removes indexes and objects TestTools.removeSchema(TestClass.class); TestTools.defineSchema(TestClass.class); PersistenceManager pm0 = TestTools.openPM(); pm0.currentTransaction().begin(); TestClass t1 = new TestClass(); TestClass t2 = new TestClass(); TestClass t3 = new TestClass(); t1.setString(null); t2.setString("lalalala"); t3.setString("lala"); pm0.makePersistent(t1); pm0.makePersistent(t2); pm0.makePersistent(t3); long oid1 = (Long) pm0.getObjectId(t1); long oid2 = (Long) pm0.getObjectId(t2); long oid3 = (Long) pm0.getObjectId(t3); //close session pm0.currentTransaction().commit(); TestTools.closePM(); //query PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); Query q = pm.newQuery(TestClass.class, "_string == 'haha'"); Collection<?> c = (Collection<?>) q.execute(); assertEquals(0, c.size()); q = pm.newQuery(TestClass.class, "_string == 'lalalala'"); c = (Collection<?>) q.execute(); assertEquals(1, c.size()); Iterator<?> it = c.iterator(); assertEquals(oid2, pm.getObjectId(it.next())); //These used to fail because the comparison in the query evaluator expected -1/1 as only //possible outcomes of value comparison q = pm.newQuery(TestClass.class, "!(_string == 'haha')"); c = (Collection<?>) q.execute(); assertEquals(3, c.size()); it = c.iterator(); assertEquals(oid1, pm.getObjectId(it.next())); assertEquals(oid2, pm.getObjectId(it.next())); assertEquals(oid3, pm.getObjectId(it.next())); q = pm.newQuery(TestClass.class, "_string != 'haha'"); c = (Collection<?>) q.execute(); assertEquals(3, c.size()); it = c.iterator(); assertEquals(oid1, pm.getObjectId(it.next())); assertEquals(oid2, pm.getObjectId(it.next())); assertEquals(oid3, pm.getObjectId(it.next())); TestTools.closePM(); } @Test public void testIndexStringWithIndex_Issue26b() { //also removes indexes and objects TestTools.removeSchema(TestClass.class); TestTools.defineSchema(TestClass.class); TestTools.defineIndex(TestClass.class, "_string", true); PersistenceManager pm0 = TestTools.openPM(); pm0.currentTransaction().begin(); TestClass t1 = new TestClass(); TestClass t2 = new TestClass(); TestClass t3 = new TestClass(); t1.setString(null); t2.setString("lalalala"); t3.setString("lala"); pm0.makePersistent(t1); pm0.makePersistent(t2); pm0.makePersistent(t3); long oid1 = (Long) pm0.getObjectId(t1); long oid2 = (Long) pm0.getObjectId(t2); long oid3 = (Long) pm0.getObjectId(t3); //close session pm0.currentTransaction().commit(); TestTools.closePM(); //query PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); Query q = pm.newQuery(TestClass.class, "_string == 'haha'"); Collection<?> c = (Collection<?>) q.execute(); assertEquals(0, c.size()); q = pm.newQuery(TestClass.class, "_string == 'lalalala'"); c = (Collection<?>) q.execute(); assertEquals(1, c.size()); Iterator<?> it = c.iterator(); assertEquals(oid2, pm.getObjectId(it.next())); //These used to fail because the comparison in the query evaluator expected -1/1 as only //possible outcomes of value comparison q = pm.newQuery(TestClass.class, "!(_string == 'haha')"); c = (Collection<?>) q.execute(); assertEquals(3, c.size()); it = c.iterator(); assertEquals(oid1, pm.getObjectId(it.next())); assertEquals(oid3, pm.getObjectId(it.next())); assertEquals(oid2, pm.getObjectId(it.next())); q = pm.newQuery(TestClass.class, "_string != 'haha'"); c = (Collection<?>) q.execute(); assertEquals(3, c.size()); it = c.iterator(); assertEquals(oid1, pm.getObjectId(it.next())); assertEquals(oid3, pm.getObjectId(it.next())); assertEquals(oid2, pm.getObjectId(it.next())); TestTools.closePM(); } /** * When missing String delimiters ' or ", then the error message should point that out. */ @Test public void testIndexStringWithIndex_Issue46() { //also removes indexes and objects TestTools.removeSchema(TestClass.class); TestTools.defineSchema(TestClass.class); PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { Query q = pm.newQuery(TestClass.class, "_string == Bug"); q.execute(); fail(); } catch (JDOUserException e) { String m = e.getMessage(); assertTrue(m, m.contains("\"")); } try { Query q = pm.newQuery(TestClass.class, "_string == Bug 46"); q.execute(); fail(); } catch (JDOUserException e) { String m = e.getMessage(); assertTrue(m, m.contains("nexpected characters")); } TestTools.closePM(); } @Test public void testQueryIterationWhileModifyingCache() { //also removes indexes and objects TestTools.removeSchema(TestClass.class); TestTools.defineSchema(TestClass.class); TestTools.defineIndex(TestClass.class, "_string", true); PersistenceManager pm = TestTools.openPM(); pm.setIgnoreCache(false); pm.currentTransaction().begin(); TestClass t1 = new TestClass(); t1.setString("1"); pm.makePersistent(t1); pm.currentTransaction().commit(); pm.currentTransaction().begin(); TestClass t2 = new TestClass(); t2.setString("2"); pm.makePersistent(t2); TestClass t3 = new TestClass(); t3.setString("3"); pm.makePersistent(t3); pm.currentTransaction().commit(); pm.currentTransaction().begin(); Query qS = pm.newQuery(TestClass.class, "_string=='1'"); @SuppressWarnings("unchecked") Collection<TestTools> cS = (Collection<TestTools>) qS.execute(); Query qI = pm.newQuery(TestClass.class, "_int==0"); @SuppressWarnings("unchecked") Collection<TestTools> cI = (Collection<TestTools>) qI.execute(); t1.setString("x1"); t2.setString("x2"); t3.setString("x3"); t1.setInt(11); t1.setInt(22); t1.setInt(33); TestClass t4 = new TestClass(); t4.setString("1"); pm.makePersistent(t4); int nS = 0; Iterator<?> itS = cS.iterator(); while (itS.hasNext()) { nS++; itS.next(); } assertEquals(1, nS); int nI = 0; Iterator<?> itI = cI.iterator(); while (itI.hasNext()) { nI++; itI.next(); } //assertEquals(1, nI); //3 implies that the collection was created before the the iterator traversed the objects assertEquals(3, nI); TestTools.closePM(); } /** * The problem is that the query evaluator simply loaded ALL dirty objects from the cache into * the query processor, without checking whether they have the correct class. * * Requires: * - Index on queried class (TestClassTiny) * - no commit after new TestClass instance */ @Test public void testQueryFieldAccess_Issue_53() { TestTools.removeSchema(TestClass.class); TestTools.defineSchema(TestClass.class); //also removes indexes and objects TestTools.removeSchema(TestClassTiny.class); TestTools.defineSchema(TestClassTiny.class); TestTools.defineIndex(TestClassTiny.class, "_int", true); PersistenceManager pm = TestTools.openPM(); pm.setIgnoreCache(false); pm.currentTransaction().begin(); TestClassTiny tt = new TestClassTiny(); tt.setInt(1); pm.makePersistent(tt); pm.currentTransaction().commit(); pm.currentTransaction().begin(); TestClass t4 = new TestClass(); pm.makePersistent(t4); // javax.jdo.JDOFatalInternalException: Cannot access field: _int class="org.zoodb.test.jdo.TestClass", declaring class="org.zoodb.test.jdo.TestClassTiny" // at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) // at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) // at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) // at java.lang.reflect.Constructor.newInstance(Constructor.java:526) // at org.zoodb.internal.util.ReflTools.newInstance(ReflTools.java:211) // at org.zoodb.internal.util.DBLogger.newEx(DBLogger.java:97) // at org.zoodb.internal.util.DBLogger.newEx(DBLogger.java:88) // at org.zoodb.internal.util.DBLogger.newFatalInternal(DBLogger.java:187) // NestedThrowablesStackTrace: // java.lang.IllegalArgumentException: Cannot set int field org.zoodb.test.jdo.TestClassTiny._int to org.zoodb.test.jdo.TestClass // at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164) // at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168) // at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55) // at sun.reflect.UnsafeIntegerFieldAccessorImpl.getInt(UnsafeIntegerFieldAccessorImpl.java:56) // at sun.reflect.UnsafeIntegerFieldAccessorImpl.get(UnsafeIntegerFieldAccessorImpl.java:36) // at java.lang.reflect.Field.get(Field.java:379) // at org.zoodb.internal.query.QueryTerm.evaluate(QueryTerm.java:77) // at org.zoodb.internal.query.QueryTreeNode.evaluate(QueryTreeNode.java:121) // at org.zoodb.jdo.impl.QueryImpl.applyQueryOnExtent(QueryImpl.java:486) // at org.zoodb.jdo.impl.QueryImpl.runQuery(QueryImpl.java:526) // at org.zoodb.jdo.impl.QueryImpl.execute(QueryImpl.java:600) // at org.zoodb.test.jdo.Test_122_QueryBugs.testQueryFieldAccess_IssueXXX2(Test_122_QueryBugs.java:411) Query qtt = pm.newQuery(TestClassTiny.class, "_int==1"); @SuppressWarnings("unchecked") Collection<TestTools> ctt = (Collection<TestTools>) qtt.execute(); assertEquals(1, ctt.size()); TestTools.closePM(); } @Test public void testKeywordsAsFieldsConflicts() { //populate db TestTools.defineSchema(TestJdoqlKeywordFields.class); PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); TestJdoqlKeywordFields pc1 = new TestJdoqlKeywordFields(1, "1"); pm.makePersistent(pc1); TestJdoqlKeywordFields pc2 = new TestJdoqlKeywordFields(2, "2"); pm.makePersistent(pc2); pc1.setRef(pc2); pm.currentTransaction().commit(); TestTools.closePM(); //test pm = TestTools.openPM(); pm.currentTransaction().begin(); //test lhs for (String kw: TestJdoqlKeywordFields.keywordsL) { String q = kw + " == '5' || " + kw + " != '-5'"; pm.newQuery(TestJdoqlKeywordFields.class, q).execute(); } for (String kw: TestJdoqlKeywordFields.keywordsU) { String q = kw + " <= 5 || " + kw + " >= -5"; pm.newQuery(TestJdoqlKeywordFields.class, q).execute(); } //test rhs for (String kw: TestJdoqlKeywordFields.keywordsL) { String q = "'5' == " + kw + " || '-5' != " + kw; pm.newQuery(TestJdoqlKeywordFields.class, q).execute(); } for (String kw: TestJdoqlKeywordFields.keywordsU) { String q = "5 <= " + kw + " || 5 >= " + kw; pm.newQuery(TestJdoqlKeywordFields.class, q).execute(); } //test functions for (String kw: TestJdoqlKeywordFields.keywordsL) { String q = kw + ".length() <= 3 || 'gg' == " + kw + ".substring(3)"; pm.newQuery(TestJdoqlKeywordFields.class, q).execute(); } //TODO System.err.println("Disable Test_111 because '+' not yet supported"); // for (String kw: TestJdoqlKeywordFields.keywordsU) { // String q = "Math.abs(" + kw + ") <= 5 || 3 >= (1+" + kw + ")"; // pm.newQuery(TestJdoqlKeywordFields.class, q).execute(); // } //test ref (especially .substring, etc. String q; q = "ref.substring.length() <= 3 || 'gg' == ref.substring.substring(3)"; pm.newQuery(TestJdoqlKeywordFields.class, q).execute(); //TODO System.err.println("Disable Test_111 because '+' not yet supported"); // q = "Math.abs(ref.MATH) <= 5 || 3 >= (1+ref.MATH)"; // pm.newQuery(TestJdoqlKeywordFields.class, q).execute(); pm.currentTransaction().rollback(); TestTools.closePM(); } @Test public void testParsing1() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "<=<dcontains0or.'"); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage().contains("unexpected end")); } } @Test public void testParsing2() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "!=.isEmpty,this,9or0contains Lcontains<= &(and.contains("); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage(), e.getMessage().contains("omparator expected")); } } @Test public void testParsing3() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "0bd00xLget|0b1this<=.(or\\"); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage().contains("Cannot parse query")); } } @Test public void testParsing4() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "this"); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage(), e.getMessage().contains("nexpected end")); } } @Test public void testParsing5() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "d<=::0!& .contains("); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage(), e.getMessage().contains("parsing error")); } } @Test public void testParsing6() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, " "); q.execute(); } @Test public void testParsing7() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "containsand!='get&0x^;f<=! isEmpty>this'"); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage().contains("arsing error")); } } @Test public void testParsing8() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "0!=::|~!="); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage(), e.getMessage().contains("arsing error")); } } @Test public void testParsing9() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "_float<=_bool"); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage().contains("annot compare")); } } @Test public void testParsing10() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "_bool<=0"); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage().contains("annot compare")); } } @Test public void testParsing11() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, ":_long0x!=_bool"); q.execute(0); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage(), e.getMessage().contains("ncomparable types")); } } @Test public void testParsing12() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, ":my_str.substring(1,3)=='xx'"); q.execute("Hello"); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage(), e.getMessage().contains("ate binding")); } } @Test public void testParsing13() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "(:my_str).substring(1,3)=='xx'"); q.execute("Hello"); fail(); } catch (JDOUserException e) { //good //TODO maybe this should actually work?? //assertTrue(e.getMessage(), e.getMessage().contains("ate binding")); } } @Test public void testParsing14() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "\"_isEmpty\">_bool"); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage(), e.getMessage().contains("annot compare")); } } @Test public void testParsing15() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "_intObj>_long"); q.execute(); } @Test public void testParsing16() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //this was found by the fuzzying tool Query q = pm.newQuery(TestClass.class, "0>=0b9"); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage(), e.getMessage().contains("parsing number")); } } @Test public void testParsing17() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //This wrongly recognized 'null' as null Query q = pm.newQuery(TestClass.class, "_ref2 == 'null'"); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage(), e.getMessage().contains("ncompatible types")); } } @Test public void testParsing18() { PersistenceManager pm = TestTools.openPM(); pm.currentTransaction().begin(); try { //This wrongly compiled Query q = pm.newQuery(TestClass.class, "_ref2 > _ref1"); q.execute(); fail(); } catch (JDOUserException e) { //good assertTrue(e.getMessage(), e.getMessage().contains("llegal operator")); } } }