Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extOracleSpatial / src / es / prodevelop / cit / gvsig / fmap / drivers / jdbc / oracle / OracleSpatialDriver.java @ 29580

History | View | Annotate | Download (113 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 Prodevelop and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *   Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *   +34 963862235
28
 *   gvsig@gva.es
29
 *   www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   Prodevelop Integraci?n de Tecnolog?as SL
34
 *   Conde Salvatierra de ?lava , 34-10
35
 *   46004 Valencia
36
 *   Spain
37
 *
38
 *   +34 963 510 612
39
 *   +34 963 510 968
40
 *   gis@prodevelop.es
41
 *   http://www.prodevelop.es
42
 */
43
package es.prodevelop.cit.gvsig.fmap.drivers.jdbc.oracle;
44

    
45
import java.awt.Shape;
46
import java.awt.geom.Point2D;
47
import java.awt.geom.Rectangle2D;
48
import java.math.BigDecimal;
49
import java.sql.Connection;
50
import java.sql.DatabaseMetaData;
51
import java.sql.PreparedStatement;
52
import java.sql.ResultSet;
53
import java.sql.ResultSetMetaData;
54
import java.sql.SQLException;
55
import java.sql.Statement;
56
import java.sql.Timestamp;
57
import java.sql.Types;
58
import java.util.ArrayList;
59
import java.util.HashMap;
60
import java.util.Hashtable;
61
import java.util.Iterator;
62
import java.util.Random;
63
import java.util.TreeMap;
64

    
65
import oracle.sql.ARRAY;
66
import oracle.sql.Datum;
67
import oracle.sql.NUMBER;
68
import oracle.sql.ROWID;
69
import oracle.sql.STRUCT;
70
import oracle.sql.StructDescriptor;
71
import oracle.sql.TIMESTAMP;
72

    
73
import org.apache.log4j.Logger;
74
import org.cresques.cts.ICoordTrans;
75
import org.cresques.cts.IProjection;
76

    
77
import com.hardcode.driverManager.IDelayedDriver;
78
import com.hardcode.gdbms.driver.exceptions.InitializeWriterException;
79
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
80
import com.hardcode.gdbms.driver.exceptions.WriteDriverException;
81
import com.hardcode.gdbms.engine.data.DataSource;
82
import com.hardcode.gdbms.engine.data.DataSourceFactory;
83
import com.hardcode.gdbms.engine.data.edition.DataWare;
84
import com.hardcode.gdbms.engine.spatial.fmap.FShapeGeneralPathX;
85
import com.hardcode.gdbms.engine.values.DoubleValue;
86
import com.hardcode.gdbms.engine.values.Value;
87
import com.hardcode.gdbms.engine.values.ValueFactory;
88
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
89
import com.iver.cit.gvsig.fmap.core.FGeometryCollection;
90
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
91
import com.iver.cit.gvsig.fmap.core.FNullGeometry;
92
import com.iver.cit.gvsig.fmap.core.FPoint2D;
93
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
94
import com.iver.cit.gvsig.fmap.core.FPolyline2D;
95
import com.iver.cit.gvsig.fmap.core.FShape;
96
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
97
import com.iver.cit.gvsig.fmap.core.ICanReproject;
98
import com.iver.cit.gvsig.fmap.core.IFeature;
99
import com.iver.cit.gvsig.fmap.core.IGeometry;
100
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
101
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
102
import com.iver.cit.gvsig.fmap.crs.CRSFactory;
103
import com.iver.cit.gvsig.fmap.drivers.ConnectionJDBC;
104
import com.iver.cit.gvsig.fmap.drivers.DBException;
105
import com.iver.cit.gvsig.fmap.drivers.DBLayerDefinition;
106
import com.iver.cit.gvsig.fmap.drivers.DefaultJDBCDriver;
107
import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
108
import com.iver.cit.gvsig.fmap.drivers.FieldDescription;
109
import com.iver.cit.gvsig.fmap.drivers.IConnection;
110
import com.iver.cit.gvsig.fmap.drivers.IFeatureIterator;
111
import com.iver.cit.gvsig.fmap.drivers.db.utils.ConnectionWithParams;
112
import com.iver.cit.gvsig.fmap.drivers.db.utils.SingleVectorialDBConnectionManager;
113
import com.iver.cit.gvsig.fmap.edition.IWriteable;
114
import com.iver.cit.gvsig.fmap.edition.IWriter;
115
import com.iver.cit.gvsig.fmap.layers.LayerFactory;
116
import com.iver.cit.gvsig.fmap.layers.XMLException;
117
import com.iver.utiles.NumberUtilities;
118
import com.iver.utiles.XMLEntity;
119
import com.vividsolutions.jts.algorithm.CGAlgorithms;
120
import com.vividsolutions.jts.geom.Coordinate;
121
import com.vividsolutions.jts.geom.Geometry;
122
import com.vividsolutions.jts.geom.GeometryFactory;
123
import com.vividsolutions.jts.geom.LineString;
124
import com.vividsolutions.jts.geom.LinearRing;
125
import com.vividsolutions.jts.geom.MultiPolygon;
126
import com.vividsolutions.jts.geom.Polygon;
127
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
128

    
129
import es.prodevelop.cit.gvsig.fmap.drivers.jdbc.oracle.OracleSpatialUtils;
130

    
131

    
132
/**
133
 * Vectorial driver to access Oracle databases geometries
134
 * Should work on Oracle Locator.
135
 *
136
 * It contains switches to test different modules to perform the
137
 * translation oracle structs --> gvsig geometries:
138
 *
139
 * - Parsing the structs directly.
140
 * - Using Oracle's JGeometry static methods
141
 * - Using Geotools utilities
142
 *
143
 *  (currently, the driver parses the structs directly)
144
 *
145
 * @author jldominguez
146
 *
147
 */
148
public class OracleSpatialDriver extends DefaultJDBCDriver
149
    implements IDelayedDriver, ICanReproject, IWriteable {
150
    private static Logger logger = Logger.getLogger(OracleSpatialDriver.class.getName());
151
    private static int FETCH_SIZE = 15000;
152

    
153
    // constants
154
    public static final int GEODETIC_FULLEXTENT_SAMPLE_SIZE = 50;
155
    public static final String GEODETIC_SRID = "8307";
156
    // public static final String ASSUMED_ORACLE_SRID = "8307";
157
    
158
    // ------------------------------------------------
159
    public static final String NAME = "Oracle Spatial Database Driver";
160
    public static final int ID_COLUMN_INDEX = 1;
161
    
162
    public static final String ALL_ORACLE_GEOMETADATA_VIEW = "ALL_SDO_GEOM_METADATA";
163
    public static final String USER_ORACLE_GEOMETADATA_VIEW = "USER_SDO_GEOM_METADATA";
164
    
165
    public static final String ORACLE_EPSG_TABLE_NAME = "ORA_EPSG";
166
    public static final String ORACLE_EPSG_FILE_NAME = "ORA_EPSG.DBF";
167
    public static final String DEFAULT_GEO_FIELD = "GEOMETRY";
168
    // public static final String DEFAULT_GEO_FIELD = "MERGEDGEOMETRY";
169

    
170
    public static final String ORACLE_ID_FIELD = "ROWID";
171
    public static final String DEFAULT_ID_FIELD_CASE_SENSITIVE = "GID";
172
    public static final String ORACLE_GEO_SCHEMA = "MDSYS";
173
    public static final String CONN_STR_BEGIN = "jdbc:oracle:thin:";
174
    
175
    public static final int VARCHAR2_STANDARD_SIZE = 80;
176
    public static final int VARCHAR2_LONG_SIZE = 256;
177
    public static final int MAX_ID_LENGTH = 30;
178
    private final static GeometryFactory geomFactory = new GeometryFactory();
179
    public static final double IRRELEVANT_DISTANCE = 0.00000001;
180
        private static final long ID_MIN_DELAY = 1000;
181

    
182
        public static final String ORACLE_JAR_FILE_NAME = "oracle.jdbc.driver.OracleDriver";
183

    
184
    static {
185
        try {
186
            Class.forName(ORACLE_JAR_FILE_NAME);
187
        }
188
        catch (ClassNotFoundException e) {
189
            throw new RuntimeException(e);
190
        }
191
    }
192

    
193
    private OracleSpatialWriter writer = null;
194

    
195
    // switch variable
196
    private boolean use_geotools = false;
197
    private boolean tableHasSrid = true;
198

    
199
    // ------------------------------------------------
200
    private boolean isNotAvailableYet = true;
201
    private Value nullVal = ValueFactory.createNullValue();
202
    private IdLoaderThread idLoader;
203
    private DriverAttributes drvAtts;
204
    private int[] pkOneBasedIndexes;
205
    private String[] fieldNames;
206
    private String not_restricted_sql = "";
207

    
208
    private Rectangle2D workingAreaInViewsCS = null;
209
    private Rectangle2D workingAreaInTablesCS = null;
210
    private STRUCT workingAreaInTablesCSStruct = null;
211

    
212
    private String idFieldNames;
213
    private int oneBasedGeoColInd = 0;
214
    private int shapeType = -1;
215
    private boolean needsCollectionLayer = true;
216

    
217
    // ----------------------------------------------
218
    // one feature is cached to avoid querying for each attribute request:
219
    private IFeature singleCachedFeature = null;
220
    private long singleCachedFeatureRowNum = -1;
221

    
222
    // ----------------------------------------------
223
    private boolean cancelIDLoad = false;
224

    
225
    // ----------------------------------------------
226
    private String fullTableName = "";
227
    private String geoColName = "";
228
    private String oracleSRID;
229
    private String epsgSRID;
230
    private String destProj = "";
231
    private Rectangle2D full_Extent = null;
232
    private boolean emptyWhereClause = true;
233
    private boolean isGeogCS = false;
234
    private boolean hasRealiableExtent = true;
235

    
236
    // new hash map to perform queries by row number:
237
    private HashMap rowToId = new HashMap();
238
        private String destProjOracle;
239
        private boolean isDestGeogCS = false;
240

    
241
    public OracleSpatialDriver() {
242
        drvAtts = new DriverAttributes();
243
        drvAtts.setLoadedInMemory(false);
244
    }
245

    
246
        public String getWhereClause() {
247
            return lyrDef.getWhereClause();
248
        }
249

    
250

    
251
    /**
252
     * This method is called when the user creates a new oracle
253
     * table from a vectorial layer
254
     *
255
     * @param params this array simply contains the parameters <tt>Connection</tt> and
256
     * <tt>DBLayerDefinition</tt>
257
     */
258
    public void setData(Object[] params) {
259
        setData((IConnection) params[0], (DBLayerDefinition) params[1]);
260
    }
261

    
262
    private void adjustLyrDef() throws SQLException {
263
        DBLayerDefinition ldef = getLyrDef();
264
        int cnt = metaData.getColumnCount();
265

    
266
        FieldDescription[] _new = new FieldDescription[cnt];
267

    
268
        for (int i = 0; i < cnt; i++) {
269
            _new[i] = new FieldDescription();
270
            _new[i].setFieldName(metaData.getColumnName(i + 1));
271
            _new[i].setDefaultValue(ValueFactory.createNullValue());
272
            _new[i].setFieldAlias(_new[i].getFieldName());
273
            _new[i].setFieldLength(getFieldWidth(i));
274

    
275
            int _type = metaData.getColumnType(i + 1);
276
            _new[i].setFieldType(_type);
277

    
278
            if ((_type == Types.FLOAT) || (_type == Types.DOUBLE) ||
279
                    (_type == Types.DECIMAL) || (_type == Types.REAL)) {
280
                _new[i].setFieldDecimalCount(6);
281
            }
282
            else {
283
                _new[i].setFieldDecimalCount(0);
284
            }
285
        }
286

    
287
        ldef.setFieldsDesc(_new);
288
        setLyrDef(ldef);
289
    }
290

    
291
    /**
292
     * Standard initializing method.
293
     */
294
    public void setData(IConnection _conn, DBLayerDefinition lyrDef) {
295
        conn = _conn;
296
        
297
        // This metadata is required to store layer in GVP
298
        // without problems:
299
        ConnectionWithParams _cwp =
300
                SingleVectorialDBConnectionManager.instance().findConnection(conn);
301
                host = _cwp.getHost();
302
                port = _cwp.getPort();
303
                dbName = _cwp.getDb();
304
                connName = _cwp.getName();
305

    
306
                try {
307
                        if (conn.isClosed()) {
308
                                SingleVectorialDBConnectionManager.instance().closeAndRemove(_cwp);
309
                                _cwp = SingleVectorialDBConnectionManager.instance().getConnection(
310
                                                _cwp.getDrvName(),
311
                                                _cwp.getUser(),
312
                                                _cwp.getPw(),
313
                                                _cwp.getName(),
314
                                                _cwp.getHost(),
315
                                                _cwp.getPort(),
316
                                                _cwp.getDb(), true);
317
                        }
318
                } catch (DBException e1) {
319
                        logger.error("While trying to reconnect: " + e1.getMessage());
320
                        logger.error("Layer will not be reloaded!");
321
                }
322
                
323
        // ------------------
324

    
325
                OracleSpatialUtils.setUpperCase(lyrDef);
326
        lyrDef.setConnection(conn);
327

    
328
        String geo_can[];
329
                try {
330
                        geo_can = getGeometryFieldsCandidates(conn, lyrDef.getTableName());
331
                        OracleSpatialUtils.removeStructFields(lyrDef, geo_can);
332
                } catch (DBException e) {
333
                        logger.error("While removing STRUCT fields: " + e.getMessage());
334
                }
335
        
336
        setLyrDef(lyrDef);
337

    
338
        geoColName = lyrDef.getFieldGeometry();
339
        
340
        String tn = lyrDef.getTableName();
341
        
342
        if (tn.indexOf(".") == -1) {
343
                
344
                if (lyrDef.getSchema() == null) {
345
                        fullTableName = _cwp.getUser().toUpperCase() + "." + tn;
346
                } else {
347
                        fullTableName = lyrDef.getSchema() + "." + tn;
348
                }
349
                
350
                
351
        } else {
352
                fullTableName = tn;
353
        }
354
        
355
        not_restricted_sql = "select " + getStandardSelectExpression() +
356
            " from " + getTableName() + " c ";
357

    
358
        // various metadata settings
359
        // getMetaDataInThisThread();
360
        cleanWhereClause();
361
        loadSdoMetadata();
362
        oneRowMetadata();
363

    
364
        setDestProjection(lyrDef.getSRID_EPSG());
365
        workingAreaInViewsCS = lyrDef.getWorkingArea();
366
        
367
        if ((workingAreaInViewsCS != null) && (epsgSRID != null)) {
368
            IProjection viewProj = CRSFactory.getCRS("EPSG:" + destProj);
369
            IProjection tableProj = CRSFactory.getCRS("EPSG:" + epsgSRID);
370
            ICoordTrans reprojecter = viewProj.getCT(tableProj);
371
                workingAreaInTablesCS = reprojecter.convert(workingAreaInViewsCS);
372
            workingAreaInTablesCSStruct = shapeToStruct(workingAreaInTablesCS,
373
                    FShape.NULL, tableHasSrid, false, true);
374
        }
375

    
376
        cancelIDLoad = false;
377
        idLoader = new IdLoaderThread(this);
378
        idLoader.start();
379
    }
380

    
381

    
382

    
383

    
384
        /**
385
     * Utility method to load IDs in a different thred, so that gvsig's gui
386
     * does not get blocked.
387
     *
388
     */
389
    public void getMetaDataInThisThread() {
390
        getMetadata();
391
    }
392

    
393
    private void getMetadata() {
394

    
395
            long id_load_start = System.currentTimeMillis();
396
        setIdRowTable();
397
        long id_load_end = System.currentTimeMillis();
398

    
399
        long delay = id_load_end - id_load_start;
400
        if (delay < ID_MIN_DELAY) {
401
                logger.info("Ids thread delayed by: " + (ID_MIN_DELAY - delay) + " ms.");
402
                try {
403
                                Thread.sleep(ID_MIN_DELAY - delay);
404
                        } catch (InterruptedException e) {
405
                                logger.error("While delaying ids thread: " + e.getMessage());
406
                        }
407
        }
408

    
409
        if (!hasRealiableExtent) {
410
                full_Extent = getEstimatedExtent(
411
                                getTableName(), geoColName, conn, 20, 1.5, isGeogCS);
412
        }
413

    
414
        if (cancelIDLoad) {
415
            return;
416
        }
417
    }
418

    
419
    private String getOracleSridFromCurrentRecord(ResultSet _rs)
420
        throws SQLException {
421
        Object obj = _rs.getObject("SRID");
422

    
423
        if (obj == null) {
424
            logger.warn("No SRID found for this table.");
425
            tableHasSrid = false;
426

    
427
            return null;
428
        }
429

    
430
        return obj.toString();
431
    }
432

    
433
    private Rectangle2D getFullExtentFromCurrentRecord(ResultSet _rs)
434
        throws SQLException {
435
        ARRAY dim_info_array = (ARRAY) _rs.getObject("DIMINFO");
436

    
437
        if (dim_info_array == null) {
438
            // no full extent found:
439
            return null;
440
        }
441
        else {
442
            Datum[] da = dim_info_array.getOracleArray();
443

    
444
            STRUCT sx = (STRUCT) da[0];
445
            STRUCT sy = (STRUCT) da[1];
446

    
447
            try {
448
                double minx = Double.parseDouble(sx.getAttributes()[1].toString());
449
                double maxx = Double.parseDouble(sx.getAttributes()[2].toString());
450
                double miny = Double.parseDouble(sy.getAttributes()[1].toString());
451
                double maxy = Double.parseDouble(sy.getAttributes()[2].toString());
452

    
453
                if (minx > maxx) {
454
                    double aux = minx;
455
                    minx = maxx;
456
                    maxx = aux;
457
                }
458

    
459
                if (miny > maxy) {
460
                    double aux = miny;
461
                    miny = maxy;
462
                    maxy = aux;
463
                }
464

    
465
                return getRectangle(minx, maxx, miny, maxy);
466

    
467
                // fullExtentJTS = shapeToGeometry(fullExtent);
468
            }
469
            catch (Exception ex) {
470
                    logger.error("While getting full extent from metadata table.");
471
                return null;
472
            }
473
        }
474
    }
475

    
476
    private void loadSdoMetadata() {
477
        try {
478
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
479
            String[] tokens = getTableName().split("\\u002E", 2);
480
            String qry;
481
            if (tokens.length > 1)
482
            {
483
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
484
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
485
                tokens[1] + "' AND COLUMN_NAME = '" + geoColName + "'";
486
            }
487
            else
488
            {
489
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
490
                " where TABLE_NAME = " + "'" + getTableName()
491
                + "' AND COLUMN_NAME = '"
492
                + geoColName + "'";
493

    
494
            }
495

    
496
            ResultSet _rs = _st.executeQuery(qry);
497

    
498
            if (_rs.next()) {
499
                oracleSRID = getOracleSridFromCurrentRecord(_rs);
500

    
501
                isGeogCS = OracleSpatialUtils.getIsGCS(oracleSRID, tableHasSrid);
502

    
503
                try {
504
                                        epsgSRID = oracleSridToEpsgSrid(oracleSRID);
505
                                } catch (Exception e) {
506
                                        logger.error("Unknown oracle SRID: " + oracleSRID);
507
                                        tableHasSrid = false;
508
                                }
509
                full_Extent = getFullExtentFromCurrentRecord(_rs);
510

    
511
                hasRealiableExtent = realiableExtent(full_Extent, isGeogCS);
512

    
513
                if (!hasRealiableExtent) {
514
                        full_Extent = getFastEstimatedExtent(
515
                                            getTableName(), geoColName, conn, 20, 10, isGeogCS);
516
                }
517

    
518
                _rs.close();
519
                _st.close();
520
            }
521
            else {
522
                throw new SQLException("Empty resultset from this query: " +
523
                    qry);
524
            }
525
        }
526
        catch (SQLException se) {
527
                logger.error("While getting SDO metadata: " + se.getMessage());
528
        }
529
    }
530

    
531
    /**
532
     * Utility method to get a geometry from a struct.
533
     *
534
     * @param theStruct the struct to be converted
535
     * @param use_gtools switch to use geotools classes or not
536
     * @return the geometry
537
     * @throws SQLException
538
     */
539
    public IGeometry getGeometryUsing(STRUCT theStruct, boolean use_gtools)
540
        throws SQLException {
541
        IGeometry _igeom = null;
542

    
543
        if (theStruct == null) {
544
            return OracleSpatialUtils.NULL_GEOM;
545
        }
546

    
547
        if (use_gtools) { // geotools
548
//            _igeom = getGeotoolsIGeometry(theStruct);
549
        }
550
        else { // jgeometry
551
            _igeom = getFMapGeometry(theStruct, false);
552
        }
553

    
554
        return _igeom;
555
    }
556
    
557
    /**
558
     * Utility method to transform a struct into a IGeometry.
559
     *
560
     * @param st the struct to be converted
561
     * @param complex comes from a complex sdo geometry
562
     * @return the IGeometry
563
     */
564
    private IGeometry getFMapGeometry(STRUCT st, boolean complex) {
565

    
566
            if (st == null) {
567
                    return new FNullGeometry();
568
            }
569
            
570

    
571
        Datum[] the_data = null;
572

    
573
        try {
574
            the_data = st.getOracleAttributes();
575

    
576
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
577
            jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype, complex);
578

    
579
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
580

    
581
            if (dim < 2) {
582
                dim = 2;
583
            }
584

    
585
            IGeometry ig = null;
586

    
587
            if (OracleSpatialUtils.isActuallyACollection(the_data)) {
588
                jgtype = FShape.MULTI;
589
            }
590

    
591
            switch (jgtype) {
592
            case FShape.MULTI:
593

    
594
                // int srid = ((NUMBER) the_data[1]).intValue();
595
                ig = getFMapGeometryCollection(the_data, dim);
596

    
597
                break;
598

    
599
            case FShape.POINT:
600
                ig = OracleSpatialUtils.getFMapGeometryPoint(the_data, dim);
601

    
602
                break;
603

    
604
            case FShape.LINE:
605
                ig = OracleSpatialUtils.getFMapGeometryMultiLineString(the_data, dim);
606

    
607
                break;
608

    
609
            case FShape.POLYGON:
610
                ig = OracleSpatialUtils.getFMapGeometryMultipolygon(the_data, dim);
611

    
612
                break;
613
            }
614

    
615
            return ig;
616
        }
617
        catch (SQLException e) {
618
            logger.error(e);
619
        }
620

    
621
        return null;
622
    }
623

    
624

    
625
    private Rectangle2D getRectangle(double minx, double maxx, double miny,
626
        double maxy) {
627
        Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx,
628
                maxy - miny);
629
        return resp;
630
    }
631

    
632
    private void oneRowMetadata() {
633
        try {
634

    
635
            st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
636
                    ResultSet.CONCUR_READ_ONLY);
637
            
638
            ResultSet _rs = null;
639
            shapeType = guessShapeType();
640
            // -----------------------
641
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
642
            metaData = _rs.getMetaData();
643
            userName = ((ConnectionJDBC)conn).getConnection().getMetaData().getUserName();
644

    
645
            // geoColInd = _rs.findColumn(geoColName);
646
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
647

    
648
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
649
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
650

    
651
            int cnt = metaData.getColumnCount();
652
            fieldNames = new String[cnt];
653

    
654
            for (int i = 0; i < cnt; i++) {
655
                fieldNames[i] = metaData.getColumnName(i + 1);
656
            }
657

    
658
            getIdFieldNames();
659
            adjustLyrDef();
660
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan
661
        }
662
        catch (SQLException se) {
663
            logger.error("While getting metadata. " + se.getMessage());
664
        }
665
    }
666

    
667
    private int guessShapeType() {
668

    
669
            int resp = FShape.MULTI;
670

    
671
        String _sql = "select " + getStandardSelectExpression() + ", c." +
672
        geoColName + " from " + getTableName() + " c ";
673

    
674
        ResultSet _rs = null;
675
        STRUCT sample_geo = null;
676
        
677
        try {
678
                _sql = _sql + " where c." + geoColName + " is not NULL AND "
679
                    + OracleSpatialUtils.EXPONENTIAL_INDICES_CONDITION;
680
                
681
            _rs = st.executeQuery(_sql);
682

    
683
            int aux = 0;
684
            ArrayList shptypes = new ArrayList();
685
            while (_rs.next()) {
686
                sample_geo = (STRUCT) _rs.getObject(geoColName);
687
                aux = OracleSpatialUtils.getShapeTypeOfStruct(sample_geo);
688
                shptypes.add(new Integer(aux));
689
            }
690
            if (shptypes.size() > 0) {
691
                    resp = getShapeTypeFromArray(shptypes);
692
            }
693
        } catch (Exception ex) {
694
                logger.error("While guessing shape type: " + ex.getMessage());
695
                logger.warn("Assumed MULTI");
696
        }
697
        
698
        return resp;
699
        }
700

    
701
        private int getShapeTypeFromArray(ArrayList arrlist) {
702
                
703
                int resp = ((Integer) arrlist.get(0)).intValue();
704
                
705
                int sz = arrlist.size();
706
                int aux = 0;
707
                for (int i=1; i<sz; i++) {
708
                        aux = ((Integer) arrlist.get(i)).intValue();
709
                        if (aux != resp) return FShape.MULTI;
710
                }
711
                return resp;
712
        }
713

    
714
        private String getIdFieldNames() {
715
        try {
716
            idFieldNames = "";
717

    
718
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
719
                idFieldNames = idFieldNames +
720
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
721
            }
722
        }
723
        catch (SQLException se) {
724
        }
725

    
726
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
727

    
728
        return idFieldNames;
729
    }
730

    
731
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
732
        int[] _res = new int[1];
733
        _res[0] = 1;
734

    
735
        return _res;
736
    }
737

    
738
    public String getSqlTotal() {
739
        // TODO Auto-generated method stub
740
        return "";
741
    }
742

    
743
    public String getCompleteWhere() {
744
        // TODO Auto-generated method stub
745
        return "";
746
    }
747

    
748
    /**
749
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
750
     * and uses directly that sentence to query the table).
751
     */
752
    public IFeatureIterator getFeatureIterator(String sql)
753
        throws ReadDriverException {
754
        if (isNotAvailableYet) {
755
                return new AnEmptyFeatureIterator();
756
            // return null;
757
        }
758

    
759
        singleCachedFeatureRowNum = -1;
760

    
761
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
762

    
763
        ResultSet localrs = (ResultSet) rs_st[0];
764
        Statement _st = (Statement) rs_st[1];
765

    
766
        return new OracleSpatialFeatureIterator(this, localrs, _st,
767
            oneBasedGeoColInd, use_geotools, false, null);
768
    }
769

    
770
    /**
771
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
772
     */
773
    public String getConnectionStringBeginning() {
774
        // oracle
775
        return CONN_STR_BEGIN;
776
    }
777

    
778
    public void open() { // throws DriverException {
779
    }
780

    
781
    /**
782
     * Gets Oracle's default port: 1521
783
     */
784
    public int getDefaultPort() {
785
        // oracle port
786
        return 1521;
787
    }
788

    
789
    /**
790
     * Gets the feature iterator for a given rectangle (the view's bounding box)
791
     * and a SRS.
792
     */
793
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
794
        throws ReadDriverException {
795
        if (isNotAvailableYet) {
796
                return new AnEmptyFeatureIterator();
797
            // return null;
798
        }
799

    
800
        singleCachedFeatureRowNum = -1;
801
        
802
        STRUCT local_st = shapeToStruct(r, FShape.NULL, tableHasSrid, false, true);
803
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
804
        ResultSet localrs = (ResultSet) rs_st[0];
805
        Statement _st = (Statement) rs_st[1];
806

    
807
        return new OracleSpatialFeatureIterator(this, localrs, _st,
808
            oneBasedGeoColInd, use_geotools, false, null);
809
    }
810

    
811
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
812
        if (workingAreaInTablesCS == null) return r;
813
        return OracleSpatialUtils.doIntersect(r, workingAreaInTablesCS);
814
    }
815

    
816
    /**
817
     * This method reverts to the one without the fields specification.
818
     * The fields have been selected from the start.
819
     */
820
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
821
        String[] alphaNumericFieldsNeeded) throws ReadDriverException {
822
            
823
        if (isNotAvailableYet) {
824
                return new AnEmptyFeatureIterator();
825
            // return null;
826
        }
827
        singleCachedFeatureRowNum = -1;
828

    
829
        if ((alphaNumericFieldsNeeded == null) || (alphaNumericFieldsNeeded.length == 0)) {
830
            return getFeatureIterator(r, strEPSG);
831
        } else {
832

    
833
            STRUCT local_st = shapeToStruct(r, FShape.NULL, tableHasSrid, false, true);
834
            Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
835
            ResultSet localrs = (ResultSet) rs_st[0];
836
            Statement _st = (Statement) rs_st[1];
837

    
838
            return new OracleSpatialFeatureIterator(this, localrs, _st,
839
                oneBasedGeoColInd, use_geotools, true, alphaNumericFieldsNeeded);
840
        }
841
    }
842

    
843
    private String getSqlFor(String[] alphaNumericFieldsNeeded, String sdo_inter) {
844
            
845
            String idswhere = getIdsQueryWhereClause(false);
846
        String custom_sel = getCustomSelect(alphaNumericFieldsNeeded, sdo_inter, idswhere);
847
                return custom_sel;
848
        }
849

    
850
        public String getGeometryField(String fieldName) {
851
        return fieldName;
852
    }
853

    
854
    public DriverAttributes getDriverAttributes() {
855
        return drvAtts;
856
    }
857

    
858
    /**
859
     * Gets the requested geometry. Always performs a new query in this case.
860
     * This should be a rare way to get the geometries. The standard way is by using
861
     * the iterators.
862
     */
863
    public IGeometry getShape(int _ind) throws ReadDriverException {
864
        if (isNotAvailableYet) {
865
            return OracleSpatialUtils.NULL_GEOM;
866
        }
867

    
868
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
869

    
870
        String _sql = "select " + geoColName + " from " + getTableName() +
871
            " where rowid = ?";
872

    
873
        try {
874
            java.sql.PreparedStatement ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(_sql);
875
            ps.setObject(1, r_id);
876

    
877
            // Statement stmnt = conn.createStatement();
878
            ps.execute();
879

    
880
            ResultSet _res = ps.getResultSet();
881

    
882
            if (_res.next()) {
883
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
884
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
885
                _res.close();
886
                ps.close();
887

    
888
                return theGeom;
889
            }
890
            else {
891
                logger.error("Unable to get shape: " + _ind +
892
                    " (probably due to edition)");
893
                
894

    
895
                return OracleSpatialUtils.NULL_GEOM;
896
            }
897
        }
898
        catch (SQLException se) {
899
            throw new ReadDriverException(getName(), se);
900
        }
901
    }
902

    
903
    public boolean isWritable() {
904
        return true;
905
    }
906

    
907
    public String getName() {
908
        return NAME;
909
    }
910

    
911
    public int[] getPrimaryKeys() throws ReadDriverException {
912
        return pkOneBasedIndexes;
913
    }
914

    
915

    
916

    
917

    
918
    private void setIdRowTable() {
919
        hashRelate = new Hashtable();
920

    
921
        java.sql.PreparedStatement ps = null;
922

    
923
        try {
924
            String _sql = getIdAndElemInfoFullResulltSetQuery();
925

    
926
            logger.debug("SQL para leer ids: " + _sql);
927
            Statement st = null;
928

    
929

    
930
            st = ((ConnectionJDBC)conn).getConnection().createStatement(
931
                            ResultSet.TYPE_FORWARD_ONLY,
932
                            ResultSet.CONCUR_READ_ONLY);
933
            
934
            
935

    
936
            // st = ((ConnectionJDBC)conn).getConnection().createStatement();
937

    
938
             st.setFetchSize(FETCH_SIZE);
939
             logger.info("FETCH_SIZE = " + FETCH_SIZE);
940

    
941
            ResultSet _r = null;
942
            _r = st.executeQuery(_sql);
943

    
944
            ROWID ri = null;
945

    
946
            int row = 0;
947
            String gid;
948
            Value aux = null;
949

    
950
            // ----------------------------------- types init
951
            ArrayList types = new ArrayList();
952
            int types_aux = 0;
953

    
954
            ARRAY info_aux;
955
            int[] info_aux_int;
956
            int size;
957

    
958
            // ----------------------------------- types init
959
            logger.debug("Beginning of result set:");
960

    
961
            while (_r.next()) {
962
                // ---------------------------------------
963
                ri = (ROWID) _r.getObject(1);
964
                gid = ri.stringValue();
965
                aux = ValueFactory.createValue(gid);
966

    
967
                Integer intobj = new Integer(row);
968
                hashRelate.put(aux, intobj);
969
                rowToId.put(intobj, ri);
970

    
971
                if ((row % 5000) == 0) {
972
                    // ------------------------------------------- cancel load
973
                    if (cancelIDLoad) {
974
                        hashRelate.clear();
975
                        rowToId.clear();
976

    
977
                        return;
978
                    }
979

    
980
                    // -------------------------------------------
981
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
982
                    logger.info("IDs read: " + fmt);
983
                }
984

    
985
                row++;
986

    
987
                // --------------------------------------- types
988
                info_aux = (ARRAY) _r.getObject(2);
989

    
990
                if (info_aux == null) {
991
                    // logger.debug("NULL info array found in record: " + row);
992
                }
993
                else {
994
                    info_aux_int = info_aux.getIntArray();
995
                    size = info_aux_int.length / 3;
996

    
997
                    for (int i = 0; i < size; i++) {
998
                        types_aux = info_aux_int[(3 * i) + 1];
999
                        types.add(new Integer(types_aux % 1000));
1000
                    }
1001
                }
1002

    
1003
                // --------------------------------------- types end
1004
            }
1005

    
1006
            _r.close();
1007
//            ps.close();
1008
            st.close();
1009
            numReg = row;
1010

    
1011
            needsCollectionLayer = OracleSpatialUtils.hasSeveralGeometryTypes(types, false);
1012

    
1013
            if (needsCollectionLayer) {
1014
                shapeType = FShape.MULTI;
1015
            }
1016
        }
1017
        catch (SQLException e) {
1018
                logger.error("While setting id-row hashmap: " +
1019
                e.getMessage());
1020
        }
1021
    }
1022

    
1023
    public int getFieldCount() throws ReadDriverException {
1024
        try {
1025
            return metaData.getColumnCount();
1026
        }
1027
        catch (SQLException e) {
1028
                logger.error("While getting field count: " + e.getMessage());
1029
            throw new ReadDriverException(getName(), e);
1030
        }
1031
    }
1032

    
1033
    public String[] getFieldNames() {
1034
        return fieldNames;
1035
    }
1036

    
1037
    public String getTotalFields() {
1038
        String strAux = "";
1039

    
1040
        for (int i = 0; i < fieldNames.length; i++) {
1041
            if (i == 0) {
1042
                strAux = fieldNames[i];
1043
            }
1044
            else {
1045
                strAux = strAux + ", " + fieldNames[i];
1046
            }
1047
        }
1048

    
1049
        return strAux;
1050
    }
1051

    
1052
    public int getFieldType(int idField) throws ReadDriverException {
1053
        int i = 0;
1054

    
1055
        try {
1056
            i = idField + 1; // idField viene basado en 0
1057

    
1058
            int __type = metaData.getColumnType(i);
1059
            int size = metaData.getPrecision(i);
1060
            int dec_pos = metaData.getScale(i);
1061

    
1062
            // we must add this entry because we did not remove the 'geometry' column
1063
            if (__type == Types.STRUCT) {
1064
                return Types.VARCHAR; // .STRUCT;
1065
                // ----------------------------------------------------------------------
1066
            }
1067

    
1068
            if (__type == Types.VARCHAR) {
1069
                return Types.VARCHAR;
1070
            }
1071

    
1072
            if (__type == Types.FLOAT) {
1073
                return Types.FLOAT;
1074
            }
1075

    
1076
            if (__type == Types.DOUBLE) {
1077
                return Types.DOUBLE;
1078
            }
1079

    
1080
            if ((__type == Types.INTEGER)
1081
                            || (__type == Types.SMALLINT)
1082
                            || (__type == Types.TINYINT)
1083
                            || (__type == Types.BIGINT)
1084
                            || ((__type == Types.NUMERIC) && (dec_pos == 0))
1085
                            ) {
1086
                    
1087
                    if (size > 10) {
1088
                            return Types.BIGINT;
1089
                    } else {
1090
                            return Types.INTEGER;
1091
                    }
1092
            }
1093

    
1094
            if (__type == Types.BIT) {
1095
                return Types.BIT;
1096
            }
1097

    
1098
            if (__type == Types.DATE) {
1099
                return Types.DATE;
1100
            }
1101

    
1102
            if (__type == Types.DECIMAL) {
1103
                return Types.DOUBLE;
1104
            }
1105

    
1106
            if (__type == Types.NUMERIC) {
1107
                    return Types.DOUBLE;
1108
            }
1109

    
1110
            if (__type == Types.DATE) {
1111
                return Types.DATE;
1112
            }
1113

    
1114
            if (__type == Types.TIME) {
1115
                return Types.TIME;
1116
            }
1117

    
1118
            if (__type == Types.TIMESTAMP) {
1119
                return Types.TIMESTAMP;
1120
            }
1121
        }
1122
        catch (SQLException e) {
1123
            logger.error("Unknown field type of : " + i);
1124
            throw new ReadDriverException(getName(), e);
1125
        }
1126

    
1127
        return -1;
1128
    }
1129

    
1130

    
1131
    public String getFieldName(int fieldId) throws ReadDriverException {
1132
        return fieldNames[fieldId];
1133
    }
1134

    
1135
    public int getFieldWidth(int fieldId) {
1136
        int i = -1;
1137

    
1138
        try {
1139
            int aux = fieldId + 1; // fieldId viene basado en 0
1140
            i = metaData.getColumnDisplaySize(aux);
1141
        }
1142
        catch (SQLException e) {
1143
            logger.error("While getting field width: " + e.getMessage());
1144
        }
1145

    
1146
        if (i < 0) {
1147
            i = 255;
1148
        }
1149

    
1150
        return i;
1151
    }
1152

    
1153
    public Value getFieldValue(long rowIndex, int field_Id) throws ReadDriverException {
1154
        if (isNotAvailableYet) {
1155
            return nullVal;
1156
        }
1157

    
1158
        if ((singleCachedFeature != null) &&
1159
                (rowIndex == singleCachedFeatureRowNum)) {
1160
            return singleCachedFeature.getAttributes()[field_Id];
1161
        }
1162

    
1163
        // return ValueFactory.createNullValue();
1164
        ResultSet _r = null;
1165
        java.sql.PreparedStatement ps = null;
1166

    
1167
        try {
1168
            String rnq = getSearchId();
1169
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1170

    
1171
            ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(rnq);
1172
            ps.setObject(1, _id);
1173

    
1174
            ps.execute();
1175
            _r = ps.getResultSet();
1176
            
1177
            if (!_r.next()) {
1178
                _r.close();
1179
                ps.close();
1180
                    throw new SQLException("No row for ROWID: " + _id.toString() + ". Possibly deleted from another app.");
1181
            }
1182
            
1183
        } catch (SQLException se) {
1184
                logger.error("While getting row " + rowIndex + " : " + se.getMessage());
1185
                return ValueFactory.createNullValue();
1186
        }
1187

    
1188
        IFeature ife = null;
1189
        Value[] atts = null;
1190

    
1191
        try {
1192
            ROWID ri = (ROWID) _r.getObject(1);
1193
            atts = getAttributes(_r, true);
1194

    
1195
            String gid = ri.stringValue();
1196
            STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1197
            IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1198
            ife = new DefaultFeature(theGeom, atts, gid);
1199
            _r.close();
1200
            ps.close();
1201
        } catch (SQLException se) {
1202
            logger.error("Error while doing next(): " + se.getMessage(), se);
1203
            return ValueFactory.createNullValue();
1204
        }
1205

    
1206
        // -------------------------------
1207
        singleCachedFeature = ife;
1208
        singleCachedFeatureRowNum = rowIndex;
1209

    
1210
        // -------------------------------
1211
        if (atts == null) {
1212
            return ValueFactory.createNullValue();
1213
        } else {
1214
            return atts[field_Id];
1215
        }
1216
    }
1217

    
1218

    
1219

    
1220
    public Rectangle2D getFullExtent() {
1221
            return full_Extent;
1222
    }
1223

    
1224

    
1225

    
1226
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim) {
1227
        // int __srid) {
1228

    
1229
            NUMBER _srid = new NUMBER(0);
1230
        NUMBER main_type = new NUMBER((dim * 1000) +
1231
                OracleSpatialUtils.getStructType(the_data));
1232

    
1233

    
1234
        Datum[] all_info_array = null;
1235
        Object[] elems_info_aray = null;
1236
        Datum[] all_ords = null;
1237

    
1238
        Object[] ords_of_groups = null;
1239
        Object[] _elems_info_aray = null;
1240
        try {
1241
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1242
            elems_info_aray = OracleSpatialUtils.groupByElement(all_info_array);
1243
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1244

    
1245
            ords_of_groups = OracleSpatialUtils.getOrdOfGroups(all_ords, elems_info_aray);
1246
            _elems_info_aray = new Object[elems_info_aray.length];
1247
        }
1248
        catch (SQLException e) {
1249
            logger.error("Unexpected error: " + e.getMessage());
1250
        }
1251

    
1252

    
1253
        for (int i = 0; i < elems_info_aray.length; i++) {
1254
            _elems_info_aray[i] = OracleSpatialUtils.updateIndexes((Datum[]) elems_info_aray[i]);
1255
        }
1256

    
1257
        // _elems_info_aray, ords_of_groups
1258
        int no_of_elems = ords_of_groups.length;
1259
        IGeometry[] geoms = new IGeometry[no_of_elems];
1260

    
1261
        for (int i = 0; i < no_of_elems; i++) {
1262
            Datum[] item_info_array = null;
1263
            Datum[] item_ords = null;
1264
            NUMBER gtype = null;
1265

    
1266
            try {
1267
                item_info_array = (Datum[]) _elems_info_aray[i];
1268
                item_ords = (Datum[]) ords_of_groups[i];
1269

    
1270
                gtype = new NUMBER((dim * 1000) +
1271
                        (item_info_array[1].intValue() % 1000));
1272

    
1273
                if (tableHasSrid) {
1274
                        _srid = new NUMBER(Integer.parseInt(oracleSRID));
1275
                }
1276
            }
1277
            catch (SQLException se) {
1278
                logger.error("Unexpected error: " + se.getMessage());
1279
            }
1280

    
1281
            // if it's the first geometry, the type is the collection's main type (no?) - no
1282
            // if (i == 0) gtype = main_type;
1283

    
1284
            STRUCT itemst = null;
1285

    
1286
            if (tableHasSrid) {
1287

    
1288
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1289
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1290
            }
1291
            else {
1292
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1293
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1294
            }
1295

    
1296
            geoms[i] = getFMapGeometry(itemst, true);
1297
        }
1298

    
1299
        return new FGeometryCollection(geoms);
1300
    }
1301

    
1302

    
1303

    
1304

    
1305

    
1306

    
1307

    
1308

    
1309
    private void cleanWhereClause() {
1310
        emptyWhereClause = false;
1311

    
1312
        String aux = getWhereClauseWithoutWhere();
1313

    
1314
        for (int i = 0; i < aux.length(); i++)
1315
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
1316
                return;
1317
            }
1318

    
1319
        getLyrDef().setWhereClause("");
1320
        emptyWhereClause = true;
1321
    }
1322

    
1323

    
1324

    
1325
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
1326
        String resp = "";
1327

    
1328
        if (isGeogCS) {
1329
            String vport = "sdo_filter(" + geoColName +
1330
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
1331
                "), 'querytype=window') = 'TRUE'";
1332

    
1333
                resp = "select " + getStandardSelectExpression() + ", c." +
1334
                    geoColName + " from " + getTableName() + " c where ";
1335
                if (idsLoadWhere.length() > 0) {
1336
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1337
                }
1338
                resp = resp + "(" + vport + ")";
1339
        }
1340
        else {
1341
                resp = "select " + getStandardSelectExpression() + ", c." +
1342
                    geoColName + " from " + getTableName() + " c where ";
1343
                if (idsLoadWhere.length() > 0) {
1344
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1345
                }
1346
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
1347
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
1348
        }
1349

    
1350
//        return "select " + getStandardSelectExpression() + ", c." +
1351
//        geoColName + " from " + getTableName() + " c";
1352
        return resp;
1353
    }
1354
    
1355
    private String getCustomSelect(String[] atts, String viewsdo, String idsLoadWhere) {
1356
        String resp = "";
1357
        
1358
        String atts_enum = "";
1359
        if ((atts == null) || (atts.length == 0)) {
1360
                
1361
        } else {
1362
                atts_enum = " c.\"" + atts[0] + "\" ";
1363
            for (int i=1; i<atts.length; i++) {
1364
                    atts_enum = atts_enum + ", " + atts[1]; 
1365
            }
1366
        }
1367

    
1368
        if (isGeogCS) {
1369
            String vport = "sdo_filter(" + geoColName +
1370
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
1371
                "), 'querytype=window') = 'TRUE'";
1372

    
1373
                resp = "select " + atts_enum + " from " + getTableName() + " c where ";
1374
                if (idsLoadWhere.length() > 0) {
1375
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1376
                }
1377
                resp = resp + "(" + vport + ")";
1378
        } else {
1379
                resp = "select " + atts_enum + " from " + getTableName() + " c where ";
1380
                if (idsLoadWhere.length() > 0) {
1381
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1382
                }
1383
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
1384
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
1385
        }
1386

    
1387
//        return "select " + getStandardSelectExpression() + ", c." +
1388
//        geoColName + " from " + getTableName() + " c";
1389
        return resp;
1390
    }    
1391

    
1392
    public void setWorkingArea(Rectangle2D rect) {
1393
    }
1394

    
1395
    private void setWAStructt() {
1396
    }
1397

    
1398

    
1399

    
1400
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
1401
        /*
1402
         * Tipos en Oracle Spatial usando JGeometry
1403
         *
1404
         * GTYPE_COLLECTION collection geometry type
1405
         * GTYPE_CURVE curve geoemtry type
1406
         * GTYPE_MULTICURVE multi-curve geometry type
1407
         * GTYPE_MULTIPOINT multi-point geometry type
1408
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
1409
         * GTYPE_POINT point geometry type
1410
         * GTYPE_POLYGON  polygon geometry type
1411
         *
1412
         * Tipos gvSIG FShape
1413
         *
1414
         * NULL = 0;
1415
         * POINT = 1;
1416
         * LINE = 2;
1417
         * POLYGON = 4;
1418
         * TEXT = 8;
1419
         * MULTI = 16;
1420
         * MULTIPOINT = 32;
1421
         * CIRCLE = 64;
1422
         * ARC = 128;
1423
         * ELLIPSE=256;
1424
         * Z=512
1425
         */
1426
        switch (type) {
1427
        case JGeometry_GTYPE_POLYGON:
1428
        case JGeometry_GTYPE_MULTIPOLYGON:
1429
            return FShape.POLYGON;
1430

    
1431
        case JGeometry_GTYPE_CURVE:
1432
        case JGeometry_GTYPE_MULTICURVE:
1433
            return FShape.LINE;
1434
        }
1435

    
1436
        logger.error("Unhandled Oracle Spatial geometry type: " + type +
1437
            " (conversion returned FShape.NULL)");
1438

    
1439
        return FShape.NULL;
1440
    }
1441
    
1442
    private String getValidViewConstructor(
1443
                    STRUCT _st,
1444
                    String ora_srid,
1445
                    boolean _hassrid,
1446
                    boolean _isgeocs) {
1447

    
1448
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
1449
            String resp = "";
1450
            if ((_hassrid) && (_isgeocs)) {
1451
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
1452
            } else {
1453
                    resp = sdo;
1454
            }
1455

    
1456
            return resp;
1457
    }
1458

    
1459

    
1460

    
1461
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
1462
        boolean hasSrid) throws ReadDriverException {
1463
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
1464
        String main_sel = "";
1465

    
1466
        if (fixsql == null) {
1467
            // main_sel = getMainSelect3(var_name);
1468
                String idswhere = getIdsQueryWhereClause(false);
1469
            main_sel = getMainSelect(sdo_intersect, idswhere);
1470
        }
1471
        else {
1472
            main_sel = fixsql;
1473
        }
1474

    
1475
        logger.debug("MAIN SEL = " + main_sel);
1476

    
1477
        ResultSet _rs = null;
1478
        Statement _stmnt = null;
1479
        Object[] _resp = new Object[2];
1480

    
1481
        try {
1482
            _stmnt = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_FORWARD_ONLY,
1483
                    ResultSet.CONCUR_READ_ONLY);
1484
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
1485
            _stmnt.setFetchSize(FETCH_SIZE);
1486

    
1487
            _rs = _stmnt.executeQuery(main_sel);
1488

    
1489
            // stmnt.close();
1490
        }
1491
        catch (SQLException se) {
1492
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
1493
                se);
1494
            throw new ReadDriverException(getName(), se);
1495
        }
1496

    
1497
        // this method returns the statement too, so that it can be closed afterwards
1498
        _resp[0] = _rs;
1499
        _resp[1] = _stmnt;
1500

    
1501
        return _resp;
1502
    }
1503

    
1504
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
1505
        String resp = "";
1506

    
1507
        try {
1508
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
1509
            String mdsys_sdo_ordinate_array = "";
1510
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
1511

    
1512
            for (int i = 0; i < vertices.length; i++) {
1513
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
1514
                    vertices[i].doubleValue() + ", ";
1515
            }
1516

    
1517
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
1518
                    mdsys_sdo_ordinate_array.length() - 2);
1519
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
1520
                mdsys_sdo_ordinate_array + ")";
1521

    
1522
            String aux = "";
1523

    
1524
            if (hasSrid) {
1525
                aux = oracleSRID;
1526

    
1527
                if (_isGeogCS) {
1528
                    aux = "0";
1529
                }
1530
            }
1531
            else {
1532
                aux = "null";
1533
            }
1534

    
1535
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
1536
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
1537
                ")";
1538
        }
1539
        catch (Exception ex) {
1540
                logger.error("While getting sdo contructor: " +
1541
                ex.getMessage());
1542
        }
1543

    
1544
        return resp;
1545
    }
1546

    
1547
    private String getIdsQueryWhereClause(boolean with_where) {
1548
                String resp = "";
1549

    
1550
                String _where = "";
1551
                if (with_where) _where = " where ";
1552

    
1553
                if (workingAreaInTablesCSStruct == null) {
1554
                        if (emptyWhereClause) {
1555
                                // return "select rowid from " + getTableName();
1556
                        } else {
1557
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
1558
                                                + ")";
1559
                        }
1560
                } else {
1561
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
1562
                                        oracleSRID, tableHasSrid, isGeogCS);
1563

    
1564
                        if (emptyWhereClause) {
1565
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
1566
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
1567
                        } else {
1568
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
1569
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
1570
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
1571
                        }
1572
                }
1573

    
1574
                // resp = resp + " order by rowid";
1575
                return resp;
1576
        }
1577

    
1578
    public String getIdAndElemInfoFullResulltSetQuery() {
1579
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
1580
            getTableName() + " c";
1581

    
1582
        resp = resp + getIdsQueryWhereClause(true);
1583
        return resp;
1584
    }
1585

    
1586
    private String getSearchId() {
1587
        if (emptyWhereClause) {
1588
            return "select " + getStandardSelectExpression() + ", c." +
1589
            geoColName + " from " + getTableName() + " c where rowid = ?";
1590
        }
1591
        else {
1592
            return "select " + getStandardSelectExpression() + ", c." +
1593
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
1594
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
1595
        }
1596
    }
1597

    
1598
    public int getShapeType() {
1599
        return shapeType;
1600
    }
1601

    
1602
    public void setShapeType(int t) {
1603
        shapeType = t;
1604
    }
1605
    
1606

    
1607
    private String getWhereClauseWithoutWhere() {
1608
        String resp = "";
1609
        String old = getLyrDef().getWhereClause();
1610
        resp = old;
1611

    
1612
        if (old.length() <= 6) {
1613
            return old;
1614
        }
1615

    
1616
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
1617
            resp = resp.substring(6, resp.length());
1618
        }
1619

    
1620
        return resp;
1621
    }
1622

    
1623

    
1624

    
1625
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
1626
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
1627

    
1628
        switch (fieldDesc.getFieldType()) {
1629
        case Types.SMALLINT:
1630
            aux = "NUMBER(5, 0)";
1631

    
1632
            break;
1633

    
1634
        case Types.INTEGER:
1635
            aux = "NUMBER(12, 0)";
1636

    
1637
            break;
1638

    
1639
        case Types.BIGINT:
1640
            aux = "NUMBER(38, 0)";
1641

    
1642
            break;
1643

    
1644
        case Types.BOOLEAN:
1645
            aux = "NUMBER(1, 0)";
1646

    
1647
            break;
1648

    
1649
        case Types.DECIMAL:
1650
            aux = "NUMBER";
1651

    
1652
            break;
1653

    
1654
        case Types.NUMERIC:
1655
            aux = "NUMBER";
1656

    
1657
            break;
1658

    
1659
        case Types.DOUBLE:
1660
            aux = "FLOAT";
1661

    
1662
            break;
1663

    
1664
        case Types.FLOAT:
1665
            aux = "FLOAT";
1666

    
1667
            break;
1668

    
1669
        case Types.CHAR:
1670
            aux = "CHAR(1 BYTE)";
1671

    
1672
            break;
1673

    
1674
        case Types.VARCHAR:
1675
            aux = "NVARCHAR2(" + nvarchar2Limited(fieldDesc.getFieldLength()) + ")";
1676

    
1677
            break;
1678

    
1679
        case Types.LONGVARCHAR:
1680
            aux = "NVARCHAR2(" + nvarchar2Limited(fieldDesc.getFieldLength()) + ")";
1681

    
1682
            break;
1683
        }
1684

    
1685
        return aux;
1686
    }
1687

    
1688
    // -----------------------------------------------------------
1689
    // -----------------------------------------------------------
1690
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
1691
        return "DROP TABLE " + dbLayerDef.getTableName() +
1692
        " CASCADE CONSTRAINTS";
1693
    }
1694

    
1695
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
1696
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
1697

    
1698
        String type = "";
1699
        String name = "";
1700
        String table_name = dbLayerDef.getTableName().toUpperCase();
1701

    
1702
        String resp = "CREATE TABLE " + table_name + " ( ";
1703

    
1704
        for (int i = 0; i < flds.length; i++) {
1705
            name = flds[i].getFieldName();
1706

    
1707
            // -------------- FORBIDDEN FIELD NAMES -----------------
1708
            if (!isOracleAllowedFieldname(name)) {
1709
                continue;
1710
            }
1711

    
1712
            // ------------------------------------------------------
1713
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
1714
            }
1715
            else {
1716
                name = getValidOracleID(name, i, false);
1717
                resp = resp + "\"" + name + "\" ";
1718
                type = fieldTypeToSqlStringType(flds[i]);
1719
                resp = resp + type + ", ";
1720
            }
1721
        }
1722

    
1723
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
1724
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
1725
        resp = resp + ", ";
1726

    
1727
        String pk = "CONSTRAINT " + getDerivedNAme(table_name, "PK") +
1728
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD_CASE_SENSITIVE +
1729
            "\") ENABLE";
1730

    
1731
        resp = resp + pk + " )";
1732

    
1733
        return resp;
1734
    }
1735

    
1736
    private static String getDerivedNAme(String tname, String suffix) {
1737

    
1738
            int ind = tname.lastIndexOf(".");
1739
            if (ind == -1) {
1740

    
1741
                    int l = Math.min(28, tname.length());
1742
                    return tname.substring(0, l) + "_" + suffix;
1743

    
1744
            } else {
1745

    
1746
                    String pre = tname.substring(0, ind);
1747
                    String post = tname.substring(ind + 1, tname.length());
1748
                    int lpost = Math.min(24, post.length());
1749
                    int lpre = Math.min(3, pre.length());
1750
                    return pre.substring(0, lpre) + "_" + post.substring(0, lpost) + "_" + suffix;
1751
            }
1752

    
1753
    }
1754

    
1755
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
1756
        String resp = "CREATE INDEX " + getDerivedNAme(dbLayerDef.getTableName(), "SX") +
1757
            " ON " + dbLayerDef.getTableName() + " (\"" +
1758
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
1759
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
1760

    
1761
        return resp;
1762
    }
1763

    
1764
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
1765

    
1766
            String tname = dbLayerDef.getTableName();
1767
            int ind = tname.lastIndexOf(".");
1768
            if (ind != -1) {
1769
                    String schema = tname.substring(0, ind);
1770
                    tname = tname.substring(ind + 1, tname.length());
1771
            return "DELETE FROM " + USER_ORACLE_GEOMETADATA_VIEW +
1772
            " WHERE TABLE_NAME = '" + tname + "'";
1773

    
1774
            } else{
1775
            return "DELETE FROM " + USER_ORACLE_GEOMETADATA_VIEW +
1776
            " WHERE TABLE_NAME = '" + tname + "'";
1777
            }
1778
    }
1779

    
1780
    /**
1781
     * UTility method to get the SQL sentence needed to update the geographic metadata table
1782
     * with a new bounding box and SRS
1783
     *
1784
     * @param tName table name
1785
     * @param ora_srid new SRS
1786
     * @param bbox new bounding box
1787
     * @param dim geometries dimension
1788
     * @param withsrid False if the SRS is set to NULL. True otherwise.
1789
     * @return the SQL sentence to perform the update
1790
     */
1791
    public static String getMetadataUpdateSql(String schema, String tName, String ora_srid,
1792
        Rectangle2D bbox, int dim, boolean withsrid) {
1793
            
1794
        String[] dim_name = new String[dim];
1795
        double tolerance = 0.5;
1796
        
1797
        String _ora_srid = ora_srid;
1798
        if (_ora_srid == null) _ora_srid = "NULL";
1799

    
1800
        if (_ora_srid.compareTo(GEODETIC_SRID) == 0) {
1801
            dim_name[0] = "LONGITUDE";
1802
            dim_name[1] = "LATITUDE";
1803
        }
1804
        else {
1805
            dim_name[0] = "X";
1806
            dim_name[1] = "Y";
1807

    
1808
            if (dim > 2) {
1809
                dim_name[2] = "Z";
1810

    
1811
                if (dim > 3) {
1812
                    dim_name[3] = "T";
1813
                }
1814
            }
1815
        }
1816
        
1817
        double minx = bbox.getMinX();
1818
        double miny = bbox.getMinY();
1819
        double maxx = bbox.getMaxX();
1820
        double maxy = bbox.getMaxY();
1821
        
1822
        String resp = "INSERT INTO " + USER_ORACLE_GEOMETADATA_VIEW + " " +
1823
            " ( TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
1824
            + "'" + tName + "', "
1825
            + "'" + DEFAULT_GEO_FIELD + "', " +
1826
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
1827
            minx + ", " + maxx + ", " + tolerance + " ), " +
1828
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + miny + ", " +
1829
            maxy + ", " + tolerance + " ))";
1830

    
1831
        if (dim > 2) {
1832
            resp = resp.substring(0, resp.length() - 1) + ",";
1833
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
1834
                "', 0.0, 100.0, " + tolerance + " ))";
1835

    
1836
            if (dim > 3) {
1837
                resp = resp.substring(0, resp.length() - 1) + ",";
1838
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
1839
                    "', 0.0, 100.0, " + tolerance + " ))";
1840
            }
1841
        }
1842

    
1843
        if (withsrid) {
1844
            resp = resp + ", " + _ora_srid + " )";
1845
        }
1846
        else {
1847
            resp = resp + ", NULL )";
1848
        }
1849

    
1850
        return resp;
1851
    }
1852

    
1853
    /**
1854
     * Gets the SQL sentence to perform an insertion.
1855
     *
1856
     * @param feat feature to be added
1857
     * @param dbLayerDef layer definition
1858
     * @param rowInd row index
1859
     * @param _geoColName geometry field name
1860
     * @return the SQL sentence to perform the insertion
1861
     */
1862
    public static String getRowInsertSql(IFeature feat,
1863
        DBLayerDefinition dbLayerDef, int rowInd,
1864
        String _geoColName,
1865
        String geo_val) {
1866
            
1867
        String name = "";
1868
        int ftype = -1;
1869
        String aux_orig = "";
1870
        String aux_limited = "";
1871
        String aux_quotes_ok = "";
1872

    
1873
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
1874

    
1875
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
1876

    
1877
        for (int i = 0; i < fieldsDescr.length; i++) {
1878
            name = fieldsDescr[i].getFieldName();
1879
            ftype = fieldsDescr[i].getFieldType();
1880

    
1881
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
1882
            if (!isOracleAllowedFieldname(name)) continue;
1883
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
1884
            // ------------------------------------------------------
1885
            if (name.compareToIgnoreCase(_geoColName) == 0) {
1886
            }
1887
            else {
1888
                name = getValidOracleID(name, i, false);
1889
                resp = resp + "\"" + name + "\"" + " , ";
1890
            }
1891
        }
1892

    
1893
        resp = resp + _geoColName + " ) VALUES ( ";
1894

    
1895
        for (int i = 0; i < fieldsDescr.length; i++) {
1896
            name = fieldsDescr[i].getFieldName();
1897
            ftype = fieldsDescr[i].getFieldType();
1898

    
1899
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
1900
            if (!isOracleAllowedFieldname(name)) continue;
1901
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
1902
            // ------------------------------------------------------
1903
            String sur = getValueSurroundFromType(fieldsDescr[i]);
1904

    
1905
            if (name.compareToIgnoreCase(_geoColName) == 0) {
1906
            }
1907
            else {
1908
                if (name.compareTo(OracleSpatialDriver.DEFAULT_ID_FIELD_CASE_SENSITIVE) == 0) {
1909
                    resp = resp + rowInd + " , ";
1910
                }
1911
                else {
1912
                    Value attValue = feat.getAttribute(i);
1913

    
1914
                    if (attValue.toString() == null) {
1915
                        resp = resp + "NULL , ";
1916
                    }
1917
                    else {
1918
                        if (sur.length() > 0) {
1919
                            aux_orig = attValue.toString();
1920
                            aux_limited = cropStringValue(aux_orig, i,
1921
                                    fieldsDescr);
1922
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
1923

    
1924
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
1925
                        }
1926
                        else {
1927
                            String _aux = attValue.toString();
1928

    
1929
                            if (_aux.length() == 0) {
1930
                                _aux = "NULL";
1931
                            }
1932

    
1933
                            resp = resp + _aux + " , ";
1934
                        }
1935
                    }
1936
                }
1937
            }
1938
        }
1939

    
1940
        resp = resp + " " + geo_val + " )";
1941
        /*
1942
        String test = "SDO_UTIL.APPEND(SDO_GEOMETRY("
1943
                        + "2002, NULL, NULL,"
1944
                        + "SDO_ELEM_INFO_ARRAY(1, 2, 2),"
1945
                        + "SDO_ORDINATE_ARRAY(500000, 4000000, 1000000, 5000000, 500000, 5000000)"
1946
                        + "), ? )";
1947

1948
        resp = resp + " " + test + " )";
1949
        */
1950
        return resp;
1951
    }
1952

    
1953
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
1954

    
1955
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
1956
                    return true;
1957
            }
1958

    
1959
            if ((ftype == Types.BINARY)
1960
                || (ftype == Types.ARRAY)
1961
                || (ftype == Types.BLOB)
1962
                || (ftype == Types.CLOB)
1963
                || (ftype == Types.STRUCT)
1964
            ) {
1965
                    return false;
1966
            }
1967
                return true;
1968
        }
1969

    
1970
        /**
1971
     * Gets the SQL sentence to perform an update.
1972
     *
1973
     * @param feat feature to be updated
1974
     * @param dbLayerDef layer definition
1975
     * @param rowInd row index
1976
     * @param geoFieldName geometry field name
1977
     * @return the SQL sentence to perform the update
1978
     */
1979
    public static String getRowUpdateSql(IFeature feat,
1980
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
1981
        String name = "";
1982
        String aux_orig = "";
1983
        String aux_limited = "";
1984
        String aux_quotes_ok = "";
1985

    
1986
        Value[] atts = feat.getAttributes();
1987
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
1988

    
1989
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
1990

    
1991
        for (int i = 0; i < _fieldsDescr.length; i++) {
1992
            name = _fieldsDescr[i].getFieldName();
1993

    
1994
            // -------------- FORBIDDEN FIELD NAMES -----------------
1995
            if (!isOracleAllowedFieldname(name)) {
1996
                logger.info("Field: " + name + " will not be updated.");
1997
                continue;
1998
            }
1999

    
2000
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
2001
                        geoFieldName)) {
2002
                logger.info("Field: " + name + " will not be updated (it's a struct).");
2003
                continue;
2004
            }
2005

    
2006
            // ------------------------------------------------------
2007
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
2008
                // resp = resp + "\"" + name + "\"" + " = ?, ";
2009
            }
2010
            else {
2011
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
2012
                aux_orig = atts[i].toString();
2013
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
2014
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
2015
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
2016
                    sur + ", ";
2017
            }
2018
        }
2019

    
2020
        resp = resp + "\"" + geoFieldName + "\" = ?";
2021
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
2022

    
2023
        return resp;
2024
    }
2025

    
2026
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
2027
        String geoname) {
2028
        if (ftype == Types.STRUCT) {
2029
            if (fldname.compareToIgnoreCase(geoname) != 0) {
2030
                return true;
2031
            }
2032
        }
2033

    
2034
        return false;
2035
    }
2036

    
2037
    /**
2038
     * Gets the SQL sentence to perform a deletion.
2039
     *
2040
     * @param dbLayerDef layer definition
2041
     * @param id ROWID of the record to be deleted
2042
     * @return the SQL sentence to perform the deletion
2043
     */
2044
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
2045
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
2046
        resp = resp + " WHERE ROWID ='" + id + "'";
2047

    
2048
        return resp;
2049
    }
2050

    
2051
    private static String cropStringValue(String orig_val, int i,
2052
        FieldDescription[] _flds) {
2053
            
2054
        if (orig_val == null) {
2055
            return "NULL";
2056
        }
2057
        
2058
        if (NumberUtilities.isNumeric(_flds[i].getFieldType())
2059
                    && (orig_val.length() == 0)) {
2060
                    return "NULL";
2061
        }
2062

    
2063
        int tpe = _flds[i].getFieldType();
2064
        int max_size = OracleSpatialUtils.maxSizeForFieldType(tpe);
2065

    
2066
        if (max_size == -1) {
2067
            return orig_val;
2068
        }
2069

    
2070
        int or_size = orig_val.length();
2071

    
2072
        if (or_size <= max_size) {
2073
            return orig_val;
2074
        }
2075

    
2076
        return orig_val.substring(0, max_size);
2077
    }
2078

    
2079
    private static String avoidQuoteProblem(String str) {
2080
        return str.replaceAll("'", "''");
2081
    }
2082

    
2083
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
2084
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
2085
            return "";
2086
        }
2087

    
2088
        return "'";
2089
    }
2090

    
2091
    /**
2092
     * Utility function to translate a SRS code from EPSG to Oracle.
2093
     * Uses a datasource based on a DBF file.
2094
     *
2095
     * @param epsg the EPSG code
2096
     * @return the Oracle code
2097
     */
2098
    public static String epsgSridToOracleSrid(String _epsg) throws Exception {
2099
            
2100
            String epsg = removePrefix(_epsg);
2101
            
2102
        String resp = "8307";
2103

    
2104
        // --------------------------------------------
2105
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
2106
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
2107
        DataSource ds = null;
2108

    
2109
        try {
2110
            ds = LayerFactory.getDataSourceFactory()
2111
                             .executeSQL(sql,
2112
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
2113

    
2114
            if (ds.getRowCount() == 0) {
2115
                logger.error("EPSG code not found in table: " + epsg);
2116
                throw new Exception("Unknown EPSG: " + epsg);
2117
            }
2118

    
2119
            if (ds.getRowCount() > 1) {
2120
                logger.error("===============");
2121
                logger.error(
2122
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
2123
                    epsg);
2124

    
2125
                for (int i = 0; i < ds.getRowCount(); i++) {
2126
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
2127

    
2128
                    if (i == 0) {
2129
                        resp = "" + aux;
2130
                    }
2131

    
2132
                    logger.error("" + aux);
2133
                }
2134

    
2135
                logger.error("===============");
2136

    
2137
                return resp;
2138
            }
2139

    
2140
            resp = "" +
2141
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
2142
        }
2143
        catch (Exception pe) {
2144
            logger.error("Error with SQL statement. " + pe.getMessage());
2145
        }
2146

    
2147
        return resp;
2148
    }
2149

    
2150
    /**
2151
     * Utility function to translate a SRS code from Oracle to EPSG.
2152
     * Uses a datasource based on a DBF file.
2153
     *
2154
     * @param ora the Oracle code
2155
     * @return the EPSG code
2156
     */
2157
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
2158
            
2159
            if (ora == null) return null;
2160
            
2161
        String resp = "4326";
2162

    
2163
        // --------------------------------------------
2164
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
2165
            " where ORACLE = " + ora + ";";
2166
        DataSource ds = null;
2167

    
2168
        try {
2169
            ds = LayerFactory.getDataSourceFactory()
2170
                             .executeSQL(sql,
2171
                    DataSourceFactory.AUTOMATIC_OPENING);
2172

    
2173
            if (ds.getRowCount() == 0) {
2174
                logger.error("Oracle Spatial code not found in table: " + ora);
2175
                throw new Exception("Unknown Oracle code: " + ora);
2176
            }
2177

    
2178
            if (ds.getRowCount() > 1) {
2179
                logger.error("===============");
2180
                logger.error(
2181
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
2182
                    ora);
2183

    
2184
                for (int i = 0; i < ds.getRowCount(); i++) {
2185
                    String aux = "" +
2186
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
2187

    
2188
                    if (i == 0) {
2189
                        resp = aux;
2190
                    }
2191

    
2192
                    logger.error("" + aux);
2193
                }
2194

    
2195
                logger.error("===============");
2196

    
2197
                return resp;
2198
            }
2199

    
2200
            resp = "" +
2201
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
2202
        }
2203
        catch (Exception pe) {
2204
            logger.error("Error with SQL statement. " + pe.getMessage());
2205
        }
2206

    
2207
        return resp;
2208
    }
2209

    
2210
    /**
2211
     * This methos creates the datasource used to translate the SRS codes:
2212
     * EPSG <--> Oracle.
2213
     *
2214
     * It's called from several places, so checks that the datasource does not exist.
2215
     */
2216

    
2217

    
2218
    /**
2219
     * Utility method to get a valid Oracle identifier (in terms of length)
2220
     *
2221
     * @param str Proposed string
2222
     * @param ind field index of the given field name (used by the method to
2223
     * improve the renaming)
2224
     * @return an acceptable oracle identifier.
2225
     */
2226
    public static String getValidOracleID(String _str, int ind, boolean force_uppercase) {
2227
            
2228
            String str = _str;
2229
            if (force_uppercase) str = _str.toUpperCase();
2230
            
2231
        if (str.length() <= MAX_ID_LENGTH) {
2232
            return str;
2233
        }
2234

    
2235
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
2236
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
2237
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
2238
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
2239
        resp = resp + "_" + (ind % 1000);
2240

    
2241
        return resp;
2242
    }
2243

    
2244
    private static ArrayList ensureSensibleShell(ArrayList cc) {
2245
        if (sameCoordinate((Coordinate) cc.get(0),
2246
                    (Coordinate) cc.get(cc.size() - 1))) {
2247
            if (cc.size() == 2) {
2248
                ArrayList resp = new ArrayList();
2249
                resp.add(cc.get(0));
2250

    
2251
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
2252
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
2253
                resp.add(newcoo);
2254

    
2255
                newcoo = new Coordinate((Coordinate) cc.get(0));
2256
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
2257
                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
2258
                resp.add(newcoo);
2259

    
2260
                resp.add(cc.get(0));
2261

    
2262
                return resp;
2263
            }
2264

    
2265
            if (cc.size() == 3) {
2266
                cc.remove(1);
2267

    
2268
                return ensureSensibleShell(cc);
2269
            }
2270

    
2271
            return cc;
2272
        }
2273
        else {
2274
            cc.add(cc.get(0));
2275

    
2276
            return cc;
2277
        }
2278
    }
2279

    
2280
    private static ArrayList ensureSensibleHole(ArrayList cc) {
2281
        if (sameCoordinate((Coordinate) cc.get(0),
2282
                    (Coordinate) cc.get(cc.size() - 1))) {
2283
            if (cc.size() == 2) {
2284
                ArrayList resp = new ArrayList();
2285
                resp.add(cc.get(0));
2286

    
2287
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
2288
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
2289
                resp.add(newcoo);
2290

    
2291
                newcoo = new Coordinate((Coordinate) cc.get(0));
2292
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
2293
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
2294
                resp.add(newcoo);
2295

    
2296
                resp.add(cc.get(0));
2297

    
2298
                return resp;
2299
            }
2300

    
2301
            if (cc.size() == 3) {
2302
                cc.remove(1);
2303

    
2304
                return ensureSensibleHole(cc);
2305
            }
2306

    
2307
            return cc;
2308
        }
2309
        else {
2310
            cc.add(cc.get(0));
2311

    
2312
            return cc;
2313
        }
2314
    }
2315

    
2316
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
2317
        if (cc.size() == 2) {
2318
            if (sameCoordinate((Coordinate) cc.get(0),
2319
                        (Coordinate) cc.get(cc.size() - 1))) {
2320
                ArrayList resp = new ArrayList();
2321
                resp.add(cc.get(0));
2322

    
2323
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
2324
                newc.x = newc.x + IRRELEVANT_DISTANCE;
2325
                resp.add(newc);
2326

    
2327
                return resp;
2328
            }
2329
        }
2330

    
2331
        return cc;
2332
    }
2333

    
2334
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
2335
        if (c1.x != c2.x) {
2336
            return false;
2337
        }
2338

    
2339
        if (c1.y != c2.y) {
2340
            return false;
2341
        }
2342

    
2343
        return true;
2344
    }
2345

    
2346
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
2347
        if (cc.size() == 2) {
2348
            return null;
2349
        }
2350

    
2351
        if (cc.size() == 3) {
2352
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
2353
                return null;
2354
            }
2355

    
2356
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
2357
                return null;
2358
            }
2359

    
2360
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
2361
                return null;
2362
            }
2363

    
2364
            cc.add(cc.get(0));
2365

    
2366
            return cc;
2367
        }
2368

    
2369
        if (!sameCoordinate((Coordinate) cc.get(0),
2370
                    (Coordinate) cc.get(cc.size() - 1))) {
2371
            cc.add(cc.get(0));
2372
        }
2373

    
2374
        return cc;
2375
    }
2376

    
2377
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
2378
        Coordinate[] p = new Coordinate[4];
2379
        p[0] = c;
2380

    
2381
        Coordinate nc = new Coordinate(c);
2382
        nc.x = nc.x + IRRELEVANT_DISTANCE;
2383

    
2384
        Coordinate nc2 = new Coordinate(nc);
2385
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
2386
        p[1] = nc;
2387
        p[2] = nc2;
2388
        p[3] = new Coordinate(c);
2389

    
2390
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
2391
        LinearRing ls = new LinearRing(cs, geomFactory);
2392
        Polygon po = new Polygon(ls, null, geomFactory);
2393
        Polygon[] pos = new Polygon[1];
2394
        pos[0] = po;
2395

    
2396
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
2397

    
2398
        return mpo;
2399
    }
2400

    
2401
    public String getSourceProjection(IConnection conn, DBLayerDefinition lyrDef) {
2402
            
2403
            String resp = null;
2404
        try {
2405
            Statement _st = ((ConnectionJDBC) conn).getConnection().createStatement();
2406
            String[] tokens = lyrDef.getName().split("\\u002E", 2);
2407
            String qry;
2408
            if (tokens.length > 1) {
2409
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2410
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
2411
                tokens[1] + "'";
2412
            } else {
2413
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2414
                " where TABLE_NAME = " + "'" + lyrDef.getName() + "'";
2415
            }
2416
            ResultSet _rs = _st.executeQuery(qry);
2417

    
2418
            if (_rs.next()) {
2419
                String aux = getOracleSridFromCurrentRecord(_rs);
2420
                try {
2421
                                        resp = oracleSridToEpsgSrid(aux);
2422
                                } catch (Exception e) {
2423
                                        logger.error("Unknown oracle SRID: " + aux);
2424
                                }
2425
            } else {
2426
                    
2427
            }
2428
        } catch (Exception ex) {
2429
                logger.error("While getting Source Projection: " + ex.getMessage());
2430
        }
2431
        
2432
        if (resp != null) {
2433
                return resp;
2434
        } else {
2435
                return getDestProjection();
2436
        }
2437
        
2438
    }
2439

    
2440
    public String getDestProjection() {
2441
        return removePrefix(destProj);
2442
    }
2443

    
2444
    public void setDestProjection(String toEPSG) {
2445
        destProj = toEPSG;
2446
        try {
2447
                        destProjOracle = epsgSridToOracleSrid(destProj);
2448
                        isDestGeogCS = OracleSpatialUtils.getIsGCS(destProjOracle, true);
2449

    
2450
                } catch (Exception e) {
2451
                        logger.error("Unknown EPSG code: " + destProj);
2452
                        destProjOracle = oracleSRID;
2453
                        isDestGeogCS = false;
2454
                }
2455

    
2456
    }
2457

    
2458
    public String getDestProjectionOracleCode() {
2459
            return destProjOracle;
2460
    }
2461

    
2462
    public boolean getIsDestProjectionGeog() {
2463
            return isDestGeogCS;
2464
    }
2465

    
2466
    public String getTableProjectionOracleCode() {
2467
            return oracleSRID;
2468
    }
2469

    
2470
    public boolean canReproject(String toEPSGdestinyProjection) {
2471
        return false;
2472
    }
2473

    
2474
    /**
2475
     * Utility function. Says whether a given field name can be a user field name
2476
     * or not (for example, "ROWID" is not a valid one because it's a system
2477
     * reserved word).
2478
     *
2479
     * @param str proposed firld name
2480
     * @return whether it is valid or not for Oracle databases
2481
     */
2482
    private static boolean isOracleAllowedFieldname(String str) {
2483
        if (str.compareToIgnoreCase("rowid") == 0) {
2484
            return false;
2485
        }
2486

    
2487
        if (str.compareToIgnoreCase("rownum") == 0) {
2488
            return false;
2489
        }
2490

    
2491
        return true;
2492
    }
2493

    
2494
    public Hashtable getHashRelate() {
2495
        return hashRelate;
2496
    }
2497

    
2498
    public void setHashRelate(Hashtable m) {
2499
        hashRelate = m;
2500
    }
2501

    
2502
    public void setNumReg(int n) {
2503
        numReg = n;
2504
    }
2505

    
2506
    private int[] getRandomSample(int maxn_one_based, int n) {
2507
        int[] resp = new int[n];
2508

    
2509
        if (maxn_one_based <= n) {
2510
            resp = new int[maxn_one_based];
2511

    
2512
            for (int i = 0; i < maxn_one_based; i++) {
2513
                resp[i] = i;
2514
            }
2515
        }
2516
        else {
2517
            Random rnd = new Random();
2518

    
2519
            for (int i = 0; i < n; i++) {
2520
                resp[i] = rnd.nextInt(maxn_one_based);
2521
            }
2522
        }
2523

    
2524
        return resp;
2525
    }
2526

    
2527
    private String getRowIdRestrictionCondition(int nrecords) {
2528
        int[] zero_based_rows = getRandomSample(nrecords,
2529
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
2530
        String resp = "(";
2531
        Object aux = "";
2532
        ROWID riaux = null;
2533

    
2534
        for (int i = 0; i < zero_based_rows.length; i++) {
2535
            aux = rowToId.get(new Integer(zero_based_rows[i]));
2536
            riaux = (ROWID) aux;
2537
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
2538
        }
2539

    
2540
        resp = resp.substring(0, resp.length() - 4);
2541
        resp = resp + ")";
2542

    
2543
        return resp;
2544
    }
2545

    
2546
    private Rectangle2D getBoundingFromSample(int n_max) {
2547
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
2548
            " WHERE " + getRowIdRestrictionCondition(n_max);
2549
        STRUCT auxstr = null;
2550
        IGeometry theGeom = null;
2551
        Rectangle2D resp = null;
2552

    
2553
        try {
2554
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
2555
            ResultSet rs = st.executeQuery(_qry);
2556

    
2557
            if (rs.next()) {
2558
                auxstr = (STRUCT) rs.getObject(1);
2559

    
2560
                if (auxstr != null) {
2561
                    theGeom = getGeometryUsing(auxstr, use_geotools);
2562

    
2563
                    if (resp == null) {
2564
                        resp = theGeom.getBounds2D();
2565
                    }
2566
                    else {
2567
                        resp.add(theGeom.getBounds2D());
2568
                    }
2569
                }
2570

    
2571
                while (rs.next()) {
2572
                    auxstr = (STRUCT) rs.getObject(1);
2573

    
2574
                    if (auxstr != null) {
2575
                        theGeom = getGeometryUsing(auxstr, use_geotools);
2576

    
2577
                        if (resp == null) {
2578
                            resp = theGeom.getBounds2D();
2579
                        }
2580
                        else {
2581
                            resp.add(theGeom.getBounds2D());
2582
                        }
2583
                    }
2584
                }
2585

    
2586
                rs.close();
2587
                st.close();
2588
            }
2589
            else {
2590
                throw new SQLException("Empty resultset from this query: " +
2591
                    _qry);
2592
            }
2593
        }
2594
        catch (SQLException se) {
2595
                logger.error("While getting sample full extent: " +
2596
                se.getMessage());
2597
        }
2598

    
2599
        if (resp == null) {
2600
            logger.warn(
2601
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
2602

    
2603
            return new Rectangle2D.Double(-180, -90, 360, 180);
2604
        }
2605

    
2606
        return resp;
2607
    }
2608

    
2609
    /**
2610
     * Does what it says, puts the LinearRing in counter clock wise
2611
     * order.
2612
     * @param ls The ring to set.
2613
     * @param gf a GeometryFactory object
2614
     * @return A new ring in CCW order.
2615
     *
2616
     */
2617
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
2618
        Coordinate[] cc = ls.getCoordinates();
2619

    
2620
        if (CGAlgorithms.isCCW(cc)) {
2621
            return gf.createLinearRing(cc);
2622
        }
2623
        else {
2624
            if (ls instanceof LinearRing) {
2625
                return reverseRing((LinearRing) ls, gf);
2626
            }
2627
            else {
2628
                return reverseLineString(ls, gf);
2629
            }
2630
        }
2631
    }
2632

    
2633
    /**
2634
     * Does what it says, reverses the order of the Coordinates in the ring.
2635
     * @param lr The ring to reverse.
2636
     * @return A new ring with the reversed Coordinates.
2637
     *
2638
     */
2639
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
2640
        int numPoints = lr.getNumPoints() - 1;
2641
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
2642

    
2643
        for (int t = numPoints; t >= 0; t--) {
2644
            newCoords[t] = lr.getCoordinateN(numPoints - t);
2645
        }
2646

    
2647
        return gf.createLinearRing(newCoords);
2648
    }
2649

    
2650
    /**
2651
     * Does what it says, reverses the order of the Coordinates in the linestring.
2652
     * @param ls The ls to reverse.
2653
     * @param gf a GeometryFactory object
2654
     * @return A new ls with the reversed Coordinates.
2655
     *
2656
     */
2657
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
2658
        int numPoints = ls.getNumPoints() - 1;
2659
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
2660

    
2661
        for (int t = numPoints; t >= 0; t--) {
2662
            newCoords[t] = ls.getCoordinateN(numPoints - t);
2663
        }
2664

    
2665
        return gf.createLinearRing(newCoords);
2666
    }
2667

    
2668
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
2669
        if (ge instanceof MultiPolygon) {
2670
            MultiPolygon mp = (MultiPolygon) ge;
2671
            int size = ge.getNumGeometries();
2672
            Polygon[] pols = new Polygon[size];
2673

    
2674
            for (int i = 0; i < size; i++)
2675
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
2676
                        gf);
2677

    
2678
            return new MultiPolygon(pols, gf);
2679
        }
2680
        else {
2681
            if (ge instanceof Polygon) {
2682
                Polygon p = (Polygon) ge;
2683
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
2684
                int nholes = p.getNumInteriorRing();
2685

    
2686
                if (nholes > 0) {
2687
                    LinearRing[] holes = new LinearRing[nholes];
2688

    
2689
                    for (int i = 0; i < nholes; i++) {
2690
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
2691
                    }
2692

    
2693
                    return gf.createPolygon(exterior, holes);
2694
                }
2695
                else {
2696
                    return gf.createPolygon(exterior, null);
2697
                }
2698
            }
2699
            else {
2700
                return ge;
2701
            }
2702
        }
2703
    }
2704

    
2705
    /**
2706
     * Converts from IGeometry to STRUCT
2707
     *
2708
     * @param ig the geometry to convert
2709
     * @param _forced_type forced type to use
2710
     * @param _conn connection
2711
     * @param _o_srid  SRS (oracle code)
2712
     * @param withSrid whether this STRUCT has a non-NULL SRS
2713
     * @param agu_bien whether or not to check the correctness of the holes
2714
     * @param _isGeoCS whether the SRS is geodetic or not
2715
     * @return the generated STRUCT
2716
     */
2717
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
2718
        IConnection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
2719
        boolean _isGeoCS) {
2720
        if (ig instanceof FGeometryCollection) {
2721
            FGeometryCollection coll = (FGeometryCollection) ig;
2722

    
2723
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
2724
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
2725

    
2726
            // logger.error("Collections no soportadas por ahora.");
2727
            // return null;
2728
        }
2729
        else {
2730
            Shape shp = ig.getInternalShape();
2731

    
2732
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
2733
                agu_bien, false, _isGeoCS);
2734
        }
2735
    }
2736

    
2737
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
2738
        boolean agu_bien, boolean isView) {
2739

    
2740
            if (shp == null) return null;
2741
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
2742
            agu_bien, isView, isGeogCS);
2743
    }
2744

    
2745
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
2746
        IConnection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
2747
        boolean isView, boolean _isGeoCS) {
2748
        int _srid = -1;
2749

    
2750
        if ((o_srid != null) && (o_srid.length() > 0)) {
2751
            _srid = Integer.parseInt(o_srid);
2752
        }
2753

    
2754
        if (shp == null) {
2755
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
2756

    
2757
            return null;
2758
        }
2759

    
2760
        if (shp instanceof Rectangle2D) {
2761
            return OracleSpatialUtils.rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
2762
                _isGeoCS, o_srid, _conn);
2763
        }
2764

    
2765
        try {
2766
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
2767
                    _srid, agu_bien, hasSrid);
2768

    
2769
            return the_struct;
2770
        }
2771
        catch (SQLException ex) {
2772
            logger.error("While creating STRUCT: " + ex.getMessage());
2773

    
2774
            return null;
2775
        }
2776
    }
2777

    
2778
    // -------------------------- not ready yet ----------------
2779
    public int getRowIndexByFID(IFeature _fid) {
2780
        if (isNotAvailableYet) {
2781
            return -1;
2782
        }
2783
        else {
2784
            return super.getRowIndexByFID(_fid);
2785
        }
2786
    }
2787

    
2788
    public int getShapeCount() throws ReadDriverException { 
2789
        if (isNotAvailableYet) {
2790
            return 0;
2791
        }
2792
        else {
2793
            return numReg;
2794
        }
2795
    }
2796

    
2797
    public void setNotAvailableYet(boolean nav) {
2798
        isNotAvailableYet = nav;
2799
    }
2800

    
2801
    // -------------------------------------------------------
2802
    // -------------------------------------------------------
2803
    public String[] getTableNames(IConnection conn, String catalog)
2804
        throws DBException {
2805
        try{
2806
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
2807
        String[] types = { "TABLE", "VIEW" };
2808
        // String[] types = { "VIEW" };
2809

    
2810
        ResultSet rs = null;
2811
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
2812
                    ALL_ORACLE_GEOMETADATA_VIEW, types), ((ConnectionJDBC)conn).getConnection());
2813
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
2814
//                          ORACLE_GEOMETADATA_VIEW, types);
2815
        TreeMap ret = new TreeMap();
2816

    
2817
        while (rs.next()) {
2818
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
2819
            ret.put(nomCompleto, nomCompleto);
2820
        }
2821

    
2822
        return (String[]) ret.keySet().toArray(new String[0]);
2823
        }catch (SQLException e) {
2824
                        throw new DBException(e);
2825
                }
2826
    }
2827

    
2828
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
2829
        throws SQLException {
2830
        String tablename = "";
2831

    
2832
        if (res.next()) {
2833
            tablename = res.getString("TABLE_NAME");
2834

    
2835
            // debug
2836
            writeMetaTableToLog(con, tablename);
2837

    
2838
            Statement __st = con.createStatement();
2839

    
2840
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
2841
                "union (select VIEW_NAME from USER_VIEWS)) " +
2842
                "intersect (select TABLE_NAME from " + tablename + ")";
2843
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
2844
            ResultSet rs = __st.executeQuery(sql);
2845

    
2846
            return rs;
2847
        }
2848
        else {
2849
            logger.error("Error while getting geometry tables.");
2850

    
2851
            return null;
2852
        }
2853
    }
2854

    
2855
    private void writeMetaTableToLog(Connection con, String tname) {
2856

    
2857
            logger.debug("======================================================");
2858
            logger.debug("=     " + ALL_ORACLE_GEOMETADATA_VIEW + "  (1 EVERY 10 TABLES) ========");
2859
            logger.debug("======================================================");
2860

    
2861
            try {
2862
            Statement _stmt = con.createStatement();
2863
            String sql = "SELECT * FROM " + tname;
2864
            ResultSet res = _stmt.executeQuery(sql);
2865
            
2866
            int count = 0;
2867
            while (res.next()) {
2868
                    
2869
                    if ((count % 10) == 0) {
2870
                        logger.debug(
2871
                                        "OWNER: " + res.getString("OWNER")
2872
                                        + ", TABLE_NAME: " + res.getString("TABLE_NAME")
2873
                                        + ", COLUMN_NAME: " + res.getString("COLUMN_NAME")
2874
                                        + ", SRID: " + res.getString("SRID"));
2875
                        ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
2876
                        String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
2877
                        logger.debug("DIMINFO: " + dinfo);
2878
                        logger.debug("=========");
2879
                    }
2880
                    count++;
2881
                    
2882
            }
2883
            } catch (Throwable th) {
2884

    
2885
            }
2886
        }
2887

    
2888
        /**
2889
     * Gets the field names that can act as row id (always ROWID)
2890
     */
2891
    public String[] getIdFieldsCandidates(IConnection conn, String table_name)
2892
        throws DBException {
2893
            try{
2894
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
2895
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
2896
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
2897
            _rs.close();
2898
            _st.close();
2899

    
2900
            String[] resp = { "ROWID" };
2901
        return resp;
2902
            }catch (SQLException e) {
2903
                        throw new DBException(e);
2904
                }
2905
    }
2906

    
2907
    /**
2908
     * Gets the field names that can act as geometry fields
2909
     * (queries the user's geographic metadata).
2910
     */
2911
    public String[] getGeometryFieldsCandidates(IConnection conn,
2912
        String table_name) throws DBException {
2913
            try{
2914
        Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
2915
        String[] tokens = table_name.split("\\u002E", 2);
2916
        String qry;
2917
        if (tokens.length > 1)
2918
        {
2919
                qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2920
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
2921
            tokens[1] + "'";
2922
        }
2923
        else
2924
        {
2925
                qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2926
            " where TABLE_NAME = " + "'" + table_name + "'";
2927

    
2928
        }
2929
        ResultSet _rs = _st.executeQuery(qry);
2930

    
2931
        ArrayList aux = new ArrayList();
2932

    
2933
        while (_rs.next()) {
2934
            String _geo = _rs.getString("COLUMN_NAME");
2935
            aux.add(_geo);
2936
        }
2937

    
2938
        _rs.close();
2939
        _st.close();
2940

    
2941
        String[] resp = (String[]) aux.toArray(new String[0]);
2942

    
2943
        return checkIndexes(conn, resp, table_name);
2944
            }catch (SQLException e) {
2945
                        throw new DBException(e);
2946
                }
2947
    }
2948

    
2949
    private String[] checkIndexes(IConnection c, String[] all, String long_table_name) throws DBException {
2950

    
2951
            ArrayList good_ones = new ArrayList();
2952
            try{
2953
            String t = long_table_name;
2954
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
2955

    
2956
            for (int i=0; i<all.length; i++) {
2957

    
2958
                String qry = "SELECT SRID, DIMINFO FROM " + ALL_ORACLE_GEOMETADATA_VIEW +
2959
            " WHERE TABLE_NAME = " + "'" + t.toUpperCase() +
2960
            "' AND COLUMN_NAME = '" + all[i].toUpperCase() + "'";
2961

    
2962
                Statement _st = ((ConnectionJDBC)c).getConnection().createStatement();
2963
                ResultSet _rs = _st.executeQuery(qry);
2964
                if (_rs.next()) {
2965
                        String _srid = toString((BigDecimal) _rs.getObject(1));
2966
                        ARRAY diminfo = (ARRAY) _rs.getObject(2);
2967
                        int len = diminfo.getOracleArray().length;
2968
                        if (allowsGeoQueries(((ConnectionJDBC)c).getConnection(), long_table_name, all[i], _srid, len)) {
2969
                                good_ones.add(all[i]);
2970
                        }
2971
                }
2972
                _rs.close();
2973
                _st.close();
2974
            }
2975

    
2976
            if (good_ones.size() == 0) {
2977
                    throw new SQLException("no_indexes_on_declared_geo_fields");
2978
            }
2979
            }catch (SQLException e) {
2980
                        throw new DBException(e);
2981
                }
2982
            return (String[]) good_ones.toArray(new String[0]);
2983
    }
2984

    
2985
    private String toString(BigDecimal number) {
2986

    
2987
            if (number == null) return "NULL";
2988
            return "" + number.intValue();
2989
        }
2990

    
2991
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
2992
            String p = getPointConstructor(dims, _srid);
2993
            String qry = "";
2994
            qry = "SELECT * FROM " + _t.toUpperCase()
2995
            + " WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'"
2996
            + " AND ROWNUM = 1";
2997

    
2998
            try {
2999
                        Statement _st = c.createStatement();
3000
                        ResultSet _rs = _st.executeQuery(qry);
3001
                        _rs.close();
3002
                        _st.close();
3003
                } catch (Exception ex) {
3004
                        return false;
3005
                }
3006
                return true;
3007
        }
3008

    
3009
        private String getPointConstructor(int dims, String _srid) {
3010

    
3011
                String coord = "";
3012
                for (int i=0; i<dims; i++) coord = coord + "0, ";
3013
                coord = coord.substring(0, coord.length() - 2);
3014

    
3015
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
3016
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
3017
        }
3018

    
3019
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
3020

    
3021
            if (l == null) return false;
3022
            if (str == null) return false;
3023

    
3024
            String item = "";
3025
            for (int i=0; i<l.size(); i++) {
3026
                    if (l.get(i) instanceof String) {
3027
                            item = (String) l.get(i);
3028
                            if (item.compareToIgnoreCase(str) == 0) return true;
3029
                    }
3030
            }
3031
            return false;
3032
    }
3033

    
3034
        /**
3035
     * Utility method to check if a given table is empty.
3036
     */
3037
    public boolean isEmptyTable(Connection conn, String tableName) {
3038
        boolean res = true;
3039

    
3040
        try {
3041
            Statement st = conn.createStatement();
3042
            ResultSet rs = null;
3043
            rs = st.executeQuery("select * from " + tableName +
3044
                    " where rownum = 1");
3045
            res = !rs.next();
3046
            rs.close();
3047
            st.close();
3048
        }
3049
        catch (Exception ex) {
3050
            res = true;
3051
        }
3052

    
3053
        return res;
3054
    }
3055

    
3056
    /**
3057
     * Gets all the fields from a table name.
3058
     */
3059
    public String[] getAllFields(IConnection conn, String table_name)
3060
        throws DBException {
3061
            try{
3062
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3063
        ResultSet rs = st.executeQuery("select * from " + table_name +
3064
                " where rownum = 1");
3065
        ResultSetMetaData rsmd = rs.getMetaData();
3066
        String[] ret = new String[rsmd.getColumnCount()];
3067

    
3068
        for (int i = 0; i < ret.length; i++) {
3069
            ret[i] = rsmd.getColumnName(i + 1);
3070
        }
3071

    
3072
        rs.close();
3073
        st.close();
3074

    
3075
        return ret;
3076
            }catch (SQLException e) {
3077
                        throw new DBException(e);
3078
                }
3079
    }
3080

    
3081
    /**
3082
     * Gets all field type names from a table.
3083
     */
3084
    public String[] getAllFieldTypeNames(IConnection conn, String table_name)
3085
        throws DBException {
3086
            try{
3087
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3088
        ResultSet rs = st.executeQuery("select * from " + table_name +
3089
                " where rownum = 1");
3090
        ResultSetMetaData rsmd = rs.getMetaData();
3091
        String[] ret = new String[rsmd.getColumnCount()];
3092

    
3093
        for (int i = 0; i < ret.length; i++) {
3094
            if (rsmd.getColumnType(i + 1) == Types.NUMERIC) {
3095
                    int scale = rsmd.getScale(i+1);
3096
                    if (scale >= 0) {
3097
                        String prec_dec = " (" + rsmd.getPrecision(i+1) + ", " + scale + ")";  
3098
                        ret[i] = rsmd.getColumnTypeName(i + 1) + prec_dec;
3099
                    } else {
3100
                            ret[i] = rsmd.getColumnTypeName(i + 1);
3101
                    }
3102
            } else {
3103
                ret[i] = rsmd.getColumnTypeName(i + 1);
3104
            }
3105
        }
3106

    
3107
        rs.close();
3108
        st.close();
3109

    
3110
        close();
3111

    
3112
        return ret;
3113
            }catch (SQLException e) {
3114
                        throw new DBException(e);
3115
                }
3116
    }
3117

    
3118
    /**
3119
     * Gets Oracle's specific connection string for the given parameters.
3120
     */
3121
    public String getConnectionString(String host, String port, String dbname,
3122
        String user, String pw) {
3123
        String _pw = pw;
3124

    
3125
        if (_pw == null) {
3126
            _pw = "null";
3127
        }
3128

    
3129
        String fullstr = CONN_STR_BEGIN;
3130
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
3131
        fullstr = fullstr + "@" + host.toLowerCase();
3132
        fullstr = fullstr + ":" + port;
3133
        fullstr = fullstr + ":" + dbname.toLowerCase();
3134

    
3135
        return fullstr;
3136
    }
3137

    
3138
    /**
3139
     * Gets the Pracle geometries writer associated with this driver.
3140
     */
3141
    public IWriter getWriter() {
3142
        // on(VectorialEditableDBAdapter.java:290)
3143
        if (writer == null) {
3144

    
3145
                long count = 0;
3146
                        try {
3147
                                count = getRowCount();
3148
                        } catch (ReadDriverException e1) {
3149
                                logger.error("While getting row count: " + e1.getMessage());
3150
                        }
3151
                
3152
            writer = new OracleSpatialWriter(count);
3153
            writer.setDriver(this);
3154
            writer.setLyrShapeType(getShapeType());
3155
            writer.setGeoCS(isGeogCS());
3156
            writer.setGeoColName(geoColName);
3157
            writer.setSRID(oracleSRID);
3158

    
3159
            try {
3160
                    DBLayerDefinition db_lyr_def = getLyrDef();
3161
                    if (db_lyr_def == null) {
3162
                            logger.warn("Found a null DB layer definition, method initialize of OracleWriter not called.");
3163
                    } else {
3164
                            writer.initialize(getLyrDef());
3165
                    }
3166
                
3167
            } catch (InitializeWriterException e) {
3168
                logger.error("While initializing OS Writer: " + e.getMessage(), e);
3169
            }
3170

    
3171
            writer.setStoreWithSrid(tableHasSrid);
3172
        }
3173

    
3174
        return writer;
3175
    }
3176

    
3177
    /**
3178
     * Tells whether the SRS is geodetic or not-
3179
     * @return whether the SRS is geodetic or not
3180
     */
3181
    public boolean isGeogCS() {
3182
        return isGeogCS;
3183
    }
3184

    
3185
    /**
3186
     * Adds a row id to the inner set od IDs.
3187
     * @param id
3188
     */
3189
    public void addRow(String id) {
3190
        Value aux = ValueFactory.createValue(id);
3191
        Integer intobj = new Integer(numReg);
3192
        hashRelate.put(aux, intobj);
3193
        rowToId.put(intobj, id);
3194

    
3195
        numReg++;
3196
    }
3197

    
3198
    /**
3199
     * Removes a row id to the inner set od IDs.
3200
     * @param id
3201
     */
3202
    public void deleteRow(String id) {
3203
        Value aux = ValueFactory.createValue(id);
3204
        Integer intobj = (Integer) hashRelate.get(aux);
3205
        hashRelate.remove(aux);
3206
        rowToId.remove(intobj);
3207

    
3208
        numReg--;
3209
    }
3210

    
3211
    private String getStandardSelectExpression() {
3212

    
3213
                String resp = "";
3214

    
3215
                String[] flds = getLyrDef().getFieldNames();
3216
                int size = flds.length;
3217

    
3218
                for (int i = 0; i < size; i++) {
3219
                        if (i > 0) {
3220
                                resp = resp + "c.\"" + flds[i] + "\", ";
3221
                        } else {
3222
                                resp = resp + flds[i] + ", ";
3223
                        }
3224
                }
3225

    
3226
                resp = resp.substring(0, resp.length() - 2);
3227
                return resp;
3228
        }
3229

    
3230
    /**
3231
         * Allows the method to decide what to do with the geometry field name
3232
         * (remove/add it from the user selected fields).
3233
         * 
3234
         * @param flds
3235
         * @param geof
3236
         * @return the possibly modified field names
3237
         */
3238
    public String[] manageGeometryField(String[] flds, String geof) {
3239
        return addEndIfNotContained(flds, geof);
3240
    }
3241

    
3242
    /**
3243
     * Allows the method to decide what to do with the ID field name
3244
     * (remove/add it from the user selected fields).
3245
     *
3246
     * @param flds
3247
     * @param idf
3248
     * @return the possibly modified field names
3249
     */
3250
    public String[] manageIdField(String[] flds, String idf) {
3251
        return addStartIfNotContained(flds, idf);
3252
    }
3253

    
3254
    private String[] addEndIfNotContained(String[] arr, String item) {
3255
        if (contains(arr, item)) {
3256
            return arr;
3257
        }
3258
        else {
3259
            int size = arr.length;
3260
            String[] resp = new String[size + 1];
3261

    
3262
            for (int i = 0; i < size; i++) {
3263
                resp[i] = arr[i];
3264
            }
3265

    
3266
            resp[size] = item;
3267

    
3268
            return resp;
3269
        }
3270
    }
3271

    
3272
    private String[] addStartIfNotContained(String[] arr, String item) {
3273
        if (contains(arr, item)) {
3274
            return arr;
3275
        }
3276
        else {
3277
            int size = arr.length;
3278
            String[] resp = new String[size + 1];
3279

    
3280
            for (int i = 1; i <= size; i++) {
3281
                resp[i] = arr[i];
3282
            }
3283

    
3284
            resp[0] = item;
3285

    
3286
            return resp;
3287
        }
3288
    }
3289

    
3290
    private boolean contains(String[] arr, String item) {
3291
        for (int i = 0; i < arr.length; i++) {
3292
            if (arr[i].compareTo(item) == 0) {
3293
                return true;
3294
            }
3295
        }
3296

    
3297
        return false;
3298
    }
3299

    
3300
    /**
3301
     * This method is called when the user removes the layer from the view.
3302
     * If the IDs were being loaded, the driver will check this field and will
3303
     * let the thread 'die' quietly.
3304
     *
3305
     */
3306
    public void remove() {
3307
        cancelIDLoad = true;
3308
    }
3309

    
3310
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
3311
            // if (!isgeodetic) return true;
3312
            if ((ext.getMinX() > -179.9) || (ext.getMinX() < -180.1)) return true;
3313
            if ((ext.getMinY() > -89.9) || (ext.getMinY() < -90.1)) return true;
3314
            if ((ext.getWidth() < 359.9) || (ext.getWidth() > 360.1)) return true;
3315
            if ((ext.getHeight() < 179.9) || (ext.getHeight() > 180.1)) return true;
3316
            return false;
3317
    }
3318

    
3319
    private Rectangle2D getFastEstimatedExtent(
3320
                    String tname,
3321
                    String gfield,
3322
                    IConnection c,
3323
                    int sample_size,
3324
                    double enlargement,
3325
                    boolean is_geo) {
3326

    
3327
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
3328
            Rectangle2D resp_aux = null;
3329
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
3330
            ResultSet _rs = null;
3331

    
3332
            try {
3333
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
3334
                        _rs = _st.executeQuery();
3335
                        while (_rs.next()) {
3336
                                STRUCT aux = (STRUCT) _rs.getObject(1);
3337
                                IGeometry ig = getGeometryUsing(aux, false);
3338

    
3339
                                if (ig == null) continue;
3340

    
3341
                                if (resp_aux == null) {
3342
                                        resp_aux = ig.getBounds2D();
3343
                                } else {
3344
                                        resp_aux.add(ig.getBounds2D());
3345
                                }
3346

    
3347
                        }
3348
                } catch (Exception ex) {
3349
                        logger.error("While getting random sample: " + ex.getMessage());
3350
                }
3351

    
3352
                if (resp_aux == null) {
3353
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
3354
                        return world;
3355
                }
3356
                
3357
                double w = resp_aux.getWidth();
3358
                double h = resp_aux.getHeight();
3359
                double x = resp_aux.getMinX();
3360
                double y = resp_aux.getMinY();
3361

    
3362
                // enlarge n times:
3363
                double newx = x - (0.5 * (enlargement - 1)) * w;
3364
                double newy = y - (0.5 * (enlargement - 1)) * h;
3365
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
3366
                                enlargement * w,
3367
                                enlargement * h);
3368

    
3369
                if (is_geo) {
3370
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
3371
                        logger.debug("FAST BB: " + resp_aux.toString());
3372
                        return resp_aux;
3373
                } else {
3374
                        logger.debug("FAST BB: " + resp_aux_large.toString());
3375
                        return resp_aux_large;
3376
                }
3377

    
3378
    }
3379

    
3380
    private Rectangle2D getEstimatedExtent(
3381
                    String tname,
3382
                    String gfield,
3383
                    IConnection c,
3384
                    int sample_size,
3385
                    double enlargement,
3386
                    boolean is_geo) {
3387

    
3388
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
3389

    
3390
            ArrayList ids = new ArrayList();
3391
            int _rnd_index = 0;
3392
            ROWID _id = null;
3393
            Random rnd = new Random(System.currentTimeMillis());
3394

    
3395
            for (int i=0; i<sample_size; i++) {
3396
                    _rnd_index = rnd.nextInt(numReg);
3397
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
3398
                    ids.add(_id.stringValue());
3399
            }
3400

    
3401
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
3402
            for (int i=0; i<ids.size(); i++) {
3403
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR ";
3404
            }
3405
            qry = qry.substring(0, qry.length() - 4) + ")";
3406

    
3407
            Rectangle2D resp_aux = null;
3408
            ResultSet _rs = null;
3409

    
3410
            try {
3411
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
3412
                        _rs = _st.executeQuery();
3413
                        while (_rs.next()) {
3414
                                STRUCT aux = (STRUCT) _rs.getObject(1);
3415
                                IGeometry ig = getGeometryUsing(aux, false);
3416

    
3417
                                if (ig == null) continue;
3418

    
3419
                                if (resp_aux == null) {
3420
                                        resp_aux = ig.getBounds2D();
3421
                                } else {
3422
                                        resp_aux.add(ig.getBounds2D());
3423
                                }
3424

    
3425
                        }
3426
                } catch (Exception ex) {
3427
                        logger.error("While getting random sample: " + ex.getMessage());
3428
                }
3429

    
3430
                if (resp_aux == null) {
3431
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
3432
                        return world;
3433
                }
3434
                
3435
                double w = resp_aux.getWidth();
3436
                double h = resp_aux.getHeight();
3437
                double x = resp_aux.getMinX();
3438
                double y = resp_aux.getMinY();
3439

    
3440
                // enlarge 10 times:
3441
                double newx = x - (0.5 * (enlargement - 1)) * w;
3442
                double newy = y - (0.5 * (enlargement - 1)) * h;
3443
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
3444
                                enlargement * w,
3445
                                enlargement * h);
3446

    
3447
                if (is_geo) {
3448
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
3449
                        logger.debug("ESTIMATED BB: " + resp_aux.toString());
3450
                        return resp_aux;
3451
                } else {
3452
                        logger.debug("ESTIMATED BB: " + resp_aux_large.toString());
3453
                        return resp_aux_large;
3454
                }
3455

    
3456
    }
3457

    
3458
    public void setUserName(String u) {
3459
            userName = u;
3460
    }
3461

    
3462
    public String getUserName() {
3463
            return userName;
3464
    }
3465

    
3466
    public static final int JGeometry_GTYPE_COLLECTION = 4;
3467
    public static final int JGeometry_GTYPE_CURVE = 2;
3468
    public static final int JGeometry_GTYPE_MULTICURVE = 6;
3469
    public static final int JGeometry_GTYPE_MULTIPOINT = 5;
3470
    public static final int JGeometry_GTYPE_MULTIPOLYGON = 7;
3471
    public static final int JGeometry_GTYPE_POINT = 1;
3472
    public static final int JGeometry_GTYPE_POLYGON = 3;
3473
        
3474

    
3475
    // ------------------------------
3476
    
3477
    public void setXMLEntity(XMLEntity xml) throws XMLException {
3478
            
3479
            super.setXMLEntity(xml);
3480
            workingAreaInTablesCS = workingArea;
3481
            
3482
            try {
3483
                    int[] ftypes = xml.getIntArrayProperty("fieldTypes");
3484
                    setLyrDefFieldTypes(ftypes);
3485
            } catch (Exception ex) {
3486
                    logger.warn("Apparently, an old GVP file has been opened," +
3487
                                    " field type values are not accurate after this point.");
3488
            }
3489
            
3490
    }
3491
    
3492
    public XMLEntity getXMLEntity() {
3493
                // ---------------------
3494

    
3495
                XMLEntity xml = new XMLEntity();
3496
                xml.putProperty("className", getClass().getName());
3497

    
3498
                xml.putProperty("catalog", getLyrDef().getCatalogName());
3499

    
3500
                int aux = userName.indexOf("@");
3501
                if (aux != -1)
3502
                        userName = userName.substring(0, aux);
3503
                xml.putProperty("username", userName);
3504

    
3505
                xml.putProperty("driverclass", ORACLE_JAR_FILE_NAME);
3506

    
3507
                xml.putProperty("tablename", getTableName());
3508
                xml.putProperty("fields", lyrDef.getFieldNames());
3509
                xml.putProperty("fieldTypes", getLyrDefFieldTypes());
3510
                xml.putProperty("FID", lyrDef.getFieldID());
3511
                xml.putProperty("THE_GEOM", lyrDef.getFieldGeometry());
3512
                xml.putProperty("whereclause", getWhereClause());
3513
                xml.putProperty("SRID", lyrDef.getSRID_EPSG());
3514

    
3515
                xml.putProperty("host", host);
3516
                xml.putProperty("port", port);
3517
                xml.putProperty("dbName", dbName);
3518
                xml.putProperty("connName", connName);
3519

    
3520
                if (workingAreaInTablesCS != null) {
3521
                        xml.putProperty("minXworkArea", workingAreaInTablesCS.getMinX());
3522
                        xml.putProperty("minYworkArea", workingAreaInTablesCS.getMinY());
3523
                        xml.putProperty("HworkArea", workingAreaInTablesCS.getHeight());
3524
                        xml.putProperty("WworkArea", workingAreaInTablesCS.getWidth());
3525
                }
3526

    
3527
                return xml;
3528
        }
3529
    
3530
    private int[] getLyrDefFieldTypes() {
3531
            FieldDescription[] fd = lyrDef.getFieldsDesc();
3532
            int sz = fd.length;
3533
            int[] resp = new int[sz];
3534
            for (int i=0; i<sz; i++) resp[i] = fd[i].getFieldType();
3535
                return resp;
3536
        }
3537
    
3538
    private void setLyrDefFieldTypes(int[] tt) {
3539
            FieldDescription[] fd = lyrDef.getFieldsDesc();
3540
            
3541
            int sz_fd = fd.length;
3542
            int sz_tt = tt.length;
3543
            int sz = sz_tt;
3544
            
3545
            if (sz_tt != sz_fd) {
3546
                    logger.error("Field count does not match. lyrDef has " + sz_fd + " fields," +
3547
                                    " but this method was called with " + sz_tt + " items (?)");
3548
                    sz = Math.min(sz_fd, sz_tt);
3549
            }
3550
            
3551
            for (int i=0; i<sz; i++) lyrDef.getFieldsDesc()[i].setFieldType(tt[i]);
3552
    }
3553

    
3554
        public String[] getTableFields(IConnection conex, String table) throws DBException {
3555
                try{
3556
                Statement st = ((ConnectionJDBC)conex).getConnection().createStatement();
3557
        // ResultSet rs = dbmd.getTables(catalog, null, dbLayerDefinition.getTable(), null);
3558
                ResultSet rs = st.executeQuery("select * from " + table + " LIMIT 1");
3559
                ResultSetMetaData rsmd = rs.getMetaData();
3560

    
3561
                String[] ret = new String[rsmd.getColumnCount()];
3562

    
3563
                for (int i = 0; i < ret.length; i++) {
3564
                        ret[i] = rsmd.getColumnName(i+1);
3565
                }
3566

    
3567
                return ret;
3568
                }catch (SQLException e) {
3569
                        throw new DBException(e);
3570
                }
3571
        }
3572

    
3573
    // Overwritten to keep old behavior: returns "schema.table_name" if
3574
    // schema is not current user
3575
        public String getTableName() {
3576
            return fullTableName; 
3577
        }
3578
        
3579
    private Timestamp flexibleTimeStamp(String s) {
3580
            
3581
            String aux = s.replace('-', ' ');
3582
            aux = aux.replace(':', ' ');
3583
            aux = aux.replace('.', ' ');
3584
            // sample: 2007 12 31 23 59 59 9999
3585
            String[] parts = aux.trim().split(" ");
3586
            
3587
            int year;
3588
            int month;
3589
            int day;
3590
            int hour;
3591
            int minute;
3592
            int second;
3593
            int a_nanos;
3594

    
3595
            if (parts.length == 7) {
3596

    
3597
                    try {
3598

    
3599
                            year = Integer.parseInt(parts[0]) - 1900;
3600
                            month = Integer.parseInt(parts[1]) - 1;
3601
                            day = Integer.parseInt(parts[2]);
3602
                            hour = Integer.parseInt(parts[3]);
3603
                            minute = Integer.parseInt(parts[4]);
3604
                            second = Integer.parseInt(parts[5]);
3605
                            a_nanos = Integer.parseInt(parts[6]);
3606
                            
3607
                    } catch (Exception ex) {
3608
                        logger.debug("Bad time stamp: " + ex.getMessage());
3609
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3610
                    }
3611

    
3612
            } else {
3613
                    
3614
                if (parts.length == 6) {
3615
                        
3616
                        try {
3617
                            year = Integer.parseInt(parts[0]) - 1900;
3618
                            month = Integer.parseInt(parts[1]) - 1;
3619
                            day = Integer.parseInt(parts[2]);
3620
                            hour = Integer.parseInt(parts[3]);
3621
                            minute = Integer.parseInt(parts[4]);
3622
                            second = Integer.parseInt(parts[5]);
3623
                            a_nanos = 0;
3624
                            
3625
                        } catch (Exception ex) {
3626
                                
3627
                            logger.debug("Bad time stamp: " + ex.getMessage());
3628
                            return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3629
                        }
3630

    
3631
                } else {
3632
                        
3633
                        logger.debug("Bad time stamp: " + s);
3634
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3635
                        
3636
                }
3637
            }
3638
            
3639
            return new Timestamp(year, month, day, hour, minute, second, a_nanos);
3640
    }
3641

    
3642
        public void write(DataWare arg0) throws WriteDriverException, ReadDriverException {
3643
        }
3644
        
3645
        public static int nvarchar2Limited(int n) {
3646
                
3647
                if (n <= VARCHAR2_STANDARD_SIZE) return VARCHAR2_STANDARD_SIZE;
3648
                if (n <= VARCHAR2_LONG_SIZE) return n;
3649
                
3650
                return VARCHAR2_LONG_SIZE;
3651
        }
3652
        
3653

    
3654
    
3655

    
3656
        
3657
        public static String removePrefix(String str) {
3658
                
3659
                int colon_ind = str.indexOf(":");
3660
                if (colon_ind != -1) {
3661
                        return str.substring(colon_ind + 1);
3662
                } else {
3663
                        return str;
3664
                }
3665
        }
3666

    
3667
    
3668
            
3669
            private class AnEmptyFeatureIterator implements IFeatureIterator {
3670
                public boolean hasNext() throws ReadDriverException { return false; }
3671
                public IFeature next() throws ReadDriverException { return null; }
3672
                public void closeIterator() throws ReadDriverException { }                
3673
        }
3674
            
3675
        private Value objToValue(Object obj, int idFld) {
3676
                
3677
            if (obj == null) {
3678
                    return ValueFactory.createNullValue();
3679
            } else {
3680
                    
3681
                    String objToString = obj.toString();
3682

    
3683
                if (obj instanceof String) {
3684
                    objToString = (String) obj;
3685
                    return ValueFactory.createValue(objToString);
3686
                } else {
3687
                    if (obj instanceof ROWID) {
3688
                        objToString = ((ROWID) obj).stringValue();
3689
                        return ValueFactory.createValue(objToString);
3690
                    } else {
3691
                        if (obj instanceof STRUCT) {
3692
                            objToString = "STRUCT";
3693
                            return ValueFactory.createValue(objToString);
3694
                        } else {
3695
                            if (obj instanceof TIMESTAMP) {
3696
                                    TIMESTAMP aux = (TIMESTAMP) obj;
3697
                                objToString = aux.stringValue();
3698
                                Timestamp ts = flexibleTimeStamp(objToString);
3699
                                return ValueFactory.createValue(ts);
3700

    
3701
                            } else {
3702

    
3703
                                    // last try
3704
                                    int _type = -1;
3705
                                                            try {
3706
                                                                    _type = getFieldType(idFld);
3707
                                        if (_type == Types.DATE) {
3708
                                                objToString = objToString.replace('-', '/');
3709
                                        }
3710
                                        return ValueFactory.createValueByType(objToString, _type);
3711
                                } catch (Exception ex) {
3712
                                        logger.debug("Failed to create Value: _type = "
3713
                                                        + _type + ", objToString = " + objToString);
3714
                                        return ValueFactory.createNullValue();
3715
                                }
3716
                                
3717
                            }
3718
                        }
3719
                    }
3720
                }
3721
            }
3722
        }
3723

    
3724
        public Value[] getAttributes(ResultSet rs, boolean use_main_metadata) {
3725
            Value[] res = null;
3726

    
3727
            int fcount = 0;
3728

    
3729
            try {
3730
                    if (use_main_metadata) {
3731
                            fcount = metaData.getColumnCount();
3732
                    } else {
3733
                            fcount = rs.getMetaData().getColumnCount();
3734
                    }
3735
                
3736
                res = new Value[fcount];
3737

    
3738
                for (int i = 0; i < fcount; i++) {
3739
                    Object obj = rs.getObject(i + 1);
3740
                    res[i] = objToValue(obj, i);
3741
                }
3742

    
3743
            } catch (Exception se) {
3744
                    logger.error("While getting resultset attribute values: " + se.getMessage());
3745
                    res = new Value[fcount];
3746
                    for (int i=0; i<fcount; i++) res[i] = ValueFactory.createNullValue();
3747
            }
3748

    
3749
            return res;
3750
        }            
3751
        
3752
        public boolean canWriteGeometry(int gvSIGgeometryType) {
3753
                if (writer == null) {
3754
                        return true;
3755
                } else {
3756
                        return writer.canWriteGeometry(gvSIGgeometryType);
3757
                }
3758
                
3759
        }
3760
        
3761
    
3762

    
3763
}