Statistics
| Revision:

root / branches / v2_0_0_prep / extensions / extOracleSpatial / src / es / prodevelop / cit / gvsig / fmap / drivers / jdbc / oracle / OracleSpatialDriver.java @ 29395

History | View | Annotate | Download (115 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
            String _sql = "select " + getStandardSelectExpression() + ", c." +
635
                geoColName + " from " + getTableName() + " c ";
636

    
637
            st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
638
                    ResultSet.CONCUR_READ_ONLY);
639

    
640
            ResultSet _rs = st.executeQuery(_sql + " where c." + geoColName + " is not NULL AND rownum = 1");
641

    
642
            if (_rs.next()) {
643
                STRUCT sample_geo = (STRUCT) _rs.getObject(geoColName);
644
                shapeType = OracleSpatialUtils.getShapeTypeOfStruct(sample_geo);
645
            }
646
            else {
647
                shapeType = FShape.MULTI;
648
            }
649

    
650
            // -----------------------
651
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
652
            metaData = _rs.getMetaData();
653

    
654
            userName = ((ConnectionJDBC)conn).getConnection().getMetaData().getUserName();
655

    
656
            // geoColInd = _rs.findColumn(geoColName);
657
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
658

    
659
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
660
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
661

    
662
            int cnt = metaData.getColumnCount();
663
            fieldNames = new String[cnt];
664

    
665
            for (int i = 0; i < cnt; i++) {
666
                fieldNames[i] = metaData.getColumnName(i + 1);
667
            }
668

    
669
            getIdFieldNames();
670

    
671
            adjustLyrDef();
672

    
673
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan
674
        }
675
        catch (SQLException se) {
676
            logger.error("While getting metadata. " + se.getMessage());
677
        }
678
    }
679

    
680

    
681

    
682
    private String getIdFieldNames() {
683
        try {
684
            idFieldNames = "";
685

    
686
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
687
                idFieldNames = idFieldNames +
688
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
689
            }
690
        }
691
        catch (SQLException se) {
692
        }
693

    
694
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
695

    
696
        return idFieldNames;
697
    }
698

    
699
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
700
        int[] _res = new int[1];
701
        _res[0] = 1;
702

    
703
        return _res;
704
    }
705

    
706
    public String getSqlTotal() {
707
        // TODO Auto-generated method stub
708
        return "";
709
    }
710

    
711
    public String getCompleteWhere() {
712
        // TODO Auto-generated method stub
713
        return "";
714
    }
715

    
716
    /**
717
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
718
     * and uses directly that sentence to query the table).
719
     */
720
    public IFeatureIterator getFeatureIterator(String sql)
721
        throws ReadDriverException {
722
        if (isNotAvailableYet) {
723
                return new AnEmptyFeatureIterator();
724
            // return null;
725
        }
726

    
727
        singleCachedFeatureRowNum = -1;
728

    
729
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
730

    
731
        ResultSet localrs = (ResultSet) rs_st[0];
732
        Statement _st = (Statement) rs_st[1];
733

    
734
        return new OracleSpatialFeatureIterator(this, localrs, _st,
735
            oneBasedGeoColInd, use_geotools, false, null);
736
    }
737

    
738
    /**
739
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
740
     */
741
    public String getConnectionStringBeginning() {
742
        // oracle
743
        return CONN_STR_BEGIN;
744
    }
745

    
746
    public void open() { // throws DriverException {
747
    }
748

    
749
    /**
750
     * Gets Oracle's default port: 1521
751
     */
752
    public int getDefaultPort() {
753
        // oracle port
754
        return 1521;
755
    }
756

    
757
    /**
758
     * Gets the feature iterator for a given rectangle (the view's bounding box)
759
     * and a SRS.
760
     */
761
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
762
        throws ReadDriverException {
763
        if (isNotAvailableYet) {
764
                return new AnEmptyFeatureIterator();
765
            // return null;
766
        }
767

    
768
        singleCachedFeatureRowNum = -1;
769
        
770
        STRUCT local_st = shapeToStruct(r, FShape.NULL, tableHasSrid, false, true);
771
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
772
        ResultSet localrs = (ResultSet) rs_st[0];
773
        Statement _st = (Statement) rs_st[1];
774

    
775
        return new OracleSpatialFeatureIterator(this, localrs, _st,
776
            oneBasedGeoColInd, use_geotools, false, null);
777
    }
778

    
779
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
780
        if (workingAreaInTablesCS == null) return r;
781
        return OracleSpatialUtils.doIntersect(r, workingAreaInTablesCS);
782
    }
783

    
784
    /**
785
     * This method reverts to the one without the fields specification.
786
     * The fields have been selected from the start.
787
     */
788
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
789
        String[] alphaNumericFieldsNeeded) throws ReadDriverException {
790
            
791
        if (isNotAvailableYet) {
792
                return new AnEmptyFeatureIterator();
793
            // return null;
794
        }
795
        singleCachedFeatureRowNum = -1;
796

    
797
        if ((alphaNumericFieldsNeeded == null) || (alphaNumericFieldsNeeded.length == 0)) {
798
            return getFeatureIterator(r, strEPSG);
799
        } else {
800

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

    
806
            return new OracleSpatialFeatureIterator(this, localrs, _st,
807
                oneBasedGeoColInd, use_geotools, true, alphaNumericFieldsNeeded);
808
        }
809
    }
810

    
811
    private String getSqlFor(String[] alphaNumericFieldsNeeded, String sdo_inter) {
812
            
813
            String idswhere = getIdsQueryWhereClause(false);
814
        String custom_sel = getCustomSelect(alphaNumericFieldsNeeded, sdo_inter, idswhere);
815
                return custom_sel;
816
        }
817

    
818
        public String getGeometryField(String fieldName) {
819
        return fieldName;
820
    }
821

    
822
    public DriverAttributes getDriverAttributes() {
823
        return drvAtts;
824
    }
825

    
826
    /**
827
     * Gets the requested geometry. Always performs a new query in this case.
828
     * This should be a rare way to get the geometries. The standard way is by using
829
     * the iterators.
830
     */
831
    public IGeometry getShape(int _ind) throws ReadDriverException {
832
        if (isNotAvailableYet) {
833
            return OracleSpatialUtils.NULL_GEOM;
834
        }
835

    
836
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
837

    
838
        String _sql = "select " + geoColName + " from " + getTableName() +
839
            " where rowid = ?";
840

    
841
        try {
842
            java.sql.PreparedStatement ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(_sql);
843
            ps.setObject(1, r_id);
844

    
845
            // Statement stmnt = conn.createStatement();
846
            ps.execute();
847

    
848
            ResultSet _res = ps.getResultSet();
849

    
850
            if (_res.next()) {
851
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
852
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
853
                _res.close();
854
                ps.close();
855

    
856
                return theGeom;
857
            }
858
            else {
859
                logger.error("Unable to get shape: " + _ind +
860
                    " (probably due to edition)");
861
                
862

    
863
                return OracleSpatialUtils.NULL_GEOM;
864
            }
865
        }
866
        catch (SQLException se) {
867
            throw new ReadDriverException(getName(), se);
868
        }
869
    }
870

    
871
    public boolean isWritable() {
872
        return true;
873
    }
874

    
875
    public String getName() {
876
        return NAME;
877
    }
878

    
879
    public int[] getPrimaryKeys() throws ReadDriverException {
880
        return pkOneBasedIndexes;
881
    }
882

    
883

    
884

    
885

    
886
    private void setIdRowTable() {
887
        hashRelate = new Hashtable();
888

    
889
        java.sql.PreparedStatement ps = null;
890

    
891
        try {
892
            String _sql = getIdAndElemInfoFullResulltSetQuery();
893

    
894
            logger.debug("SQL para leer ids: " + _sql);
895
            Statement st = null;
896

    
897

    
898
            st = ((ConnectionJDBC)conn).getConnection().createStatement(
899
                            ResultSet.TYPE_FORWARD_ONLY,
900
                            ResultSet.CONCUR_READ_ONLY);
901
            
902
            
903

    
904
            // st = ((ConnectionJDBC)conn).getConnection().createStatement();
905

    
906
             st.setFetchSize(FETCH_SIZE);
907
             logger.info("FETCH_SIZE = " + FETCH_SIZE);
908

    
909
            ResultSet _r = null;
910
            _r = st.executeQuery(_sql);
911

    
912
            ROWID ri = null;
913

    
914
            int row = 0;
915
            String gid;
916
            Value aux = null;
917

    
918
            // ----------------------------------- types init
919
            ArrayList types = new ArrayList();
920
            int types_aux = 0;
921

    
922
            ARRAY info_aux;
923
            int[] info_aux_int;
924
            int size;
925

    
926
            // ----------------------------------- types init
927
            logger.debug("Beginning of result set:");
928

    
929
            while (_r.next()) {
930
                // ---------------------------------------
931
                ri = (ROWID) _r.getObject(1);
932
                gid = ri.stringValue();
933
                aux = ValueFactory.createValue(gid);
934

    
935
                Integer intobj = new Integer(row);
936
                hashRelate.put(aux, intobj);
937
                rowToId.put(intobj, ri);
938

    
939
                if ((row % 5000) == 0) {
940
                    // ------------------------------------------- cancel load
941
                    if (cancelIDLoad) {
942
                        hashRelate.clear();
943
                        rowToId.clear();
944

    
945
                        return;
946
                    }
947

    
948
                    // -------------------------------------------
949
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
950
                    logger.info("IDs read: " + fmt);
951
                }
952

    
953
                row++;
954

    
955
                // --------------------------------------- types
956
                info_aux = (ARRAY) _r.getObject(2);
957

    
958
                if (info_aux == null) {
959
                    // logger.debug("NULL info array found in record: " + row);
960
                }
961
                else {
962
                    info_aux_int = info_aux.getIntArray();
963
                    size = info_aux_int.length / 3;
964

    
965
                    for (int i = 0; i < size; i++) {
966
                        types_aux = info_aux_int[(3 * i) + 1];
967
                        types.add(new Integer(types_aux % 1000));
968
                    }
969
                }
970

    
971
                // --------------------------------------- types end
972
            }
973

    
974
            _r.close();
975
//            ps.close();
976
            st.close();
977
            numReg = row;
978

    
979
            needsCollectionLayer = OracleSpatialUtils.hasSeveralGeometryTypes(types, false);
980

    
981
            if (needsCollectionLayer) {
982
                shapeType = FShape.MULTI;
983
            }
984
        }
985
        catch (SQLException e) {
986
                logger.error("While setting id-row hashmap: " +
987
                e.getMessage());
988
        }
989
    }
990

    
991
    public int getFieldCount() throws ReadDriverException {
992
        try {
993
            return metaData.getColumnCount();
994
        }
995
        catch (SQLException e) {
996
                logger.error("While getting field count: " + e.getMessage());
997
            throw new ReadDriverException(getName(), e);
998
        }
999
    }
1000

    
1001
    public String[] getFieldNames() {
1002
        return fieldNames;
1003
    }
1004

    
1005
    public String getTotalFields() {
1006
        String strAux = "";
1007

    
1008
        for (int i = 0; i < fieldNames.length; i++) {
1009
            if (i == 0) {
1010
                strAux = fieldNames[i];
1011
            }
1012
            else {
1013
                strAux = strAux + ", " + fieldNames[i];
1014
            }
1015
        }
1016

    
1017
        return strAux;
1018
    }
1019

    
1020
    public int getFieldType(int idField) throws ReadDriverException {
1021
        int i = 0;
1022

    
1023
        try {
1024
            i = idField + 1; // idField viene basado en 0
1025

    
1026
            int __type = metaData.getColumnType(i);
1027
            int size = metaData.getPrecision(i);
1028
            int dec_pos = metaData.getScale(i);
1029

    
1030
            // we must add this entry because we did not remove the 'geometry' column
1031
            if (__type == Types.STRUCT) {
1032
                return Types.VARCHAR; // .STRUCT;
1033
                // ----------------------------------------------------------------------
1034
            }
1035

    
1036
            if (__type == Types.VARCHAR) {
1037
                return Types.VARCHAR;
1038
            }
1039

    
1040
            if (__type == Types.FLOAT) {
1041
                return Types.FLOAT;
1042
            }
1043

    
1044
            if (__type == Types.DOUBLE) {
1045
                return Types.DOUBLE;
1046
            }
1047

    
1048
            if ((__type == Types.INTEGER)
1049
                            || (__type == Types.SMALLINT)
1050
                            || (__type == Types.TINYINT)
1051
                            || (__type == Types.BIGINT)
1052
                            || ((__type == Types.NUMERIC) && (dec_pos == 0))
1053
                            ) {
1054
                    
1055
                    if (size > 10) {
1056
                            return Types.BIGINT;
1057
                    } else {
1058
                            return Types.INTEGER;
1059
                    }
1060
            }
1061

    
1062
            if (__type == Types.BIT) {
1063
                return Types.BIT;
1064
            }
1065

    
1066
            if (__type == Types.DATE) {
1067
                return Types.DATE;
1068
            }
1069

    
1070
            if (__type == Types.DECIMAL) {
1071
                return Types.DOUBLE;
1072
            }
1073

    
1074
            if (__type == Types.NUMERIC) {
1075
                    return Types.DOUBLE;
1076
            }
1077

    
1078
            if (__type == Types.DATE) {
1079
                return Types.DATE;
1080
            }
1081

    
1082
            if (__type == Types.TIME) {
1083
                return Types.TIME;
1084
            }
1085

    
1086
            if (__type == Types.TIMESTAMP) {
1087
                return Types.TIMESTAMP;
1088
            }
1089
        }
1090
        catch (SQLException e) {
1091
            logger.error("Unknown field type of : " + i);
1092
            throw new ReadDriverException(getName(), e);
1093
        }
1094

    
1095
        return -1;
1096
    }
1097

    
1098

    
1099
    public String getFieldName(int fieldId) throws ReadDriverException {
1100
        return fieldNames[fieldId];
1101
    }
1102

    
1103
    public int getFieldWidth(int fieldId) {
1104
        int i = -1;
1105

    
1106
        try {
1107
            int aux = fieldId + 1; // fieldId viene basado en 0
1108
            i = metaData.getColumnDisplaySize(aux);
1109
        }
1110
        catch (SQLException e) {
1111
            logger.error("While getting field width: " + e.getMessage());
1112
        }
1113

    
1114
        if (i < 0) {
1115
            i = 255;
1116
        }
1117

    
1118
        return i;
1119
    }
1120

    
1121
    public Value getFieldValue(long rowIndex, int field_Id) throws ReadDriverException {
1122
        if (isNotAvailableYet) {
1123
            return nullVal;
1124
        }
1125

    
1126
        if ((singleCachedFeature != null) &&
1127
                (rowIndex == singleCachedFeatureRowNum)) {
1128
            return singleCachedFeature.getAttributes()[field_Id];
1129
        }
1130

    
1131
        // return ValueFactory.createNullValue();
1132
        ResultSet _r = null;
1133
        java.sql.PreparedStatement ps = null;
1134

    
1135
        try {
1136
            String rnq = getSearchId();
1137
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1138

    
1139
            ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(rnq);
1140
            ps.setObject(1, _id);
1141

    
1142
            ps.execute();
1143
            _r = ps.getResultSet();
1144
            
1145
            if (!_r.next()) {
1146
                _r.close();
1147
                ps.close();
1148
                    throw new SQLException("No row for ROWID: " + _id.toString() + ". Possibly deleted from another app.");
1149
            }
1150
            
1151
        } catch (SQLException se) {
1152
                logger.error("While getting row " + rowIndex + " : " + se.getMessage());
1153
                return ValueFactory.createNullValue();
1154
        }
1155

    
1156
        IFeature ife = null;
1157
        Value[] atts = null;
1158

    
1159
        try {
1160
            ROWID ri = (ROWID) _r.getObject(1);
1161
            atts = getAttributes(_r, true);
1162

    
1163
            String gid = ri.stringValue();
1164
            STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1165
            IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1166
            ife = new DefaultFeature(theGeom, atts, gid);
1167
            _r.close();
1168
            ps.close();
1169
        } catch (SQLException se) {
1170
            logger.error("Error while doing next(): " + se.getMessage(), se);
1171
            return ValueFactory.createNullValue();
1172
        }
1173

    
1174
        // -------------------------------
1175
        singleCachedFeature = ife;
1176
        singleCachedFeatureRowNum = rowIndex;
1177

    
1178
        // -------------------------------
1179
        if (atts == null) {
1180
            return ValueFactory.createNullValue();
1181
        } else {
1182
            return atts[field_Id];
1183
        }
1184
    }
1185

    
1186

    
1187

    
1188
    public Rectangle2D getFullExtent() {
1189
            return full_Extent;
1190
    }
1191

    
1192

    
1193

    
1194
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim) {
1195
        // int __srid) {
1196

    
1197
            NUMBER _srid = new NUMBER(0);
1198
        NUMBER main_type = new NUMBER((dim * 1000) +
1199
                OracleSpatialUtils.getStructType(the_data));
1200

    
1201

    
1202
        Datum[] all_info_array = null;
1203
        Object[] elems_info_aray = null;
1204
        Datum[] all_ords = null;
1205

    
1206
        Object[] ords_of_groups = null;
1207
        Object[] _elems_info_aray = null;
1208
        try {
1209
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1210
            elems_info_aray = OracleSpatialUtils.groupByElement(all_info_array);
1211
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1212

    
1213
            ords_of_groups = OracleSpatialUtils.getOrdOfGroups(all_ords, elems_info_aray);
1214
            _elems_info_aray = new Object[elems_info_aray.length];
1215
        }
1216
        catch (SQLException e) {
1217
            logger.error("Unexpected error: " + e.getMessage());
1218
        }
1219

    
1220

    
1221
        for (int i = 0; i < elems_info_aray.length; i++) {
1222
            _elems_info_aray[i] = OracleSpatialUtils.updateIndexes((Datum[]) elems_info_aray[i]);
1223
        }
1224

    
1225
        // _elems_info_aray, ords_of_groups
1226
        int no_of_elems = ords_of_groups.length;
1227
        IGeometry[] geoms = new IGeometry[no_of_elems];
1228

    
1229
        for (int i = 0; i < no_of_elems; i++) {
1230
            Datum[] item_info_array = null;
1231
            Datum[] item_ords = null;
1232
            NUMBER gtype = null;
1233

    
1234
            try {
1235
                item_info_array = (Datum[]) _elems_info_aray[i];
1236
                item_ords = (Datum[]) ords_of_groups[i];
1237

    
1238
                gtype = new NUMBER((dim * 1000) +
1239
                        (item_info_array[1].intValue() % 1000));
1240

    
1241
                if (tableHasSrid) {
1242
                        _srid = new NUMBER(Integer.parseInt(oracleSRID));
1243
                }
1244
            }
1245
            catch (SQLException se) {
1246
                logger.error("Unexpected error: " + se.getMessage());
1247
            }
1248

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

    
1252
            STRUCT itemst = null;
1253

    
1254
            if (tableHasSrid) {
1255

    
1256
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1257
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1258
            }
1259
            else {
1260
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1261
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1262
            }
1263

    
1264
            geoms[i] = getFMapGeometry(itemst, true);
1265
        }
1266

    
1267
        return new FGeometryCollection(geoms);
1268
    }
1269

    
1270

    
1271

    
1272

    
1273

    
1274

    
1275

    
1276

    
1277
    private void cleanWhereClause() {
1278
        emptyWhereClause = false;
1279

    
1280
        String aux = getWhereClauseWithoutWhere();
1281

    
1282
        for (int i = 0; i < aux.length(); i++)
1283
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
1284
                return;
1285
            }
1286

    
1287
        getLyrDef().setWhereClause("");
1288
        emptyWhereClause = true;
1289
    }
1290

    
1291

    
1292

    
1293
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
1294
        String resp = "";
1295

    
1296
        if (isGeogCS) {
1297
            String vport = "sdo_filter(" + geoColName +
1298
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
1299
                "), 'querytype=window') = 'TRUE'";
1300

    
1301
                resp = "select " + getStandardSelectExpression() + ", c." +
1302
                    geoColName + " from " + getTableName() + " c where ";
1303
                if (idsLoadWhere.length() > 0) {
1304
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1305
                }
1306
                resp = resp + "(" + vport + ")";
1307
        }
1308
        else {
1309
                resp = "select " + getStandardSelectExpression() + ", c." +
1310
                    geoColName + " from " + getTableName() + " c where ";
1311
                if (idsLoadWhere.length() > 0) {
1312
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1313
                }
1314
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
1315
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
1316
        }
1317

    
1318
//        return "select " + getStandardSelectExpression() + ", c." +
1319
//        geoColName + " from " + getTableName() + " c";
1320
        return resp;
1321
    }
1322
    
1323
    private String getCustomSelect(String[] atts, String viewsdo, String idsLoadWhere) {
1324
        String resp = "";
1325
        
1326
        String atts_enum = "";
1327
        if ((atts == null) || (atts.length == 0)) {
1328
                
1329
        } else {
1330
                atts_enum = " c.\"" + atts[0] + "\" ";
1331
            for (int i=1; i<atts.length; i++) {
1332
                    atts_enum = atts_enum + ", " + atts[1]; 
1333
            }
1334
        }
1335

    
1336
        if (isGeogCS) {
1337
            String vport = "sdo_filter(" + geoColName +
1338
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
1339
                "), 'querytype=window') = 'TRUE'";
1340

    
1341
                resp = "select " + atts_enum + " from " + getTableName() + " c where ";
1342
                if (idsLoadWhere.length() > 0) {
1343
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1344
                }
1345
                resp = resp + "(" + vport + ")";
1346
        } else {
1347
                resp = "select " + atts_enum + " from " + getTableName() + " c where ";
1348
                if (idsLoadWhere.length() > 0) {
1349
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1350
                }
1351
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
1352
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
1353
        }
1354

    
1355
//        return "select " + getStandardSelectExpression() + ", c." +
1356
//        geoColName + " from " + getTableName() + " c";
1357
        return resp;
1358
    }    
1359

    
1360
    public void setWorkingArea(Rectangle2D rect) {
1361
    }
1362

    
1363
    private void setWAStructt() {
1364
    }
1365

    
1366

    
1367

    
1368
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
1369
        /*
1370
         * Tipos en Oracle Spatial usando JGeometry
1371
         *
1372
         * GTYPE_COLLECTION collection geometry type
1373
         * GTYPE_CURVE curve geoemtry type
1374
         * GTYPE_MULTICURVE multi-curve geometry type
1375
         * GTYPE_MULTIPOINT multi-point geometry type
1376
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
1377
         * GTYPE_POINT point geometry type
1378
         * GTYPE_POLYGON  polygon geometry type
1379
         *
1380
         * Tipos gvSIG FShape
1381
         *
1382
         * NULL = 0;
1383
         * POINT = 1;
1384
         * LINE = 2;
1385
         * POLYGON = 4;
1386
         * TEXT = 8;
1387
         * MULTI = 16;
1388
         * MULTIPOINT = 32;
1389
         * CIRCLE = 64;
1390
         * ARC = 128;
1391
         * ELLIPSE=256;
1392
         * Z=512
1393
         */
1394
        switch (type) {
1395
        case JGeometry_GTYPE_POLYGON:
1396
        case JGeometry_GTYPE_MULTIPOLYGON:
1397
            return FShape.POLYGON;
1398

    
1399
        case JGeometry_GTYPE_CURVE:
1400
        case JGeometry_GTYPE_MULTICURVE:
1401
            return FShape.LINE;
1402
        }
1403

    
1404
        logger.error("Unhandled Oracle Spatial geometry type: " + type +
1405
            " (conversion returned FShape.NULL)");
1406

    
1407
        return FShape.NULL;
1408
    }
1409
    
1410
    private String getValidViewConstructor(
1411
                    STRUCT _st,
1412
                    String ora_srid,
1413
                    boolean _hassrid,
1414
                    boolean _isgeocs) {
1415

    
1416
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
1417
            String resp = "";
1418
            if ((_hassrid) && (_isgeocs)) {
1419
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
1420
            } else {
1421
                    resp = sdo;
1422
            }
1423

    
1424
            return resp;
1425
    }
1426

    
1427

    
1428

    
1429
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
1430
        boolean hasSrid) throws ReadDriverException {
1431
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
1432
        String main_sel = "";
1433

    
1434
        if (fixsql == null) {
1435
            // main_sel = getMainSelect3(var_name);
1436
                String idswhere = getIdsQueryWhereClause(false);
1437
            main_sel = getMainSelect(sdo_intersect, idswhere);
1438
        }
1439
        else {
1440
            main_sel = fixsql;
1441
        }
1442

    
1443
        logger.debug("MAIN SEL = " + main_sel);
1444

    
1445
        ResultSet _rs = null;
1446
        Statement _stmnt = null;
1447
        Object[] _resp = new Object[2];
1448

    
1449
        try {
1450
            _stmnt = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_FORWARD_ONLY,
1451
                    ResultSet.CONCUR_READ_ONLY);
1452
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
1453
            _stmnt.setFetchSize(FETCH_SIZE);
1454

    
1455
            _rs = _stmnt.executeQuery(main_sel);
1456

    
1457
            // stmnt.close();
1458
        }
1459
        catch (SQLException se) {
1460
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
1461
                se);
1462
            throw new ReadDriverException(getName(), se);
1463
        }
1464

    
1465
        // this method returns the statement too, so that it can be closed afterwards
1466
        _resp[0] = _rs;
1467
        _resp[1] = _stmnt;
1468

    
1469
        return _resp;
1470
    }
1471

    
1472
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
1473
        String resp = "";
1474

    
1475
        try {
1476
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
1477
            String mdsys_sdo_ordinate_array = "";
1478
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
1479

    
1480
            for (int i = 0; i < vertices.length; i++) {
1481
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
1482
                    vertices[i].doubleValue() + ", ";
1483
            }
1484

    
1485
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
1486
                    mdsys_sdo_ordinate_array.length() - 2);
1487
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
1488
                mdsys_sdo_ordinate_array + ")";
1489

    
1490
            String aux = "";
1491

    
1492
            if (hasSrid) {
1493
                aux = oracleSRID;
1494

    
1495
                if (_isGeogCS) {
1496
                    aux = "0";
1497
                }
1498
            }
1499
            else {
1500
                aux = "null";
1501
            }
1502

    
1503
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
1504
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
1505
                ")";
1506
        }
1507
        catch (Exception ex) {
1508
                logger.error("While getting sdo contructor: " +
1509
                ex.getMessage());
1510
        }
1511

    
1512
        return resp;
1513
    }
1514

    
1515
    private String getIdsQueryWhereClause(boolean with_where) {
1516
                String resp = "";
1517

    
1518
                String _where = "";
1519
                if (with_where) _where = " where ";
1520

    
1521
                if (workingAreaInTablesCSStruct == null) {
1522
                        if (emptyWhereClause) {
1523
                                // return "select rowid from " + getTableName();
1524
                        } else {
1525
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
1526
                                                + ")";
1527
                        }
1528
                } else {
1529
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
1530
                                        oracleSRID, tableHasSrid, isGeogCS);
1531

    
1532
                        if (emptyWhereClause) {
1533
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
1534
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
1535
                        } else {
1536
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
1537
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
1538
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
1539
                        }
1540
                }
1541

    
1542
                // resp = resp + " order by rowid";
1543
                return resp;
1544
        }
1545

    
1546
    public String getIdAndElemInfoFullResulltSetQuery() {
1547
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
1548
            getTableName() + " c";
1549

    
1550
        resp = resp + getIdsQueryWhereClause(true);
1551
        return resp;
1552
    }
1553

    
1554
    private String getSearchId() {
1555
        if (emptyWhereClause) {
1556
            return "select " + getStandardSelectExpression() + ", c." +
1557
            geoColName + " from " + getTableName() + " c where rowid = ?";
1558
        }
1559
        else {
1560
            return "select " + getStandardSelectExpression() + ", c." +
1561
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
1562
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
1563
        }
1564
    }
1565

    
1566
    public int getShapeType() {
1567
        return shapeType;
1568
    }
1569

    
1570
    public void setShapeType(int t) {
1571
        shapeType = t;
1572
    }
1573
    
1574

    
1575
    private String getWhereClauseWithoutWhere() {
1576
        String resp = "";
1577
        String old = getLyrDef().getWhereClause();
1578
        resp = old;
1579

    
1580
        if (old.length() <= 6) {
1581
            return old;
1582
        }
1583

    
1584
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
1585
            resp = resp.substring(6, resp.length());
1586
        }
1587

    
1588
        return resp;
1589
    }
1590

    
1591

    
1592

    
1593
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
1594
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
1595

    
1596
        switch (fieldDesc.getFieldType()) {
1597
        case Types.SMALLINT:
1598
            aux = "NUMBER(5, 0)";
1599

    
1600
            break;
1601

    
1602
        case Types.INTEGER:
1603
            aux = "NUMBER(12, 0)";
1604

    
1605
            break;
1606

    
1607
        case Types.BIGINT:
1608
            aux = "NUMBER(38, 0)";
1609

    
1610
            break;
1611

    
1612
        case Types.BOOLEAN:
1613
            aux = "NUMBER(1, 0)";
1614

    
1615
            break;
1616

    
1617
        case Types.DECIMAL:
1618
            aux = "NUMBER";
1619

    
1620
            break;
1621

    
1622
        case Types.NUMERIC:
1623
            aux = "NUMBER";
1624

    
1625
            break;
1626

    
1627
        case Types.DOUBLE:
1628
            aux = "FLOAT";
1629

    
1630
            break;
1631

    
1632
        case Types.FLOAT:
1633
            aux = "FLOAT";
1634

    
1635
            break;
1636

    
1637
        case Types.CHAR:
1638
            aux = "CHAR(1 BYTE)";
1639

    
1640
            break;
1641

    
1642
        case Types.VARCHAR:
1643
            aux = "NVARCHAR2(" + nvarchar2Limited(fieldDesc.getFieldLength()) + ")";
1644

    
1645
            break;
1646

    
1647
        case Types.LONGVARCHAR:
1648
            aux = "NVARCHAR2(" + nvarchar2Limited(fieldDesc.getFieldLength()) + ")";
1649

    
1650
            break;
1651
        }
1652

    
1653
        return aux;
1654
    }
1655

    
1656
    // -----------------------------------------------------------
1657
    // -----------------------------------------------------------
1658
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
1659
        return "DROP TABLE " + dbLayerDef.getTableName() +
1660
        " CASCADE CONSTRAINTS";
1661
    }
1662

    
1663
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
1664
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
1665

    
1666
        String type = "";
1667
        String name = "";
1668
        String table_name = dbLayerDef.getTableName().toUpperCase();
1669

    
1670
        String resp = "CREATE TABLE " + table_name + " ( ";
1671

    
1672
        for (int i = 0; i < flds.length; i++) {
1673
            name = flds[i].getFieldName();
1674

    
1675
            // -------------- FORBIDDEN FIELD NAMES -----------------
1676
            if (!isOracleAllowedFieldname(name)) {
1677
                continue;
1678
            }
1679

    
1680
            // ------------------------------------------------------
1681
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
1682
            }
1683
            else {
1684
                name = getValidOracleID(name, i, false);
1685
                resp = resp + "\"" + name + "\" ";
1686
                type = fieldTypeToSqlStringType(flds[i]);
1687
                resp = resp + type + ", ";
1688
            }
1689
        }
1690

    
1691
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
1692
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
1693
        resp = resp + ", ";
1694

    
1695
        String pk = "CONSTRAINT " + getDerivedNAme(table_name, "PK") +
1696
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD_CASE_SENSITIVE +
1697
            "\") ENABLE";
1698

    
1699
        resp = resp + pk + " )";
1700

    
1701
        return resp;
1702
    }
1703

    
1704
    private static String getDerivedNAme(String tname, String suffix) {
1705

    
1706
            int ind = tname.lastIndexOf(".");
1707
            if (ind == -1) {
1708

    
1709
                    int l = Math.min(28, tname.length());
1710
                    return tname.substring(0, l) + "_" + suffix;
1711

    
1712
            } else {
1713

    
1714
                    String pre = tname.substring(0, ind);
1715
                    String post = tname.substring(ind + 1, tname.length());
1716
                    int lpost = Math.min(24, post.length());
1717
                    int lpre = Math.min(3, pre.length());
1718
                    return pre.substring(0, lpre) + "_" + post.substring(0, lpost) + "_" + suffix;
1719
            }
1720

    
1721
    }
1722

    
1723
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
1724
        String resp = "CREATE INDEX " + getDerivedNAme(dbLayerDef.getTableName(), "SX") +
1725
            " ON " + dbLayerDef.getTableName() + " (\"" +
1726
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
1727
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
1728

    
1729
        return resp;
1730
    }
1731

    
1732
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
1733

    
1734
            String tname = dbLayerDef.getTableName();
1735
            int ind = tname.lastIndexOf(".");
1736
            if (ind != -1) {
1737
                    String schema = tname.substring(0, ind);
1738
                    tname = tname.substring(ind + 1, tname.length());
1739
            return "DELETE FROM " + USER_ORACLE_GEOMETADATA_VIEW +
1740
            " WHERE TABLE_NAME = '" + tname + "'";
1741

    
1742
            } else{
1743
            return "DELETE FROM " + USER_ORACLE_GEOMETADATA_VIEW +
1744
            " WHERE TABLE_NAME = '" + tname + "'";
1745
            }
1746
    }
1747

    
1748
    /**
1749
     * UTility method to get the SQL sentence needed to update the geographic metadata table
1750
     * with a new bounding box and SRS
1751
     *
1752
     * @param tName table name
1753
     * @param ora_srid new SRS
1754
     * @param bbox new bounding box
1755
     * @param dim geometries dimension
1756
     * @param withsrid False if the SRS is set to NULL. True otherwise.
1757
     * @return the SQL sentence to perform the update
1758
     */
1759
    public static String getMetadataUpdateSql(String schema, String tName, String ora_srid,
1760
        Rectangle2D bbox, int dim, boolean withsrid) {
1761
            
1762
        String[] dim_name = new String[dim];
1763
        double tolerance = 0.5;
1764
        
1765
        String _ora_srid = ora_srid;
1766
        if (_ora_srid == null) _ora_srid = "NULL";
1767

    
1768
        if (_ora_srid.compareTo(GEODETIC_SRID) == 0) {
1769
            dim_name[0] = "LONGITUDE";
1770
            dim_name[1] = "LATITUDE";
1771
        }
1772
        else {
1773
            dim_name[0] = "X";
1774
            dim_name[1] = "Y";
1775

    
1776
            if (dim > 2) {
1777
                dim_name[2] = "Z";
1778

    
1779
                if (dim > 3) {
1780
                    dim_name[3] = "T";
1781
                }
1782
            }
1783
        }
1784
        
1785
        double minx = bbox.getMinX();
1786
        double miny = bbox.getMinY();
1787
        double maxx = bbox.getMaxX();
1788
        double maxy = bbox.getMaxY();
1789
        
1790
        String resp = "INSERT INTO " + USER_ORACLE_GEOMETADATA_VIEW + " " +
1791
            " ( TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
1792
            + "'" + tName + "', "
1793
            + "'" + DEFAULT_GEO_FIELD + "', " +
1794
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
1795
            minx + ", " + maxx + ", " + tolerance + " ), " +
1796
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + miny + ", " +
1797
            maxy + ", " + tolerance + " ))";
1798

    
1799
        if (dim > 2) {
1800
            resp = resp.substring(0, resp.length() - 1) + ",";
1801
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
1802
                "', 0.0, 100.0, " + tolerance + " ))";
1803

    
1804
            if (dim > 3) {
1805
                resp = resp.substring(0, resp.length() - 1) + ",";
1806
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
1807
                    "', 0.0, 100.0, " + tolerance + " ))";
1808
            }
1809
        }
1810

    
1811
        if (withsrid) {
1812
            resp = resp + ", " + _ora_srid + " )";
1813
        }
1814
        else {
1815
            resp = resp + ", NULL )";
1816
        }
1817

    
1818
        return resp;
1819
    }
1820

    
1821
    /**
1822
     * Gets the SQL sentence to perform an insertion.
1823
     *
1824
     * @param feat feature to be added
1825
     * @param dbLayerDef layer definition
1826
     * @param rowInd row index
1827
     * @param _geoColName geometry field name
1828
     * @return the SQL sentence to perform the insertion
1829
     */
1830
    public static String getRowInsertSql(IFeature feat,
1831
        DBLayerDefinition dbLayerDef, int rowInd,
1832
        String _geoColName,
1833
        String geo_val) {
1834
            
1835
        String name = "";
1836
        int ftype = -1;
1837
        String aux_orig = "";
1838
        String aux_limited = "";
1839
        String aux_quotes_ok = "";
1840

    
1841
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
1842

    
1843
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
1844

    
1845
        for (int i = 0; i < fieldsDescr.length; i++) {
1846
            name = fieldsDescr[i].getFieldName();
1847
            ftype = fieldsDescr[i].getFieldType();
1848

    
1849
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
1850
            if (!isOracleAllowedFieldname(name)) continue;
1851
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
1852
            // ------------------------------------------------------
1853
            if (name.compareToIgnoreCase(_geoColName) == 0) {
1854
            }
1855
            else {
1856
                name = getValidOracleID(name, i, false);
1857
                resp = resp + "\"" + name + "\"" + " , ";
1858
            }
1859
        }
1860

    
1861
        resp = resp + _geoColName + " ) VALUES ( ";
1862

    
1863
        for (int i = 0; i < fieldsDescr.length; i++) {
1864
            name = fieldsDescr[i].getFieldName();
1865
            ftype = fieldsDescr[i].getFieldType();
1866

    
1867
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
1868
            if (!isOracleAllowedFieldname(name)) continue;
1869
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
1870
            // ------------------------------------------------------
1871
            String sur = getValueSurroundFromType(fieldsDescr[i]);
1872

    
1873
            if (name.compareToIgnoreCase(_geoColName) == 0) {
1874
            }
1875
            else {
1876
                if (name.compareTo(OracleSpatialDriver.DEFAULT_ID_FIELD_CASE_SENSITIVE) == 0) {
1877
                    resp = resp + rowInd + " , ";
1878
                }
1879
                else {
1880
                    Value attValue = feat.getAttribute(i);
1881

    
1882
                    if (attValue.toString() == null) {
1883
                        resp = resp + "NULL , ";
1884
                    }
1885
                    else {
1886
                        if (sur.length() > 0) {
1887
                            aux_orig = attValue.toString();
1888
                            aux_limited = cropStringValue(aux_orig, i,
1889
                                    fieldsDescr);
1890
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
1891

    
1892
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
1893
                        }
1894
                        else {
1895
                            String _aux = attValue.toString();
1896

    
1897
                            if (_aux.length() == 0) {
1898
                                _aux = "NULL";
1899
                            }
1900

    
1901
                            resp = resp + _aux + " , ";
1902
                        }
1903
                    }
1904
                }
1905
            }
1906
        }
1907

    
1908
        resp = resp + " " + geo_val + " )";
1909
        /*
1910
        String test = "SDO_UTIL.APPEND(SDO_GEOMETRY("
1911
                        + "2002, NULL, NULL,"
1912
                        + "SDO_ELEM_INFO_ARRAY(1, 2, 2),"
1913
                        + "SDO_ORDINATE_ARRAY(500000, 4000000, 1000000, 5000000, 500000, 5000000)"
1914
                        + "), ? )";
1915

1916
        resp = resp + " " + test + " )";
1917
        */
1918
        return resp;
1919
    }
1920

    
1921
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
1922

    
1923
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
1924
                    return true;
1925
            }
1926

    
1927
            if ((ftype == Types.BINARY)
1928
                || (ftype == Types.ARRAY)
1929
                || (ftype == Types.BLOB)
1930
                || (ftype == Types.CLOB)
1931
                || (ftype == Types.STRUCT)
1932
            ) {
1933
                    return false;
1934
            }
1935
                return true;
1936
        }
1937

    
1938
        /**
1939
     * Gets the SQL sentence to perform an update.
1940
     *
1941
     * @param feat feature to be updated
1942
     * @param dbLayerDef layer definition
1943
     * @param rowInd row index
1944
     * @param geoFieldName geometry field name
1945
     * @return the SQL sentence to perform the update
1946
     */
1947
    public static String getRowUpdateSql(IFeature feat,
1948
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
1949
        String name = "";
1950
        String aux_orig = "";
1951
        String aux_limited = "";
1952
        String aux_quotes_ok = "";
1953

    
1954
        Value[] atts = feat.getAttributes();
1955
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
1956

    
1957
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
1958

    
1959
        for (int i = 0; i < _fieldsDescr.length; i++) {
1960
            name = _fieldsDescr[i].getFieldName();
1961

    
1962
            // -------------- FORBIDDEN FIELD NAMES -----------------
1963
            if (!isOracleAllowedFieldname(name)) {
1964
                logger.info("Field: " + name + " will not be updated.");
1965
                continue;
1966
            }
1967

    
1968
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
1969
                        geoFieldName)) {
1970
                logger.info("Field: " + name + " will not be updated (it's a struct).");
1971
                continue;
1972
            }
1973

    
1974
            // ------------------------------------------------------
1975
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
1976
                // resp = resp + "\"" + name + "\"" + " = ?, ";
1977
            }
1978
            else {
1979
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
1980
                aux_orig = atts[i].toString();
1981
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
1982
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
1983
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
1984
                    sur + ", ";
1985
            }
1986
        }
1987

    
1988
        resp = resp + "\"" + geoFieldName + "\" = ?";
1989
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
1990

    
1991
        return resp;
1992
    }
1993

    
1994
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
1995
        String geoname) {
1996
        if (ftype == Types.STRUCT) {
1997
            if (fldname.compareToIgnoreCase(geoname) != 0) {
1998
                return true;
1999
            }
2000
        }
2001

    
2002
        return false;
2003
    }
2004

    
2005
    /**
2006
     * Gets the SQL sentence to perform a deletion.
2007
     *
2008
     * @param dbLayerDef layer definition
2009
     * @param id ROWID of the record to be deleted
2010
     * @return the SQL sentence to perform the deletion
2011
     */
2012
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
2013
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
2014
        resp = resp + " WHERE ROWID ='" + id + "'";
2015

    
2016
        return resp;
2017
    }
2018

    
2019
    private static String cropStringValue(String orig_val, int i,
2020
        FieldDescription[] _flds) {
2021
            
2022
        if (orig_val == null) {
2023
            return "NULL";
2024
        }
2025
        
2026
        if (NumberUtilities.isNumeric(_flds[i].getFieldType())
2027
                    && (orig_val.length() == 0)) {
2028
                    return "NULL";
2029
        }
2030

    
2031
        int tpe = _flds[i].getFieldType();
2032
        int max_size = OracleSpatialUtils.maxSizeForFieldType(tpe);
2033

    
2034
        if (max_size == -1) {
2035
            return orig_val;
2036
        }
2037

    
2038
        int or_size = orig_val.length();
2039

    
2040
        if (or_size <= max_size) {
2041
            return orig_val;
2042
        }
2043

    
2044
        return orig_val.substring(0, max_size);
2045
    }
2046

    
2047
    private static String avoidQuoteProblem(String str) {
2048
        return str.replaceAll("'", "''");
2049
    }
2050

    
2051
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
2052
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
2053
            return "";
2054
        }
2055

    
2056
        return "'";
2057
    }
2058

    
2059
    /**
2060
     * Utility function to translate a SRS code from EPSG to Oracle.
2061
     * Uses a datasource based on a DBF file.
2062
     *
2063
     * @param epsg the EPSG code
2064
     * @return the Oracle code
2065
     */
2066
    public static String epsgSridToOracleSrid(String _epsg) throws Exception {
2067
            
2068
            String epsg = removePrefix(_epsg);
2069
            
2070
        String resp = "8307";
2071

    
2072
        // --------------------------------------------
2073
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
2074
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
2075
        DataSource ds = null;
2076

    
2077
        try {
2078
            ds = LayerFactory.getDataSourceFactory()
2079
                             .executeSQL(sql,
2080
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
2081

    
2082
            if (ds.getRowCount() == 0) {
2083
                logger.error("EPSG code not found in table: " + epsg);
2084
                throw new Exception("Unknown EPSG: " + epsg);
2085
            }
2086

    
2087
            if (ds.getRowCount() > 1) {
2088
                logger.error("===============");
2089
                logger.error(
2090
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
2091
                    epsg);
2092

    
2093
                for (int i = 0; i < ds.getRowCount(); i++) {
2094
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
2095

    
2096
                    if (i == 0) {
2097
                        resp = "" + aux;
2098
                    }
2099

    
2100
                    logger.error("" + aux);
2101
                }
2102

    
2103
                logger.error("===============");
2104

    
2105
                return resp;
2106
            }
2107

    
2108
            resp = "" +
2109
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
2110
        }
2111
        catch (Exception pe) {
2112
            logger.error("Error with SQL statement. " + pe.getMessage());
2113
        }
2114

    
2115
        return resp;
2116
    }
2117

    
2118
    /**
2119
     * Utility function to translate a SRS code from Oracle to EPSG.
2120
     * Uses a datasource based on a DBF file.
2121
     *
2122
     * @param ora the Oracle code
2123
     * @return the EPSG code
2124
     */
2125
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
2126
            
2127
            if (ora == null) return null;
2128
            
2129
        String resp = "4326";
2130

    
2131
        // --------------------------------------------
2132
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
2133
            " where ORACLE = " + ora + ";";
2134
        DataSource ds = null;
2135

    
2136
        try {
2137
            ds = LayerFactory.getDataSourceFactory()
2138
                             .executeSQL(sql,
2139
                    DataSourceFactory.AUTOMATIC_OPENING);
2140

    
2141
            if (ds.getRowCount() == 0) {
2142
                logger.error("Oracle Spatial code not found in table: " + ora);
2143
                throw new Exception("Unknown Oracle code: " + ora);
2144
            }
2145

    
2146
            if (ds.getRowCount() > 1) {
2147
                logger.error("===============");
2148
                logger.error(
2149
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
2150
                    ora);
2151

    
2152
                for (int i = 0; i < ds.getRowCount(); i++) {
2153
                    String aux = "" +
2154
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
2155

    
2156
                    if (i == 0) {
2157
                        resp = aux;
2158
                    }
2159

    
2160
                    logger.error("" + aux);
2161
                }
2162

    
2163
                logger.error("===============");
2164

    
2165
                return resp;
2166
            }
2167

    
2168
            resp = "" +
2169
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
2170
        }
2171
        catch (Exception pe) {
2172
            logger.error("Error with SQL statement. " + pe.getMessage());
2173
        }
2174

    
2175
        return resp;
2176
    }
2177

    
2178
    /**
2179
     * This methos creates the datasource used to translate the SRS codes:
2180
     * EPSG <--> Oracle.
2181
     *
2182
     * It's called from several places, so checks that the datasource does not exist.
2183
     */
2184

    
2185

    
2186
    /**
2187
     * Utility method to get a valid Oracle identifier (in terms of length)
2188
     *
2189
     * @param str Proposed string
2190
     * @param ind field index of the given field name (used by the method to
2191
     * improve the renaming)
2192
     * @return an acceptable oracle identifier.
2193
     */
2194
    public static String getValidOracleID(String _str, int ind, boolean force_uppercase) {
2195
            
2196
            String str = _str;
2197
            if (force_uppercase) str = _str.toUpperCase();
2198
            
2199
        if (str.length() <= MAX_ID_LENGTH) {
2200
            return str;
2201
        }
2202

    
2203
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
2204
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
2205
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
2206
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
2207
        resp = resp + "_" + (ind % 1000);
2208

    
2209
        return resp;
2210
    }
2211

    
2212
    private static ArrayList ensureSensibleShell(ArrayList cc) {
2213
        if (sameCoordinate((Coordinate) cc.get(0),
2214
                    (Coordinate) cc.get(cc.size() - 1))) {
2215
            if (cc.size() == 2) {
2216
                ArrayList resp = new ArrayList();
2217
                resp.add(cc.get(0));
2218

    
2219
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
2220
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
2221
                resp.add(newcoo);
2222

    
2223
                newcoo = new Coordinate((Coordinate) cc.get(0));
2224
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
2225
                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
2226
                resp.add(newcoo);
2227

    
2228
                resp.add(cc.get(0));
2229

    
2230
                return resp;
2231
            }
2232

    
2233
            if (cc.size() == 3) {
2234
                cc.remove(1);
2235

    
2236
                return ensureSensibleShell(cc);
2237
            }
2238

    
2239
            return cc;
2240
        }
2241
        else {
2242
            cc.add(cc.get(0));
2243

    
2244
            return cc;
2245
        }
2246
    }
2247

    
2248
    private static ArrayList ensureSensibleHole(ArrayList cc) {
2249
        if (sameCoordinate((Coordinate) cc.get(0),
2250
                    (Coordinate) cc.get(cc.size() - 1))) {
2251
            if (cc.size() == 2) {
2252
                ArrayList resp = new ArrayList();
2253
                resp.add(cc.get(0));
2254

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

    
2259
                newcoo = new Coordinate((Coordinate) cc.get(0));
2260
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
2261
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
2262
                resp.add(newcoo);
2263

    
2264
                resp.add(cc.get(0));
2265

    
2266
                return resp;
2267
            }
2268

    
2269
            if (cc.size() == 3) {
2270
                cc.remove(1);
2271

    
2272
                return ensureSensibleHole(cc);
2273
            }
2274

    
2275
            return cc;
2276
        }
2277
        else {
2278
            cc.add(cc.get(0));
2279

    
2280
            return cc;
2281
        }
2282
    }
2283

    
2284
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
2285
        if (cc.size() == 2) {
2286
            if (sameCoordinate((Coordinate) cc.get(0),
2287
                        (Coordinate) cc.get(cc.size() - 1))) {
2288
                ArrayList resp = new ArrayList();
2289
                resp.add(cc.get(0));
2290

    
2291
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
2292
                newc.x = newc.x + IRRELEVANT_DISTANCE;
2293
                resp.add(newc);
2294

    
2295
                return resp;
2296
            }
2297
        }
2298

    
2299
        return cc;
2300
    }
2301

    
2302
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
2303
        if (c1.x != c2.x) {
2304
            return false;
2305
        }
2306

    
2307
        if (c1.y != c2.y) {
2308
            return false;
2309
        }
2310

    
2311
        return true;
2312
    }
2313

    
2314
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
2315
        if (cc.size() == 2) {
2316
            return null;
2317
        }
2318

    
2319
        if (cc.size() == 3) {
2320
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
2321
                return null;
2322
            }
2323

    
2324
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
2325
                return null;
2326
            }
2327

    
2328
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
2329
                return null;
2330
            }
2331

    
2332
            cc.add(cc.get(0));
2333

    
2334
            return cc;
2335
        }
2336

    
2337
        if (!sameCoordinate((Coordinate) cc.get(0),
2338
                    (Coordinate) cc.get(cc.size() - 1))) {
2339
            cc.add(cc.get(0));
2340
        }
2341

    
2342
        return cc;
2343
    }
2344

    
2345
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
2346
        Coordinate[] p = new Coordinate[4];
2347
        p[0] = c;
2348

    
2349
        Coordinate nc = new Coordinate(c);
2350
        nc.x = nc.x + IRRELEVANT_DISTANCE;
2351

    
2352
        Coordinate nc2 = new Coordinate(nc);
2353
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
2354
        p[1] = nc;
2355
        p[2] = nc2;
2356
        p[3] = new Coordinate(c);
2357

    
2358
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
2359
        LinearRing ls = new LinearRing(cs, geomFactory);
2360
        Polygon po = new Polygon(ls, null, geomFactory);
2361
        Polygon[] pos = new Polygon[1];
2362
        pos[0] = po;
2363

    
2364
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
2365

    
2366
        return mpo;
2367
    }
2368

    
2369
    public String getSourceProjection(IConnection conn, DBLayerDefinition lyrDef) {
2370
            
2371
            String resp = null;
2372
        try {
2373
            Statement _st = ((ConnectionJDBC) conn).getConnection().createStatement();
2374
            String[] tokens = lyrDef.getName().split("\\u002E", 2);
2375
            String qry;
2376
            if (tokens.length > 1) {
2377
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2378
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
2379
                tokens[1] + "'";
2380
            } else {
2381
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2382
                " where TABLE_NAME = " + "'" + lyrDef.getName() + "'";
2383
            }
2384
            ResultSet _rs = _st.executeQuery(qry);
2385

    
2386
            if (_rs.next()) {
2387
                String aux = getOracleSridFromCurrentRecord(_rs);
2388
                try {
2389
                                        resp = oracleSridToEpsgSrid(aux);
2390
                                } catch (Exception e) {
2391
                                        logger.error("Unknown oracle SRID: " + aux);
2392
                                }
2393
            } else {
2394
                    
2395
            }
2396
        } catch (Exception ex) {
2397
                logger.error("While getting Source Projection: " + ex.getMessage());
2398
        }
2399
        
2400
        if (resp != null) {
2401
                return resp;
2402
        } else {
2403
                return getDestProjection();
2404
        }
2405
        
2406
    }
2407

    
2408
    public String getDestProjection() {
2409
        return removePrefix(destProj);
2410
    }
2411

    
2412
    public void setDestProjection(String toEPSG) {
2413
        destProj = toEPSG;
2414
        try {
2415
                        destProjOracle = epsgSridToOracleSrid(destProj);
2416
                        isDestGeogCS = OracleSpatialUtils.getIsGCS(destProjOracle, true);
2417

    
2418
                } catch (Exception e) {
2419
                        logger.error("Unknown EPSG code: " + destProj);
2420
                        destProjOracle = oracleSRID;
2421
                        isDestGeogCS = false;
2422
                }
2423

    
2424
    }
2425

    
2426
    public String getDestProjectionOracleCode() {
2427
            return destProjOracle;
2428
    }
2429

    
2430
    public boolean getIsDestProjectionGeog() {
2431
            return isDestGeogCS;
2432
    }
2433

    
2434
    public String getTableProjectionOracleCode() {
2435
            return oracleSRID;
2436
    }
2437

    
2438
    public boolean canReproject(String toEPSGdestinyProjection) {
2439
        return false;
2440
    }
2441

    
2442
    /**
2443
     * Utility function. Says whether a given field name can be a user field name
2444
     * or not (for example, "ROWID" is not a valid one because it's a system
2445
     * reserved word).
2446
     *
2447
     * @param str proposed firld name
2448
     * @return whether it is valid or not for Oracle databases
2449
     */
2450
    private static boolean isOracleAllowedFieldname(String str) {
2451
        if (str.compareToIgnoreCase("rowid") == 0) {
2452
            return false;
2453
        }
2454

    
2455
        if (str.compareToIgnoreCase("rownum") == 0) {
2456
            return false;
2457
        }
2458

    
2459
        return true;
2460
    }
2461

    
2462
    public Hashtable getHashRelate() {
2463
        return hashRelate;
2464
    }
2465

    
2466
    public void setHashRelate(Hashtable m) {
2467
        hashRelate = m;
2468
    }
2469

    
2470
    public void setNumReg(int n) {
2471
        numReg = n;
2472
    }
2473

    
2474
    private int[] getRandomSample(int maxn_one_based, int n) {
2475
        int[] resp = new int[n];
2476

    
2477
        if (maxn_one_based <= n) {
2478
            resp = new int[maxn_one_based];
2479

    
2480
            for (int i = 0; i < maxn_one_based; i++) {
2481
                resp[i] = i;
2482
            }
2483
        }
2484
        else {
2485
            Random rnd = new Random();
2486

    
2487
            for (int i = 0; i < n; i++) {
2488
                resp[i] = rnd.nextInt(maxn_one_based);
2489
            }
2490
        }
2491

    
2492
        return resp;
2493
    }
2494

    
2495
    private String getRowIdRestrictionCondition(int nrecords) {
2496
        int[] zero_based_rows = getRandomSample(nrecords,
2497
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
2498
        String resp = "(";
2499
        Object aux = "";
2500
        ROWID riaux = null;
2501

    
2502
        for (int i = 0; i < zero_based_rows.length; i++) {
2503
            aux = rowToId.get(new Integer(zero_based_rows[i]));
2504
            riaux = (ROWID) aux;
2505
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
2506
        }
2507

    
2508
        resp = resp.substring(0, resp.length() - 4);
2509
        resp = resp + ")";
2510

    
2511
        return resp;
2512
    }
2513

    
2514
    private Rectangle2D getBoundingFromSample(int n_max) {
2515
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
2516
            " WHERE " + getRowIdRestrictionCondition(n_max);
2517
        STRUCT auxstr = null;
2518
        IGeometry theGeom = null;
2519
        Rectangle2D resp = null;
2520

    
2521
        try {
2522
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
2523
            ResultSet rs = st.executeQuery(_qry);
2524

    
2525
            if (rs.next()) {
2526
                auxstr = (STRUCT) rs.getObject(1);
2527

    
2528
                if (auxstr != null) {
2529
                    theGeom = getGeometryUsing(auxstr, use_geotools);
2530

    
2531
                    if (resp == null) {
2532
                        resp = theGeom.getBounds2D();
2533
                    }
2534
                    else {
2535
                        resp.add(theGeom.getBounds2D());
2536
                    }
2537
                }
2538

    
2539
                while (rs.next()) {
2540
                    auxstr = (STRUCT) rs.getObject(1);
2541

    
2542
                    if (auxstr != null) {
2543
                        theGeom = getGeometryUsing(auxstr, use_geotools);
2544

    
2545
                        if (resp == null) {
2546
                            resp = theGeom.getBounds2D();
2547
                        }
2548
                        else {
2549
                            resp.add(theGeom.getBounds2D());
2550
                        }
2551
                    }
2552
                }
2553

    
2554
                rs.close();
2555
                st.close();
2556
            }
2557
            else {
2558
                throw new SQLException("Empty resultset from this query: " +
2559
                    _qry);
2560
            }
2561
        }
2562
        catch (SQLException se) {
2563
                logger.error("While getting sample full extent: " +
2564
                se.getMessage());
2565
        }
2566

    
2567
        if (resp == null) {
2568
            logger.warn(
2569
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
2570

    
2571
            return new Rectangle2D.Double(-180, -90, 360, 180);
2572
        }
2573

    
2574
        return resp;
2575
    }
2576

    
2577
    /**
2578
     * Does what it says, puts the LinearRing in counter clock wise
2579
     * order.
2580
     * @param ls The ring to set.
2581
     * @param gf a GeometryFactory object
2582
     * @return A new ring in CCW order.
2583
     *
2584
     */
2585
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
2586
        Coordinate[] cc = ls.getCoordinates();
2587

    
2588
        if (CGAlgorithms.isCCW(cc)) {
2589
            return gf.createLinearRing(cc);
2590
        }
2591
        else {
2592
            if (ls instanceof LinearRing) {
2593
                return reverseRing((LinearRing) ls, gf);
2594
            }
2595
            else {
2596
                return reverseLineString(ls, gf);
2597
            }
2598
        }
2599
    }
2600

    
2601
    /**
2602
     * Does what it says, reverses the order of the Coordinates in the ring.
2603
     * @param lr The ring to reverse.
2604
     * @return A new ring with the reversed Coordinates.
2605
     *
2606
     */
2607
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
2608
        int numPoints = lr.getNumPoints() - 1;
2609
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
2610

    
2611
        for (int t = numPoints; t >= 0; t--) {
2612
            newCoords[t] = lr.getCoordinateN(numPoints - t);
2613
        }
2614

    
2615
        return gf.createLinearRing(newCoords);
2616
    }
2617

    
2618
    /**
2619
     * Does what it says, reverses the order of the Coordinates in the linestring.
2620
     * @param ls The ls to reverse.
2621
     * @param gf a GeometryFactory object
2622
     * @return A new ls with the reversed Coordinates.
2623
     *
2624
     */
2625
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
2626
        int numPoints = ls.getNumPoints() - 1;
2627
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
2628

    
2629
        for (int t = numPoints; t >= 0; t--) {
2630
            newCoords[t] = ls.getCoordinateN(numPoints - t);
2631
        }
2632

    
2633
        return gf.createLinearRing(newCoords);
2634
    }
2635

    
2636
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
2637
        if (ge instanceof MultiPolygon) {
2638
            MultiPolygon mp = (MultiPolygon) ge;
2639
            int size = ge.getNumGeometries();
2640
            Polygon[] pols = new Polygon[size];
2641

    
2642
            for (int i = 0; i < size; i++)
2643
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
2644
                        gf);
2645

    
2646
            return new MultiPolygon(pols, gf);
2647
        }
2648
        else {
2649
            if (ge instanceof Polygon) {
2650
                Polygon p = (Polygon) ge;
2651
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
2652
                int nholes = p.getNumInteriorRing();
2653

    
2654
                if (nholes > 0) {
2655
                    LinearRing[] holes = new LinearRing[nholes];
2656

    
2657
                    for (int i = 0; i < nholes; i++) {
2658
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
2659
                    }
2660

    
2661
                    return gf.createPolygon(exterior, holes);
2662
                }
2663
                else {
2664
                    return gf.createPolygon(exterior, null);
2665
                }
2666
            }
2667
            else {
2668
                return ge;
2669
            }
2670
        }
2671
    }
2672

    
2673
    /**
2674
     * Converts from IGeometry to STRUCT
2675
     *
2676
     * @param ig the geometry to convert
2677
     * @param _forced_type forced type to use
2678
     * @param _conn connection
2679
     * @param _o_srid  SRS (oracle code)
2680
     * @param withSrid whether this STRUCT has a non-NULL SRS
2681
     * @param agu_bien whether or not to check the correctness of the holes
2682
     * @param _isGeoCS whether the SRS is geodetic or not
2683
     * @return the generated STRUCT
2684
     */
2685
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
2686
        IConnection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
2687
        boolean _isGeoCS) {
2688
        if (ig instanceof FGeometryCollection) {
2689
            FGeometryCollection coll = (FGeometryCollection) ig;
2690

    
2691
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
2692
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
2693

    
2694
            // logger.error("Collections no soportadas por ahora.");
2695
            // return null;
2696
        }
2697
        else {
2698
            Shape shp = ig.getInternalShape();
2699

    
2700
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
2701
                agu_bien, false, _isGeoCS);
2702
        }
2703
    }
2704

    
2705
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
2706
        boolean agu_bien, boolean isView) {
2707

    
2708
            if (shp == null) return null;
2709
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
2710
            agu_bien, isView, isGeogCS);
2711
    }
2712

    
2713
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
2714
        IConnection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
2715
        boolean isView, boolean _isGeoCS) {
2716
        int _srid = -1;
2717

    
2718
        if ((o_srid != null) && (o_srid.length() > 0)) {
2719
            _srid = Integer.parseInt(o_srid);
2720
        }
2721

    
2722
        if (shp == null) {
2723
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
2724

    
2725
            return null;
2726
        }
2727

    
2728
        if (shp instanceof Rectangle2D) {
2729
            return OracleSpatialUtils.rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
2730
                _isGeoCS, o_srid, _conn);
2731
        }
2732

    
2733
        try {
2734
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
2735
                    _srid, agu_bien, hasSrid);
2736

    
2737
            return the_struct;
2738
        }
2739
        catch (SQLException ex) {
2740
            logger.error("While creating STRUCT: " + ex.getMessage());
2741

    
2742
            return null;
2743
        }
2744
    }
2745

    
2746
    // -------------------------- not ready yet ----------------
2747
    public int getRowIndexByFID(IFeature _fid) {
2748
        if (isNotAvailableYet) {
2749
            return -1;
2750
        }
2751
        else {
2752
            return super.getRowIndexByFID(_fid);
2753
        }
2754
    }
2755

    
2756
    public int getShapeCount() throws ReadDriverException { 
2757
        if (isNotAvailableYet) {
2758
            return 0;
2759
        }
2760
        else {
2761
            return numReg;
2762
        }
2763
    }
2764

    
2765
    public void setNotAvailableYet(boolean nav) {
2766
        isNotAvailableYet = nav;
2767
    }
2768

    
2769
    // -------------------------------------------------------
2770
    // -------------------------------------------------------
2771
    public String[] getTableNames(IConnection conn, String catalog)
2772
        throws DBException {
2773
        try{
2774
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
2775
        String[] types = { "TABLE", "VIEW" };
2776
        // String[] types = { "VIEW" };
2777

    
2778
        ResultSet rs = null;
2779
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
2780
                    ALL_ORACLE_GEOMETADATA_VIEW, types), ((ConnectionJDBC)conn).getConnection());
2781
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
2782
//                          ORACLE_GEOMETADATA_VIEW, types);
2783
        TreeMap ret = new TreeMap();
2784

    
2785
        while (rs.next()) {
2786
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
2787
            ret.put(nomCompleto, nomCompleto);
2788
        }
2789

    
2790
        return (String[]) ret.keySet().toArray(new String[0]);
2791
        }catch (SQLException e) {
2792
                        throw new DBException(e);
2793
                }
2794
    }
2795

    
2796
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
2797
        throws SQLException {
2798
        String tablename = "";
2799

    
2800
        if (res.next()) {
2801
            tablename = res.getString("TABLE_NAME");
2802

    
2803
            // debug
2804
            writeMetaTableToLog(con, tablename);
2805

    
2806
            Statement __st = con.createStatement();
2807

    
2808
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
2809
                "union (select VIEW_NAME from USER_VIEWS)) " +
2810
                "intersect (select TABLE_NAME from " + tablename + ")";
2811
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
2812
            ResultSet rs = __st.executeQuery(sql);
2813

    
2814
            return rs;
2815
        }
2816
        else {
2817
            logger.error("Error while getting geometry tables.");
2818

    
2819
            return null;
2820
        }
2821
    }
2822

    
2823
    private void writeMetaTableToLog(Connection con, String tname) {
2824

    
2825
            logger.debug("======================================================");
2826
            logger.debug("=     " + ALL_ORACLE_GEOMETADATA_VIEW + "  (1 EVERY 10 TABLES) ========");
2827
            logger.debug("======================================================");
2828

    
2829
            try {
2830
            Statement _stmt = con.createStatement();
2831
            String sql = "SELECT * FROM " + tname;
2832
            ResultSet res = _stmt.executeQuery(sql);
2833
            
2834
            int count = 0;
2835
            while (res.next()) {
2836
                    
2837
                    if ((count % 10) == 0) {
2838
                        logger.debug(
2839
                                        "OWNER: " + res.getString("OWNER")
2840
                                        + ", TABLE_NAME: " + res.getString("TABLE_NAME")
2841
                                        + ", COLUMN_NAME: " + res.getString("COLUMN_NAME")
2842
                                        + ", SRID: " + res.getString("SRID"));
2843
                        ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
2844
                        String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
2845
                        logger.debug("DIMINFO: " + dinfo);
2846
                        logger.debug("=========");
2847
                    }
2848
                    count++;
2849
                    
2850
            }
2851
            } catch (Throwable th) {
2852

    
2853
            }
2854
        }
2855

    
2856
        /**
2857
     * Gets the field names that can act as row id (always ROWID)
2858
     */
2859
    public String[] getIdFieldsCandidates(IConnection conn, String table_name)
2860
        throws DBException {
2861
            try{
2862
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
2863
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
2864
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
2865
            _rs.close();
2866
            _st.close();
2867

    
2868
            String[] resp = { "ROWID" };
2869
        return resp;
2870
            }catch (SQLException e) {
2871
                        throw new DBException(e);
2872
                }
2873
    }
2874

    
2875
    /**
2876
     * Gets the field names that can act as geometry fields
2877
     * (queries the user's geographic metadata).
2878
     */
2879
    public String[] getGeometryFieldsCandidates(IConnection conn,
2880
        String table_name) throws DBException {
2881
            try{
2882
        Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
2883
        String[] tokens = table_name.split("\\u002E", 2);
2884
        String qry;
2885
        if (tokens.length > 1)
2886
        {
2887
                qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2888
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
2889
            tokens[1] + "'";
2890
        }
2891
        else
2892
        {
2893
                qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2894
            " where TABLE_NAME = " + "'" + table_name + "'";
2895

    
2896
        }
2897
        ResultSet _rs = _st.executeQuery(qry);
2898

    
2899
        ArrayList aux = new ArrayList();
2900

    
2901
        while (_rs.next()) {
2902
            String _geo = _rs.getString("COLUMN_NAME");
2903
            aux.add(_geo);
2904
        }
2905

    
2906
        _rs.close();
2907
        _st.close();
2908

    
2909
        String[] resp = (String[]) aux.toArray(new String[0]);
2910

    
2911
        return checkIndexes(conn, resp, table_name);
2912
            }catch (SQLException e) {
2913
                        throw new DBException(e);
2914
                }
2915
    }
2916

    
2917
    private String[] checkIndexes(IConnection c, String[] all, String long_table_name) throws DBException {
2918

    
2919
            ArrayList good_ones = new ArrayList();
2920
            try{
2921
            String t = long_table_name;
2922
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
2923

    
2924
            for (int i=0; i<all.length; i++) {
2925

    
2926
                String qry = "SELECT SRID, DIMINFO FROM " + ALL_ORACLE_GEOMETADATA_VIEW +
2927
            " WHERE TABLE_NAME = " + "'" + t.toUpperCase() +
2928
            "' AND COLUMN_NAME = '" + all[i].toUpperCase() + "'";
2929

    
2930
                Statement _st = ((ConnectionJDBC)c).getConnection().createStatement();
2931
                ResultSet _rs = _st.executeQuery(qry);
2932
                if (_rs.next()) {
2933
                        String _srid = toString((BigDecimal) _rs.getObject(1));
2934
                        ARRAY diminfo = (ARRAY) _rs.getObject(2);
2935
                        int len = diminfo.getOracleArray().length;
2936
                        if (allowsGeoQueries(((ConnectionJDBC)c).getConnection(), long_table_name, all[i], _srid, len)) {
2937
                                good_ones.add(all[i]);
2938
                        }
2939
                }
2940
                _rs.close();
2941
                _st.close();
2942
            }
2943

    
2944
            if (good_ones.size() == 0) {
2945
                    throw new SQLException("no_indexes_on_declared_geo_fields");
2946
            }
2947
            }catch (SQLException e) {
2948
                        throw new DBException(e);
2949
                }
2950
            return (String[]) good_ones.toArray(new String[0]);
2951
    }
2952

    
2953
    private String toString(BigDecimal number) {
2954

    
2955
            if (number == null) return "NULL";
2956
            return "" + number.intValue();
2957
        }
2958

    
2959
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
2960
            String p = getPointConstructor(dims, _srid);
2961
            String qry = "";
2962
            qry = "SELECT * FROM " + _t.toUpperCase()
2963
            + " WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'"
2964
            + " AND ROWNUM = 1";
2965

    
2966
            try {
2967
                        Statement _st = c.createStatement();
2968
                        ResultSet _rs = _st.executeQuery(qry);
2969
                        _rs.close();
2970
                        _st.close();
2971
                } catch (Exception ex) {
2972
                        return false;
2973
                }
2974
                return true;
2975
        }
2976

    
2977
        private String getPointConstructor(int dims, String _srid) {
2978

    
2979
                String coord = "";
2980
                for (int i=0; i<dims; i++) coord = coord + "0, ";
2981
                coord = coord.substring(0, coord.length() - 2);
2982

    
2983
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
2984
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
2985
        }
2986

    
2987
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
2988

    
2989
            if (l == null) return false;
2990
            if (str == null) return false;
2991

    
2992
            String item = "";
2993
            for (int i=0; i<l.size(); i++) {
2994
                    if (l.get(i) instanceof String) {
2995
                            item = (String) l.get(i);
2996
                            if (item.compareToIgnoreCase(str) == 0) return true;
2997
                    }
2998
            }
2999
            return false;
3000
    }
3001

    
3002
        /**
3003
     * Utility method to check if a given table is empty.
3004
     */
3005
    public boolean isEmptyTable(Connection conn, String tableName) {
3006
        boolean res = true;
3007

    
3008
        try {
3009
            Statement st = conn.createStatement();
3010
            ResultSet rs = null;
3011
            rs = st.executeQuery("select * from " + tableName +
3012
                    " where rownum = 1");
3013
            res = !rs.next();
3014
            rs.close();
3015
            st.close();
3016
        }
3017
        catch (Exception ex) {
3018
            res = true;
3019
        }
3020

    
3021
        return res;
3022
    }
3023

    
3024
    /**
3025
     * Gets all the fields from a table name.
3026
     */
3027
    public String[] getAllFields(IConnection conn, String table_name)
3028
        throws DBException {
3029
            try{
3030
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3031
        ResultSet rs = st.executeQuery("select * from " + table_name +
3032
                " where rownum = 1");
3033
        ResultSetMetaData rsmd = rs.getMetaData();
3034
        String[] ret = new String[rsmd.getColumnCount()];
3035

    
3036
        for (int i = 0; i < ret.length; i++) {
3037
            ret[i] = rsmd.getColumnName(i + 1);
3038
        }
3039

    
3040
        rs.close();
3041
        st.close();
3042

    
3043
        return ret;
3044
            }catch (SQLException e) {
3045
                        throw new DBException(e);
3046
                }
3047
    }
3048

    
3049
    /**
3050
     * Gets all field type names from a table.
3051
     */
3052
    public String[] getAllFieldTypeNames(IConnection conn, String table_name)
3053
        throws DBException {
3054
            try{
3055
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3056
        ResultSet rs = st.executeQuery("select * from " + table_name +
3057
                " where rownum = 1");
3058
        ResultSetMetaData rsmd = rs.getMetaData();
3059
        String[] ret = new String[rsmd.getColumnCount()];
3060

    
3061
        for (int i = 0; i < ret.length; i++) {
3062
            if (rsmd.getColumnType(i + 1) == Types.NUMERIC) {
3063
                    int scale = rsmd.getScale(i+1);
3064
                    if (scale >= 0) {
3065
                        String prec_dec = " (" + rsmd.getPrecision(i+1) + ", " + scale + ")";  
3066
                        ret[i] = rsmd.getColumnTypeName(i + 1) + prec_dec;
3067
                    } else {
3068
                            ret[i] = rsmd.getColumnTypeName(i + 1);
3069
                    }
3070
            } else {
3071
                ret[i] = rsmd.getColumnTypeName(i + 1);
3072
            }
3073
        }
3074

    
3075
        rs.close();
3076
        st.close();
3077

    
3078
        close();
3079

    
3080
        return ret;
3081
            }catch (SQLException e) {
3082
                        throw new DBException(e);
3083
                }
3084
    }
3085

    
3086
    /**
3087
     * Gets Oracle's specific connection string for the given parameters.
3088
     */
3089
    public String getConnectionString(String host, String port, String dbname,
3090
        String user, String pw) {
3091
        String _pw = pw;
3092

    
3093
        if (_pw == null) {
3094
            _pw = "null";
3095
        }
3096

    
3097
        String fullstr = CONN_STR_BEGIN;
3098
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
3099
        fullstr = fullstr + "@" + host.toLowerCase();
3100
        fullstr = fullstr + ":" + port;
3101
        fullstr = fullstr + ":" + dbname.toLowerCase();
3102

    
3103
        return fullstr;
3104
    }
3105

    
3106
    /**
3107
     * Gets the Pracle geometries writer associated with this driver.
3108
     */
3109
    public IWriter getWriter() {
3110
        // on(VectorialEditableDBAdapter.java:290)
3111
        if (writer == null) {
3112

    
3113
                long count = 0;
3114
                        try {
3115
                                count = getRowCount();
3116
                        } catch (ReadDriverException e1) {
3117
                                logger.error("While getting row count: " + e1.getMessage());
3118
                        }
3119
                
3120
            writer = new OracleSpatialWriter(count);
3121
            writer.setDriver(this);
3122
            writer.setLyrShapeType(getShapeType());
3123
            writer.setGeoCS(isGeogCS());
3124
            writer.setGeoColName(geoColName);
3125
            writer.setSRID(oracleSRID);
3126

    
3127
            try {
3128
                    DBLayerDefinition db_lyr_def = getLyrDef();
3129
                    if (db_lyr_def == null) {
3130
                            logger.warn("Found a null DB layer definition, method initialize of OracleWriter not called.");
3131
                    } else {
3132
                            writer.initialize(getLyrDef());
3133
                    }
3134
                
3135
            } catch (InitializeWriterException e) {
3136
                logger.error("While initializing OS Writer: " + e.getMessage(), e);
3137
            }
3138

    
3139
            writer.setStoreWithSrid(tableHasSrid);
3140
        }
3141

    
3142
        return writer;
3143
    }
3144

    
3145
    /**
3146
     * Tells whether the SRS is geodetic or not-
3147
     * @return whether the SRS is geodetic or not
3148
     */
3149
    public boolean isGeogCS() {
3150
        return isGeogCS;
3151
    }
3152

    
3153
    /**
3154
     * Adds a row id to the inner set od IDs.
3155
     * @param id
3156
     */
3157
    public void addRow(String id) {
3158
        Value aux = ValueFactory.createValue(id);
3159
        Integer intobj = new Integer(numReg);
3160
        hashRelate.put(aux, intobj);
3161
        rowToId.put(intobj, id);
3162

    
3163
        numReg++;
3164
    }
3165

    
3166
    /**
3167
     * Removes a row id to the inner set od IDs.
3168
     * @param id
3169
     */
3170
    public void deleteRow(String id) {
3171
        Value aux = ValueFactory.createValue(id);
3172
        Integer intobj = (Integer) hashRelate.get(aux);
3173
        hashRelate.remove(aux);
3174
        rowToId.remove(intobj);
3175

    
3176
        numReg--;
3177
    }
3178

    
3179
    private String getStandardSelectExpression() {
3180

    
3181
                String resp = "";
3182

    
3183
                String[] flds = getLyrDef().getFieldNames();
3184
                int size = flds.length;
3185

    
3186
                for (int i = 0; i < size; i++) {
3187
                        if (i > 0) {
3188
                                resp = resp + "c.\"" + flds[i] + "\", ";
3189
                        } else {
3190
                                resp = resp + flds[i] + ", ";
3191
                        }
3192
                }
3193

    
3194
                resp = resp.substring(0, resp.length() - 2);
3195
                return resp;
3196
        }
3197

    
3198
    /**
3199
         * Allows the method to decide what to do with the geometry field name
3200
         * (remove/add it from the user selected fields).
3201
         * 
3202
         * @param flds
3203
         * @param geof
3204
         * @return the possibly modified field names
3205
         */
3206
    public String[] manageGeometryField(String[] flds, String geof) {
3207
        return addEndIfNotContained(flds, geof);
3208
    }
3209

    
3210
    /**
3211
     * Allows the method to decide what to do with the ID field name
3212
     * (remove/add it from the user selected fields).
3213
     *
3214
     * @param flds
3215
     * @param idf
3216
     * @return the possibly modified field names
3217
     */
3218
    public String[] manageIdField(String[] flds, String idf) {
3219
        return addStartIfNotContained(flds, idf);
3220
    }
3221

    
3222
    private String[] addEndIfNotContained(String[] arr, String item) {
3223
        if (contains(arr, item)) {
3224
            return arr;
3225
        }
3226
        else {
3227
            int size = arr.length;
3228
            String[] resp = new String[size + 1];
3229

    
3230
            for (int i = 0; i < size; i++) {
3231
                resp[i] = arr[i];
3232
            }
3233

    
3234
            resp[size] = item;
3235

    
3236
            return resp;
3237
        }
3238
    }
3239

    
3240
    private String[] addStartIfNotContained(String[] arr, String item) {
3241
        if (contains(arr, item)) {
3242
            return arr;
3243
        }
3244
        else {
3245
            int size = arr.length;
3246
            String[] resp = new String[size + 1];
3247

    
3248
            for (int i = 1; i <= size; i++) {
3249
                resp[i] = arr[i];
3250
            }
3251

    
3252
            resp[0] = item;
3253

    
3254
            return resp;
3255
        }
3256
    }
3257

    
3258
    private boolean contains(String[] arr, String item) {
3259
        for (int i = 0; i < arr.length; i++) {
3260
            if (arr[i].compareTo(item) == 0) {
3261
                return true;
3262
            }
3263
        }
3264

    
3265
        return false;
3266
    }
3267

    
3268
    /**
3269
     * This method is called when the user removes the layer from the view.
3270
     * If the IDs were being loaded, the driver will check this field and will
3271
     * let the thread 'die' quietly.
3272
     *
3273
     */
3274
    public void remove() {
3275
        cancelIDLoad = true;
3276
    }
3277

    
3278
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
3279
            // if (!isgeodetic) return true;
3280
            if ((ext.getMinX() > -179.9) || (ext.getMinX() < -180.1)) return true;
3281
            if ((ext.getMinY() > -89.9) || (ext.getMinY() < -90.1)) return true;
3282
            if ((ext.getWidth() < 359.9) || (ext.getWidth() > 360.1)) return true;
3283
            if ((ext.getHeight() < 179.9) || (ext.getHeight() > 180.1)) return true;
3284
            return false;
3285
    }
3286

    
3287
    private Rectangle2D getFastEstimatedExtent(
3288
                    String tname,
3289
                    String gfield,
3290
                    IConnection c,
3291
                    int sample_size,
3292
                    double enlargement,
3293
                    boolean is_geo) {
3294

    
3295
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
3296
            Rectangle2D resp_aux = null;
3297
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
3298
            ResultSet _rs = null;
3299

    
3300
            try {
3301
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
3302
                        _rs = _st.executeQuery();
3303
                        while (_rs.next()) {
3304
                                STRUCT aux = (STRUCT) _rs.getObject(1);
3305
                                IGeometry ig = getGeometryUsing(aux, false);
3306

    
3307
                                if (ig == null) continue;
3308

    
3309
                                if (resp_aux == null) {
3310
                                        resp_aux = ig.getBounds2D();
3311
                                } else {
3312
                                        resp_aux.add(ig.getBounds2D());
3313
                                }
3314

    
3315
                        }
3316
                } catch (Exception ex) {
3317
                        logger.error("While getting random sample: " + ex.getMessage());
3318
                }
3319

    
3320
                if (resp_aux == null) {
3321
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
3322
                        return world;
3323
                }
3324
                
3325
                double w = resp_aux.getWidth();
3326
                double h = resp_aux.getHeight();
3327
                double x = resp_aux.getMinX();
3328
                double y = resp_aux.getMinY();
3329

    
3330
                // enlarge n times:
3331
                double newx = x - (0.5 * (enlargement - 1)) * w;
3332
                double newy = y - (0.5 * (enlargement - 1)) * h;
3333
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
3334
                                enlargement * w,
3335
                                enlargement * h);
3336

    
3337
                if (is_geo) {
3338
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
3339
                        logger.debug("FAST BB: " + resp_aux.toString());
3340
                        return resp_aux;
3341
                } else {
3342
                        logger.debug("FAST BB: " + resp_aux_large.toString());
3343
                        return resp_aux_large;
3344
                }
3345

    
3346
    }
3347

    
3348
    private Rectangle2D getEstimatedExtent(
3349
                    String tname,
3350
                    String gfield,
3351
                    IConnection c,
3352
                    int sample_size,
3353
                    double enlargement,
3354
                    boolean is_geo) {
3355

    
3356
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
3357

    
3358
            ArrayList ids = new ArrayList();
3359
            int _rnd_index = 0;
3360
            ROWID _id = null;
3361
            Random rnd = new Random(System.currentTimeMillis());
3362

    
3363
            for (int i=0; i<sample_size; i++) {
3364
                    _rnd_index = rnd.nextInt(numReg);
3365
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
3366
                    ids.add(_id.stringValue());
3367
            }
3368

    
3369
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
3370
            for (int i=0; i<ids.size(); i++) {
3371
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR ";
3372
            }
3373
            qry = qry.substring(0, qry.length() - 4) + ")";
3374

    
3375
            Rectangle2D resp_aux = null;
3376
            ResultSet _rs = null;
3377

    
3378
            try {
3379
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
3380
                        _rs = _st.executeQuery();
3381
                        while (_rs.next()) {
3382
                                STRUCT aux = (STRUCT) _rs.getObject(1);
3383
                                IGeometry ig = getGeometryUsing(aux, false);
3384

    
3385
                                if (ig == null) continue;
3386

    
3387
                                if (resp_aux == null) {
3388
                                        resp_aux = ig.getBounds2D();
3389
                                } else {
3390
                                        resp_aux.add(ig.getBounds2D());
3391
                                }
3392

    
3393
                        }
3394
                } catch (Exception ex) {
3395
                        logger.error("While getting random sample: " + ex.getMessage());
3396
                }
3397

    
3398
                if (resp_aux == null) {
3399
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
3400
                        return world;
3401
                }
3402
                
3403
                double w = resp_aux.getWidth();
3404
                double h = resp_aux.getHeight();
3405
                double x = resp_aux.getMinX();
3406
                double y = resp_aux.getMinY();
3407

    
3408
                // enlarge 10 times:
3409
                double newx = x - (0.5 * (enlargement - 1)) * w;
3410
                double newy = y - (0.5 * (enlargement - 1)) * h;
3411
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
3412
                                enlargement * w,
3413
                                enlargement * h);
3414

    
3415
                if (is_geo) {
3416
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
3417
                        logger.debug("ESTIMATED BB: " + resp_aux.toString());
3418
                        return resp_aux;
3419
                } else {
3420
                        logger.debug("ESTIMATED BB: " + resp_aux_large.toString());
3421
                        return resp_aux_large;
3422
                }
3423

    
3424
    }
3425

    
3426
    public void setUserName(String u) {
3427
            userName = u;
3428
    }
3429

    
3430
    public String getUserName() {
3431
            return userName;
3432
    }
3433

    
3434
    public static final int JGeometry_GTYPE_COLLECTION = 4;
3435
    public static final int JGeometry_GTYPE_CURVE = 2;
3436
    public static final int JGeometry_GTYPE_MULTICURVE = 6;
3437
    public static final int JGeometry_GTYPE_MULTIPOINT = 5;
3438
    public static final int JGeometry_GTYPE_MULTIPOLYGON = 7;
3439
    public static final int JGeometry_GTYPE_POINT = 1;
3440
    public static final int JGeometry_GTYPE_POLYGON = 3;
3441
        
3442

    
3443
    // ------------------------------
3444
    
3445
    public void setXMLEntity(XMLEntity xml) throws XMLException {
3446
            
3447
            super.setXMLEntity(xml);
3448
            workingAreaInTablesCS = workingArea;
3449
            
3450
            try {
3451
                    int[] ftypes = xml.getIntArrayProperty("fieldTypes");
3452
                    setLyrDefFieldTypes(ftypes);
3453
            } catch (Exception ex) {
3454
                    logger.warn("Apparently, an old GVP file has been opened," +
3455
                                    " field type values are not accurate after this point.");
3456
            }
3457
            
3458
    }
3459
    
3460
    public XMLEntity getXMLEntity() {
3461
                // ---------------------
3462

    
3463
                XMLEntity xml = new XMLEntity();
3464
                xml.putProperty("className", getClass().getName());
3465

    
3466
                xml.putProperty("catalog", getLyrDef().getCatalogName());
3467

    
3468
                int aux = userName.indexOf("@");
3469
                if (aux != -1)
3470
                        userName = userName.substring(0, aux);
3471
                xml.putProperty("username", userName);
3472

    
3473
                xml.putProperty("driverclass", ORACLE_JAR_FILE_NAME);
3474

    
3475
                xml.putProperty("tablename", getTableName());
3476
                xml.putProperty("fields", lyrDef.getFieldNames());
3477
                xml.putProperty("fieldTypes", getLyrDefFieldTypes());
3478
                xml.putProperty("FID", lyrDef.getFieldID());
3479
                xml.putProperty("THE_GEOM", lyrDef.getFieldGeometry());
3480
                xml.putProperty("whereclause", getWhereClause());
3481
                xml.putProperty("SRID", lyrDef.getSRID_EPSG());
3482

    
3483
                xml.putProperty("host", host);
3484
                xml.putProperty("port", port);
3485
                xml.putProperty("dbName", dbName);
3486
                xml.putProperty("connName", connName);
3487

    
3488
                if (workingAreaInTablesCS != null) {
3489
                        xml.putProperty("minXworkArea", workingAreaInTablesCS.getMinX());
3490
                        xml.putProperty("minYworkArea", workingAreaInTablesCS.getMinY());
3491
                        xml.putProperty("HworkArea", workingAreaInTablesCS.getHeight());
3492
                        xml.putProperty("WworkArea", workingAreaInTablesCS.getWidth());
3493
                }
3494

    
3495
                return xml;
3496
        }
3497
    
3498
    private int[] getLyrDefFieldTypes() {
3499
            FieldDescription[] fd = lyrDef.getFieldsDesc();
3500
            int sz = fd.length;
3501
            int[] resp = new int[sz];
3502
            for (int i=0; i<sz; i++) resp[i] = fd[i].getFieldType();
3503
                return resp;
3504
        }
3505
    
3506
    private void setLyrDefFieldTypes(int[] tt) {
3507
            FieldDescription[] fd = lyrDef.getFieldsDesc();
3508
            
3509
            int sz_fd = fd.length;
3510
            int sz_tt = tt.length;
3511
            int sz = sz_tt;
3512
            
3513
            if (sz_tt != sz_fd) {
3514
                    logger.error("Field count does not match. lyrDef has " + sz_fd + " fields," +
3515
                                    " but this method was called with " + sz_tt + " items (?)");
3516
                    sz = Math.min(sz_fd, sz_tt);
3517
            }
3518
            
3519
            for (int i=0; i<sz; i++) lyrDef.getFieldsDesc()[i].setFieldType(tt[i]);
3520
    }
3521

    
3522
        public String[] getTableFields(IConnection conex, String table) throws DBException {
3523
                try{
3524
                Statement st = ((ConnectionJDBC)conex).getConnection().createStatement();
3525
        // ResultSet rs = dbmd.getTables(catalog, null, dbLayerDefinition.getTable(), null);
3526
                ResultSet rs = st.executeQuery("select * from " + table + " LIMIT 1");
3527
                ResultSetMetaData rsmd = rs.getMetaData();
3528

    
3529
                String[] ret = new String[rsmd.getColumnCount()];
3530

    
3531
                for (int i = 0; i < ret.length; i++) {
3532
                        ret[i] = rsmd.getColumnName(i+1);
3533
                }
3534

    
3535
                return ret;
3536
                }catch (SQLException e) {
3537
                        throw new DBException(e);
3538
                }
3539
        }
3540

    
3541
    // Overwritten to keep old behavior: returns "schema.table_name" if
3542
    // schema is not current user
3543
        public String getTableName() {
3544
            return fullTableName; 
3545
        }
3546
        
3547
    private Timestamp flexibleTimeStamp(String s) {
3548
            
3549
            String aux = s.replace('-', ' ');
3550
            aux = aux.replace(':', ' ');
3551
            aux = aux.replace('.', ' ');
3552
            // sample: 2007 12 31 23 59 59 9999
3553
            String[] parts = aux.trim().split(" ");
3554
            
3555
            int year;
3556
            int month;
3557
            int day;
3558
            int hour;
3559
            int minute;
3560
            int second;
3561
            int a_nanos;
3562

    
3563
            if (parts.length == 7) {
3564

    
3565
                    try {
3566

    
3567
                            year = Integer.parseInt(parts[0]) - 1900;
3568
                            month = Integer.parseInt(parts[1]) - 1;
3569
                            day = Integer.parseInt(parts[2]);
3570
                            hour = Integer.parseInt(parts[3]);
3571
                            minute = Integer.parseInt(parts[4]);
3572
                            second = Integer.parseInt(parts[5]);
3573
                            a_nanos = Integer.parseInt(parts[6]);
3574
                            
3575
                    } catch (Exception ex) {
3576
                        logger.debug("Bad time stamp: " + ex.getMessage());
3577
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3578
                    }
3579

    
3580
            } else {
3581
                    
3582
                if (parts.length == 6) {
3583
                        
3584
                        try {
3585
                            year = Integer.parseInt(parts[0]) - 1900;
3586
                            month = Integer.parseInt(parts[1]) - 1;
3587
                            day = Integer.parseInt(parts[2]);
3588
                            hour = Integer.parseInt(parts[3]);
3589
                            minute = Integer.parseInt(parts[4]);
3590
                            second = Integer.parseInt(parts[5]);
3591
                            a_nanos = 0;
3592
                            
3593
                        } catch (Exception ex) {
3594
                                
3595
                            logger.debug("Bad time stamp: " + ex.getMessage());
3596
                            return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3597
                        }
3598

    
3599
                } else {
3600
                        
3601
                        logger.debug("Bad time stamp: " + s);
3602
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3603
                        
3604
                }
3605
            }
3606
            
3607
            return new Timestamp(year, month, day, hour, minute, second, a_nanos);
3608
    }
3609

    
3610
        public void write(DataWare arg0) throws WriteDriverException, ReadDriverException {
3611
        }
3612
        
3613
        public static int nvarchar2Limited(int n) {
3614
                
3615
                if (n <= VARCHAR2_STANDARD_SIZE) return VARCHAR2_STANDARD_SIZE;
3616
                if (n <= VARCHAR2_LONG_SIZE) return n;
3617
                
3618
                return VARCHAR2_LONG_SIZE;
3619
        }
3620
        
3621

    
3622
    
3623

    
3624
        
3625
        public static String removePrefix(String str) {
3626
                
3627
                int colon_ind = str.indexOf(":");
3628
                if (colon_ind != -1) {
3629
                        return str.substring(colon_ind + 1);
3630
                } else {
3631
                        return str;
3632
                }
3633
        }
3634

    
3635
    
3636
            
3637
            private class AnEmptyFeatureIterator implements IFeatureIterator {
3638
                public boolean hasNext() throws ReadDriverException { return false; }
3639
                public IFeature next() throws ReadDriverException { return null; }
3640
                public void closeIterator() throws ReadDriverException { }                
3641
        }
3642
            
3643
        private Value objToValue(Object obj, int idFld) {
3644
                
3645
            if (obj == null) {
3646
                    return ValueFactory.createNullValue();
3647
            } else {
3648
                    
3649
                    String objToString = obj.toString();
3650

    
3651
                if (obj instanceof String) {
3652
                    objToString = (String) obj;
3653
                    return ValueFactory.createValue(objToString);
3654
                } else {
3655
                    if (obj instanceof ROWID) {
3656
                        objToString = ((ROWID) obj).stringValue();
3657
                        return ValueFactory.createValue(objToString);
3658
                    } else {
3659
                        if (obj instanceof STRUCT) {
3660
                            objToString = "STRUCT";
3661
                            return ValueFactory.createValue(objToString);
3662
                        } else {
3663
                            if (obj instanceof TIMESTAMP) {
3664
                                    TIMESTAMP aux = (TIMESTAMP) obj;
3665
                                objToString = aux.stringValue();
3666
                                Timestamp ts = flexibleTimeStamp(objToString);
3667
                                return ValueFactory.createValue(ts);
3668

    
3669
                            } else {
3670

    
3671
                                    // last try
3672
                                    int _type = -1;
3673
                                                            try {
3674
                                                                    _type = getFieldType(idFld);
3675
                                        if (_type == Types.DATE) {
3676
                                                objToString = objToString.replace('-', '/');
3677
                                        }
3678
                                        return ValueFactory.createValueByType(objToString, _type);
3679
                                } catch (Exception ex) {
3680
                                        logger.debug("Failed to create Value: _type = "
3681
                                                        + _type + ", objToString = " + objToString);
3682
                                        return ValueFactory.createNullValue();
3683
                                }
3684
                                
3685
                            }
3686
                        }
3687
                    }
3688
                }
3689
            }
3690
        }
3691

    
3692
        public Value[] getAttributes(ResultSet rs, boolean use_main_metadata) {
3693
            Value[] res = null;
3694

    
3695
            int fcount = 0;
3696

    
3697
            try {
3698
                    if (use_main_metadata) {
3699
                            fcount = metaData.getColumnCount();
3700
                    } else {
3701
                            fcount = rs.getMetaData().getColumnCount();
3702
                    }
3703
                
3704
                res = new Value[fcount];
3705

    
3706
                for (int i = 0; i < fcount; i++) {
3707
                    Object obj = rs.getObject(i + 1);
3708
                    res[i] = objToValue(obj, i);
3709
                }
3710

    
3711
            } catch (Exception se) {
3712
                    logger.error("While getting resultset attribute values: " + se.getMessage());
3713
                    res = new Value[fcount];
3714
                    for (int i=0; i<fcount; i++) res[i] = ValueFactory.createNullValue();
3715
            }
3716

    
3717
            return res;
3718
        }            
3719
        
3720
        public boolean canWriteGeometry(int gvSIGgeometryType) {
3721
                if (writer == null) {
3722
                        return true;
3723
                } else {
3724
                        return writer.canWriteGeometry(gvSIGgeometryType);
3725
                }
3726
                
3727
        }
3728
        
3729
    
3730

    
3731
}