Revision: 4687
          http://sourceforge.net/p/jump-pilot/code/4687
Author:   elnico
Date:     2015-12-27 13:00:10 +0000 (Sun, 27 Dec 2015)
Log Message:
-----------
MariaDB/MySQL: 
 - Added support for OGC spatial metadata layout (geometry_columns table 
listing geometric tables)
 - Kept native support if OGC tables not found (extent, srid)
 - Changed query to get layer extent, now based on aggregate query on table.
 - Changed native geometry binary format detection: MySQL format stores SRID in 
the first 4 bytes of the blob. (todo: how to guess between OGC and MySQL binary 
formats ?)

SpatialDatabases: Corrected SRID retrieval: default to 0 if database value is 
"null"

Modified Paths:
--------------
    
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbDSMetadata.java
    
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbSQLBuilder.java
    
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbValueConverterFactory.java
    
core/trunk/src/com/vividsolutions/jump/datastore/spatialdatabases/SpatialDatabasesDSMetadata.java

Modified: 
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbDSMetadata.java
===================================================================
--- 
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbDSMetadata.java 
    2015-12-27 12:54:25 UTC (rev 4686)
+++ 
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbDSMetadata.java 
    2015-12-27 13:00:10 UTC (rev 4687)
@@ -3,61 +3,168 @@
 import com.vividsolutions.jump.datastore.DataStoreConnection;
 import com.vividsolutions.jump.datastore.spatialdatabases.*;
 import com.vividsolutions.jump.datastore.GeometryColumn;
+import com.vividsolutions.jump.datastore.jdbc.JDBCUtil;
+import com.vividsolutions.jump.datastore.jdbc.ResultSetBlock;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.List;
 
 public class MariadbDSMetadata extends SpatialDatabasesDSMetadata {
 
-    public MariadbDSMetadata(DataStoreConnection con) {
-        conn = con;
-        // TODO: defaults to database name ?
-        defaultSchemaName = "";
-        // TODO: use bind parameters to avoid SQL injection
-        datasetNameQuery = "select distinct t.TABLE_SCHEMA, t.TABLE_NAME \n" +
-            "from information_schema.TABLES t join information_schema.COLUMNS 
C \n" +
-            "  on t.TABLE_NAME = c.TABLE_NAME and t.TABLE_SCHEMA = 
c.TABLE_SCHEMA\n" +
-            "where t.TABLE_TYPE not in ('SYSTEM VIEW')\n" +
-            "and c.COLUMN_TYPE = 'geometry';";
-        spatialDbName = "MariaDB/MySQL";
-        spatialExtentQuery1 = "select 
st_asBinary(st_envelope(Geomfromtext(concat(concat(\"geometrycollection(\",group_concat(astext(%s))),\")\"))))
 from %s.%s;";
-        // NO metadata => same query is defined.
-        spatialExtentQuery2 = spatialExtentQuery1;
-        geoColumnsQuery = "select c.COLUMN_NAME, 0, 'geometry' \n" +
-            "from information_schema.TABLES t join information_schema.COLUMNS 
C \n" +
-            "  on t.TABLE_NAME = c.TABLE_NAME and t.TABLE_SCHEMA = 
c.TABLE_SCHEMA\n" +
-            "where t.TABLE_TYPE not in ('SYSTEM VIEW')\n" +
-            "and t.TABLE_SCHEMA = '%s' and t.TABLE_NAME = '%s'\n" +
-            "and c.COLUMN_TYPE = 'geometry'";
-        sridQuery = "select case when min(st_srid(%s)) <> max(st_srid(%s)) 
then 0 else min(st_srid(%s)) end as srid\n" +
-                "from %s.%s";
-    }
+  /**
+   * The second query to get geometric columns
+   */
+  private String geoColumnsQuery2;
+  /**
+   * The second query to get SRID
+   */
+  private String sridQuery2;
 
-    @Override
-    public String getSpatialExtentQuery1(String schema, String table, String 
attributeName) {
-        return String.format(this.spatialExtentQuery1, attributeName, schema, 
table);
-    }
+  public MariadbDSMetadata(DataStoreConnection con) {
+    conn = con;
+    // TODO: defaults to database name ?
+    defaultSchemaName = "";
+    // TODO: use bind parameters to avoid SQL injection
+    datasetNameQuery = "select distinct t.TABLE_SCHEMA, t.TABLE_NAME \n"
+        + "from information_schema.TABLES t join information_schema.COLUMNS C 
\n"
+        + "  on t.TABLE_NAME = c.TABLE_NAME and t.TABLE_SCHEMA = 
c.TABLE_SCHEMA\n"
+        + "where t.TABLE_TYPE not in ('SYSTEM VIEW')\n"
+        + "and c.COLUMN_TYPE = 'geometry';";
+    spatialDbName = "MariaDB/MySQL";
+    // No safe way found to get layer's extent from database.
+    // text aggregation trick (select 
st_asBinary(st_envelope(Geomfromtext(concat(concat(\"geometrycollection(\",group_concat(astext(%s))),\")\"))))
 from %s.%s)
+    // does not work well with JDBC: group_concat_max_len param should maybe 
be set in the driver prefs ?
+    // Use extent of first record only as an hint to layer location
+    spatialExtentQuery1 = "select 
st_asbinary(st_geomfromtext(concat('POLYGON((', minx, ' ', miny, ', ',\n" +
+                "              maxx, ' ', miny, ', ',\n" +
+                "              maxx, ' ', maxy, ', ',\n" +
+                "              minx, ' ', maxy, ', ',\n" +
+                "              minx, ' ', miny, '))'))) as geom\n" +
+                "from (\n" +
+                "  SELECT\n" +
+                "    min(st_x(st_pointN(geom, 1))) AS minx,\n" +
+                "    min(st_y(st_pointN(geom, 1))) AS miny,\n" +
+                "    max(st_x(st_pointN(geom, 3))) AS maxx,\n" +
+                "    max(st_y(st_pointN(geom, 3))) AS maxy\n" +
+                "  FROM (\n" +
+                "         SELECT st_ExteriorRing(st_envelope(%s)) AS geom\n" +
+                "         FROM %s.%s\n" +
+                "       ) AS t\n" +
+                ") as t2";
+    
+    // NO metadata => same query is defined.
+    spatialExtentQuery2 = spatialExtentQuery1;
+    geoColumnsQuery = "SELECT f_geometry_column, srid, type FROM 
geometry_columns where f_table_name = '%s'";
 
-    @Override
-    public String getSpatialExtentQuery2(String schema, String table, String 
attributeName) {
-        return String.format(this.spatialExtentQuery2, attributeName, schema, 
table);
-    }
+    // Double mechanism is used for Maria/MySQL: ogr, for instance, creates 
+    // and populates a geometry_columns table with geo MD
+    // Original mechanism was based on pure MySQL MD to guess geo column
+    // Keep both mechanisms to handle all cases.
+    geoColumnsQuery2 = "select c.COLUMN_NAME, 0, 'geometry' \n"
+        + "from information_schema.TABLES t join information_schema.COLUMNS C 
\n"
+        + "  on t.TABLE_NAME = c.TABLE_NAME and t.TABLE_SCHEMA = 
c.TABLE_SCHEMA\n"
+        + "where t.TABLE_TYPE not in ('SYSTEM VIEW')\n"
+        + "and t.TABLE_SCHEMA = '%s' and t.TABLE_NAME = '%s'\n"
+        + "and c.COLUMN_TYPE = 'geometry'";
+    // TODO: test for big datasets...
+    sridQuery = "SELECT srid FROM geometry_columns where f_table_name = '%s' 
and f_geometry_column = '%s'";
+    sridQuery2 = "select case when min(st_srid(%s)) <> max(st_srid(%s)) then 0 
else min(st_srid(%s)) end as srid\n"
+        + "from %s.%s";
+  }
 
-    @Override
-    public String getGeoColumnsQuery(String datasetName) {
-        return String.format(this.geoColumnsQuery, getSchemaName(datasetName), 
getTableName(datasetName));
-    }
+  @Override
+  public String getSpatialExtentQuery1(String schema, String table, String 
attributeName) {
+    return String.format(this.spatialExtentQuery1, attributeName, schema, 
table);
+  }
 
-    @Override
-    public String getSridQuery(String schemaName, String tableName, String 
colName) {
-        // TODO
-        return String.format(this.sridQuery, colName, colName, colName, 
schemaName, tableName);
+  @Override
+  public String getSpatialExtentQuery2(String schema, String table, String 
attributeName) {
+    return String.format(this.spatialExtentQuery2, attributeName, schema, 
table);
+  }
+
+  @Override
+  public String getGeoColumnsQuery(String datasetName) {
+    return String.format(this.geoColumnsQuery, getTableName(datasetName));
+  }
+
+  public String getGeoColumnsQuery2(String datasetName) {
+    return String.format(this.geoColumnsQuery2, getSchemaName(datasetName), 
getTableName(datasetName));
+  }
+
+  @Override
+  public String getSridQuery(String schemaName, String tableName, String 
colName) {
+    return String.format(this.sridQuery, tableName, colName);
+  }
+
+  public String getSridQuery2(String schemaName, String tableName, String 
colName) {
+    return String.format(this.sridQuery2, colName, colName, colName, 
schemaName, tableName);
+  }
+
+  @Override
+  public List<GeometryColumn> getGeometryAttributes(String datasetName) {
+    String sql = this.getGeoColumnsQuery(datasetName);
+    return getGeometryAttributes(sql, datasetName);
+  }
+
+  /**
+   * Retrieves geometric attributes for given dataset using 2 methods: 
classical
+   * method from OGC metadata (geometryColumns) and DB metadata method, 
querying
+   * system catalog.
+   *
+   * @param sql
+   * @param datasetName
+   * @return
+   */
+  @Override
+  protected List<GeometryColumn> getGeometryAttributes(String sql, String 
datasetName) {
+    final List<GeometryColumn> geometryAttributes2 = new 
ArrayList<GeometryColumn>();
+    try {
+      final List<GeometryColumn> geometryAttributes = 
super.getGeometryAttributes(sql, datasetName);
+      return geometryAttributes;
+    } catch (Exception e) {
+      // second method
+      String sql2 = getGeoColumnsQuery2(datasetName);
+      JDBCUtil.execute(
+          conn.getJdbcConnection(), sql2,
+          new ResultSetBlock() {
+            public void yield(ResultSet resultSet) throws SQLException {
+              while (resultSet.next()) {
+                geometryAttributes2.add(new GeometryColumn(
+                        resultSet.getString(1),
+                        resultSet.getInt(2),
+                        resultSet.getString(3)));
+              }
+            }
+          });
     }
-    
-    @Override
-    public List<GeometryColumn> getGeometryAttributes(String datasetName) {
-        String sql = this.getGeoColumnsQuery(datasetName);
-        // TODO: manage srid by executing 2 SQL queries: one for geo cols, one 
for
-        // srids.
-        return getGeometryAttributes(sql, datasetName);
+    return geometryAttributes2;
+  }
+  
+  /**
+   * Gets the SRID of the dataset using a second method if OGC metadata does 
not work.
+   * @param datasetName
+   * @param colName
+   * @return 
+   */
+  @Override
+  protected String querySRID(String datasetName, String colName) {
+    final StringBuffer srid = new StringBuffer();
+    try {
+      srid.append(super.querySRID(datasetName, colName));
+    } catch (Exception e) {
+      // TODO: log ex message ?
+      String sql = this.getSridQuery2(this.getSchemaName(datasetName), 
this.getTableName(datasetName), colName);
+      JDBCUtil.execute(conn.getJdbcConnection(), sql, new ResultSetBlock() {
+        public void yield(ResultSet resultSet) throws SQLException {
+          if (resultSet.next()) {
+            srid.append(resultSet.getString(1));
+          }
+        }
+      });
     }
 
+    return srid.toString();
+  }
+
 }

Modified: 
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbSQLBuilder.java
===================================================================
--- 
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbSQLBuilder.java 
    2015-12-27 12:54:25 UTC (rev 4686)
+++ 
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbSQLBuilder.java 
    2015-12-27 13:00:10 UTC (rev 4687)
@@ -72,6 +72,8 @@
     Envelope env = query.getFilterGeometry().getEnvelopeInternal();
 
     // Example of MariaDB SQL: where st_Intersects(b.geom, 
st_polygonFromText('POLYGON((4 4, 5 4, 5 5, 4 5, 4 4))'))
+    // Nicolas Ribot: 23 dec: MySQL 5.7.10 checks geom SRID and reject the 
query if bbox has not correct srid
+    String s = this.defaultSRID == null ? "0" : this.defaultSRID.getString();
     StringBuilder buf = new StringBuilder();
     
buf.append("st_intersects(").append(query.getGeometryAttributeName()).append(", 
st_polygonFromText('POLYGON((");
     buf.append(env.getMinX()).append(" ").append(env.getMinY()).append(",")
@@ -79,7 +81,7 @@
         .append(env.getMaxX()).append(" ").append(env.getMaxY()).append(",")
         .append(env.getMinX()).append(" ").append(env.getMaxY()).append(",")
         .append(env.getMinX()).append(" ").append(env.getMinY());
-    buf.append("))'))");
+    buf.append("))', ").append(s).append("))");
     return buf.toString();
   }
 }

Modified: 
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbValueConverterFactory.java
===================================================================
--- 
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbValueConverterFactory.java
  2015-12-27 12:54:25 UTC (rev 4686)
+++ 
core/trunk/src/com/vividsolutions/jump/datastore/mariadb/MariadbValueConverterFactory.java
  2015-12-27 13:00:10 UTC (rev 4687)
@@ -70,9 +70,8 @@
         WKBReader wr = new WKBReader();
 
         if (nativeFormat) {
-
-                //copy the byte array, removing the first four
-          //zero bytes added by mysql
+          //copy the byte array, removing the first four
+          //zero bytes added by mysql to store SRID in binary
           byte[] wkb = new byte[bytes.length - 4];
           System.arraycopy(bytes, 4, wkb, 0, wkb.length);
           geometry = wr.read(wkb);
@@ -90,6 +89,7 @@
    * From Larry Reeder, code to detect MySQL spatial type.
    * Added detection code for older/strange mysql geometry format beginning 
with 6A 08 00 00 
    * TODO: make method public static in its package ?
+   * Newest MySQL/MariaDB version stores srid at the beginning of the blob, as 
int
    * The JUMP DB Query Plugin is Copyright (C) 2007  Larry Reeder
    *  JUMP is Copyright (C) 2003 Vivid Solutions
    * 
@@ -117,9 +117,10 @@
         nativeFormat = true;
       }
 
-    } else if (Arrays.equals(ctrl, firstFour)) {
-      // Nicolas Ribot: some geometries begin with: 6A 08 00 00 
-      // TODO: document how/why...
+      // TODO: how to recognize MySQL binary from wkb ?
+//    } else if (Arrays.equals(ctrl, firstFour)) {
+    } else if (true) {
+      // Nicolas Ribot: mysql now stores srid at the beginning of the geom ?
       nativeFormat = true;
     }
     return nativeFormat;

Modified: 
core/trunk/src/com/vividsolutions/jump/datastore/spatialdatabases/SpatialDatabasesDSMetadata.java
===================================================================
--- 
core/trunk/src/com/vividsolutions/jump/datastore/spatialdatabases/SpatialDatabasesDSMetadata.java
   2015-12-27 12:54:25 UTC (rev 4686)
+++ 
core/trunk/src/com/vividsolutions/jump/datastore/spatialdatabases/SpatialDatabasesDSMetadata.java
   2015-12-27 13:00:10 UTC (rev 4687)
@@ -439,7 +439,9 @@
     JDBCUtil.execute(conn.getJdbcConnection(), sql, new ResultSetBlock() {
       public void yield(ResultSet resultSet) throws SQLException {
         if (resultSet.next()) {
-          srid.append(resultSet.getString(1));
+          // Nicolas Ribot: test if a null is returned
+          String s = resultSet.getString(1);
+          srid.append(s == null ? "0" : s);
         }
       }
     });


------------------------------------------------------------------------------
_______________________________________________
Jump-pilot-devel mailing list
Jump-pilot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel

Reply via email to