/**
* OrbisGIS is a java GIS application dedicated to research in GIScience.
* OrbisGIS is developed by the GIS group of the DECIDE team of the
* Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>.
*
* The GIS group of the DECIDE team is located at :
*
* Laboratoire Lab-STICC – CNRS UMR 6285
* Equipe DECIDE
* UNIVERSITÉ DE BRETAGNE-SUD
* Institut Universitaire de Technologie de Vannes
* 8, Rue Montaigne - BP 561 56017 Vannes Cedex
*
* OrbisGIS is distributed under GPL 3 license.
*
* Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488)
* Copyright (C) 2015-2017 CNRS (Lab-STICC UMR CNRS 6285)
*
* This file is part of OrbisGIS.
*
* OrbisGIS 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.
*
* OrbisGIS 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
* OrbisGIS. If not, see <http://www.gnu.org/licenses/>.
*
* For more information, please consult: <http://www.orbisgis.org/>
* or contact directly:
* info_at_ orbisgis.org
*/
package org.orbisgis.corejdbc;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.GeometryFactory;
import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import javax.sql.DataSource;
import org.h2gis.functions.factory.H2GISDBFactory;
import org.h2gis.functions.factory.H2GISFunctions;
import org.h2gis.functions.io.DriverManager;
import org.h2gis.utilities.JDBCUtilities;
import org.h2gis.utilities.SFSUtilities;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.BeforeClass;
import org.junit.Test;
import org.orbisgis.corejdbc.common.LongUnion;
import org.orbisgis.corejdbc.internal.DataManagerImpl;
import org.orbisgis.commons.progress.NullProgressMonitor;
/**
* @author Nicolas Fortin
*/
public class JDBCUtilityTest {
private static DataSource dataSource;
private static Connection connection;
@BeforeClass
public static void tearUp() throws Exception {
dataSource = SFSUtilities.wrapSpatialDataSource(H2GISDBFactory.createDataSource(JDBCUtilityTest.class.getSimpleName(), true));
connection = dataSource.getConnection();
H2GISFunctions.registerFunction(connection.createStatement(), new DriverManager(), "");
}
@AfterClass
public static void tearDown() throws Exception {
if(connection!=null) {
connection.close();
}
}
@Test
public void sortTest() throws SQLException {
DataManager factory = new DataManagerImpl(dataSource);
try(Statement st = connection.createStatement()) {
st.execute("DROP TABLE INTTABLE IF EXISTS");
try {
// Test without PK
st.execute("CREATE TABLE INTTABLE (\"vals\" integer)");
st.execute("INSERT INTO INTTABLE VALUES (20), (5), (15), (4), (1)");
// Create original order resultset
ReadRowSet readRowSet = factory.createReadRowSet();
readRowSet.setCommand("SELECT * FROM INTTABLE");
readRowSet.execute();
// Test ascending
Collection<Integer> sortedRowId = ReadTable.getSortedColumnRowIndex(connection, readRowSet, "INTTABLE", "vals", true, new NullProgressMonitor());
Iterator<Integer> itTest = sortedRowId.iterator();
assertEquals(5, itTest.next().intValue());
assertEquals(4, itTest.next().intValue());
assertEquals(2, itTest.next().intValue());
assertEquals(3, itTest.next().intValue());
assertEquals(1, itTest.next().intValue());
// Test descending
sortedRowId = ReadTable.getSortedColumnRowIndex(connection, readRowSet, "INTTABLE", "vals", false, new NullProgressMonitor());
itTest = sortedRowId.iterator();
assertEquals(1, itTest.next().intValue());
assertEquals(3, itTest.next().intValue());
assertEquals(2, itTest.next().intValue());
assertEquals(4, itTest.next().intValue());
assertEquals(5, itTest.next().intValue());
readRowSet.close();
} finally {
st.execute("DROP TABLE INTTABLE IF EXISTS");
}
st.execute("DROP TABLE INTTABLE IF EXISTS");
try {
// Test with PK
st.execute("CREATE TABLE INTTABLE (id integer primary key, \"vals\" integer)");
st.execute("INSERT INTO INTTABLE VALUES (1,20), (2,5), (4,15), (8,4), (16,1)");
// Create original order resultset
ReadRowSet readRowSet = factory.createReadRowSet();
readRowSet.setCommand("SELECT * FROM INTTABLE");
readRowSet.execute();
// Test ascending
Collection<Integer> sortedRowId = ReadTable.getSortedColumnRowIndex(connection, readRowSet, "INTTABLE", "vals", true, new NullProgressMonitor());
Iterator<Integer> itTest = sortedRowId.iterator();
assertEquals(5, itTest.next().intValue());
assertEquals(4, itTest.next().intValue());
assertEquals(2, itTest.next().intValue());
assertEquals(3, itTest.next().intValue());
assertEquals(1, itTest.next().intValue());
// Test descending
sortedRowId = ReadTable.getSortedColumnRowIndex(connection, readRowSet, "INTTABLE", "vals", false, new NullProgressMonitor());
itTest = sortedRowId.iterator();
assertEquals(1, itTest.next().intValue());
assertEquals(3, itTest.next().intValue());
assertEquals(2, itTest.next().intValue());
assertEquals(4, itTest.next().intValue());
assertEquals(5, itTest.next().intValue());
readRowSet.close();
} finally {
st.execute("DROP TABLE inttable IF EXISTS");
}
}
}
@Test
public void testSortNullPk() throws SQLException {
DataManager factory = new DataManagerImpl(dataSource);
try(Statement st = connection.createStatement()) {
st.execute("DROP TABLE INTTABLE IF EXISTS");
st.execute("CREATE TABLE INTTABLE (id integer primary key, \"vals\" integer)");
st.execute("INSERT INTO INTTABLE VALUES (1,20), (2,null), (4,15), (8,4), (16,null)");
// Create original order resultset
ReadRowSet readRowSet = factory.createReadRowSet();
readRowSet.setCommand("SELECT * FROM INTTABLE");
readRowSet.execute();
// Test ascending
Collection<Integer> sortedRowId = ReadTable.getSortedColumnRowIndex(connection,readRowSet, "INTTABLE", "vals", true, new NullProgressMonitor());
Iterator<Integer> itTest = sortedRowId.iterator();
assertEquals(2, itTest.next().intValue());
assertEquals(5, itTest.next().intValue());
assertEquals(4, itTest.next().intValue());
assertEquals(3, itTest.next().intValue());
assertEquals(1, itTest.next().intValue());
// Test descending
sortedRowId = ReadTable.getSortedColumnRowIndex(connection, readRowSet, "INTTABLE", "vals", false, new NullProgressMonitor());
itTest = sortedRowId.iterator();
assertEquals(1, itTest.next().intValue());
assertEquals(3, itTest.next().intValue());
assertEquals(4, itTest.next().intValue());
assertEquals(2, itTest.next().intValue());
assertEquals(5, itTest.next().intValue());
readRowSet.close();
}
}
@Test
public void testSortNullNoPk() throws SQLException {
DataManager factory = new DataManagerImpl(dataSource);
try(Statement st = connection.createStatement()) {
st.execute("DROP TABLE INTTABLE IF EXISTS");
st.execute("CREATE TABLE INTTABLE (\"vals\" integer)");
st.execute("INSERT INTO INTTABLE VALUES (20), (null), (15), (4), (null)");
// Create original order resultset
ReadRowSet readRowSet = factory.createReadRowSet();
readRowSet.setCommand("SELECT * FROM INTTABLE");
readRowSet.execute();
// Test ascending
Collection<Integer> sortedRowId = ReadTable.getSortedColumnRowIndex(connection,readRowSet, "INTTABLE", "vals", true, new NullProgressMonitor());
Iterator<Integer> itTest = sortedRowId.iterator();
assertEquals(2, itTest.next().intValue());
assertEquals(5, itTest.next().intValue());
assertEquals(4, itTest.next().intValue());
assertEquals(3, itTest.next().intValue());
assertEquals(1, itTest.next().intValue());
// Test descending
sortedRowId = ReadTable.getSortedColumnRowIndex(connection,readRowSet, "INTTABLE", "vals", false, new NullProgressMonitor());
itTest = sortedRowId.iterator();
assertEquals(1, itTest.next().intValue());
assertEquals(3, itTest.next().intValue());
assertEquals(4, itTest.next().intValue());
assertEquals(5, itTest.next().intValue());
assertEquals(2, itTest.next().intValue());
readRowSet.close();
}
}
private static void checkStats(String[] props) {
assertEquals(0, Double.valueOf(props[ReadTable.STATS.MIN.ordinal()]).intValue());
assertEquals(78, Double.valueOf(props[ReadTable.STATS.MAX.ordinal()]).intValue());
assertEquals(19.5, Double.valueOf(props[ReadTable.STATS.AVG.ordinal()]),1e-12);
assertEquals(10, Double.valueOf(props[ReadTable.STATS.COUNT.ordinal()]).intValue());
assertEquals(24.998888864196434, Double.valueOf(props[ReadTable.STATS.STDDEV_SAMP.ordinal()]),1e-15);
assertEquals(195, Double.valueOf(props[ReadTable.STATS.SUM.ordinal()]).intValue());
}
@Test
public void testStats() throws SQLException {
Set<Long> indexes = new TreeSet<>(Arrays.asList(new Long[]{0l, 2l, 3l, 4l, 8l, 10l, 15l, 30l, 45l, 78l}));
try(Statement st = connection.createStatement()) {
String table = CreateTable.createIndexTempTable(connection, new NullProgressMonitor(), indexes,"ROWID", 5);
// Do stats using sql
String[] props = ReadTable.computeStatsSQL(connection, table, "ROWID", new NullProgressMonitor());
checkStats(props);
// Do stats using apache math
props = ReadTable.computeStatsLocal(connection, table, "ROWID",getSortedSet(1,11) , new NullProgressMonitor());
checkStats(props);
st.execute("DROP TABLE "+table);
}
}
private static SortedSet<Integer> getSortedSet(int begin,int end) {
SortedSet<Integer> set = new TreeSet<>();
for(int i = begin; i < end; i++) {
set.add(i);
}
return set;
}
@Test
public void testSelection() throws SQLException {
DataManager dataManager = new DataManagerImpl(dataSource);
try(Statement st = connection.createStatement()) {
st.execute("DROP TABLE IF EXISTS TEST");
st.execute("CREATE TABLE TEST(gid integer primary key auto_increment, geom MULTIPOLYGON)");
st.execute("INSERT INTO TEST(geom) VALUES ('MULTIPOLYGON (((-111 -24, -121 17, -69 25, -66 -38, -111 -24)))'), " +
"('MULTIPOLYGON (((-50 -2, -59 50, 48 48, -20 20, -50 -2)))'), " +
"('MULTIPOLYGON (((-75 -67, -38 -16, 44 24, 99 26, 112 4, -35 -79, -75 -67)))');");
// Check selection algorithm
Envelope envelope = new Envelope(-116, -55, -69, -19);
Set<Long> intersected = ReadTable.getTablePkByEnvelope(dataManager, "TEST", "GEOM", new GeometryFactory().toGeometry(envelope),
false);
LongUnion rowIds = new LongUnion(intersected);
Iterator<Long> it = rowIds.iterator();
assertEquals(1 ,it.next().intValue());
assertEquals(3 ,it.next().intValue());
assertFalse(it.hasNext());
}
}
@Test
public void testColumnInfos() throws SQLException {
Locale oldLocale = Locale.getDefault();
Locale.setDefault(Locale.ENGLISH);
try(Statement st = connection.createStatement()) {
st.execute("DROP TABLE IF EXISTS TESTMETA");
st.execute("CREATE TABLE TESTMETA(gid integer primary key auto_increment, geom MULTIPOLYGON, value double)");
st.execute("ALTER TABLE TESTMETA ADD CHECK (value > 5)");
}
String meta = MetaData.getColumnInformations(connection.getMetaData(), "TESTMETA", 1);
assertTrue(meta.startsWith("\n" +
"Field name :\tGID\n" +
"Field type :\tINTEGER\n" +
"Size :\t10\n" +
"Decimal digits :\t0\n" +
"Nullable : NO\n" +
"Default value :\t(NEXT VALUE FOR PUBLIC."));
assertTrue(meta.endsWith("Auto increment :\tYES\n" +
"Constraints :\n" +
"\tType :\tother index\n"));
meta = MetaData.getColumnInformations(connection.getMetaData(), "TESTMETA", 2);
assertEquals("\n" +
"Field name :\tGEOM\n" +
"Field type :\tGEOMETRY\n" +
"Size :\t6\n" +
"Decimal digits :\t0\n" +
"Nullable : allows NULL values\n" +
"Default value :\tnull\n" +
"Auto increment :\tNO\n" +
"Constraints :\n", meta);
meta = MetaData.getColumnInformations(connection.getMetaData(), "TESTMETA", 3);
assertEquals("\n" +
"Field name :\tVALUE\n" +
"Field type :\tDOUBLE\n" +
"Size :\t17\n" +
"Decimal digits :\t0\n" +
"Nullable : allows NULL values\n" +
"Default value :\tnull\n" +
"Auto increment :\tNO\n" +
"Constraints :\n", meta);
Locale.setDefault(oldLocale);
}
@Test
public void pkTest() throws SQLException {
try(Statement st = connection.createStatement()) {
st.execute("DROP TABLE IF EXISTS TEST");
st.execute("CREATE TABLE TEST(gid integer auto_increment, geom MULTIPOLYGON)");
assertEquals("_ROWID_", MetaData.getPkName(connection, "TEST", true));
}
}
@Test
public void testTableType() throws SQLException {
try(Statement st = connection.createStatement()) {
st.execute("DROP TABLE IF EXISTS TABLE_TEST");
st.execute("CREATE TABLE TABLE_TEST(gid integer auto_increment)");
assertEquals(MetaData.getTableType(connection, "TABLE_TEST"), MetaData.TableType.TABLE);
st.execute("DROP TABLE IF EXISTS TABLE_GLOBAL");
st.execute("CREATE GLOBAL TEMPORARY TABLE TABLE_GLOBAL(gid integer auto_increment)");
//H2 database type is limited
assertEquals(MetaData.getTableType(connection, "TABLE_GLOBAL"), MetaData.TableType.TABLE);
st.execute("DROP VIEW IF EXISTS VIEW_TEST");
st.execute("CREATE VIEW VIEW_TEST as SELECT * FROM TABLE_TEST");
assertEquals(MetaData.getTableType(connection, "VIEW_TEST"), MetaData.TableType.VIEW);
st.execute("drop table if exists EXTERNAL_TABLE");
try {
st.execute("CALL FILE_TABLE('" + JDBCUtilityTest.class.getResource("bv_sap.shp").getPath() + "', 'EXTERNAL_TABLE');");
assertEquals(MetaData.getTableType(connection, "EXTERNAL_TABLE"), MetaData.TableType.EXTERNAL);
} finally {
st.execute("drop table if exists EXTERNAL_TABLE");
}
}
}
@Test
public void testTableCreateFromPK() throws SQLException {
try(Statement st = connection.createStatement()) {
st.execute("DROP TABLE IF EXISTS INTTABLE, INTTABLE_SEL");
st.execute("CREATE TABLE INTTABLE (pk bigint primary key, \"vals\" integer)");
st.execute("INSERT INTO INTTABLE VALUES (1, 20), (2, 5), (3, 15), (4, 4), (5, 1)");
CreateTable.createTableFromRowPkSelection(dataSource, "INTTABLE", new HashSet<>(Arrays.asList(1l, 3l, 5l)),
"INTTABLE_SEL",new NullProgressMonitor());
try(ResultSet rs = st.executeQuery("SELECT \"vals\" FROM INTTABLE_SEL")) {
assertTrue(rs.next());
assertEquals(20, rs.getInt(1));
assertTrue(rs.next());
assertEquals(15, rs.getInt(1));
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
}
}
}
/**
* Given a file path, test if table is not linked multiple times
*/
@Test
public void testFindTablePath() throws SQLException, URISyntaxException {
try(Statement st = connection.createStatement()) {
st.execute("DROP TABLE IF EXISTS BV_SAP, BV_SAP_1, BV_SAP2");
DataManager dataManager = new DataManagerImpl(dataSource);
String tableIdentifier = dataManager.registerDataSource(JDBCUtilityTest.class.getResource("bv_sap.shp").toURI());
dataManager.registerDataSource(JDBCUtilityTest.class.getResource("bv_sap.shp").toURI());
assertTrue("BV_SAP does not exist, created "+tableIdentifier,JDBCUtilities.tableExists(connection, "BV_SAP"));
assertFalse(JDBCUtilities.tableExists(connection, "BV_SAP_1"));
assertFalse(JDBCUtilities.tableExists(connection, "BV_SAP_2"));
}
}
}