Statistics
| Revision:

root / trunk / extensions / extOracleSpatial / src / es / prodevelop / cit / gvsig / fmap / drivers / jdbc / oracle / OracleSpatialDriver.java @ 36210

History | View | Annotate | Download (118 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.Rectangle2D;
47
import java.math.BigDecimal;
48
import java.sql.Connection;
49
import java.sql.DatabaseMetaData;
50
import java.sql.PreparedStatement;
51
import java.sql.ResultSet;
52
import java.sql.ResultSetMetaData;
53
import java.sql.SQLException;
54
import java.sql.Statement;
55
import java.sql.Timestamp;
56
import java.sql.Types;
57
import java.util.ArrayList;
58
import java.util.HashMap;
59
import java.util.Hashtable;
60
import java.util.Random;
61
import java.util.TreeMap;
62

    
63
import oracle.sql.ARRAY;
64
import oracle.sql.Datum;
65
import oracle.sql.NUMBER;
66
import oracle.sql.ROWID;
67
import oracle.sql.STRUCT;
68
import oracle.sql.TIMESTAMP;
69

    
70
import org.apache.log4j.Logger;
71
import org.cresques.cts.ICoordTrans;
72
import org.cresques.cts.IProjection;
73

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

    
119

    
120
/**
121
 * Vectorial driver to access Oracle databases geometries
122
 * Should work on Oracle Locator.
123
 *
124
 * It contains switches to test different modules to perform the
125
 * translation oracle structs --> gvsig geometries:
126
 *
127
 * - Parsing the structs directly.
128
 * - Using Oracle's JGeometry static methods
129
 * - Using Geotools utilities
130
 *
131
 *  (currently, the driver parses the structs directly)
132
 *
133
 * @author jldominguez
134
 *
135
 */
136
public class OracleSpatialDriver extends DefaultJDBCDriver
137
    implements IDelayedDriver, ICanReproject, IWriteable {
138
    private static Logger logger = Logger.getLogger(OracleSpatialDriver.class.getName());
139

    
140
    // constants
141
    public static final int GEODETIC_FULLEXTENT_SAMPLE_SIZE = 50;
142
    public static final String GEODETIC_SRID = "8307";
143
    // public static final String ASSUMED_ORACLE_SRID = "8307";
144
    
145
    // -----------------------------------------------
146
    public static final String NAME = "Oracle Spatial";
147
    public static final int ID_COLUMN_INDEX = 1;
148
    
149
    public static final String ALL_ORACLE_GEOMETADATA_VIEW = "ALL_SDO_GEOM_METADATA";
150
    public static final String USER_ORACLE_GEOMETADATA_VIEW = "USER_SDO_GEOM_METADATA";
151
    
152
    public static final String ORACLE_EPSG_TABLE_NAME = "ORA_EPSG";
153
    public static final String ORACLE_EPSG_FILE_NAME = "ORA_EPSG.DBF";
154
    public static final String DEFAULT_GEO_FIELD = "GEOMETRY";
155
    // public static final String DEFAULT_GEO_FIELD = "MERGEDGEOMETRY";
156

    
157
    
158
    public static final String ORACLE_ID_FIELD = "ROWID";
159
    public static final String DEFAULT_ID_FIELD_CASE_SENSITIVE = "GID";
160
    public static final String ORACLE_GEO_SCHEMA = "MDSYS";
161
    public static final String CONN_STR_BEGIN = "jdbc:oracle:thin:";
162
    
163
    // public static final int VARCHAR2_DEFAULT_SIZE = 2000; //  512;  
164
    public static final int VARCHAR2_MAX_SIZE = 4000;
165
    
166
    public static final int MAX_ID_LENGTH = 30;
167
    private final static GeometryFactory geomFactory = new GeometryFactory();
168
    public static final double IRRELEVANT_DISTANCE = 0.00000001;
169
        private static final long ID_MIN_DELAY = 1000;
170

    
171
        public static final String ORACLE_JAR_FILE_NAME = "oracle.jdbc.driver.OracleDriver";
172

    
173
        
174
    static {
175
        try {
176
            Class.forName(ORACLE_JAR_FILE_NAME);
177
                    logger.info("*-----------------------------------------------------------------------*");
178
                    logger.info("* Found the Oracle JDBC library! :)                                     *");
179
                    logger.info("*-----------------------------------------------------------------------*");
180
            
181
        } catch (ClassNotFoundException e) {
182
                       logger.warn("*-----------------------------------------------------------------------*");
183
                       logger.warn("* Oracle JDBC library (ojdbc*.jar) not found. You need to copy that");
184
                       logger.warn("* jar file to gvSIG's main lib folder if you intend to access");
185
                       logger.warn("* Oracle Spatial/Locator databases.");
186
                       logger.warn("* Read gvSIG manual (Oracle driver section) for details.");
187
                       logger.warn("*-----------------------------------------------------------------------*");
188
        }
189
    }
190

    
191
    private OracleSpatialWriter writer = null;
192

    
193
    // switch variable
194
    private boolean use_geotools = false;
195
    private boolean table_HasSrid = true;
196

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

    
206
    private Rectangle2D workingAreaInViewsCS = null;
207
    private Rectangle2D workingAreaInTablesCS = null;
208
    private STRUCT workingAreaInTablesCSStruct = null;
209

    
210
    private String idFieldNames;
211
    private int oneBasedGeoColInd = 0;
212
    private int shapeType = -1;
213

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

    
219
    // ----------------------------------------------
220
    private boolean cancelIDLoad = false;
221

    
222
    // ----------------------------------------------
223
    private String fullTableName = "";
224
    private String geoColName = "";
225
    private String oracleSRID;
226
    private String epsg_SRID;
227
    private String destProj = "";
228
    private Rectangle2D full_Extent = null;
229
    private boolean emptyWhereClause = true;
230
    private boolean isGeogCS = false;
231
    private boolean hasRealiableExtent = true;
232

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

    
238
        private int adaptedFetchSize = 100;
239
    // private static int FETCH_SIZE = 15000;
240

    
241

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

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

    
251

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

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

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

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

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

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

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

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

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

    
328
                OracleSpatialUtils.setUpperCase(lyrDef);
329
        lyrDef.setConnection(conn);
330

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

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

    
361
        // various metadata settings
362
        // getMetaDataInThisThread();
363
        cleanWhereClause();
364
        loadSdoMetadata();
365
        oneRowMetadata(); 
366

    
367
        setDestProjection(lyrDef.getSRID_EPSG());
368
        workingAreaInViewsCS = lyrDef.getWorkingArea();
369
        
370
        if ((workingAreaInViewsCS != null) && isTableHasSrid() && (getEpsgSRID() != null)) {
371
            IProjection viewProj = CRSFactory.getCRS(destProj);
372
            IProjection tableProj = CRSFactory.getCRS("EPSG:" + getEpsgSRID());
373
            ICoordTrans reprojecter = viewProj.getCT(tableProj);
374
                workingAreaInTablesCS = reprojecter.convert(workingAreaInViewsCS);
375
            workingAreaInTablesCSStruct = shapeToStruct(workingAreaInTablesCS,
376
                    FShape.NULL, isTableHasSrid(), false, true);
377
        } else {
378
            if (workingAreaInViewsCS != null) {
379
                    workingAreaInTablesCS = (Rectangle2D) workingAreaInViewsCS.clone();
380
                workingAreaInTablesCSStruct = shapeToStruct(workingAreaInTablesCS,
381
                        FShape.NULL, isTableHasSrid(), false, true);
382
            }
383
        }
384

    
385
        cancelIDLoad = false;
386
        idLoader = new IdLoaderThread(this);
387
        idLoader.start();
388
    }
389

    
390

    
391

    
392

    
393
        /**
394
     * Utility method to load IDs in a different thred, so that gvsig's gui
395
     * does not get blocked.
396
     *
397
     */
398
    public void getMetaDataInThisThread() throws SQLException {
399

    
400
            long id_load_start = System.currentTimeMillis();
401
        setIdRowTable(false);
402
        long id_load_end = System.currentTimeMillis();
403

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

    
414
        if (!hasRealiableExtent) {
415
                full_Extent = getEstimatedExtent(
416
                                getTableName(), geoColName, conn, 20, 1.5, isGeogCS);
417
        }
418

    
419
        if (cancelIDLoad) {
420
            return;
421
        }
422
    }
423

    
424
    private String getOracleSridFromCurrentRecord(ResultSet _rs)
425
        throws SQLException {
426
        Object obj = _rs.getObject("SRID");
427

    
428
        if (obj == null) {
429
            logger.warn("No SRID found for this table.");
430
            setTableHasSrid(false);
431

    
432
            return null;
433
        }
434

    
435
        return obj.toString();
436
    }
437

    
438
    private Rectangle2D getFullExtentFromCurrentRecord(ResultSet _rs)
439
        throws SQLException {
440
        ARRAY dim_info_array = (ARRAY) _rs.getObject("DIMINFO");
441

    
442
        if (dim_info_array == null) {
443
            // no full extent found:
444
            return null;
445
        }
446
        else {
447
            Datum[] da = dim_info_array.getOracleArray();
448

    
449
            STRUCT sx = (STRUCT) da[0];
450
            STRUCT sy = (STRUCT) da[1];
451

    
452
            try {
453
                double minx = Double.parseDouble(sx.getAttributes()[1].toString());
454
                double maxx = Double.parseDouble(sx.getAttributes()[2].toString());
455
                double miny = Double.parseDouble(sy.getAttributes()[1].toString());
456
                double maxy = Double.parseDouble(sy.getAttributes()[2].toString());
457

    
458
                if (minx > maxx) {
459
                    double aux = minx;
460
                    minx = maxx;
461
                    maxx = aux;
462
                }
463

    
464
                if (miny > maxy) {
465
                    double aux = miny;
466
                    miny = maxy;
467
                    maxy = aux;
468
                }
469

    
470
                return getRectangle(minx, maxx, miny, maxy);
471

    
472
                // fullExtentJTS = shapeToGeometry(fullExtent);
473
            }
474
            catch (Exception ex) {
475
                    logger.error("While getting full extent from metadata table.");
476
                return null;
477
            }
478
        }
479
    }
480

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

    
499
            }
500

    
501
            ResultSet _rs = _st.executeQuery(qry); 
502

    
503
            if (_rs.next()) {
504
                oracleSRID = getOracleSridFromCurrentRecord(_rs);
505

    
506
                isGeogCS = OracleSpatialUtils.getIsGCS(oracleSRID, isTableHasSrid());
507

    
508
                if (oracleSRID == null) {
509
                                        setTableHasSrid(false);
510
                } else {
511
                    try {
512
                                            setEpsgSRID( oracleSridToEpsgSrid(oracleSRID) );
513
                                    } catch (Exception e) {
514
                                            // logger.error("Unknown oracle SRID: " + oracleSRID);
515
                                            setTableHasSrid(true);
516
                                            setEpsgSRID( oracleSRID );
517
                                    }
518
                }
519
                
520
                full_Extent = getFullExtentFromCurrentRecord(_rs);
521

    
522
                hasRealiableExtent = realiableExtent(full_Extent, isGeogCS);
523

    
524
                if (!hasRealiableExtent) {
525
                        full_Extent = getFastEstimatedExtent(
526
                                            getTableName(), geoColName, conn, 20, 10, isGeogCS);
527
                }
528

    
529
                _rs.close();
530
                _st.close();
531
            }
532
            else {
533
                throw new SQLException("Empty resultset from this query: " +
534
                    qry);
535
            }
536
        }
537
        catch (SQLException se) {
538
                logger.error("While getting SDO metadata: " + se.getMessage());
539
        }
540
    }
541

    
542
    /**
543
     * Utility method to get a geometry from a struct.
544
     *
545
     * @param theStruct the struct to be converted
546
     * @param use_gtools switch to use geotools classes or not
547
     * @return the geometry
548
     * @throws SQLException
549
     */
550
    public IGeometry getGeometryUsing(STRUCT theStruct, boolean use_gtools)
551
        throws SQLException {
552
        IGeometry _igeom = null;
553

    
554
        if (theStruct == null) {
555
            return OracleSpatialUtils.NULL_GEOM;
556
        }
557

    
558
        if (use_gtools) { // geotools
559
//            _igeom = getGeotoolsIGeometry(theStruct);
560
        }
561
        else { // jgeometry
562
                // lastGeom = printStruct(theStruct.getOracleAttributes());
563
            _igeom = getFMapGeometry(theStruct, false, 0);
564
        }
565

    
566
        return _igeom;
567
    }
568
    
569
    // private static String lastGeom = "";
570
    
571
    /**
572
     * Utility method to transform a struct into a IGeometry.
573
     *
574
     * @param st the struct to be converted
575
     * @param complex comes from a complex sdo geometry
576
     * @return the IGeometry
577
     */
578
    private IGeometry getFMapGeometry(STRUCT st, boolean complex, int rec_iter) {
579

    
580
            if (st == null) {
581
                    return new FNullGeometry();
582
            }
583
            
584
        Datum[] the_data = null;
585

    
586
        
587
        
588
        try {
589
            the_data = st.getOracleAttributes();
590
            
591
            /*
592
                if (rec_iter > 4) {
593
                        logger.error(lastGeom);
594
                        return new FNullGeometry();
595
                }
596
                */
597

    
598
            int full_gtype = ((NUMBER) the_data[0]).intValue();
599
            // int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
600
            int fshape_type = OracleSpatialUtils.oracleGTypeToFShapeType(full_gtype, complex);
601

    
602
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
603

    
604
            if (dim < 2) {
605
                dim = 2;
606
            }
607

    
608
            IGeometry ig = null;
609
            // ========================== collection issue with rects
610
            int collec_val = OracleSpatialUtils.isCollection(the_data);
611
            switch (collec_val) {
612
            case OracleSpatialUtils.COLLECTION_VALUE_YES_COLLECTION:
613
                    fshape_type = FShape.MULTI;
614
                    break;
615
            case OracleSpatialUtils.COLLECTION_VALUE_MERGE_COLLECTION_IN_POLYGON:
616
                    fshape_type = FShape.MULTI;
617
                    break;
618
            case OracleSpatialUtils.COLLECTION_VALUE_NOT_COLLECTION:
619
                    break;
620
            }
621
            // ========================================================
622

    
623
            switch (fshape_type) {
624
            case FShape.MULTI:
625
                ig = getFMapGeometryCollection(the_data, dim, rec_iter);
626
                    if (collec_val == OracleSpatialUtils.COLLECTION_VALUE_MERGE_COLLECTION_IN_POLYGON) {
627
                            ig = OracleSpatialUtils.mergePolygons((FGeometryCollection) ig);
628
                    }
629
                break;
630

    
631
            case FShape.POINT:
632
                ig = OracleSpatialUtils.getFMapGeometryPoint(the_data, dim);
633

    
634
                break;
635

    
636
            case FShape.LINE:
637
                ig = OracleSpatialUtils.getFMapGeometryMultiLineString(the_data, dim);
638

    
639
                break;
640

    
641
            case FShape.POLYGON:
642
                ig = OracleSpatialUtils.getFMapGeometryMultipolygon(the_data, dim);
643

    
644
                break;
645
            }
646

    
647
            return ig;
648
        }
649
        catch (Exception e) {
650
            logger.error(e);
651
        }
652

    
653
        return new FNullGeometry();
654
    }
655

    
656

    
657
        private static String printStruct(Datum[] datt) {
658
            
659
            String resp = "\n";
660
            resp = resp + "============= START === PRINTING STRUCT:\n";
661
            int sz = datt.length;
662
            for (int i=0; i<sz; i++) {
663
                    resp = resp + printDatum(i, datt[i]);
664
            }
665
            resp = resp + "============= END === PRINTING STRUCT\n";
666
            return resp;
667
        }
668
    
669
    
670

    
671
        private static String printDatum(int n, Datum d) {
672
                
673
                String resp = "";
674
                if (d == null) {
675
                        resp = "============= DATUM: " + n + " ; VALUE = NULL\n";
676
                        return resp;
677
                }
678
                
679
                if (d instanceof ARRAY) {
680
                        ARRAY arr = (ARRAY) d;
681
                        double[] darr = null;
682
                        int[] iarr = null;
683
                        try {
684
                                
685
                                resp = "============= DATUM: " + n + " ; VALUE:\n";
686
                                darr = arr.getDoubleArray();
687
                                // String valstr = "";
688
                                int sz = darr.length;
689
                                for (int i=0; i<sz; i++) {
690
                                        resp = resp + darr[i] + " , "; 
691
                                }
692
                                resp = resp + "\n"; 
693
                                
694
                        } catch (SQLException e) {
695
                                try {
696
                                        resp = "============= DATUM: " + n + " ; VALUE:\n";
697
                                        iarr = arr.getIntArray();
698
                                        // String valstr = "";
699
                                        int sz = iarr.length;
700
                                        for (int i=0; i<sz; i++) {
701
                                                resp = resp + iarr[i] + " , "; 
702
                                        }
703
                                        resp = resp + "\n"; 
704
                                } catch (SQLException e2) {
705
                                        resp = "============= DATUM: " + n + " ; VALUE = " + d.toString() + " (CAST FAILED)\n";
706
                                }
707
                        }
708
                } else {
709
                        if (d instanceof NUMBER) {
710
                                int v = -10;
711
                                try {
712
                                        v = ((NUMBER) d).intValue();
713
                                        resp = "============= DATUM: " + n + " ; VALUE = " + v + "\n";
714
                                } catch (SQLException e) {
715
                                        resp = "============= DATUM: " + n + " ; VALUE = " + d.toString() + " (CAST TO INT FAILED)\n";
716
                                }
717
                        } else {
718
                                resp = "============= DATUM: " + n + " ; VALUE = " + d.toString() + " (NOT NUMBER)\n";
719
                        }
720
                }
721
                return resp;
722
                
723
        }
724

    
725
        private Rectangle2D getRectangle(double minx, double maxx, double miny,
726
        double maxy) {
727
        Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx,
728
                maxy - miny);
729
        return resp;
730
    }
731

    
732
    private void oneRowMetadata() {
733
        try {
734

    
735
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
736
                    ResultSet.CONCUR_READ_ONLY);
737
            
738
            ResultSet _rs = null;
739
            shapeType = guessShapeType();
740
            // -----------------------
741
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
742
            metaData = _rs.getMetaData(); 
743
            
744
            this.setAdaptedFetchSize(OracleSpatialUtils.estimateGoodFetchSize(metaData));
745
            
746
            userName = ((ConnectionJDBC)conn).getConnection().getMetaData().getUserName();
747

    
748
            // geoColInd = _rs.findColumn(geoColName);
749
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
750

    
751
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
752
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
753

    
754
            int cnt = metaData.getColumnCount();
755
            fieldNames = new String[cnt];
756

    
757
            for (int i = 0; i < cnt; i++) {
758
                fieldNames[i] = metaData.getColumnName(i + 1);
759
            }
760

    
761
            getIdFieldNames();
762
            adjustLyrDef();
763
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan
764
        }
765
        catch (SQLException se) {
766
            logger.error("While getting metadata. " + se.getMessage());
767
        }
768
    }
769

    
770
    private int guessShapeType() {
771

    
772
            int resp = FShape.MULTI;
773

    
774
        String _sql = "select " + getStandardSelectExpression() + ", c." +
775
        geoColName + " from " + getTableName() + " c ";
776

    
777
        ResultSet _rs = null;
778
        STRUCT sample_geo = null;
779
        
780
        try {
781
                _sql = _sql + " where c." + geoColName + " is not NULL AND "
782
                    + OracleSpatialUtils.EXPONENTIAL_INDICES_CONDITION;
783
                
784
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
785
                ResultSet.CONCUR_READ_ONLY);
786

    
787
            _rs = st.executeQuery(_sql);
788

    
789
            int aux = 0;
790
            ArrayList shptypes = new ArrayList();
791
            while (_rs.next()) {
792
                sample_geo = (STRUCT) _rs.getObject(geoColName);
793
                aux = OracleSpatialUtils.getShapeTypeOfStruct(sample_geo);
794
                shptypes.add(new Integer(aux));
795
            }
796
            if (shptypes.size() > 0) {
797
                    resp = getShapeTypeFromArray(shptypes);
798
            }
799
        } catch (Exception ex) {
800
                logger.error("While guessing shape type: " + ex.getMessage());
801
                logger.warn("Assumed MULTI");
802
        }
803
        
804
        return resp; 
805
        }
806

    
807
        private int getShapeTypeFromArray(ArrayList arrlist) {
808
                
809
                int sz = arrlist.size();
810
                
811
                if (sz == 0) {
812
                        return FShape.MULTI;
813
                }
814
                
815
                int resp = ((Integer) arrlist.get(0)).intValue();
816
                boolean needs3d = (resp > FShape.Z) ? true : false;
817
                
818
                int aux = 0;
819
                for (int i=1; i<sz; i++) {
820
                        aux = ((Integer) arrlist.get(i)).intValue();
821
                        if (aux != resp) {
822
                                resp = FShape.MULTI;
823
                        }
824
                        if (aux > FShape.Z) {
825
                                needs3d = true;
826
                        }
827
                }
828
                return needs3d ? ((resp % FShape.Z) + FShape.Z) : (resp % FShape.Z);
829
        }
830

    
831
        private String getIdFieldNames() {
832
        try {
833
            idFieldNames = "";
834

    
835
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
836
                idFieldNames = idFieldNames +
837
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
838
            }
839
        }
840
        catch (SQLException se) {
841
        }
842

    
843
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
844

    
845
        return idFieldNames;
846
    }
847

    
848
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
849
        int[] _res = new int[1];
850
        _res[0] = 1;
851

    
852
        return _res;
853
    }
854

    
855
    public String getSqlTotal() {
856
        // TODO Auto-generated method stub
857
        return "";
858
    }
859

    
860
    public String getCompleteWhere() {
861
        // TODO Auto-generated method stub
862
        return "";
863
    }
864

    
865
    /**
866
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
867
     * and uses directly that sentence to query the table).
868
     */
869
    public IFeatureIterator getFeatureIterator(String sql)
870
        throws ReadDriverException {
871
        if (isNotAvailableYet) {
872
                return new AnEmptyFeatureIterator();
873
            // return null;
874
        }
875

    
876
        singleCachedFeatureRowNum = -1;
877

    
878
        Object[] rs_st = getViewResultSet(null, sql, isTableHasSrid());
879

    
880
        ResultSet localrs = (ResultSet) rs_st[0];
881
        Statement _st = (Statement) rs_st[1];
882

    
883
        return new OracleSpatialFeatureIterator(this, localrs, _st,
884
            oneBasedGeoColInd, use_geotools, false, null);
885
    }
886

    
887
    /**
888
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
889
     */
890
    public String getConnectionStringBeginning() {
891
        // oracle
892
        return CONN_STR_BEGIN;
893
    }
894

    
895
    public void open() { // throws DriverException {
896
    }
897

    
898
    /**
899
     * Gets Oracle's default port: 1521
900
     */
901
    public int getDefaultPort() {
902
        // oracle port
903
        return 1521;
904
    }
905

    
906
    /**
907
     * Gets the feature iterator for a given rectangle (the view's bounding box)
908
     * and a SRS.
909
     */
910
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
911
        throws ReadDriverException {
912
        if (isNotAvailableYet) {
913
                return new AnEmptyFeatureIterator();
914
            // return null;
915
        }
916

    
917
        singleCachedFeatureRowNum = -1;
918
        
919
        STRUCT local_st = shapeToStruct(r, FShape.NULL, isTableHasSrid(), false, true);
920
        Object[] rs_st = getViewResultSet(local_st, null, isTableHasSrid());
921
        ResultSet localrs = (ResultSet) rs_st[0];
922
        Statement _st = (Statement) rs_st[1];
923

    
924
        return new OracleSpatialFeatureIterator(this, localrs, _st,
925
            oneBasedGeoColInd, use_geotools, false, null);
926
    }
927

    
928
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
929
        if (workingAreaInTablesCS == null) return r;
930
        return OracleSpatialUtils.doIntersect(r, workingAreaInTablesCS);
931
    }
932

    
933
    /**
934
     * This method reverts to the one without the fields specification.
935
     * The fields have been selected from the start.
936
     */
937
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
938
        String[] alphaNumericFieldsNeeded) throws ReadDriverException {
939
            
940
        if (isNotAvailableYet) {
941
                return new AnEmptyFeatureIterator();
942
            // return null;
943
        }
944
        singleCachedFeatureRowNum = -1;
945

    
946
        if ((alphaNumericFieldsNeeded == null) || (alphaNumericFieldsNeeded.length == 0)) {
947
            return getFeatureIterator(r, strEPSG);
948
        } else {
949

    
950
            STRUCT local_st = shapeToStruct(r, FShape.NULL, isTableHasSrid(), false, true);
951
            Object[] rs_st = getViewResultSet(local_st, null, isTableHasSrid());
952
            ResultSet localrs = (ResultSet) rs_st[0];
953
            Statement _st = (Statement) rs_st[1];
954

    
955
            return new OracleSpatialFeatureIterator(this, localrs, _st,
956
                oneBasedGeoColInd, use_geotools, true, alphaNumericFieldsNeeded);
957
        }
958
    }
959

    
960
    private String getSqlFor(String[] alphaNumericFieldsNeeded, String sdo_inter) {
961
            
962
            String idswhere = getIdsQueryWhereClause(false);
963
        String custom_sel = getCustomSelect(alphaNumericFieldsNeeded, sdo_inter, idswhere);
964
                return custom_sel;
965
        }
966

    
967
        public String getGeometryField(String fieldName) {
968
        return fieldName;
969
    }
970

    
971
    public DriverAttributes getDriverAttributes() {
972
        return drvAtts;
973
    }
974

    
975
    /**
976
     * Gets the requested geometry. Always performs a new query in this case.
977
     * This should be a rare way to get the geometries. The standard way is by using
978
     * the iterators.
979
     */
980
    public IGeometry getShape(int _ind) throws ReadDriverException {
981
        if (isNotAvailableYet) {
982
            return OracleSpatialUtils.NULL_GEOM;
983
        }
984

    
985
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
986

    
987
        String _sql = "select " + geoColName + " from " + getTableName() +
988
            " where rowid = ?";
989

    
990
        try {
991
            java.sql.PreparedStatement ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(_sql);
992
            ps.setObject(1, r_id);
993

    
994
            // Statement stmnt = conn.createStatement();
995
            ps.execute();
996

    
997
            ResultSet _res = ps.getResultSet();
998

    
999
            if (_res.next()) {
1000
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
1001
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1002
                _res.close();
1003
                ps.close();
1004

    
1005
                return theGeom;
1006
            }
1007
            else {
1008
                logger.error("Unable to get shape: " + _ind +
1009
                    " (probably due to edition)");
1010
                
1011

    
1012
                return OracleSpatialUtils.NULL_GEOM;
1013
            }
1014
        }
1015
        catch (SQLException se) {
1016
            throw new ReadDriverException(getName(), se);
1017
        }
1018
    }
1019

    
1020
    public boolean isWritable() {
1021
        return true;
1022
    }
1023

    
1024
    public String getName() {
1025
        return NAME;
1026
    }
1027

    
1028
    public int[] getPrimaryKeys() throws ReadDriverException {
1029
        return pkOneBasedIndexes;
1030
    }
1031

    
1032

    
1033

    
1034

    
1035
    private void setIdRowTable(boolean only_test) throws SQLException  {
1036
        hashRelate = new Hashtable();
1037

    
1038
        java.sql.PreparedStatement ps = null;
1039

    
1040
        try {
1041
            String _sql = getIdAndElemInfoFullResulltSetQuery();
1042

    
1043
            logger.debug("SQL para leer ids: " + _sql);
1044
            Statement st = null;
1045
            st = ((ConnectionJDBC)conn).getConnection().createStatement(
1046
                            ResultSet.TYPE_FORWARD_ONLY,
1047
                            ResultSet.CONCUR_READ_ONLY);
1048

    
1049
             st.setFetchSize(getAdaptedFetchSize());
1050
             logger.info("FETCH_SIZE = " + getAdaptedFetchSize());
1051

    
1052
            ResultSet _r = null;
1053
            _r = st.executeQuery(_sql);
1054

    
1055
            ROWID ri = null;
1056

    
1057
            int row = 0;
1058
            String gid;
1059
            Value aux = null;
1060

    
1061
            // ----------------------------------- types init
1062
            ArrayList types = new ArrayList();
1063
            int types_aux = 0;
1064

    
1065
            ARRAY info_aux;
1066
            int[] info_aux_int;
1067
            int size;
1068

    
1069
            // ----------------------------------- types init
1070
            logger.debug("Beginning of result set:");
1071

    
1072
            while (_r.next()) {
1073
                // ---------------------------------------
1074
                ri = (ROWID) _r.getObject(1);
1075
                gid = ri.stringValue();
1076
                aux = ValueFactory.createValue(gid);
1077

    
1078
                Integer intobj = new Integer(row);
1079
                hashRelate.put(aux, intobj);
1080
                rowToId.put(intobj, ri);
1081

    
1082
                if ((row % 5000) == 0) {
1083
                    // ------------------------------------------- cancel load
1084
                    if (cancelIDLoad) {
1085
                        hashRelate.clear();
1086
                        rowToId.clear();
1087

    
1088
                        return;
1089
                    }
1090

    
1091
                    // -------------------------------------------
1092
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
1093
                    logger.info("IDs read: " + fmt);
1094
                }
1095

    
1096
                row++;
1097

    
1098
                // --------------------------------------- types
1099
                info_aux = (ARRAY) _r.getObject(2);
1100

    
1101
                if (info_aux == null) {
1102
                    // logger.debug("NULL info array found in record: " + row);
1103
                }
1104
                else {
1105
                    info_aux_int = info_aux.getIntArray();
1106
                    size = info_aux_int.length / 3;
1107

    
1108
                    for (int i = 0; i < size; i++) {
1109
                        types_aux = info_aux_int[(3 * i) + 1];
1110
                        types.add(new Integer(types_aux % 1000));
1111
                    }
1112
                }
1113

    
1114
                // --------------------------------------- types end
1115
            }
1116

    
1117
            _r.close();
1118
//            ps.close();
1119
            st.close();
1120
            numReg = row;
1121

    
1122
            /*
1123
            boolean needsCollectionLayer = OracleSpatialUtils.hasSeveralGeometryTypes(types, false);
1124

1125
            if (needsCollectionLayer) {
1126
                shapeType = FShape.MULTI;
1127
            }
1128
            */
1129
        }
1130
        catch (SQLException e) {
1131
                logger.error("While setting id-row hashmap: " + e.getMessage());
1132
                throw e;
1133
        }
1134
    }
1135

    
1136
    public int getFieldCount() throws ReadDriverException {
1137
        try {
1138
            return metaData.getColumnCount();
1139
        }
1140
        catch (SQLException e) {
1141
                logger.error("While getting field count: " + e.getMessage());
1142
            throw new ReadDriverException(getName(), e);
1143
        }
1144
    }
1145

    
1146
    public String[] getFieldNames() {
1147
        return fieldNames;
1148
    }
1149

    
1150
    public String getTotalFields() {
1151
        String strAux = "";
1152

    
1153
        for (int i = 0; i < fieldNames.length; i++) {
1154
            if (i == 0) {
1155
                strAux = fieldNames[i];
1156
            }
1157
            else {
1158
                strAux = strAux + ", " + fieldNames[i];
1159
            }
1160
        }
1161

    
1162
        return strAux;
1163
    }
1164

    
1165
    public int getFieldType(int idField) throws ReadDriverException {
1166
        int i = 0;
1167

    
1168
        try {
1169
            i = idField + 1; // idField viene basado en 0
1170

    
1171
            int __type = metaData.getColumnType(i);
1172
            
1173
            int size = 1;
1174
            // avoid exception
1175
            try { size = metaData.getPrecision(i); } catch (Exception ex) { }
1176
            
1177
            int dec_pos = metaData.getScale(i);
1178

    
1179
            // we must add this entry because we did not remove the 'geometry' column
1180
            if (__type == Types.STRUCT) {
1181
                return Types.VARCHAR; // .STRUCT;
1182
                // ----------------------------------------------------------------------
1183
            }
1184

    
1185
            if (__type == Types.VARCHAR) {
1186
                return Types.VARCHAR;
1187
            }
1188

    
1189
            if (__type == Types.FLOAT) {
1190
                return Types.FLOAT;
1191
            }
1192

    
1193
            if (__type == Types.DOUBLE) {
1194
                return Types.DOUBLE;
1195
            }
1196

    
1197
            if ((__type == Types.INTEGER)
1198
                            || (__type == Types.SMALLINT)
1199
                            || (__type == Types.TINYINT)
1200
                            || (__type == Types.BIGINT)
1201
                            || ((__type == Types.NUMERIC) && (dec_pos == 0))
1202
                            ) {
1203
                    
1204
                    if (size > 10) {
1205
                            return Types.BIGINT;
1206
                    } else {
1207
                            return Types.INTEGER;
1208
                    }
1209
            }
1210

    
1211
            if (__type == Types.BIT) {
1212
                return Types.BIT;
1213
            }
1214

    
1215
            if (__type == Types.DATE) {
1216
                return Types.DATE;
1217
            }
1218

    
1219
            if (__type == Types.DECIMAL) {
1220
                return Types.DOUBLE;
1221
            }
1222

    
1223
            if (__type == Types.NUMERIC) {
1224
                    return Types.DOUBLE;
1225
            }
1226

    
1227
            if (__type == Types.DATE) {
1228
                return Types.DATE;
1229
            }
1230

    
1231
            if (__type == Types.TIME) {
1232
                return Types.TIME;
1233
            }
1234

    
1235
            if (__type == Types.TIMESTAMP) {
1236
                return Types.TIMESTAMP;
1237
            }
1238
        }
1239
        catch (SQLException e) {
1240
            logger.error("Unknown field type of : " + i);
1241
            throw new ReadDriverException(getName(), e);
1242
        }
1243

    
1244
        return -1;
1245
    }
1246

    
1247

    
1248
    public String getFieldName(int fieldId) throws ReadDriverException {
1249
        return fieldNames[fieldId];
1250
    }
1251

    
1252
    public int getFieldWidth(int fieldId) {
1253
        int i = -1;
1254

    
1255
        try {
1256
            int aux = fieldId + 1; // fieldId viene basado en 0
1257
            int _type = metaData.getColumnType(aux);
1258
            if (NumberUtilities.isNumeric(_type)) {
1259
                i = metaData.getPrecision(aux);
1260
            } else {
1261
                i = metaData.getColumnDisplaySize(aux);
1262
            }
1263
        }
1264
        catch (SQLException e) {
1265
            logger.error("While getting field width: " + e.getMessage());
1266
        }
1267

    
1268
        if (i < 0) {
1269
            i = 255;
1270
        }
1271

    
1272
        return i;
1273
    }
1274

    
1275
    public Value getFieldValue(long rowIndex, int field_Id) throws ReadDriverException {
1276
        if (isNotAvailableYet) {
1277
            return nullVal;
1278
        }
1279

    
1280
        if ((singleCachedFeature != null) &&
1281
                (rowIndex == singleCachedFeatureRowNum)) {
1282
            return singleCachedFeature.getAttributes()[field_Id];
1283
        }
1284

    
1285
        // return ValueFactory.createNullValue();
1286
        ResultSet _r = null;
1287
        java.sql.PreparedStatement ps = null;
1288

    
1289
        try {
1290
            String rnq = getSearchId();
1291
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1292

    
1293
            ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(rnq);
1294
            ps.setObject(1, _id);
1295

    
1296
            ps.execute();
1297
            _r = ps.getResultSet();
1298
            
1299
            if (!_r.next()) {
1300
                _r.close();
1301
                ps.close();
1302
                    throw new SQLException("No row for ROWID: " + _id.toString() + ". Possibly deleted from another app.");
1303
            }
1304
            
1305
        } catch (SQLException se) {
1306
                logger.error("While getting row " + rowIndex + " : " + se.getMessage());
1307
                return ValueFactory.createNullValue();
1308
        }
1309

    
1310
        IFeature ife = null;
1311
        Value[] atts = null;
1312

    
1313
        try {
1314
            ROWID ri = (ROWID) _r.getObject(1);
1315
            atts = getAttributes(_r, true);
1316

    
1317
            String gid = ri.stringValue();
1318
            STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1319
            IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1320
            ife = new DefaultFeature(theGeom, atts, gid);
1321
            _r.close();
1322
            ps.close();
1323
        } catch (SQLException se) {
1324
            logger.error("Error while doing next(): " + se.getMessage(), se);
1325
            return ValueFactory.createNullValue();
1326
        }
1327

    
1328
        // -------------------------------
1329
        singleCachedFeature = ife;
1330
        singleCachedFeatureRowNum = rowIndex;
1331

    
1332
        // -------------------------------
1333
        if (atts == null) {
1334
            return ValueFactory.createNullValue();
1335
        } else {
1336
            return atts[field_Id];
1337
        }
1338
    }
1339

    
1340

    
1341

    
1342
    public Rectangle2D getFullExtent() {
1343
            return full_Extent;
1344
    }
1345

    
1346

    
1347

    
1348
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim, int reciter) {
1349
        // int __srid) {
1350

    
1351
            NUMBER _srid = new NUMBER(0);
1352
        NUMBER main_type = new NUMBER((dim * 1000) +
1353
                OracleSpatialUtils.getStructType(the_data));
1354

    
1355
        Datum[] all_info_array = null;
1356
        Object[] elems_info_aray = null;
1357
        Datum[] all_ords = null;
1358

    
1359
        Object[] ords_of_groups = null;
1360
        Object[] _elems_info_aray = null;
1361
        try {
1362
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1363
            elems_info_aray = OracleSpatialUtils.groupByElement(all_info_array);
1364
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1365

    
1366
            ords_of_groups = OracleSpatialUtils.getOrdOfGroups(all_ords, elems_info_aray);
1367
            _elems_info_aray = new Object[elems_info_aray.length];
1368
        }
1369
        catch (SQLException e) { 
1370
            logger.error("Unexpected error: " + e.getMessage());
1371
        }
1372

    
1373

    
1374
        for (int i = 0; i < elems_info_aray.length; i++) {
1375
            _elems_info_aray[i] = OracleSpatialUtils.updateIndexes((Datum[]) elems_info_aray[i]);
1376
        }
1377

    
1378
        // _elems_info_aray, ords_of_groups
1379
        int no_of_elems = ords_of_groups.length;
1380
        IGeometry[] geoms = new IGeometry[no_of_elems];
1381

    
1382
        for (int i = 0; i < no_of_elems; i++) {
1383
            Datum[] item_info_array = null;
1384
            Datum[] item_ords = null;
1385
            NUMBER gtype = null;
1386

    
1387
            try {
1388
                item_info_array = (Datum[]) _elems_info_aray[i];
1389
                item_ords = (Datum[]) ords_of_groups[i];
1390

    
1391
                gtype = new NUMBER((dim * 1000) +
1392
                        (item_info_array[1].intValue() % 1000));
1393

    
1394
                if (isTableHasSrid()) {
1395
                        _srid = new NUMBER(Integer.parseInt(oracleSRID));
1396
                }
1397
            }
1398
            catch (SQLException se) {
1399
                logger.error("Unexpected error: " + se.getMessage());
1400
            }
1401

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

    
1405
            STRUCT itemst = null;
1406

    
1407
            if (isTableHasSrid()) {
1408

    
1409
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1410
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1411
            }
1412
            else {
1413
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1414
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1415
            }
1416

    
1417
            geoms[i] = getFMapGeometry(itemst, true, reciter + 1);
1418
        }
1419

    
1420
        return new FGeometryCollection(geoms);
1421
    }
1422

    
1423

    
1424

    
1425

    
1426

    
1427

    
1428

    
1429

    
1430
    private void cleanWhereClause() {
1431
        emptyWhereClause = false;
1432

    
1433
        String aux = getWhereClauseWithoutWhere();
1434

    
1435
        for (int i = 0; i < aux.length(); i++)
1436
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
1437
                return;
1438
            }
1439

    
1440
        getLyrDef().setWhereClause("");
1441
        emptyWhereClause = true;
1442
    }
1443

    
1444

    
1445

    
1446
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
1447
        String resp = "";
1448

    
1449
        if (isGeogCS) {
1450
            String vport = "sdo_filter(" + geoColName +
1451
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
1452
                "), 'querytype=window') = 'TRUE'";
1453

    
1454
                resp = "select " + getStandardSelectExpression() + ", c." +
1455
                    geoColName + " from " + getTableName() + " c where ";
1456
                if (idsLoadWhere.length() > 0) {
1457
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1458
                }
1459
                resp = resp + "(" + vport + ")";
1460
        }
1461
        else {
1462
                resp = "select " + getStandardSelectExpression() + ", c." +
1463
                    geoColName + " from " + getTableName() + " c where ";
1464
                if (idsLoadWhere.length() > 0) {
1465
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1466
                }
1467
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
1468
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
1469
        }
1470

    
1471
//        return "select " + getStandardSelectExpression() + ", c." +
1472
//        geoColName + " from " + getTableName() + " c";
1473
        return resp;
1474
    }
1475
    
1476
    private String getCustomSelect(String[] atts, String viewsdo, String idsLoadWhere) {
1477
        String resp = "";
1478
        
1479
        String atts_enum = "";
1480
        if ((atts == null) || (atts.length == 0)) {
1481
                
1482
        } else {
1483
                atts_enum = " c.\"" + atts[0] + "\" ";
1484
            for (int i=1; i<atts.length; i++) {
1485
                    atts_enum = atts_enum + ", " + atts[1]; 
1486
            }
1487
        }
1488

    
1489
        if (isGeogCS) {
1490
            String vport = "sdo_filter(" + geoColName +
1491
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
1492
                "), 'querytype=window') = 'TRUE'";
1493

    
1494
                resp = "select " + atts_enum + " from " + getTableName() + " c where ";
1495
                if (idsLoadWhere.length() > 0) {
1496
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1497
                }
1498
                resp = resp + "(" + vport + ")";
1499
        } else {
1500
                resp = "select " + atts_enum + " from " + getTableName() + " c where ";
1501
                if (idsLoadWhere.length() > 0) {
1502
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1503
                }
1504
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
1505
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
1506
        }
1507

    
1508
//        return "select " + getStandardSelectExpression() + ", c." +
1509
//        geoColName + " from " + getTableName() + " c";
1510
        return resp;
1511
    }    
1512

    
1513
    public void setWorkingArea(Rectangle2D rect) {
1514
    }
1515

    
1516
    private void setWAStructt() {
1517
    }
1518

    
1519

    
1520

    
1521
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
1522
        /*
1523
         * Tipos en Oracle Spatial usando JGeometry
1524
         *
1525
         * GTYPE_COLLECTION collection geometry type
1526
         * GTYPE_CURVE curve geoemtry type
1527
         * GTYPE_MULTICURVE multi-curve geometry type
1528
         * GTYPE_MULTIPOINT multi-point geometry type
1529
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
1530
         * GTYPE_POINT point geometry type
1531
         * GTYPE_POLYGON  polygon geometry type
1532
         *
1533
         * Tipos gvSIG FShape
1534
         *
1535
         * NULL = 0;
1536
         * POINT = 1;
1537
         * LINE = 2;
1538
         * POLYGON = 4;
1539
         * TEXT = 8;
1540
         * MULTI = 16;
1541
         * MULTIPOINT = 32;
1542
         * CIRCLE = 64;
1543
         * ARC = 128;
1544
         * ELLIPSE=256;
1545
         * Z=512
1546
         */
1547
        switch (type) {
1548
        case JGeometry_GTYPE_POLYGON:
1549
        case JGeometry_GTYPE_MULTIPOLYGON:
1550
            return FShape.POLYGON;
1551

    
1552
        case JGeometry_GTYPE_CURVE:
1553
        case JGeometry_GTYPE_MULTICURVE:
1554
            return FShape.LINE;
1555
        }
1556

    
1557
        logger.error("Unhandled Oracle Spatial geometry type: " + type +
1558
            " (conversion returned FShape.NULL)");
1559

    
1560
        return FShape.NULL;
1561
    }
1562
    
1563
    private String getValidViewConstructor(
1564
                    STRUCT _st,
1565
                    String ora_srid,
1566
                    boolean _hassrid,
1567
                    boolean _isgeocs) {
1568

    
1569
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
1570
            String resp = "";
1571
            if ((_hassrid) && (_isgeocs)) {
1572
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
1573
            } else {
1574
                    resp = sdo;
1575
            }
1576

    
1577
            return resp;
1578
    }
1579

    
1580

    
1581

    
1582
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
1583
        boolean hasSrid) throws ReadDriverException {
1584
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
1585
        String main_sel = "";
1586

    
1587
        if (fixsql == null) {
1588
            // main_sel = getMainSelect3(var_name);
1589
                String idswhere = getIdsQueryWhereClause(false);
1590
            main_sel = getMainSelect(sdo_intersect, idswhere);
1591
        }
1592
        else {
1593
            main_sel = fixsql;
1594
        }
1595

    
1596
        logger.debug("MAIN SEL = " + main_sel);
1597

    
1598
        ResultSet _rs = null;
1599
        Statement _stmnt = null;
1600
        Object[] _resp = new Object[2];
1601

    
1602
        try {
1603
            _stmnt = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_FORWARD_ONLY,
1604
                    ResultSet.CONCUR_READ_ONLY);
1605
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
1606
            _stmnt.setFetchSize(getAdaptedFetchSize());
1607

    
1608
            _rs = _stmnt.executeQuery(main_sel);
1609

    
1610
            // stmnt.close();
1611
        }
1612
        catch (SQLException se) {
1613
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
1614
                se);
1615
            throw new ReadDriverException(getName(), se);
1616
        }
1617

    
1618
        // this method returns the statement too, so that it can be closed afterwards
1619
        _resp[0] = _rs;
1620
        _resp[1] = _stmnt;
1621

    
1622
        return _resp;
1623
    }
1624

    
1625
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
1626
        String resp = "";
1627

    
1628
        try {
1629
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
1630
            String mdsys_sdo_ordinate_array = "";
1631
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
1632

    
1633
            for (int i = 0; i < vertices.length; i++) {
1634
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
1635
                    vertices[i].doubleValue() + ", ";
1636
            }
1637

    
1638
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
1639
                    mdsys_sdo_ordinate_array.length() - 2);
1640
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
1641
                mdsys_sdo_ordinate_array + ")";
1642

    
1643
            String aux = "";
1644

    
1645
            if (hasSrid) {
1646
                aux = oracleSRID;
1647

    
1648
                if (_isGeogCS) {
1649
                    aux = "0";
1650
                }
1651
            }
1652
            else {
1653
                aux = "null";
1654
            }
1655

    
1656
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
1657
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
1658
                ")";
1659
        }
1660
        catch (Exception ex) {
1661
                logger.error("While getting sdo contructor: " +
1662
                ex.getMessage());
1663
        }
1664

    
1665
        return resp;
1666
    }
1667

    
1668
    private String getIdsQueryWhereClause(boolean with_where) {
1669
                String resp = "";
1670

    
1671
                String _where = "";
1672
                if (with_where) _where = " where ";
1673

    
1674
                if (workingAreaInTablesCSStruct == null) {
1675
                        if (emptyWhereClause) {
1676
                                // return "select rowid from " + getTableName();
1677
                        } else {
1678
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
1679
                                                + ")";
1680
                        }
1681
                } else {
1682
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
1683
                                        oracleSRID, isTableHasSrid(), isGeogCS);
1684

    
1685
                        if (emptyWhereClause) {
1686
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
1687
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
1688
                        } else {
1689
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
1690
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
1691
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
1692
                        }
1693
                }
1694

    
1695
                // resp = resp + " order by rowid";
1696
                return resp;
1697
        }
1698

    
1699
    public String getIdAndElemInfoFullResulltSetQuery() {
1700
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
1701
            getTableName() + " c";
1702

    
1703
        resp = resp + getIdsQueryWhereClause(true);
1704
        return resp;
1705
    }
1706

    
1707
    private String getSearchId() {
1708
        if (emptyWhereClause) {
1709
            return "select " + getStandardSelectExpression() + ", c." +
1710
            geoColName + " from " + getTableName() + " c where rowid = ?";
1711
        }
1712
        else {
1713
            return "select " + getStandardSelectExpression() + ", c." +
1714
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
1715
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
1716
        }
1717
    }
1718

    
1719
    public int getShapeType() {
1720
        return shapeType;
1721
    }
1722

    
1723
    public void setShapeType(int t) {
1724
        shapeType = t;
1725
    }
1726
    
1727

    
1728
    private String getWhereClauseWithoutWhere() {
1729
        String resp = "";
1730
        String old = getLyrDef().getWhereClause();
1731
        resp = old;
1732

    
1733
        if (old.length() <= 6) {
1734
            return old;
1735
        }
1736

    
1737
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
1738
            resp = resp.substring(6, resp.length());
1739
        }
1740

    
1741
        return resp;
1742
    }
1743

    
1744

    
1745

    
1746
    public static String fieldTypeToSqlStringType(FieldDescription fd) {
1747
            
1748
        String aux = "VARCHAR2(" + VARCHAR2_MAX_SIZE + ")"; // Por defecto.
1749
        int the_type = fd.getFieldType();
1750
        
1751
        int _w = fd.getFieldLength();
1752
        int _dec = 0;
1753
        
1754
        if (NumberUtilities.isNumeric(the_type)) {
1755
                _dec = fd.getFieldDecimalCount(); 
1756
        }
1757
        
1758
        if (_w < (_dec + 1)) {
1759
                _w = Math.max(6+_dec,2*_dec);
1760
        }
1761

    
1762
        switch (the_type) {
1763
        case Types.SMALLINT:
1764
            aux = "NUMBER(" + _w + ", 0)";
1765
            break;
1766

    
1767
        case Types.INTEGER:
1768
            aux = "NUMBER(" + _w + ", 0)";
1769
            break;
1770

    
1771
        case Types.BIGINT:
1772
            aux = "NUMBER(" + _w + ", 0)";
1773
            break;
1774

    
1775
        case Types.BOOLEAN:
1776
            aux = "NUMBER(1, 0)";
1777
            break;
1778

    
1779
        case Types.DECIMAL:
1780
            aux = "NUMBER(" + _w + ", " + _dec + ")";
1781
            break;
1782

    
1783
        case Types.NUMERIC:
1784
            aux = "NUMBER(" + _w + ", " + _dec + ")";
1785
            break;
1786

    
1787
        case Types.DOUBLE:
1788
            aux = "NUMBER(" + _w + ", " + _dec + ")";
1789
            break;
1790

    
1791
        case Types.FLOAT:
1792
            aux = "NUMBER(" + _w + ", " + _dec + ")";
1793
            break;
1794

    
1795
        case Types.CHAR:
1796
            aux = "CHAR(1 BYTE)";
1797
            break;
1798

    
1799
        case Types.VARCHAR:
1800
            aux = "VARCHAR2(" + _w + ")";
1801
            break;
1802

    
1803
        case Types.LONGVARCHAR:
1804
            aux = "VARCHAR2(" + _w + ")";
1805
            break;
1806
            
1807
        case Types.DATE:
1808
            aux = "DATE";
1809
            break;
1810

    
1811
        }
1812

    
1813
        return aux;
1814
    }
1815

    
1816
    // -----------------------------------------------------------
1817
    // -----------------------------------------------------------
1818
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
1819
        return "DROP TABLE " + dbLayerDef.getTableName() +
1820
        " CASCADE CONSTRAINTS";
1821
    }
1822

    
1823
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
1824
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
1825

    
1826
        String type = "";
1827
        String name = "";
1828
        String table_name = dbLayerDef.getTableName().toUpperCase();
1829

    
1830
        String resp = "CREATE TABLE " + table_name + " ( ";
1831

    
1832
        for (int i = 0; i < flds.length; i++) {
1833
            name = flds[i].getFieldName();
1834

    
1835
            // -------------- FORBIDDEN FIELD NAMES -----------------
1836
            if (!isOracleAllowedFieldname(name)) {
1837
                continue;
1838
            }
1839

    
1840
            // ------------------------------------------------------
1841
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
1842
            }
1843
            else {
1844
                name = getValidOracleID(name, i, false);
1845
                resp = resp + "\"" + name + "\" ";
1846
                type = fieldTypeToSqlStringType(flds[i]);
1847
                resp = resp + type + ", ";
1848
            }
1849
        }
1850

    
1851
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
1852
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
1853
        resp = resp + ", ";
1854

    
1855
        String pk = "CONSTRAINT " + getDerivedNAme(table_name, "PK") +
1856
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD_CASE_SENSITIVE +
1857
            "\") ENABLE";
1858

    
1859
        resp = resp + pk + " )";
1860

    
1861
        return resp;
1862
    }
1863

    
1864
    private static String getDerivedNAme(String tname, String suffix) {
1865

    
1866
            int ind = tname.lastIndexOf(".");
1867
            if (ind == -1) {
1868

    
1869
                    int l = Math.min(28, tname.length());
1870
                    return tname.substring(0, l) + "_" + suffix;
1871

    
1872
            } else {
1873

    
1874
                    String pre = tname.substring(0, ind);
1875
                    String post = tname.substring(ind + 1, tname.length());
1876
                    int lpost = Math.min(24, post.length());
1877
                    int lpre = Math.min(3, pre.length());
1878
                    return pre.substring(0, lpre) + "_" + post.substring(0, lpost) + "_" + suffix;
1879
            }
1880

    
1881
    }
1882

    
1883
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
1884
        String resp = "CREATE INDEX " + getDerivedNAme(dbLayerDef.getTableName(), "SX") +
1885
            " ON " + dbLayerDef.getTableName() + " (\"" +
1886
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
1887
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
1888

    
1889
        return resp;
1890
    }
1891

    
1892
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
1893

    
1894
            String tname = dbLayerDef.getTableName();
1895
            int ind = tname.lastIndexOf(".");
1896
            if (ind != -1) {
1897
                    String schema = tname.substring(0, ind);
1898
                    tname = tname.substring(ind + 1, tname.length());
1899
            return "DELETE FROM " + USER_ORACLE_GEOMETADATA_VIEW +
1900
            " WHERE TABLE_NAME = '" + tname + "'";
1901

    
1902
            } else{
1903
            return "DELETE FROM " + USER_ORACLE_GEOMETADATA_VIEW +
1904
            " WHERE TABLE_NAME = '" + tname + "'";
1905
            }
1906
    }
1907

    
1908
    /**
1909
     * UTility method to get the SQL sentence needed to update the geographic metadata table
1910
     * with a new bounding box and SRS
1911
     *
1912
     * @param tName table name
1913
     * @param ora_srid new SRS
1914
     * @param bbox new bounding box
1915
     * @param dim geometries dimension
1916
     * @param withsrid False if the SRS is set to NULL. True otherwise.
1917
     * @return the SQL sentence to perform the update
1918
     */
1919
    public static String getMetadataUpdateSql(String schema, String tName, String ora_srid,
1920
        Rectangle2D bbox, int dim, boolean withsrid) {
1921
            
1922
        String[] dim_name = new String[dim];
1923

    
1924
        
1925
        String _ora_srid = ora_srid;
1926
        if (_ora_srid == null) _ora_srid = "NULL";
1927

    
1928
        if (_ora_srid.compareTo(GEODETIC_SRID) == 0) {
1929
            dim_name[0] = "LONGITUDE";
1930
            dim_name[1] = "LATITUDE";
1931
        }
1932
        else {
1933
            dim_name[0] = "X";
1934
            dim_name[1] = "Y";
1935

    
1936
            if (dim > 2) {
1937
                dim_name[2] = "Z";
1938

    
1939
                if (dim > 3) {
1940
                    dim_name[3] = "T";
1941
                }
1942
            }
1943
        }
1944
        
1945
        double minx = bbox.getMinX();
1946
        double miny = bbox.getMinY();
1947
        double maxx = bbox.getMaxX();
1948
        double maxy = bbox.getMaxY();
1949
        
1950
        String resp = "INSERT INTO " + USER_ORACLE_GEOMETADATA_VIEW + " " +
1951
            " ( TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
1952
            + "'" + tName + "', "
1953
            + "'" + DEFAULT_GEO_FIELD + "', " +
1954
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
1955
            minx + ", " + maxx + ", " + OracleSpatialUtils.ORACLE_GEOM_METADATA_TOLERANCE + " ), " +
1956
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + miny + ", " +
1957
            maxy + ", " + OracleSpatialUtils.ORACLE_GEOM_METADATA_TOLERANCE + " ))";
1958

    
1959
        if (dim > 2) {
1960
            resp = resp.substring(0, resp.length() - 1) + ",";
1961
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
1962
                "', 0.0, 100.0, " + OracleSpatialUtils.ORACLE_GEOM_METADATA_TOLERANCE + " ))";
1963

    
1964
            if (dim > 3) {
1965
                resp = resp.substring(0, resp.length() - 1) + ",";
1966
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
1967
                    "', 0.0, 100.0, " + OracleSpatialUtils.ORACLE_GEOM_METADATA_TOLERANCE + " ))";
1968
            }
1969
        }
1970

    
1971
        if (withsrid) {
1972
            resp = resp + ", " + _ora_srid + " )";
1973
        }
1974
        else {
1975
            resp = resp + ", NULL )";
1976
        }
1977

    
1978
        return resp;
1979
    }
1980

    
1981
    /**
1982
     * Gets the SQL sentence to perform an insertion.
1983
     *
1984
     * @param feat feature to be added
1985
     * @param dbLayerDef layer definition
1986
     * @param rowInd row index
1987
     * @param _geoColName geometry field name
1988
     * @return the SQL sentence to perform the insertion
1989
     */
1990
    public static String getRowInsertSql(IFeature feat,
1991
        DBLayerDefinition dbLayerDef, int rowInd,
1992
        String _geoColName,
1993
        String geo_val) {
1994
            
1995
        String name = "";
1996
        int ftype = -1;
1997
        String aux_orig = "";
1998
        String aux_limited = "";
1999
        String aux_quotes_ok = "";
2000

    
2001
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2002

    
2003
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
2004

    
2005
        for (int i = 0; i < fieldsDescr.length; i++) {
2006
            name = fieldsDescr[i].getFieldName();
2007
            ftype = fieldsDescr[i].getFieldType();
2008

    
2009
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
2010
            if (!isOracleAllowedFieldname(name)) continue;
2011
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2012
            // ------------------------------------------------------
2013
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2014
            }
2015
            else {
2016
                name = getValidOracleID(name, i, false);
2017
                resp = resp + "\"" + name + "\"" + " , ";
2018
            }
2019
        }
2020

    
2021
        resp = resp + _geoColName + " ) VALUES ( ";
2022

    
2023
        for (int i = 0; i < fieldsDescr.length; i++) {
2024
            name = fieldsDescr[i].getFieldName();
2025
            ftype = fieldsDescr[i].getFieldType();
2026

    
2027
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2028
            if (!isOracleAllowedFieldname(name)) continue;
2029
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2030
            // ------------------------------------------------------
2031
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2032

    
2033
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2034
            }
2035
            else {
2036
                if (name.compareTo(OracleSpatialDriver.DEFAULT_ID_FIELD_CASE_SENSITIVE) == 0) {
2037
                    resp = resp + rowInd + " , ";
2038
                }
2039
                else {
2040
                    Value attValue = feat.getAttribute(i);
2041

    
2042
                    if (attValue.toString() == null) {
2043
                        resp = resp + "NULL , ";
2044
                    }
2045
                    else {
2046
                        if (sur.length() > 0) {
2047
                            aux_orig = attValue.toString();
2048
                            aux_limited = cropStringValue(aux_orig, i,
2049
                                    fieldsDescr);
2050
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
2051

    
2052
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
2053
                        }
2054
                        else {
2055
                            String _aux = attValue.toString();
2056

    
2057
                            if (_aux.length() == 0) {
2058
                                _aux = "NULL";
2059
                            }
2060

    
2061
                            resp = resp + _aux + " , ";
2062
                        }
2063
                    }
2064
                }
2065
            }
2066
        }
2067

    
2068
        resp = resp + " " + geo_val + " )";
2069
        /*
2070
        String test = "SDO_UTIL.APPEND(SDO_GEOMETRY("
2071
                        + "2002, NULL, NULL,"
2072
                        + "SDO_ELEM_INFO_ARRAY(1, 2, 2),"
2073
                        + "SDO_ORDINATE_ARRAY(500000, 4000000, 1000000, 5000000, 500000, 5000000)"
2074
                        + "), ? )";
2075

2076
        resp = resp + " " + test + " )";
2077
        */
2078
        return resp;
2079
    }
2080

    
2081
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
2082

    
2083
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
2084
                    return true;
2085
            }
2086

    
2087
            if ((ftype == Types.BINARY)
2088
                || (ftype == Types.ARRAY)
2089
                || (ftype == Types.BLOB)
2090
                || (ftype == Types.CLOB)
2091
                || (ftype == Types.STRUCT)
2092
            ) {
2093
                    return false;
2094
            }
2095
                return true;
2096
        }
2097

    
2098
        /**
2099
     * Gets the SQL sentence to perform an update.
2100
     *
2101
     * @param feat feature to be updated
2102
     * @param dbLayerDef layer definition
2103
     * @param rowInd row index
2104
     * @param geoFieldName geometry field name
2105
     * @return the SQL sentence to perform the update
2106
     */
2107
    public static String getRowUpdateSql(IFeature feat,
2108
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
2109
        String name = "";
2110
        String aux_orig = "";
2111
        String aux_limited = "";
2112
        String aux_quotes_ok = "";
2113

    
2114
        Value[] atts = feat.getAttributes();
2115
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
2116

    
2117
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
2118

    
2119
        for (int i = 0; i < _fieldsDescr.length; i++) {
2120
            name = _fieldsDescr[i].getFieldName();
2121

    
2122
            // -------------- FORBIDDEN FIELD NAMES -----------------
2123
            if (!isOracleAllowedFieldname(name)) {
2124
                logger.info("Field: " + name + " will not be updated.");
2125
                continue;
2126
            }
2127

    
2128
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
2129
                        geoFieldName)) {
2130
                logger.info("Field: " + name + " will not be updated (it's a struct).");
2131
                continue;
2132
            }
2133

    
2134
            // ------------------------------------------------------
2135
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
2136
                // resp = resp + "\"" + name + "\"" + " = ?, ";
2137
            }
2138
            else {
2139
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
2140
                aux_orig = atts[i].toString();
2141
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
2142
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
2143
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
2144
                    sur + ", ";
2145
            }
2146
        }
2147

    
2148
        resp = resp + "\"" + geoFieldName + "\" = ?";
2149
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
2150

    
2151
        return resp;
2152
    }
2153

    
2154
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
2155
        String geoname) {
2156
        if (ftype == Types.STRUCT) {
2157
            if (fldname.compareToIgnoreCase(geoname) != 0) {
2158
                return true;
2159
            }
2160
        }
2161

    
2162
        return false;
2163
    }
2164

    
2165
    /**
2166
     * Gets the SQL sentence to perform a deletion.
2167
     *
2168
     * @param dbLayerDef layer definition
2169
     * @param id ROWID of the record to be deleted
2170
     * @return the SQL sentence to perform the deletion
2171
     */
2172
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
2173
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
2174
        resp = resp + " WHERE ROWID ='" + id + "'";
2175

    
2176
        return resp;
2177
    }
2178

    
2179
    private static String cropStringValue(String orig_val, int i,
2180
        FieldDescription[] _flds) {
2181
            
2182
        if (orig_val == null) {
2183
            return "NULL";
2184
        }
2185
        
2186
        if (NumberUtilities.isNumeric(_flds[i].getFieldType())
2187
                    && (orig_val.length() == 0)) {
2188
                    return "NULL";
2189
        }
2190

    
2191
        int tpe = _flds[i].getFieldType();
2192
        int max_size = OracleSpatialUtils.maxSizeForFieldType(tpe);
2193

    
2194
        if (max_size == -1) {
2195
            return orig_val;
2196
        }
2197

    
2198
        int or_size = orig_val.length();
2199

    
2200
        if (or_size <= max_size) {
2201
            return orig_val;
2202
        }
2203

    
2204
        return orig_val.substring(0, max_size);
2205
    }
2206

    
2207
    private static String avoidQuoteProblem(String str) {
2208
        return str.replaceAll("'", "''");
2209
    }
2210

    
2211
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
2212
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
2213
            return "";
2214
        }
2215

    
2216
        return "'";
2217
    }
2218

    
2219
    /**
2220
     * Utility function to translate a SRS code from EPSG to Oracle.
2221
     * Uses a datasource based on a DBF file.
2222
     *
2223
     * @param epsg the EPSG code
2224
     * @return the Oracle code
2225
     */
2226
    public static String epsgSridToOracleSrid(String _epsg) throws Exception {
2227
            
2228
            String epsg = removePrefix(_epsg);
2229
            
2230
        String resp = "8307";
2231

    
2232
        // --------------------------------------------
2233
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
2234
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
2235
        DataSource ds = null;
2236

    
2237
        try {
2238
            ds = LayerFactory.getDataSourceFactory()
2239
                             .executeSQL(sql,
2240
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
2241

    
2242
            if (ds.getRowCount() == 0) {
2243
                logger.error("EPSG code not found in table: " + epsg);
2244
                throw new Exception("Unknown EPSG: " + epsg);
2245
            }
2246

    
2247
            if (ds.getRowCount() > 1) {
2248
                // logger.error("===============");
2249
                logger.warn(
2250
                    "DBF file is wrong?: More than one preferred Oracle Spatial code found for EPSG code: " +
2251
                    epsg);
2252

    
2253
                for (int i = 0; i < ds.getRowCount(); i++) {
2254
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
2255

    
2256
                    if (i == 0) {
2257
                        resp = "" + aux;
2258
                    }
2259
                    // logger.error("" + aux);
2260
                }
2261
                // logger.error("===============");
2262
                return resp;
2263
            }
2264

    
2265
            resp = "" +
2266
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
2267
        } catch (Exception pe) {
2268
                throw pe;
2269
            // logger.error("Error with SQL statement. " + pe.getMessage());
2270
        }
2271

    
2272
        return resp;
2273
    }
2274

    
2275
    /**
2276
     * Utility function to translate a SRS code from Oracle to EPSG.
2277
     * Uses a datasource based on a DBF file.
2278
     *
2279
     * @param ora the Oracle code
2280
     * @return the EPSG code
2281
     */
2282
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
2283
            
2284
            if (ora == null) return null;
2285
            
2286
        String resp = "4326";
2287

    
2288
        // --------------------------------------------
2289
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
2290
            " where ORACLE = " + ora + ";";
2291
        DataSource ds = null;
2292

    
2293
        try {
2294
            ds = LayerFactory.getDataSourceFactory()
2295
                             .executeSQL(sql,
2296
                    DataSourceFactory.AUTOMATIC_OPENING);
2297

    
2298
            if (ds.getRowCount() == 0) {
2299
                logger.warn("Oracle Spatial code not found in table: " + ora);
2300
                throw new Exception("Unknown Oracle code: " + ora);
2301
            }
2302

    
2303
            if (ds.getRowCount() > 1) {
2304
                // logger.error("===============");
2305
                logger.warn(
2306
                    "DBF file is wrong?: More than one EPSG code found for Oracle Spatial code: " +
2307
                    ora);
2308

    
2309
                for (int i = 0; i < ds.getRowCount(); i++) {
2310
                    String aux = "" +
2311
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
2312

    
2313
                    if (i == 0) {
2314
                        resp = aux;
2315
                    }
2316

    
2317
                 // logger.error("" + aux);
2318
                }
2319

    
2320
             // logger.error("===============");
2321

    
2322
                return resp;
2323
            }
2324

    
2325
            resp = "" +
2326
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
2327
        } catch (Exception pe) {
2328
                throw pe;
2329
            // logger.warn("Error with SQL statement. " + pe.getMessage());
2330
        }
2331

    
2332
        return resp;
2333
    }
2334

    
2335
    /**
2336
     * This methos creates the datasource used to translate the SRS codes:
2337
     * EPSG <--> Oracle.
2338
     *
2339
     * It's called from several places, so checks that the datasource does not exist.
2340
     */
2341

    
2342

    
2343
    /**
2344
     * Utility method to get a valid Oracle identifier (in terms of length)
2345
     *
2346
     * @param str Proposed string
2347
     * @param ind field index of the given field name (used by the method to
2348
     * improve the renaming)
2349
     * @return an acceptable oracle identifier.
2350
     */
2351
    public static String getValidOracleID(String _str, int ind, boolean force_uppercase) {
2352
            
2353
            String str = _str;
2354
            if (force_uppercase) str = _str.toUpperCase();
2355
            
2356
        if (str.length() <= MAX_ID_LENGTH) {
2357
            return str;
2358
        }
2359

    
2360
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
2361
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
2362
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
2363
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
2364
        resp = resp + "_" + (ind % 1000);
2365

    
2366
        return resp;
2367
    }
2368

    
2369
    private static ArrayList ensureSensibleShell(ArrayList cc) {
2370
        if (sameCoordinate((Coordinate) cc.get(0),
2371
                    (Coordinate) cc.get(cc.size() - 1))) {
2372
            if (cc.size() == 2) {
2373
                ArrayList resp = new ArrayList();
2374
                resp.add(cc.get(0));
2375

    
2376
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
2377
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
2378
                resp.add(newcoo);
2379

    
2380
                newcoo = new Coordinate((Coordinate) cc.get(0));
2381
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
2382
                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
2383
                resp.add(newcoo);
2384

    
2385
                resp.add(cc.get(0));
2386

    
2387
                return resp;
2388
            }
2389

    
2390
            if (cc.size() == 3) {
2391
                cc.remove(1);
2392

    
2393
                return ensureSensibleShell(cc);
2394
            }
2395

    
2396
            return cc;
2397
        }
2398
        else {
2399
            cc.add(cc.get(0));
2400

    
2401
            return cc;
2402
        }
2403
    }
2404

    
2405
    private static ArrayList ensureSensibleHole(ArrayList cc) {
2406
        if (sameCoordinate((Coordinate) cc.get(0),
2407
                    (Coordinate) cc.get(cc.size() - 1))) {
2408
            if (cc.size() == 2) {
2409
                ArrayList resp = new ArrayList();
2410
                resp.add(cc.get(0));
2411

    
2412
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
2413
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
2414
                resp.add(newcoo);
2415

    
2416
                newcoo = new Coordinate((Coordinate) cc.get(0));
2417
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
2418
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
2419
                resp.add(newcoo);
2420

    
2421
                resp.add(cc.get(0));
2422

    
2423
                return resp;
2424
            }
2425

    
2426
            if (cc.size() == 3) {
2427
                cc.remove(1);
2428

    
2429
                return ensureSensibleHole(cc);
2430
            }
2431

    
2432
            return cc;
2433
        }
2434
        else {
2435
            cc.add(cc.get(0));
2436

    
2437
            return cc;
2438
        }
2439
    }
2440

    
2441
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
2442
        if (cc.size() == 2) {
2443
            if (sameCoordinate((Coordinate) cc.get(0),
2444
                        (Coordinate) cc.get(cc.size() - 1))) {
2445
                ArrayList resp = new ArrayList();
2446
                resp.add(cc.get(0));
2447

    
2448
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
2449
                newc.x = newc.x + IRRELEVANT_DISTANCE;
2450
                resp.add(newc);
2451

    
2452
                return resp;
2453
            }
2454
        }
2455

    
2456
        return cc;
2457
    }
2458

    
2459
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
2460
        if (c1.x != c2.x) {
2461
            return false;
2462
        }
2463

    
2464
        if (c1.y != c2.y) {
2465
            return false;
2466
        }
2467

    
2468
        return true;
2469
    }
2470

    
2471
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
2472
        if (cc.size() == 2) {
2473
            return null;
2474
        }
2475

    
2476
        if (cc.size() == 3) {
2477
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
2478
                return null;
2479
            }
2480

    
2481
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
2482
                return null;
2483
            }
2484

    
2485
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
2486
                return null;
2487
            }
2488

    
2489
            cc.add(cc.get(0));
2490

    
2491
            return cc;
2492
        }
2493

    
2494
        if (!sameCoordinate((Coordinate) cc.get(0),
2495
                    (Coordinate) cc.get(cc.size() - 1))) {
2496
            cc.add(cc.get(0));
2497
        }
2498

    
2499
        return cc;
2500
    }
2501

    
2502
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
2503
        Coordinate[] p = new Coordinate[4];
2504
        p[0] = c;
2505

    
2506
        Coordinate nc = new Coordinate(c);
2507
        nc.x = nc.x + IRRELEVANT_DISTANCE;
2508

    
2509
        Coordinate nc2 = new Coordinate(nc);
2510
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
2511
        p[1] = nc;
2512
        p[2] = nc2;
2513
        p[3] = new Coordinate(c);
2514

    
2515
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
2516
        LinearRing ls = new LinearRing(cs, geomFactory);
2517
        Polygon po = new Polygon(ls, null, geomFactory);
2518
        Polygon[] pos = new Polygon[1];
2519
        pos[0] = po;
2520

    
2521
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
2522

    
2523
        return mpo;
2524
    }
2525

    
2526
    public String getSourceProjection(IConnection conn, DBLayerDefinition lyrDef) {
2527
            
2528
            String resp = null;
2529
        try {
2530
            Statement _st = ((ConnectionJDBC) conn).getConnection().createStatement();
2531
            String[] tokens = lyrDef.getName().split("\\u002E", 2);
2532
            String qry;
2533
            if (tokens.length > 1) {
2534
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2535
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
2536
                tokens[1] + "'";
2537
            } else {
2538
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2539
                " where TABLE_NAME = " + "'" + lyrDef.getName() + "'";
2540
            }
2541
            ResultSet _rs = _st.executeQuery(qry);
2542

    
2543
            if (_rs.next()) {
2544
                String aux = getOracleSridFromCurrentRecord(_rs);
2545
                try {
2546
                                        resp = oracleSridToEpsgSrid(aux);
2547
                                } catch (Exception e) {
2548
                                        logger.error("Unknown oracle SRID: " + aux);
2549
                                }
2550
            } else {
2551
                    
2552
            }
2553
        } catch (Exception ex) {
2554
                logger.error("While getting Source Projection: " + ex.getMessage());
2555
        }
2556
        
2557
        if (resp != null) {
2558
                return resp;
2559
        } else {
2560
                return getDestProjection();
2561
        }
2562
        
2563
    }
2564

    
2565
    public String getDestProjection() {
2566
        return removePrefix(destProj);
2567
    }
2568

    
2569
    public void setDestProjection(String toEPSG) {
2570
        destProj = toEPSG;
2571
        try {
2572
                        destProjOracle = epsgSridToOracleSrid(destProj);
2573
                        isDestGeogCS = OracleSpatialUtils.getIsGCS(destProjOracle, true);
2574

    
2575
                } catch (Exception e) {
2576
                        logger.error("Unknown EPSG code: " + destProj);
2577
                        destProjOracle = oracleSRID;
2578
                        isDestGeogCS = false;
2579
                }
2580

    
2581
    }
2582

    
2583
    public String getDestProjectionOracleCode() {
2584
            return destProjOracle;
2585
    }
2586

    
2587
    public boolean getIsDestProjectionGeog() {
2588
            return isDestGeogCS;
2589
    }
2590

    
2591
    public String getTableProjectionOracleCode() {
2592
            return oracleSRID;
2593
    }
2594

    
2595
    public boolean canReproject(String toEPSGdestinyProjection) {
2596
        return false;
2597
    }
2598

    
2599
    /**
2600
     * Utility function. Says whether a given field name can be a user field name
2601
     * or not (for example, "ROWID" is not a valid one because it's a system
2602
     * reserved word).
2603
     *
2604
     * @param str proposed firld name
2605
     * @return whether it is valid or not for Oracle databases
2606
     */
2607
    private static boolean isOracleAllowedFieldname(String str) {
2608
        if (str.compareToIgnoreCase("rowid") == 0) {
2609
            return false;
2610
        }
2611

    
2612
        if (str.compareToIgnoreCase("rownum") == 0) {
2613
            return false;
2614
        }
2615

    
2616
        return true;
2617
    }
2618

    
2619
    public Hashtable getHashRelate() {
2620
        return hashRelate;
2621
    }
2622

    
2623
    public void setHashRelate(Hashtable m) {
2624
        hashRelate = m;
2625
    }
2626

    
2627
    public void setNumReg(int n) {
2628
        numReg = n;
2629
    }
2630

    
2631
    private int[] getRandomSample(int maxn_one_based, int n) {
2632
        int[] resp = new int[n];
2633

    
2634
        if (maxn_one_based <= n) {
2635
            resp = new int[maxn_one_based];
2636

    
2637
            for (int i = 0; i < maxn_one_based; i++) {
2638
                resp[i] = i;
2639
            }
2640
        }
2641
        else {
2642
            Random rnd = new Random();
2643

    
2644
            for (int i = 0; i < n; i++) {
2645
                resp[i] = rnd.nextInt(maxn_one_based);
2646
            }
2647
        }
2648

    
2649
        return resp;
2650
    }
2651

    
2652
    private String getRowIdRestrictionCondition(int nrecords) {
2653
        int[] zero_based_rows = getRandomSample(nrecords,
2654
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
2655
        String resp = "(";
2656
        Object aux = "";
2657
        ROWID riaux = null;
2658

    
2659
        for (int i = 0; i < zero_based_rows.length; i++) {
2660
            aux = rowToId.get(new Integer(zero_based_rows[i]));
2661
            riaux = (ROWID) aux;
2662
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
2663
        }
2664

    
2665
        resp = resp.substring(0, resp.length() - 4);
2666
        resp = resp + ")";
2667

    
2668
        return resp;
2669
    }
2670

    
2671
    private Rectangle2D getBoundingFromSample(int n_max) {
2672
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
2673
            " WHERE " + getRowIdRestrictionCondition(n_max);
2674
        STRUCT auxstr = null;
2675
        IGeometry theGeom = null;
2676
        Rectangle2D resp = null;
2677

    
2678
        try {
2679
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
2680
            ResultSet rs = st.executeQuery(_qry);
2681

    
2682
            if (rs.next()) {
2683
                auxstr = (STRUCT) rs.getObject(1);
2684

    
2685
                if (auxstr != null) {
2686
                    theGeom = getGeometryUsing(auxstr, use_geotools);
2687

    
2688
                    if (resp == null) {
2689
                        resp = theGeom.getBounds2D();
2690
                    }
2691
                    else {
2692
                        resp.add(theGeom.getBounds2D());
2693
                    }
2694
                }
2695

    
2696
                while (rs.next()) {
2697
                    auxstr = (STRUCT) rs.getObject(1);
2698

    
2699
                    if (auxstr != null) {
2700
                        theGeom = getGeometryUsing(auxstr, use_geotools);
2701

    
2702
                        if (resp == null) {
2703
                            resp = theGeom.getBounds2D();
2704
                        }
2705
                        else {
2706
                            resp.add(theGeom.getBounds2D());
2707
                        }
2708
                    }
2709
                }
2710

    
2711
                rs.close();
2712
                st.close();
2713
            }
2714
            else {
2715
                throw new SQLException("Empty resultset from this query: " +
2716
                    _qry);
2717
            }
2718
        }
2719
        catch (SQLException se) {
2720
                logger.error("While getting sample full extent: " +
2721
                se.getMessage());
2722
        }
2723

    
2724
        if (resp == null) {
2725
            logger.warn(
2726
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
2727

    
2728
            return new Rectangle2D.Double(-180, -90, 360, 180);
2729
        }
2730

    
2731
        return resp;
2732
    }
2733

    
2734
    /**
2735
     * Does what it says, puts the LinearRing in counter clock wise
2736
     * order.
2737
     * @param ls The ring to set.
2738
     * @param gf a GeometryFactory object
2739
     * @return A new ring in CCW order.
2740
     *
2741
     */
2742
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
2743
        Coordinate[] cc = ls.getCoordinates();
2744

    
2745
        if (CGAlgorithms.isCCW(cc)) {
2746
            return gf.createLinearRing(cc);
2747
        }
2748
        else {
2749
            if (ls instanceof LinearRing) {
2750
                return reverseRing((LinearRing) ls, gf);
2751
            }
2752
            else {
2753
                return reverseLineString(ls, gf);
2754
            }
2755
        }
2756
    }
2757

    
2758
    /**
2759
     * Does what it says, reverses the order of the Coordinates in the ring.
2760
     * @param lr The ring to reverse.
2761
     * @return A new ring with the reversed Coordinates.
2762
     *
2763
     */
2764
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
2765
        int numPoints = lr.getNumPoints() - 1;
2766
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
2767

    
2768
        for (int t = numPoints; t >= 0; t--) {
2769
            newCoords[t] = lr.getCoordinateN(numPoints - t);
2770
        }
2771

    
2772
        return gf.createLinearRing(newCoords);
2773
    }
2774

    
2775
    /**
2776
     * Does what it says, reverses the order of the Coordinates in the linestring.
2777
     * @param ls The ls to reverse.
2778
     * @param gf a GeometryFactory object
2779
     * @return A new ls with the reversed Coordinates.
2780
     *
2781
     */
2782
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
2783
        int numPoints = ls.getNumPoints() - 1;
2784
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
2785

    
2786
        for (int t = numPoints; t >= 0; t--) {
2787
            newCoords[t] = ls.getCoordinateN(numPoints - t);
2788
        }
2789

    
2790
        return gf.createLinearRing(newCoords);
2791
    }
2792

    
2793
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
2794
        if (ge instanceof MultiPolygon) {
2795
            MultiPolygon mp = (MultiPolygon) ge;
2796
            int size = ge.getNumGeometries();
2797
            Polygon[] pols = new Polygon[size];
2798

    
2799
            for (int i = 0; i < size; i++)
2800
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
2801
                        gf);
2802

    
2803
            return new MultiPolygon(pols, gf);
2804
        }
2805
        else {
2806
            if (ge instanceof Polygon) {
2807
                Polygon p = (Polygon) ge;
2808
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
2809
                int nholes = p.getNumInteriorRing();
2810

    
2811
                if (nholes > 0) {
2812
                    LinearRing[] holes = new LinearRing[nholes];
2813

    
2814
                    for (int i = 0; i < nholes; i++) {
2815
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
2816
                    }
2817

    
2818
                    return gf.createPolygon(exterior, holes);
2819
                }
2820
                else {
2821
                    return gf.createPolygon(exterior, null);
2822
                }
2823
            }
2824
            else {
2825
                return ge;
2826
            }
2827
        }
2828
    }
2829

    
2830
    /**
2831
     * Converts from IGeometry to STRUCT
2832
     *
2833
     * @param ig the geometry to convert
2834
     * @param _forced_type forced type to use
2835
     * @param _conn connection
2836
     * @param _o_srid  SRS (oracle code)
2837
     * @param withSrid whether this STRUCT has a non-NULL SRS
2838
     * @param agu_bien whether or not to check the correctness of the holes
2839
     * @param _isGeoCS whether the SRS is geodetic or not
2840
     * @return the generated STRUCT
2841
     */
2842
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
2843
        IConnection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
2844
        boolean _isGeoCS) {
2845
        if (ig instanceof FGeometryCollection) {
2846
            FGeometryCollection coll = (FGeometryCollection) ig;
2847

    
2848
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
2849
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
2850

    
2851
            // logger.error("Collections no soportadas por ahora.");
2852
            // return null;
2853
        }
2854
        else {
2855
            Shape shp = ig.getInternalShape();
2856

    
2857
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
2858
                agu_bien, false, _isGeoCS);
2859
        }
2860
    }
2861

    
2862
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
2863
        boolean agu_bien, boolean isView) {
2864

    
2865
            if (shp == null) return null;
2866
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
2867
            agu_bien, isView, isGeogCS);
2868
    }
2869

    
2870
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
2871
        IConnection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
2872
        boolean isView, boolean _isGeoCS) {
2873
        int _srid = -1;
2874

    
2875
        if ((o_srid != null) && (o_srid.length() > 0)) {
2876
            _srid = Integer.parseInt(o_srid);
2877
        }
2878

    
2879
        if (shp == null) {
2880
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
2881

    
2882
            return null;
2883
        }
2884

    
2885
        if (shp instanceof Rectangle2D) {
2886
            return OracleSpatialUtils.rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
2887
                _isGeoCS, o_srid, _conn);
2888
        }
2889

    
2890
        try {
2891
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
2892
                    _srid, agu_bien, hasSrid, _isGeoCS, forced_type);
2893

    
2894
            return the_struct;
2895
        }
2896
        catch (SQLException ex) {
2897
            logger.error("While creating STRUCT: " + ex.getMessage());
2898

    
2899
            return null;
2900
        }
2901
    }
2902

    
2903
    // -------------------------- not ready yet ----------------
2904
    public int getRowIndexByFID(IFeature _fid) {
2905
        if (isNotAvailableYet) {
2906
            return -1;
2907
        }
2908
        else {
2909
            return super.getRowIndexByFID(_fid);
2910
        }
2911
    }
2912

    
2913
    public int getShapeCount() throws ReadDriverException { 
2914
        if (isNotAvailableYet) {
2915
            return 0;
2916
        }
2917
        else {
2918
            return numReg;
2919
        }
2920
    }
2921

    
2922
    public void setNotAvailableYet(boolean nav) {
2923
        isNotAvailableYet = nav;
2924
    }
2925

    
2926
    // -------------------------------------------------------
2927
    // -------------------------------------------------------
2928
    public String[] getTableNames(IConnection conn, String catalog)
2929
        throws DBException {
2930
        try{
2931
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
2932
        String[] types = { "TABLE", "VIEW" };
2933
        // String[] types = { "VIEW" };
2934

    
2935
        ResultSet rs = null;
2936
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
2937
                    ALL_ORACLE_GEOMETADATA_VIEW, types), ((ConnectionJDBC)conn).getConnection());
2938
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
2939
//                          ORACLE_GEOMETADATA_VIEW, types);
2940
        TreeMap ret = new TreeMap();
2941

    
2942
        while (rs.next()) {
2943
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
2944
            ret.put(nomCompleto, nomCompleto);
2945
        }
2946

    
2947
        return (String[]) ret.keySet().toArray(new String[0]);
2948
        }catch (SQLException e) {
2949
                        throw new DBException(e);
2950
                }
2951
    }
2952

    
2953
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
2954
        throws SQLException {
2955
        String tablename = "";
2956

    
2957
        if (res.next()) {
2958
            tablename = res.getString("TABLE_NAME");
2959

    
2960
            // debug
2961
            writeMetaTableToLog(con, tablename);
2962

    
2963
            Statement __st = con.createStatement();
2964

    
2965
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
2966
                "union (select VIEW_NAME from USER_VIEWS)) " +
2967
                "intersect (select TABLE_NAME from " + tablename + ")";
2968
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
2969
            ResultSet rs = __st.executeQuery(sql);
2970

    
2971
            return rs;
2972
        }
2973
        else {
2974
            logger.error("Error while getting geometry tables.");
2975

    
2976
            return null;
2977
        }
2978
    }
2979

    
2980
    private void writeMetaTableToLog(Connection con, String tname) {
2981

    
2982
            logger.debug("======================================================");
2983
            logger.debug("=     " + ALL_ORACLE_GEOMETADATA_VIEW + "  (1 EVERY 10 TABLES) ========");
2984
            logger.debug("======================================================");
2985

    
2986
            try {
2987
            Statement _stmt = con.createStatement();
2988
            String sql = "SELECT * FROM " + tname;
2989
            ResultSet res = _stmt.executeQuery(sql);
2990
            
2991
            int count = 0;
2992
            while (res.next()) {
2993
                    
2994
                    if ((count % 10) == 0) {
2995
                        logger.debug(
2996
                                        "OWNER: " + res.getString("OWNER")
2997
                                        + ", TABLE_NAME: " + res.getString("TABLE_NAME")
2998
                                        + ", COLUMN_NAME: " + res.getString("COLUMN_NAME")
2999
                                        + ", SRID: " + res.getString("SRID"));
3000
                        ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
3001
                        String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
3002
                        logger.debug("DIMINFO: " + dinfo);
3003
                        logger.debug("=========");
3004
                    }
3005
                    count++;
3006
                    
3007
            }
3008
            } catch (Throwable th) {
3009

    
3010
            }
3011
        }
3012

    
3013
        /**
3014
     * Gets the field names that can act as row id (always ROWID)
3015
     */
3016
    public String[] getIdFieldsCandidates(IConnection conn, String table_name)
3017
        throws DBException {
3018
            try{
3019
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
3020
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3021
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
3022
            _rs.close();
3023
            _st.close();
3024

    
3025
            String[] resp = { "ROWID" };
3026
        return resp;
3027
            }catch (SQLException e) {
3028
                        throw new DBException(e);
3029
                }
3030
    }
3031

    
3032
    /**
3033
     * Gets the field names that can act as geometry fields
3034
     * (queries the user's geographic metadata).
3035
     */
3036
    public String[] getGeometryFieldsCandidates(IConnection conn,
3037
        String table_name) throws DBException {
3038
            try{
3039
        Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3040
        String[] tokens = table_name.split("\\u002E", 2);
3041
        String qry;
3042
        if (tokens.length > 1)
3043
        {
3044
                qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
3045
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
3046
            tokens[1] + "'";
3047
        }
3048
        else
3049
        {
3050
                qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
3051
            " where TABLE_NAME = " + "'" + table_name + "'";
3052

    
3053
        }
3054
        ResultSet _rs = _st.executeQuery(qry);
3055

    
3056
        ArrayList aux = new ArrayList();
3057

    
3058
        while (_rs.next()) {
3059
            String _geo = _rs.getString("COLUMN_NAME");
3060
            aux.add(_geo);
3061
        }
3062

    
3063
        _rs.close();
3064
        _st.close();
3065

    
3066
        String[] resp = (String[]) aux.toArray(new String[0]);
3067

    
3068
        return checkIndexes(conn, resp, table_name);
3069
            }catch (SQLException e) {
3070
                        throw new DBException(e);
3071
                }
3072
    }
3073

    
3074
    private String[] checkIndexes(IConnection c, String[] all, String long_table_name) throws DBException {
3075

    
3076
            ArrayList good_ones = new ArrayList();
3077
            try{
3078
            String t = long_table_name;
3079
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
3080

    
3081
            for (int i=0; i<all.length; i++) {
3082

    
3083
                String qry = "SELECT SRID, DIMINFO FROM " + ALL_ORACLE_GEOMETADATA_VIEW +
3084
            " WHERE TABLE_NAME = " + "'" + t.toUpperCase() +
3085
            "' AND COLUMN_NAME = '" + all[i].toUpperCase() + "'";
3086

    
3087
                Statement _st = ((ConnectionJDBC)c).getConnection().createStatement();
3088
                ResultSet _rs = _st.executeQuery(qry);
3089
                if (_rs.next()) {
3090
                        String _srid = toString((BigDecimal) _rs.getObject(1));
3091
                        ARRAY diminfo = (ARRAY) _rs.getObject(2);
3092
                        int len = diminfo.getOracleArray().length;
3093
                        if (allowsGeoQueries(((ConnectionJDBC)c).getConnection(), long_table_name, all[i], _srid, len)) {
3094
                                good_ones.add(all[i]);
3095
                        }
3096
                }
3097
                _rs.close();
3098
                _st.close();
3099
            }
3100

    
3101
            if (good_ones.size() == 0) {
3102
                    throw new SQLException("no_indexes_on_declared_geo_fields");
3103
            }
3104
            }catch (SQLException e) {
3105
                        throw new DBException(e);
3106
                }
3107
            return (String[]) good_ones.toArray(new String[0]);
3108
    }
3109

    
3110
    private String toString(BigDecimal number) {
3111

    
3112
            if (number == null) return "NULL";
3113
            return "" + number.intValue();
3114
        }
3115

    
3116
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
3117
            String p = getPointConstructor(dims, _srid);
3118
            String qry = "";
3119
            qry = "SELECT * FROM " + _t.toUpperCase()
3120
            + " WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'"
3121
            + " AND ROWNUM = 1";
3122

    
3123
            try {
3124
                        Statement _st = c.createStatement();
3125
                        ResultSet _rs = _st.executeQuery(qry);
3126
                        _rs.close();
3127
                        _st.close();
3128
                } catch (Exception ex) {
3129
                        return false;
3130
                }
3131
                return true;
3132
        }
3133

    
3134
        private String getPointConstructor(int dims, String _srid) {
3135

    
3136
                String coord = "";
3137
                for (int i=0; i<dims; i++) coord = coord + "0, ";
3138
                coord = coord.substring(0, coord.length() - 2);
3139

    
3140
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
3141
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
3142
        }
3143

    
3144
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
3145

    
3146
            if (l == null) return false;
3147
            if (str == null) return false;
3148

    
3149
            String item = "";
3150
            for (int i=0; i<l.size(); i++) {
3151
                    if (l.get(i) instanceof String) {
3152
                            item = (String) l.get(i);
3153
                            if (item.compareToIgnoreCase(str) == 0) return true;
3154
                    }
3155
            }
3156
            return false;
3157
    }
3158

    
3159
        /**
3160
     * Utility method to check if a given table is empty.
3161
     */
3162
    public boolean isEmptyTable(Connection conn, String tableName) {
3163
        boolean res = true;
3164

    
3165
        try {
3166
            Statement st = conn.createStatement();
3167
            ResultSet rs = null;
3168
            rs = st.executeQuery("select * from " + tableName +
3169
                    " where rownum = 1");
3170
            res = !rs.next();
3171
            rs.close();
3172
            st.close();
3173
        }
3174
        catch (Exception ex) {
3175
            res = true;
3176
        }
3177

    
3178
        return res;
3179
    }
3180

    
3181
    /**
3182
     * Gets all the fields from a table name.
3183
     */
3184
    public String[] getAllFields(IConnection conn, String table_name)
3185
        throws DBException {
3186
            try{
3187
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3188
        ResultSet rs = st.executeQuery("select * from " + table_name +
3189
                " where rownum = 1");
3190
        ResultSetMetaData rsmd = rs.getMetaData();
3191
        String[] ret = new String[rsmd.getColumnCount()];
3192

    
3193
        for (int i = 0; i < ret.length; i++) {
3194
            ret[i] = rsmd.getColumnName(i + 1);
3195
        }
3196

    
3197
        rs.close();
3198
        st.close();
3199

    
3200
        return ret;
3201
            }catch (SQLException e) {
3202
                        throw new DBException(e);
3203
                }
3204
    }
3205

    
3206
    /**
3207
     * Gets all field type names from a table.
3208
     */
3209
    public String[] getAllFieldTypeNames(IConnection conn, String table_name)
3210
        throws DBException {
3211
            try{
3212
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3213
        ResultSet rs = st.executeQuery("select * from " + table_name +
3214
                " where rownum = 1");
3215
        ResultSetMetaData rsmd = rs.getMetaData();
3216
        String[] ret = new String[rsmd.getColumnCount()];
3217

    
3218
        for (int i = 0; i < ret.length; i++) {
3219
            if (rsmd.getColumnType(i + 1) == Types.NUMERIC) {
3220
                    int scale = rsmd.getScale(i+1);
3221
                    if (scale >= 0) {
3222
                        String prec_dec = " (" + rsmd.getPrecision(i+1) + ", " + scale + ")";  
3223
                        ret[i] = rsmd.getColumnTypeName(i + 1) + prec_dec;
3224
                    } else {
3225
                            ret[i] = rsmd.getColumnTypeName(i + 1);
3226
                    }
3227
            } else {
3228
                ret[i] = rsmd.getColumnTypeName(i + 1);
3229
            }
3230
        }
3231

    
3232
        rs.close();
3233
        st.close();
3234

    
3235
        close();
3236

    
3237
        return ret;
3238
            }catch (SQLException e) {
3239
                        throw new DBException(e);
3240
                }
3241
    }
3242

    
3243
    /**
3244
     * Gets Oracle's specific connection string for the given parameters.
3245
     */
3246
    public String getConnectionString(String host, String port, String dbname,
3247
        String user, String pw) {
3248
        String _pw = pw;
3249

    
3250
        if (_pw == null) {
3251
            _pw = "null";
3252
        }
3253

    
3254
        String fullstr = CONN_STR_BEGIN;
3255
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
3256
        fullstr = fullstr + "@" + host.toLowerCase();
3257
        fullstr = fullstr + ":" + port;
3258
        fullstr = fullstr + ":" + dbname.toLowerCase();
3259

    
3260
        return fullstr;
3261
    }
3262

    
3263
    /**
3264
     * Gets the Pracle geometries writer associated with this driver.
3265
     */
3266
    public IWriter getWriter() {
3267
        // on(VectorialEditableDBAdapter.java:290)
3268
        if (writer == null) {
3269

    
3270
                long count = 0;
3271
                        try {
3272
                                count = getRowCount();
3273
                        } catch (ReadDriverException e1) {
3274
                                logger.error("While getting row count: " + e1.getMessage());
3275
                        }
3276
                
3277
            writer = new OracleSpatialWriter(count);
3278
            writer.setDriver(this);
3279
            writer.setLyrShapeType(getShapeType());
3280
            writer.setGeoCS(isGeogCS());
3281
            writer.setGeoColName(geoColName);
3282
            writer.setSRID(oracleSRID);
3283

    
3284
            try {
3285
                    DBLayerDefinition db_lyr_def = getLyrDef();
3286
                    if (db_lyr_def == null) {
3287
                            logger.warn("Found a null DB layer definition, method initialize of OracleWriter not called.");
3288
                    } else {
3289
                            writer.initialize(getLyrDef());
3290
                    }
3291
                
3292
            } catch (InitializeWriterException e) {
3293
                logger.error("While initializing OS Writer: " + e.getMessage(), e);
3294
            }
3295

    
3296
            writer.setStoreWithSrid(isTableHasSrid());
3297
        }
3298

    
3299
        return writer;
3300
    }
3301

    
3302
    /**
3303
     * Tells whether the SRS is geodetic or not-
3304
     * @return whether the SRS is geodetic or not
3305
     */
3306
    public boolean isGeogCS() {
3307
        return isGeogCS;
3308
    }
3309

    
3310
    /**
3311
     * Adds a row id to the inner set od IDs.
3312
     * @param id
3313
     */
3314
    public void addRow(String id) {
3315
        Value aux = ValueFactory.createValue(id);
3316
        Integer intobj = new Integer(numReg);
3317
        hashRelate.put(aux, intobj);
3318
        rowToId.put(intobj, id);
3319

    
3320
        numReg++;
3321
    }
3322

    
3323
    /**
3324
     * Removes a row id to the inner set od IDs.
3325
     * @param id
3326
     */
3327
    public void deleteRow(String id) {
3328
        Value aux = ValueFactory.createValue(id);
3329
        Integer intobj = (Integer) hashRelate.get(aux);
3330
        hashRelate.remove(aux);
3331
        rowToId.remove(intobj);
3332

    
3333
        numReg--;
3334
    }
3335

    
3336
    private String getStandardSelectExpression() {
3337

    
3338
                String resp = "";
3339

    
3340
                String[] flds = getLyrDef().getFieldNames();
3341
                int size = flds.length;
3342

    
3343
                for (int i = 0; i < size; i++) {
3344
                        if (i > 0) {
3345
                                resp = resp + "c.\"" + flds[i] + "\", ";
3346
                        } else {
3347
                                resp = resp + flds[i] + ", ";
3348
                        }
3349
                }
3350

    
3351
                resp = resp.substring(0, resp.length() - 2);
3352
                return resp;
3353
        }
3354

    
3355
    /**
3356
         * Allows the method to decide what to do with the geometry field name
3357
         * (remove/add it from the user selected fields).
3358
         * 
3359
         * @param flds
3360
         * @param geof
3361
         * @return the possibly modified field names
3362
         */
3363
    public String[] manageGeometryField(String[] flds, String geof) {
3364
        return addEndIfNotContained(flds, geof);
3365
    }
3366

    
3367
    /**
3368
     * Allows the method to decide what to do with the ID field name
3369
     * (remove/add it from the user selected fields).
3370
     *
3371
     * @param flds
3372
     * @param idf
3373
     * @return the possibly modified field names
3374
     */
3375
    public String[] manageIdField(String[] flds, String idf) {
3376
        return addStartIfNotContained(flds, idf);
3377
    }
3378

    
3379
    private String[] addEndIfNotContained(String[] arr, String item) {
3380
        if (contains(arr, item)) {
3381
            return arr;
3382
        }
3383
        else {
3384
            int size = arr.length;
3385
            String[] resp = new String[size + 1];
3386

    
3387
            for (int i = 0; i < size; i++) {
3388
                resp[i] = arr[i];
3389
            }
3390

    
3391
            resp[size] = item;
3392

    
3393
            return resp;
3394
        }
3395
    }
3396

    
3397
    private String[] addStartIfNotContained(String[] arr, String item) {
3398
        if (contains(arr, item)) {
3399
            return arr;
3400
        }
3401
        else {
3402
            int size = arr.length;
3403
            String[] resp = new String[size + 1];
3404

    
3405
            for (int i = 1; i <= size; i++) {
3406
                resp[i] = arr[i];
3407
            }
3408

    
3409
            resp[0] = item;
3410

    
3411
            return resp;
3412
        }
3413
    }
3414

    
3415
    private boolean contains(String[] arr, String item) {
3416
        for (int i = 0; i < arr.length; i++) {
3417
            if (arr[i].compareTo(item) == 0) {
3418
                return true;
3419
            }
3420
        }
3421

    
3422
        return false;
3423
    }
3424

    
3425
    /**
3426
     * This method is called when the user removes the layer from the view.
3427
     * If the IDs were being loaded, the driver will check this field and will
3428
     * let the thread 'die' quietly.
3429
     *
3430
     */
3431
    public void remove() {
3432
        cancelIDLoad = true;
3433
    }
3434

    
3435
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
3436
            // if (!isgeodetic) return true;
3437
            if ((ext.getMinX() > -179.9) || (ext.getMinX() < -180.1)) return true;
3438
            if ((ext.getMinY() > -89.9) || (ext.getMinY() < -90.1)) return true;
3439
            if ((ext.getWidth() < 359.9) || (ext.getWidth() > 360.1)) return true;
3440
            if ((ext.getHeight() < 179.9) || (ext.getHeight() > 180.1)) return true;
3441
            return false;
3442
    }
3443

    
3444
    private Rectangle2D getFastEstimatedExtent(
3445
                    String tname,
3446
                    String gfield,
3447
                    IConnection c,
3448
                    int sample_size,
3449
                    double enlargement,
3450
                    boolean is_geo) {
3451

    
3452
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
3453
            Rectangle2D resp_aux = null;
3454
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
3455
            ResultSet _rs = null;
3456

    
3457
            try {
3458
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
3459
                        _rs = _st.executeQuery();
3460
                        while (_rs.next()) {
3461
                                STRUCT aux = (STRUCT) _rs.getObject(1);
3462
                                IGeometry ig = getGeometryUsing(aux, false);
3463

    
3464
                                if (ig == null) continue;
3465

    
3466
                                if (resp_aux == null) {
3467
                                        resp_aux = ig.getBounds2D();
3468
                                } else {
3469
                                        resp_aux.add(ig.getBounds2D());
3470
                                }
3471

    
3472
                        }
3473
                } catch (Exception ex) {
3474
                        logger.error("While getting random sample: " + ex.getMessage());
3475
                }
3476

    
3477
                if (resp_aux == null) {
3478
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
3479
                        return world;
3480
                }
3481
                
3482
                double w = resp_aux.getWidth();
3483
                double h = resp_aux.getHeight();
3484
                double x = resp_aux.getMinX();
3485
                double y = resp_aux.getMinY();
3486

    
3487
                // enlarge n times:
3488
                double newx = x - (0.5 * (enlargement - 1)) * w;
3489
                double newy = y - (0.5 * (enlargement - 1)) * h;
3490
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
3491
                                enlargement * w,
3492
                                enlargement * h);
3493

    
3494
                if (is_geo) {
3495
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
3496
                        logger.debug("FAST BB: " + resp_aux.toString());
3497
                        return resp_aux;
3498
                } else {
3499
                        logger.debug("FAST BB: " + resp_aux_large.toString());
3500
                        return resp_aux_large;
3501
                }
3502

    
3503
    }
3504

    
3505
    private Rectangle2D getEstimatedExtent(
3506
                    String tname,
3507
                    String gfield,
3508
                    IConnection c,
3509
                    int sample_size,
3510
                    double enlargement,
3511
                    boolean is_geo) {
3512

    
3513
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
3514
            
3515
            if (numReg == 0) {
3516
                    logger.warn("numReg is 0, returned worlld bbox in getEstimatedExtent(...).");
3517
                    return world;
3518
            }
3519

    
3520
            ArrayList ids = new ArrayList();
3521
            int _rnd_index = 0;
3522
            ROWID _id = null;
3523
            Random rnd = new Random(System.currentTimeMillis());
3524

    
3525
            for (int i=0; i<sample_size; i++) {
3526
                    _rnd_index = rnd.nextInt(numReg);
3527
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
3528
                    ids.add(_id.stringValue());
3529
            }
3530

    
3531
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
3532
            for (int i=0; i<ids.size(); i++) {
3533
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR ";
3534
            }
3535
            qry = qry.substring(0, qry.length() - 4) + ")";
3536

    
3537
            Rectangle2D resp_aux = null;
3538
            ResultSet _rs = null;
3539

    
3540
            try {
3541
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
3542
                        _rs = _st.executeQuery();
3543
                        while (_rs.next()) {
3544
                                STRUCT aux = (STRUCT) _rs.getObject(1);
3545
                                IGeometry ig = getGeometryUsing(aux, false);
3546

    
3547
                                if (ig == null) continue;
3548

    
3549
                                if (resp_aux == null) {
3550
                                        resp_aux = ig.getBounds2D();
3551
                                } else {
3552
                                        resp_aux.add(ig.getBounds2D());
3553
                                }
3554

    
3555
                        }
3556
                } catch (Exception ex) {
3557
                        logger.error("While getting random sample: " + ex.getMessage());
3558
                }
3559

    
3560
                if (resp_aux == null) {
3561
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
3562
                        return world;
3563
                }
3564
                
3565
                double w = resp_aux.getWidth();
3566
                double h = resp_aux.getHeight();
3567
                double x = resp_aux.getMinX();
3568
                double y = resp_aux.getMinY();
3569

    
3570
                // enlarge 10 times:
3571
                double newx = x - (0.5 * (enlargement - 1)) * w;
3572
                double newy = y - (0.5 * (enlargement - 1)) * h;
3573
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
3574
                                enlargement * w,
3575
                                enlargement * h);
3576

    
3577
                if (is_geo) {
3578
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
3579
                        logger.debug("ESTIMATED BB: " + resp_aux.toString());
3580
                        return resp_aux;
3581
                } else {
3582
                        logger.debug("ESTIMATED BB: " + resp_aux_large.toString());
3583
                        return resp_aux_large;
3584
                }
3585

    
3586
    }
3587

    
3588
    public void setUserName(String u) {
3589
            userName = u;
3590
    }
3591

    
3592
    public String getUserName() {
3593
            return userName;
3594
    }
3595

    
3596
    public static final int JGeometry_GTYPE_COLLECTION = 4;
3597
    public static final int JGeometry_GTYPE_CURVE = 2;
3598
    public static final int JGeometry_GTYPE_MULTICURVE = 6;
3599
    public static final int JGeometry_GTYPE_MULTIPOINT = 5;
3600
    public static final int JGeometry_GTYPE_MULTIPOLYGON = 7;
3601
    public static final int JGeometry_GTYPE_POINT = 1;
3602
    public static final int JGeometry_GTYPE_POLYGON = 3;
3603
        
3604

    
3605
    // ------------------------------
3606
    
3607
    public void setXMLEntity(XMLEntity xml) throws XMLException {
3608
            
3609
            super.setXMLEntity(xml);
3610
            workingAreaInTablesCS = workingArea;
3611
            
3612
            try {
3613
                    int[] ftypes = xml.getIntArrayProperty("fieldTypes");
3614
                    setLyrDefFieldTypes(ftypes);
3615
            } catch (Exception ex) {
3616
                    logger.warn("Apparently, an old GVP file has been opened," +
3617
                                    " field type values are not accurate after this point.");
3618
            }
3619
            
3620
    }
3621
    
3622
    public XMLEntity getXMLEntity() {
3623
                // ---------------------
3624

    
3625
                XMLEntity xml = new XMLEntity();
3626
                xml.putProperty("className", getClass().getName());
3627

    
3628
                xml.putProperty("catalog", getLyrDef().getCatalogName());
3629

    
3630
                int aux = userName.indexOf("@");
3631
                if (aux != -1)
3632
                        userName = userName.substring(0, aux);
3633
                xml.putProperty("username", userName);
3634

    
3635
                xml.putProperty("driverclass", ORACLE_JAR_FILE_NAME);
3636

    
3637
                xml.putProperty("tablename", getTableName());
3638
                xml.putProperty("fields", lyrDef.getFieldNames());
3639
                xml.putProperty("fieldTypes", getLyrDefFieldTypes());
3640
                xml.putProperty("FID", lyrDef.getFieldID());
3641
                xml.putProperty("THE_GEOM", lyrDef.getFieldGeometry());
3642
                xml.putProperty("whereclause", getWhereClause());
3643
                xml.putProperty("SRID", lyrDef.getSRID_EPSG());
3644

    
3645
                xml.putProperty("host", host);
3646
                xml.putProperty("port", port);
3647
                xml.putProperty("dbName", dbName);
3648
                xml.putProperty("connName", connName);
3649

    
3650
                if (workingAreaInTablesCS != null) {
3651
                        xml.putProperty("minXworkArea", workingAreaInTablesCS.getMinX());
3652
                        xml.putProperty("minYworkArea", workingAreaInTablesCS.getMinY());
3653
                        xml.putProperty("HworkArea", workingAreaInTablesCS.getHeight());
3654
                        xml.putProperty("WworkArea", workingAreaInTablesCS.getWidth());
3655
                }
3656

    
3657
                return xml;
3658
        }
3659
    
3660
    private int[] getLyrDefFieldTypes() {
3661
            FieldDescription[] fd = lyrDef.getFieldsDesc();
3662
            int sz = fd.length;
3663
            int[] resp = new int[sz];
3664
            for (int i=0; i<sz; i++) resp[i] = fd[i].getFieldType();
3665
                return resp;
3666
        }
3667
    
3668
    private void setLyrDefFieldTypes(int[] tt) {
3669
            FieldDescription[] fd = lyrDef.getFieldsDesc();
3670
            
3671
            int sz_fd = fd.length;
3672
            int sz_tt = tt.length;
3673
            int sz = sz_tt;
3674
            
3675
            if (sz_tt != sz_fd) {
3676
                    logger.error("Field count does not match. lyrDef has " + sz_fd + " fields," +
3677
                                    " but this method was called with " + sz_tt + " items (?)");
3678
                    sz = Math.min(sz_fd, sz_tt);
3679
            }
3680
            
3681
            for (int i=0; i<sz; i++) lyrDef.getFieldsDesc()[i].setFieldType(tt[i]);
3682
    }
3683

    
3684
        public String[] getTableFields(IConnection conex, String table) throws DBException {
3685
                try{
3686
                Statement st = ((ConnectionJDBC)conex).getConnection().createStatement();
3687
        // ResultSet rs = dbmd.getTables(catalog, null, dbLayerDefinition.getTable(), null);
3688
                ResultSet rs = st.executeQuery("select * from " + table + " LIMIT 1");
3689
                ResultSetMetaData rsmd = rs.getMetaData();
3690

    
3691
                String[] ret = new String[rsmd.getColumnCount()];
3692

    
3693
                for (int i = 0; i < ret.length; i++) {
3694
                        ret[i] = rsmd.getColumnName(i+1);
3695
                }
3696

    
3697
                return ret;
3698
                }catch (SQLException e) {
3699
                        throw new DBException(e);
3700
                }
3701
        }
3702

    
3703
    // Overwritten to keep old behavior: returns "schema.table_name" if
3704
    // schema is not current user
3705
        public String getTableName() {
3706
            return fullTableName; 
3707
        }
3708
        
3709
    private Timestamp flexibleTimeStamp(String s) {
3710
            
3711
            String aux = s.replace('-', ' ');
3712
            aux = aux.replace(':', ' ');
3713
            aux = aux.replace('.', ' ');
3714
            // sample: 2007 12 31 23 59 59 9999
3715
            String[] parts = aux.trim().split(" ");
3716
            
3717
            int year;
3718
            int month;
3719
            int day;
3720
            int hour;
3721
            int minute;
3722
            int second;
3723
            int a_nanos;
3724

    
3725
            if (parts.length == 7) {
3726

    
3727
                    try {
3728

    
3729
                            year = Integer.parseInt(parts[0]) - 1900;
3730
                            month = Integer.parseInt(parts[1]) - 1;
3731
                            day = Integer.parseInt(parts[2]);
3732
                            hour = Integer.parseInt(parts[3]);
3733
                            minute = Integer.parseInt(parts[4]);
3734
                            second = Integer.parseInt(parts[5]);
3735
                            a_nanos = Integer.parseInt(parts[6]);
3736
                            
3737
                    } catch (Exception ex) {
3738
                        logger.debug("Bad time stamp: " + ex.getMessage());
3739
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3740
                    }
3741

    
3742
            } else {
3743
                    
3744
                if (parts.length == 6) {
3745
                        
3746
                        try {
3747
                            year = Integer.parseInt(parts[0]) - 1900;
3748
                            month = Integer.parseInt(parts[1]) - 1;
3749
                            day = Integer.parseInt(parts[2]);
3750
                            hour = Integer.parseInt(parts[3]);
3751
                            minute = Integer.parseInt(parts[4]);
3752
                            second = Integer.parseInt(parts[5]);
3753
                            a_nanos = 0;
3754
                            
3755
                        } catch (Exception ex) {
3756
                                
3757
                            logger.debug("Bad time stamp: " + ex.getMessage());
3758
                            return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3759
                        }
3760

    
3761
                } else {
3762
                        
3763
                        logger.debug("Bad time stamp: " + s);
3764
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3765
                        
3766
                }
3767
            }
3768
            
3769
            return new Timestamp(year, month, day, hour, minute, second, a_nanos);
3770
    }
3771

    
3772
        public void write(DataWare arg0) throws WriteDriverException, ReadDriverException {
3773
        }
3774
        
3775
        public static String removePrefix(String str) {
3776
                
3777
                int colon_ind = str.indexOf(":");
3778
                if (colon_ind != -1) {
3779
                        return str.substring(colon_ind + 1);
3780
                } else {
3781
                        return str;
3782
                }
3783
        }
3784

    
3785
    
3786
            
3787
            private class AnEmptyFeatureIterator implements IFeatureIterator {
3788
                public boolean hasNext() throws ReadDriverException { return false; }
3789
                public IFeature next() throws ReadDriverException { return null; }
3790
                public void closeIterator() throws ReadDriverException { }                
3791
        }
3792
            
3793
        private Value objToValue(Object obj, int idFld) {
3794
                
3795
            if (obj == null) {
3796
                    return ValueFactory.createNullValue();
3797
            } else {
3798
                    
3799
                    String objToString = obj.toString();
3800

    
3801
                if (obj instanceof String) {
3802
                    objToString = (String) obj;
3803
                    return ValueFactory.createValue(objToString);
3804
                } else {
3805
                    if (obj instanceof ROWID) {
3806
                        objToString = ((ROWID) obj).stringValue();
3807
                        return ValueFactory.createValue(objToString);
3808
                    } else {
3809
                        if (obj instanceof STRUCT) {
3810
                            objToString = "STRUCT";
3811
                            return ValueFactory.createValue(objToString);
3812
                        } else {
3813
                            if (obj instanceof TIMESTAMP) {
3814
                                    TIMESTAMP aux = (TIMESTAMP) obj;
3815
                                objToString = aux.stringValue();
3816
                                Timestamp ts = flexibleTimeStamp(objToString);
3817
                                return ValueFactory.createValue(ts);
3818

    
3819
                            } else {
3820

    
3821
                                    // last try
3822
                                    int _type = -1;
3823
                                                            try {
3824
                                                                    _type = getFieldType(idFld);
3825
                                        if (_type == Types.DATE) {
3826
                                                objToString = objToString.replace('-', '/');
3827
                                        }
3828
                                        return ValueFactory.createValueByType(objToString, _type);
3829
                                } catch (Exception ex) {
3830
                                        logger.debug("Failed to create Value: _type = "
3831
                                                        + _type + ", objToString = " + objToString);
3832
                                        return ValueFactory.createNullValue();
3833
                                }
3834
                                
3835
                            }
3836
                        }
3837
                    }
3838
                }
3839
            }
3840
        }
3841

    
3842
        public Value[] getAttributes(ResultSet rs, boolean use_main_metadata) {
3843
            Value[] res = null;
3844

    
3845
            int fcount = 0;
3846

    
3847
            try {
3848
                    if (use_main_metadata) {
3849
                            fcount = metaData.getColumnCount();
3850
                    } else {
3851
                            fcount = rs.getMetaData().getColumnCount();
3852
                    }
3853
                
3854
                res = new Value[fcount];
3855

    
3856
                for (int i = 0; i < fcount; i++) {
3857
                    Object obj = rs.getObject(i + 1);
3858
                    res[i] = objToValue(obj, i);
3859
                }
3860

    
3861
            } catch (Exception se) {
3862
                    logger.error("While getting resultset attribute values: " + se.getMessage());
3863
                    res = new Value[fcount];
3864
                    for (int i=0; i<fcount; i++) res[i] = ValueFactory.createNullValue();
3865
            }
3866

    
3867
            return res;
3868
        }            
3869
        
3870
        public boolean canWriteGeometry(int gvSIGgeometryType) {
3871
                if (writer == null) {
3872
                        return true;
3873
                } else {
3874
                        return writer.canWriteGeometry(gvSIGgeometryType);
3875
                }
3876
        }
3877

    
3878
        public static String getTableExistsSql(DBLayerDefinition dbLayerDef) {
3879
                
3880
        return "SELECT * FROM " + dbLayerDef.getTableName();
3881
        }
3882

    
3883
        public int getAdaptedFetchSize() {
3884
                return adaptedFetchSize;
3885
        }
3886

    
3887
        public void setAdaptedFetchSize(int v) {
3888
                adaptedFetchSize = v;
3889
        }
3890

    
3891
        private boolean isTableHasSrid() {
3892
                return table_HasSrid;
3893
        }
3894

    
3895
        private void setTableHasSrid(boolean b) {
3896
                this.table_HasSrid = b;
3897
        }
3898

    
3899
        private String getEpsgSRID() {
3900
                return epsg_SRID; 
3901
        }
3902

    
3903
        private void setEpsgSRID(String e) {
3904
                this.epsg_SRID = e;
3905
        }
3906

    
3907
}
3908

    
3909
// [eiel-gestion-conexiones]
3910