/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2015, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotools.jdbc; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import org.geotools.data.Join; import org.geotools.data.Join.Type; import org.geotools.data.Query; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.data.store.ContentDataStore; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import org.opengis.filter.FilterFactory2; import org.opengis.filter.sort.SortBy; import org.opengis.filter.sort.SortOrder; public abstract class JDBCJoinOnlineTest extends JDBCTestSupport { @Override protected abstract JDBCJoinTestSetup createTestSetup(); public void testSimpleJoin() throws Exception { doTestSimpleJoin(false); doTestSimpleJoin(true); } public void testJoinSchema() throws Exception { FilterFactory ff = dataStore.getFilterFactory(); Query q = new Query(tname("ft1")); Join join = new Join(tname("ftjoin"), ff.equal(ff.property(aname("stringProperty")), ff.property(aname("name")), true)); join.setAlias("b"); q.getJoins().add(join); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); SimpleFeatureType schema = features.getSchema(); AttributeDescriptor ad = schema.getDescriptor("b"); assertNotNull(ad); assertEquals(SimpleFeature.class, ad.getType().getBinding()); SimpleFeatureType joinedSchema = (SimpleFeatureType) ad.getUserData() .get(ContentDataStore.JOINED_FEATURE_TYPE); assertEquals(dataStore.getSchema(tname("ftjoin")), joinedSchema); } void doTestSimpleJoin(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); try (SimpleFeatureIterator ita = dataStore.getFeatureSource(tname("ft1")).getFeatures() .features()) { try (SimpleFeatureIterator itb = dataStore.getFeatureSource(tname("ftjoin")) .getFeatures().features()) { FilterFactory ff = dataStore.getFilterFactory(); Query q = new Query(tname("ft1")); q.getJoins() .add(new Join(tname("ftjoin"), ff.equal(ff.property(aname("stringProperty")), ff.property(aname("name")), true))); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")) .getFeatures(q); assertEquals(dataStore.getFeatureSource(tname("ft1")).getFeatures(q).size(), features.size()); try (SimpleFeatureIterator it = features.features()) { assertTrue(it.hasNext() && ita.hasNext() && itb.hasNext()); while (it.hasNext()) { SimpleFeature f = it.next(); assertEquals(5 + (exposePrimaryKeys ? 1 : 0), f.getAttributeCount()); SimpleFeature g = (SimpleFeature) f.getAttribute(tname("ftjoin")); SimpleFeature a = ita.next(); SimpleFeature b = itb.next(); for (int i = 0; i < a.getAttributeCount(); i++) { assertAttributeValuesEqual(a.getAttribute(i), f.getAttribute(i)); } for (int i = 0; i < b.getAttributeCount(); i++) { assertAttributeValuesEqual(b.getAttribute(i), g.getAttribute(i)); } } } } } } public void testSimpleJoinOnPrimaryKey() throws Exception { dataStore.setExposePrimaryKeyColumns(true); try( SimpleFeatureIterator ita = dataStore.getFeatureSource(tname("ft1")).getFeatures() .features(); SimpleFeatureIterator itb = dataStore.getFeatureSource(tname("ftjoin")).getFeatures() .features()) { FilterFactory ff = dataStore.getFilterFactory(); Query q = new Query(tname("ft1")); Join join = new Join(tname("ftjoin"), ff.equal(ff.property(aname("id")), ff.property(aname("ftjoin.id")), true)); join.setAlias(tname("ftjoin")); q.getJoins().add(join); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(dataStore.getFeatureSource(tname("ft1")).getFeatures(q).size(), features.size()); try(SimpleFeatureIterator it = features.features()) { assertTrue(it.hasNext() && ita.hasNext() && itb.hasNext()); while (it.hasNext()) { SimpleFeature f = it.next(); assertEquals(6, f.getAttributeCount()); SimpleFeature g = (SimpleFeature) f.getAttribute(tname("ftjoin")); SimpleFeature a = ita.next(); SimpleFeature b = itb.next(); for (int i = 0; i < a.getAttributeCount(); i++) { assertAttributeValuesEqual(a.getAttribute(i), f.getAttribute(i)); } for (int i = 0; i < b.getAttributeCount(); i++) { assertAttributeValuesEqual(b.getAttribute(i), g.getAttribute(i)); } } } } } public void testSimpleJoinInvertedAliases() throws Exception { doTestSimpleJoinInvertedAliases(false); doTestSimpleJoinInvertedAliases(true); } void doTestSimpleJoinInvertedAliases(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); try(SimpleFeatureIterator ita = dataStore.getFeatureSource(tname("ft1")).getFeatures() .features(); SimpleFeatureIterator itb = dataStore.getFeatureSource(tname("ftjoin")).getFeatures() .features()) { FilterFactory ff = dataStore.getFilterFactory(); Query q = new Query(tname("ft1")); q.setAlias("b"); Join join = new Join(tname("ftjoin"), ff.equal(ff.property(aname("stringProperty")), ff.property(aname("name")), true)); join.setAlias("a"); q.getJoins().add(join); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(dataStore.getFeatureSource(tname("ft1")).getFeatures(q).size(), features.size()); try(SimpleFeatureIterator it = features.features()) { assertTrue(it.hasNext() && ita.hasNext() && itb.hasNext()); while (it.hasNext()) { SimpleFeature f = it.next(); assertEquals(5 + (exposePrimaryKeys ? 1 : 0), f.getAttributeCount()); SimpleFeature g = (SimpleFeature) f.getAttribute("a"); SimpleFeature a = ita.next(); SimpleFeature b = itb.next(); for (int i = 0; i < a.getAttributeCount(); i++) { assertAttributeValuesEqual(a.getAttribute(i), f.getAttribute(i)); } for (int i = 0; i < b.getAttributeCount(); i++) { assertAttributeValuesEqual(b.getAttribute(i), g.getAttribute(i)); } } } } } public void testSimpleJoinWithFilter() throws Exception { doTestSimpleJoinWithFilter(false); doTestSimpleJoinWithFilter(true); } void doTestSimpleJoinWithFilter(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory ff = dataStore.getFilterFactory(); Query q = new Query(tname("ft1")); q.getJoins().add(new Join(tname("ftjoin"), ff.equal(ff.property(aname("stringProperty")), ff.property(aname("name")), true))); q.setFilter(ff.equal(ff.property(aname("stringProperty")), ff.literal("two"), true)); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(1, features.size()); try(SimpleFeatureIterator it = features.features()) { SimpleFeature f = it.next(); assertEquals(5 + (exposePrimaryKeys ? 1 : 0), f.getAttributeCount()); assertEquals(2, ((Number)f.getAttribute(aname("intProperty"))).intValue()); assertEquals("two", f.getAttribute(aname("stringProperty"))); SimpleFeature g = (SimpleFeature) f.getAttribute(aname("ftjoin")); assertEquals(3 + (exposePrimaryKeys ? 1 : 0), g.getAttributeCount()); if (exposePrimaryKeys) { assertEquals(2, ((Number) g.getAttribute(aname("id"))).intValue()); } assertEquals("two", g.getAttribute(aname("name"))); } } public void testSimpleJoinWithFilterNoProperties() throws Exception { doTestSimpleJoinWithFilterNoProperties(false); doTestSimpleJoinWithFilterNoProperties(true); } void doTestSimpleJoinWithFilterNoProperties(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory ff = dataStore.getFilterFactory(); Query q = new Query(tname("ft1")); Join j = new Join(tname("ftjoin"), ff.equal(ff.property(aname("stringProperty")), ff.property(aname("name")), true)); j.setProperties(Query.NO_PROPERTIES); q.getJoins().add(j); q.setFilter(ff.equal(ff.property(aname("stringProperty")), ff.literal("two"), true)); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(1, features.size()); try(SimpleFeatureIterator it = features.features()) { SimpleFeature f = it.next(); assertEquals(5 + (exposePrimaryKeys ? 1 : 0), f.getAttributeCount()); assertEquals(2, ((Number)f.getAttribute(aname("intProperty"))).intValue()); assertEquals("two", f.getAttribute(aname("stringProperty"))); SimpleFeature g = (SimpleFeature) f.getAttribute(aname("ftjoin")); assertEquals(0, g.getAttributeCount()); } } public void testSimpleJoinWithFilterCount() throws Exception { doTestSimpleJoinWithFilterCount(false); doTestSimpleJoinWithFilterCount(true); } void doTestSimpleJoinWithFilterCount(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory ff = dataStore.getFilterFactory(); Query q = new Query(tname("ft1")); Join j = new Join(tname("ftjoin"), ff.equal(ff.property(aname("stringProperty")), ff.property(aname("name")), true)); j.filter(ff.greater(ff.property(aname("join1intProperty")), ff.literal(1))); q.getJoins().add(j); q.setFilter(ff.less(ff.property(aname("intProperty")), ff.literal(3))); assertEquals(1, dataStore.getFeatureSource(tname("ft1")).getCount(q)); } public void testSimpleJoinWithPostFilter() throws Exception { doTestSimpleJoinWithPostFilter(false); doTestSimpleJoinWithPostFilter(true); } void doTestSimpleJoinWithPostFilter(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory ff = dataStore.getFilterFactory(); Filter j = ff.equal(ff.property(aname("stringProperty")), ff.property(aname("name")), true); Query q = new Query(tname("ft1")); q.getJoins().add(new Join(tname("ftjoin"), j)); q.setFilter(ff.equal( ff.function("__equals", ff.property(aname("stringProperty")), ff.literal("one")), ff.literal(true), true)); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(1, features.size()); //test with post filter on table being joined q = new Query(tname("ft1")); Join join = new Join(tname("ftjoin"), j); join.filter(ff.equal( ff.function("__equals", ff.property(aname("name")), ff.literal("one")), ff.literal(true), true)); q.getJoins().add(join); features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(1, features.size()); } public void testSimpleJoinWithPostFilterNoProperties() throws Exception { doTestSimpleJoinWithPostFilterNoProperties(false); doTestSimpleJoinWithPostFilterNoProperties(true); } void doTestSimpleJoinWithPostFilterNoProperties(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory ff = dataStore.getFilterFactory(); Filter j = ff.equal(ff.property(aname("stringProperty")), ff.property(aname("name")), true); Query q = new Query(tname("ft1")); Join join = new Join(tname("ftjoin"), j); join.setProperties(Query.NO_PROPERTIES); q.getJoins().add(join); q.setFilter(ff.equal( ff.function("__equals", ff.property(aname("stringProperty")), ff.literal("one")), ff.literal(true), true)); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(1, features.size()); //test with post filter on table being joined q = new Query(tname("ft1")); join = new Join(tname("ftjoin"), j); join.setProperties(Query.NO_PROPERTIES); join.filter(ff.equal( ff.function("__equals", ff.property(aname("name")), ff.literal("one")), ff.literal(true), true)); q.getJoins().add(join); features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(1, features.size()); } public void testSimpleJoinWithSort() throws Exception { doTestSimpleJoinWithSort(false); doTestSimpleJoinWithSort(true); } void doTestSimpleJoinWithSort(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory ff = dataStore.getFilterFactory(); Filter j = ff.equal(ff.property(aname("stringProperty")), ff.property(aname("name")), true); Query q = new Query(tname("ft1")); q.getJoins().add(new Join(tname("ftjoin"), j)); q.setSortBy(new SortBy[]{ff.sort(aname("intProperty"), SortOrder.DESCENDING)}); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); try(SimpleFeatureIterator it = features.features()) { assertTrue(it.hasNext()); assertEquals("two", it.next().getAttribute(aname("stringProperty"))); assertTrue(it.hasNext()); assertEquals("one", it.next().getAttribute(aname("stringProperty"))); assertTrue(it.hasNext()); assertEquals("zero", it.next().getAttribute(aname("stringProperty"))); } } public void testSimpleJoinWithLimitOffset() throws Exception { doTestSimpleJoinWithLimitOffset(false); doTestSimpleJoinWithLimitOffset(true); } void doTestSimpleJoinWithLimitOffset(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory ff = dataStore.getFilterFactory(); Filter j = ff.equal(ff.property(aname("stringProperty")), ff.property(aname("name")), true); Query q = new Query(tname("ft1")); q.getJoins().add(new Join(tname("ftjoin"), j)); q.setFilter(ff.greater(ff.property(aname("intProperty")), ff.literal(0))); q.setStartIndex(1); q.setSortBy(new SortBy[]{ff.sort(aname("intProperty"), SortOrder.ASCENDING)}); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(1, features.size()); try(SimpleFeatureIterator it = features.features()) { assertTrue(it.hasNext()); SimpleFeature f = it.next(); assertEquals("two", f.getAttribute(aname("stringProperty"))); SimpleFeature g = (SimpleFeature) f.getAttribute(aname("ftjoin")); assertEquals("two", g.getAttribute(aname("name"))); } } public void testSelfJoin() throws Exception { doTestSelfJoin(false); doTestSelfJoin(true); } public void doTestSelfJoin(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory ff = dataStore.getFilterFactory(); Query q = new Query(tname("ft1")); q.getJoins().add(new Join(tname("ft1"), ff.equal(ff.property(aname("intProperty")), ff.property(aname("foo.intProperty")), true)).alias(aname("foo"))); q.setFilter(ff.equal(ff.property(aname("stringProperty")), ff.literal("two"), true)); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(1, features.size()); try(SimpleFeatureIterator it = features.features()) { assertTrue(it.hasNext()); SimpleFeature f = it.next(); assertEquals(5 + (exposePrimaryKeys ? 1 : 0), f.getAttributeCount()); assertEquals(2, ((Number)f.getAttribute(aname("intProperty"))).intValue()); assertEquals("two", f.getAttribute(aname("stringProperty"))); SimpleFeature g = (SimpleFeature) f.getAttribute(aname("foo")); assertEquals(4 + (exposePrimaryKeys ? 1 : 0), g.getAttributeCount()); assertEquals(2, ((Number)g.getAttribute(aname("intProperty"))).intValue()); assertEquals("two", g.getAttribute(aname("stringProperty"))); } } public void testSpatialJoin() throws Exception { // doTestSpatialJoin(false); doTestSpatialJoin(true); } void doTestSpatialJoin(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory2 ff = (FilterFactory2) dataStore.getFilterFactory(); Query q = new Query(tname("ft1")); q.setPropertyNames(Arrays.asList(aname("geometry"), aname("intProperty"))); q.setSortBy(new SortBy[]{ff.sort(aname("intProperty"), SortOrder.ASCENDING)}); q.getJoins().add(new Join(tname("ftjoin"), ff.contains(ff.property(aname("geom")), ff.property(aname("geometry"))))); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ft1")).getFeatures(q); assertEquals(6, features.size()); try(SimpleFeatureIterator it = features.features()) { SimpleFeature f; Set<String> s = new HashSet<String>(Arrays.asList("zero", "one", "two")); assertTrue(it.hasNext()); f = it.next(); assertEquals(0, ((Number)f.getAttribute(aname("intProperty"))).intValue()); s.remove(((SimpleFeature)f.getAttribute(tname("ftjoin"))).getAttribute(aname("name"))); assertTrue(it.hasNext()); f = it.next(); assertEquals(0, ((Number)f.getAttribute(aname("intProperty"))).intValue()); s.remove(((SimpleFeature)f.getAttribute(tname("ftjoin"))).getAttribute(aname("name"))); assertTrue(it.hasNext()); f = it.next(); assertEquals(0, ((Number)f.getAttribute(aname("intProperty"))).intValue()); s.remove(((SimpleFeature)f.getAttribute(tname("ftjoin"))).getAttribute(aname("name"))); assertEquals(0, s.size()); s = new HashSet<String>(Arrays.asList("one", "two")); assertTrue(it.hasNext()); f = it.next(); assertEquals(1, ((Number)f.getAttribute(aname("intProperty"))).intValue()); s.remove(((SimpleFeature)f.getAttribute(tname("ftjoin"))).getAttribute(aname("name"))); assertTrue(it.hasNext()); f = it.next(); assertEquals(1, ((Number)f.getAttribute(aname("intProperty"))).intValue()); s.remove(((SimpleFeature)f.getAttribute(tname("ftjoin"))).getAttribute(aname("name"))); assertEquals(0, s.size()); assertTrue(it.hasNext()); f = it.next(); assertEquals(2, ((Number)f.getAttribute(aname("intProperty"))).intValue()); assertEquals("two", ((SimpleFeature)f.getAttribute(tname("ftjoin"))).getAttribute(aname("name"))); assertFalse(it.hasNext()); } } public void testOuterJoin() throws Exception { doTestOuterJoin(false); doTestOuterJoin(true); } void doTestOuterJoin(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory ff = dataStore.getFilterFactory(); Query q = new Query(tname("ftjoin")); q.getJoins().add(new Join(tname("ft1"), ff.equal(ff.property(aname("name")), ff.property(aname("stringProperty")), true)).type(Type.OUTER)); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ftjoin")).getFeatures(q); assertEquals(dataStore.getFeatureSource(tname("ftjoin")).getFeatures(q).size(), features.size()); try(SimpleFeatureIterator it = features.features()) { while(it.hasNext()) { SimpleFeature f = it.next(); assertEquals(4 + (exposePrimaryKeys ? 1 : 0), f.getAttributeCount()); SimpleFeature g = (SimpleFeature) f.getAttribute(tname("ft1")); if ("three".equals(f.getAttribute(aname("name")))) { assertNull(g); } else { assertNotNull(g); } } } } public void testJoinMoreThanTwo() throws Exception { doJoinMoreThanTwo(false); doJoinMoreThanTwo(true); } void doJoinMoreThanTwo(boolean exposePrimaryKeys) throws Exception { dataStore.setExposePrimaryKeyColumns(exposePrimaryKeys); FilterFactory ff = dataStore.getFilterFactory(); Query q = new Query(tname("ftjoin")); q.getJoins().add(new Join(tname("ft1"), ff.equal(ff.property(aname("name")), ff.property(aname("stringProperty")), true))); q.getJoins().add(new Join(tname("ftjoin2"), ff.equal(ff.property(aname("join2intProperty")), ff.property(aname("join1intProperty")), true))); SimpleFeatureCollection features = dataStore.getFeatureSource(tname("ftjoin")).getFeatures(q); assertEquals(3, features.size()); try(SimpleFeatureIterator it = features.features()) { String[] ft1StringProp = new String[]{"zero","one","two"}; String[] ftjoin2StringProp = new String[]{"2nd zero","2nd one","2nd two"}; while(it.hasNext()) { SimpleFeature f = it.next(); assertEquals(5 + (exposePrimaryKeys ? 1 : 0), f.getAttributeCount()); Number nmb = (Number) f.getAttribute(aname("join1intProperty")); Integer idx = nmb.intValue(); assertTrue(idx < 3); SimpleFeature g = (SimpleFeature) f.getAttribute(tname("ft1")); assertNotNull(g); assertEquals(ft1StringProp[idx], g.getAttribute(aname("stringProperty"))); g = (SimpleFeature) f.getAttribute(tname("ftjoin2")); assertNotNull(g); assertEquals(ftjoin2StringProp[idx], g.getAttribute(aname("stringProperty2"))); } } } }