001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.filter;
017:
018: import java.io.IOException;
019: import java.util.logging.Logger;
020:
021: import com.vividsolutions.jts.geom.Geometry;
022: import com.vividsolutions.jts.io.WKTWriter;
023:
024: /**
025: * Encodes a filter into a SQL WHERE statement for MySQL. This class adds
026: * the ability to turn geometry filters into sql statements if they are
027: * bboxes.
028: *
029: * @author Chris Holmes, TOPP
030: * @author Debasish Sahu, debasish.sahu@rmsi.com
031: *
032: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/mysql/src/main/java/org/geotools/filter/SQLEncoderMySQL.java $
033: */
034: public class SQLEncoderMySQL extends SQLEncoder implements
035: org.geotools.filter.FilterVisitor {
036: /** Standard java logger */
037: private static Logger LOGGER = org.geotools.util.logging.Logging
038: .getLogger("org.geotools.filter");
039:
040: /** To write geometry so postgis can read it. */
041: private static WKTWriter wkt = new WKTWriter();
042:
043: /**
044: * The srid of the schema, so the bbox conforms. Could be better to have
045: * it in the bbox filter itself, but this works for now.
046: */
047: private int srid;
048:
049: /** The geometry attribute to use if none is specified. */
050: private String defaultGeom;
051:
052: /** The standard SQL multicharacter wild card. */
053: private static final String SQL_WILD_MULTI = "%";
054:
055: /** The standard SQL single character wild card. */
056: private static final String SQL_WILD_SINGLE = "_";
057: /** The escaped version of the multiple wildcard for the REGEXP pattern. */
058: private String escapedWildcardMulti = "\\.\\*";
059:
060: /** The escaped version of the single wildcard for the REGEXP pattern. */
061: private String escapedWildcardSingle = "\\.\\?";
062:
063: /**
064: * Empty constructor TODO: rethink empty constructor, as BBOXes _need_ an
065: * SRID, must make client set it somehow. Maybe detect when encode is
066: * called?
067: */
068: public SQLEncoderMySQL() {
069: capabilities = createFilterCapabilities();
070:
071: setSqlNameEscape("");
072: }
073:
074: public SQLEncoderMySQL(int srid) {
075: this .srid = srid;
076: }
077:
078: /**
079: * @see org.geotools.filter.SQLEncoder#createFilterCapabilities()
080: */
081: protected FilterCapabilities createFilterCapabilities() {
082: FilterCapabilities capabilities = new FilterCapabilities();
083:
084: capabilities.addType(FilterCapabilities.LOGIC_OR);
085: capabilities.addType(FilterCapabilities.LOGIC_AND);
086: capabilities.addType(FilterCapabilities.LOGIC_NOT);
087: capabilities.addType(FilterCapabilities.COMPARE_EQUALS);
088: capabilities.addType(FilterCapabilities.COMPARE_NOT_EQUALS);
089: capabilities.addType(FilterCapabilities.COMPARE_LESS_THAN);
090: capabilities.addType(FilterCapabilities.COMPARE_GREATER_THAN);
091: capabilities
092: .addType(FilterCapabilities.COMPARE_LESS_THAN_EQUAL);
093: capabilities
094: .addType(FilterCapabilities.COMPARE_GREATER_THAN_EQUAL);
095: capabilities.addType(FilterCapabilities.NULL_CHECK);
096: capabilities.addType(FilterCapabilities.BETWEEN);
097: capabilities.addType(FilterCapabilities.NONE);
098: capabilities.addType(FilterCapabilities.ALL);
099: capabilities.addType(FilterCapabilities.SPATIAL_BBOX);
100: capabilities.addType(FilterCapabilities.FID);
101: capabilities.addType(FilterCapabilities.LIKE);
102: return capabilities;
103: }
104:
105: /**
106: * Sets a spatial reference system ESPG number, so that the geometry can be
107: * properly encoded for postgis. If geotools starts actually creating
108: * geometries with valid srids then this method will no longer be needed.
109: *
110: * @param srid the integer code for the EPSG spatial reference system.
111: */
112: public void setSRID(int srid) {
113: this .srid = srid;
114: }
115:
116: /**
117: * Sets the default geometry, so that filters with null for one of their
118: * expressions can assume that the default geometry is intended.
119: *
120: * @param name the name of the default geometry Attribute.
121: *
122: * @task REVISIT: pass in a featureType so that geometries can figure out
123: * their own default geometry?
124: */
125: public void setDefaultGeometry(String name) {
126: //Do we really want clients to be using malformed filters?
127: //I mean, this is a useful method for unit tests, but shouldn't
128: //fully formed filters usually be used? Though I guess adding
129: //the option wouldn't hurt. -ch
130: this .defaultGeom = name;
131: }
132:
133: /**
134: * Turns a geometry filter into the postgis sql bbox statement.
135: *
136: * @param filter the geometry filter to be encoded.
137: *
138: * @throws RuntimeException for IO exception (need a better error)
139: */
140: public void visit(GeometryFilter filter) throws RuntimeException {
141: LOGGER.finer("exporting GeometryFilter");
142:
143: if (filter.getFilterType() == AbstractFilter.GEOMETRY_BBOX) {
144: DefaultExpression left = (DefaultExpression) filter
145: .getLeftGeometry();
146: DefaultExpression right = (DefaultExpression) filter
147: .getRightGeometry();
148:
149: // left and right have to be valid expressions
150: try {
151: out.write("MBRIntersects(");
152: if (left == null) {
153: out.write(defaultGeom);
154: } else {
155: left.accept(this );
156: }
157: out.write(", ");
158: if (right == null) {
159: out.write(defaultGeom);
160: } else {
161: right.accept(this );
162: }
163: out.write(")");
164: } catch (java.io.IOException ioe) {
165: LOGGER.warning("Unable to export filter" + ioe);
166: }
167: } else {
168: LOGGER
169: .warning("exporting unknown filter type, only bbox supported");
170: throw new RuntimeException(
171: "Only BBox is currently supported");
172: }
173: }
174:
175: /**
176: * Checks to see if the literal is a geometry, and encodes it if it is, if
177: * not just sends to the parent class.
178: *
179: * @param expression the expression to visit and encode.
180: *
181: * @throws IOException for IO exception (need a better error)
182: */
183: public void visitLiteralGeometry(LiteralExpression expression)
184: throws IOException {
185: Geometry bbox = (Geometry) expression.getLiteral();
186: String geomText = wkt.write(bbox);
187: out.write("GeometryFromText('" + geomText + "', " + srid + ")");
188: }
189:
190: public void visit(LikeFilter filter) {
191: try {
192: String pattern = filter.getPattern();
193:
194: pattern = pattern.replaceAll(escapedWildcardMulti,
195: SQL_WILD_MULTI);
196: pattern = pattern.replaceAll(escapedWildcardSingle,
197: SQL_WILD_SINGLE);
198:
199: //pattern = pattern.replace('\\', ''); //get rid of java escapes.
200: out.write("UPPER(");
201: ((Expression) filter.getValue()).accept(this );
202: out.write(") LIKE ");
203: out.write("UPPER('" + pattern + "')");
204:
205: String esc = filter.getEscape();
206:
207: if (pattern.indexOf(esc) != -1) { //if it uses the escape char
208: out.write(" ESCAPE " + "'" + esc + "'"); //this needs testing
209: }
210:
211: //TODO figure out when to add ESCAPE clause, probably just for the
212: // '_' char.
213: } catch (java.io.IOException ioe) {
214: LOGGER.warning("Unable to export filter" + ioe);
215: }
216:
217: }
218: }
|