001    //$HeadURL: svn+ssh://mschneider@svn.wald.intevation.org/deegree/base/trunk/src/org/deegree/io/datastore/sql/postgis/PostGISWhereBuilder.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    
037    package org.deegree.io.datastore.sql.mysql;
038    
039    import java.sql.Types;
040    
041    import org.deegree.io.datastore.DatastoreException;
042    import org.deegree.io.datastore.schema.MappedFeatureType;
043    import org.deegree.io.datastore.sql.StatementBuffer;
044    import org.deegree.io.datastore.sql.TableAliasGenerator;
045    import org.deegree.io.datastore.sql.VirtualContentProvider;
046    import org.deegree.io.datastore.sql.postgis.PGgeometryAdapter;
047    import org.deegree.io.datastore.sql.wherebuilder.WhereBuilder;
048    import org.deegree.model.filterencoding.Filter;
049    import org.deegree.model.filterencoding.OperationDefines;
050    import org.deegree.model.filterencoding.SpatialOperation;
051    import org.deegree.model.spatialschema.Envelope;
052    import org.deegree.model.spatialschema.Geometry;
053    import org.deegree.model.spatialschema.GeometryException;
054    import org.deegree.model.spatialschema.GeometryFactory;
055    import org.deegree.model.spatialschema.Surface;
056    import org.deegree.ogcbase.SortProperty;
057    import org.postgis.PGgeometry;
058    import org.postgis.binary.BinaryWriter;
059    
060    /**
061     * {@link WhereBuilder} implementation for MySQL spatial databases.
062     *
063     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </A>
064     * @author last edited by: $Author: aschmitz $
065     *
066     * @version $Revision: 12482 $, $Date: 2008-06-23 11:23:34 +0000 (Mo, 23 Jun 2008) $
067     */
068    class MySQLWhereBuilder extends WhereBuilder {
069    
070        /**
071         * Creates a new instance of <code>MySQLWhereBuilder</code> from the given parameters.
072         *
073         * @param rootFts
074         *            selected feature types, more than one type means that the types are joined
075         * @param aliases
076         *            aliases for the feature types, may be null (must have same length as rootFts otherwise)
077         * @param filter
078         *            filter that restricts the matched features
079         * @param sortProperties
080         *            sort criteria for the result, may be null or empty
081         * @param aliasGenerator
082         *            used to generate unique table aliases
083         * @param vcProvider
084         * @throws DatastoreException
085         */
086        public MySQLWhereBuilder( MappedFeatureType[] rootFts, String[] aliases, Filter filter,
087                                  SortProperty[] sortProperties, TableAliasGenerator aliasGenerator,
088                                  VirtualContentProvider vcProvider ) throws DatastoreException {
089            super( rootFts, aliases, filter, sortProperties, aliasGenerator, vcProvider );
090        }
091    
092        /**
093         * Generates an SQL-fragment for the given object.
094         *
095         * @throws DatastoreException
096         */
097        @Override
098        protected void appendSpatialOperationAsSQL( StatementBuffer query, SpatialOperation operation )
099                                throws DatastoreException {
100    
101            try {
102                switch ( operation.getOperatorId() ) {
103                case OperationDefines.BBOX: {
104                    appendBBOXOperationAsSQL( query, operation );
105                    break;
106                }
107                case OperationDefines.INTERSECTS: {
108                    appendSimpleOperationAsSQL( query, operation, "Intersects" );
109                    break;
110                }
111                case OperationDefines.CROSSES: {
112                    appendSimpleOperationAsSQL( query, operation, "Crosses" );
113                    break;
114                }
115                case OperationDefines.EQUALS: {
116                    appendSimpleOperationAsSQL( query, operation, "Equals" );
117                    break;
118                }
119                case OperationDefines.WITHIN: {
120                    appendSimpleOperationAsSQL( query, operation, "Within" );
121                    break;
122                }
123                case OperationDefines.OVERLAPS: {
124                    appendSimpleOperationAsSQL( query, operation, "Overlaps" );
125                    break;
126                }
127                case OperationDefines.TOUCHES: {
128                    appendSimpleOperationAsSQL( query, operation, "Touches" );
129                    break;
130                }
131                case OperationDefines.DISJOINT: {
132                    appendSimpleOperationAsSQL( query, operation, "Disjoint" );
133                    break;
134                }
135                case OperationDefines.CONTAINS: {
136                    appendSimpleOperationAsSQL( query, operation, "Contains" );
137                    break;
138                }
139                case OperationDefines.DWITHIN: {
140                    appendDWithinOperationAsSQL( query, operation );
141                    break;
142                }
143                case OperationDefines.BEYOND: {
144                    appendBeyondOperationAsSQL( query, operation );
145                    break;
146                }
147                default: {
148                    String msg = "Spatial operator " + OperationDefines.getNameById( operation.getOperatorId() )
149                                 + " is not supported by '" + this.getClass().toString() + "'.";
150                    throw new DatastoreException( msg );
151                }
152                }
153            } catch ( GeometryException e ) {
154                throw new DatastoreException( e );
155            }
156        }
157    
158        private void appendSimpleOperationAsSQL( StatementBuffer query, SpatialOperation operation, String operationName ) {
159            query.append( operationName );
160            query.append( "(" );
161            appendPropertyNameAsSQL( query, operation.getPropertyName() );
162            query.append( ",GeomFromWKB(?))" );
163            query.addArgument( operation.getGeometry(), Types.OTHER );
164        }
165    
166        private void appendBBOXOperationAsSQL( StatementBuffer query, SpatialOperation operation )
167                                throws GeometryException {
168    
169            // a polygon is used as parameter here, because MySQL spatial does not seem to offer
170            // an envelope type
171            Envelope env = operation.getGeometry().getEnvelope();
172            Surface surface = GeometryFactory.createSurface( env, env.getCoordinateSystem() );
173    
174            query.append( "Intersects(" );
175            appendPropertyNameAsSQL( query, operation.getPropertyName() );
176            query.append( ",GeomFromWKB(?))" );
177            addMySQLGeometryArgument( query, surface );
178        }
179    
180        private void appendDWithinOperationAsSQL( StatementBuffer query, SpatialOperation operation ) throws GeometryException {
181            query.append( "Distance(" );
182            appendPropertyNameAsSQL( query, operation.getPropertyName() );
183            query.append( ",GeomFromWKB(?))<=" );
184            addMySQLGeometryArgument( query, operation.getGeometry() );
185            query.append( "" + operation.getDistance() );
186        }
187    
188        private void appendBeyondOperationAsSQL( StatementBuffer query, SpatialOperation operation ) throws GeometryException {
189            query.append( "Distance(" );
190            appendPropertyNameAsSQL( query, operation.getPropertyName() );
191            query.append( ",GeomFromWKB(?))>" );
192            addMySQLGeometryArgument( query, operation.getGeometry() );
193            query.append( "" + operation.getDistance() );
194        }
195    
196        private void addMySQLGeometryArgument( StatementBuffer query, Geometry geometry )
197                                throws GeometryException {
198    
199            PGgeometry pgGeometry = PGgeometryAdapter.export( geometry, -1 );
200            byte[] wkb = new BinaryWriter().writeBinary( pgGeometry.getGeometry() );
201            query.addArgument( wkb, org.deegree.datatypes.Types.BINARY );
202        }
203    }