/* * Geotools2 - OpenSource GIS mapping toolkit http://geotools.org * (C) 2002-2005, Geotools Project Managment Committee (PMC) * * 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. * * File may contain documentation and or interfaces derived from Open Geospatial * Consortium, Inc. (OGC) specifications. The work of the OGC is acknowledged. */ package org.geotools.filter; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.io.WKTWriter; import java.io.IOException; import java.util.logging.Logger; /** * Encodes a filter into a SQL WHERE statement for mysql. This class adds * the ability to turn geometry filters into sql statements if they are * bboxes. * * @author Chris Holmes, TOPP * */ public class SQLEncoderMySQL extends SQLEncoder implements org.geotools.filter.FilterVisitor { /** Standard java logger */ private static Logger LOGGER = Logger.getLogger("org.geotools.filter"); /** To write geometry so postgis can read it. */ private static WKTWriter wkt = new WKTWriter(); /** * The filters that this encoder can processed. (Note this value shadows * private capabilities in superclass) */ private FilterCapabilities capabilities = new FilterCapabilities(); /** * The srid of the schema, so the bbox conforms. Could be better to have * it in the bbox filter itself, but this works for now. */ private int srid; /** The geometry attribute to use if none is specified. */ private String defaultGeom; /** * Empty constructor TODO: rethink empty constructor, as BBOXes _need_ an * SRID, must make client set it somehow. Maybe detect when encode is * called? * */ public SQLEncoderMySQL() { capabilities = createFilterCapabilities(); } public SQLEncoderMySQL(int srid) { this.srid = srid; } /** * * @see org.geotools.filter.SQLEncoder#createFilterCapabilities() */ protected FilterCapabilities createFilterCapabilities() { FilterCapabilities capabilities = new FilterCapabilities(); capabilities.addType(AbstractFilter.LOGIC_OR); capabilities.addType(AbstractFilter.LOGIC_AND); capabilities.addType(AbstractFilter.LOGIC_NOT); capabilities.addType(AbstractFilter.COMPARE_EQUALS); capabilities.addType(AbstractFilter.COMPARE_NOT_EQUALS); capabilities.addType(AbstractFilter.COMPARE_LESS_THAN); capabilities.addType(AbstractFilter.COMPARE_GREATER_THAN); capabilities.addType(AbstractFilter.COMPARE_LESS_THAN_EQUAL); capabilities.addType(AbstractFilter.COMPARE_GREATER_THAN_EQUAL); capabilities.addType(AbstractFilter.NULL); capabilities.addType(AbstractFilter.BETWEEN); capabilities.addType((short) 12345); capabilities.addType((short) -12345); capabilities.addType(AbstractFilter.GEOMETRY_BBOX); capabilities.addType(AbstractFilter.FID); return capabilities; } /** * Sets a spatial reference system ESPG number, so that the geometry can be * properly encoded for postgis. If geotools starts actually creating * geometries with valid srids then this method will no longer be needed. * * @param srid the integer code for the EPSG spatial reference system. */ public void setSRID(int srid) { this.srid = srid; } /** * Sets the default geometry, so that filters with null for one of their * expressions can assume that the default geometry is intended. * * @param name the name of the default geometry Attribute. * * @task REVISIT: pass in a featureType so that geometries can figure out * their own default geometry? */ public void setDefaultGeometry(String name) { this.defaultGeom = name; } /** * Turns a geometry filter into a MySQL Geometry filter. This currently * only supports the BBOX filter, which only operates against the envelopes * of the geometries. This is because MySQL has not implemented any * further functions. Using things this way seems like a reasonable * strategy as that's what we did with PostGIS's && function before * geos came along and added real filtering. MySQL actually has a number * of other spatial options, but all operate against the bounding box, * not the actual geometries, so I think we should hold off on implementing * those. What could be good is a 'loose geometry' option, that lets * users pick if they want things to be strictly correct, or if they * just want them as fast as possible. * * @param filter the geometry filter to be encoded. * * @throws RuntimeException for IO exception (need a better error) */ public void visit(GeometryFilter filter) throws RuntimeException { LOGGER.finer("exporting GeometryFilter"); if (filter.getFilterType() == AbstractFilter.GEOMETRY_BBOX) { DefaultExpression left = (DefaultExpression) filter.getLeftGeometry(); DefaultExpression right = (DefaultExpression) filter.getRightGeometry(); // left and right have to be valid expressions try { out.write("MBRIntersects("); if (left == null) { out.write(defaultGeom); } else { left.accept(this); } out.write(", "); if (right == null) { out.write(defaultGeom); } else { right.accept(this); } out.write(")"); } catch (java.io.IOException ioe) { LOGGER.warning("Unable to export filter" + ioe); } } else { LOGGER.warning("exporting unknown filter type, only bbox supported"); throw new RuntimeException("Only BBox is currently supported"); } } /** * Checks to see if the literal is a geometry, and encodes it if it is, if * not just sends to the parent class. * * @param expression the expression to visit and encode. * * @throws IOException for IO exception (need a better error) */ public void visitLiteralGeometry(LiteralExpression expression) throws IOException { Geometry bbox = (Geometry) expression.getLiteral(); String geomText = wkt.write(bbox); out.write("GeometryFromText('" + geomText + "', " + srid + ")"); } }