Statistics
| Revision:

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

History | View | Annotate | Download (117 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
    public static final String ORACLE_ID_FIELD = "ROWID";
158
    public static final String DEFAULT_ID_FIELD_CASE_SENSITIVE = "GID";
159
    public static final String ORACLE_GEO_SCHEMA = "MDSYS";
160
    public static final String CONN_STR_BEGIN = "jdbc:oracle:thin:";
161
    
162
    // public static final int VARCHAR2_DEFAULT_SIZE = 2000; //  512;  
163
    public static final int VARCHAR2_MAX_SIZE = 4000;
164
    
165
    public static final int MAX_ID_LENGTH = 30;
166
    private final static GeometryFactory geomFactory = new GeometryFactory();
167
    public static final double IRRELEVANT_DISTANCE = 0.00000001;
168
        private static final long ID_MIN_DELAY = 1000;
169

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

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

    
190
    private OracleSpatialWriter writer = null;
191

    
192
    // switch variable
193
    private boolean use_geotools = false;
194
    private boolean tableHasSrid = true;
195

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

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

    
209
    private String idFieldNames;
210
    private int oneBasedGeoColInd = 0;
211
    private int shapeType = -1;
212
    private boolean needsCollectionLayer = true;
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 epsgSRID;
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) {
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) && (epsgSRID != null)) {
371
            IProjection viewProj = CRSFactory.getCRS(destProj);
372
            IProjection tableProj = CRSFactory.getCRS("EPSG:" + epsgSRID);
373
            ICoordTrans reprojecter = viewProj.getCT(tableProj);
374
                workingAreaInTablesCS = reprojecter.convert(workingAreaInViewsCS);
375
            workingAreaInTablesCSStruct = shapeToStruct(workingAreaInTablesCS,
376
                    FShape.NULL, tableHasSrid, false, true);
377
        }
378

    
379
        cancelIDLoad = false;
380
        idLoader = new IdLoaderThread(this);
381
        idLoader.start();
382
    }
383

    
384

    
385

    
386

    
387
        /**
388
     * Utility method to load IDs in a different thred, so that gvsig's gui
389
     * does not get blocked.
390
     *
391
     */
392
    public void getMetaDataInThisThread() throws SQLException {
393

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

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

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

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

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

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

    
426
            return null;
427
        }
428

    
429
        return obj.toString();
430
    }
431

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

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

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

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

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

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

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

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

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

    
493
            }
494

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

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

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

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

    
510
                hasRealiableExtent = realiableExtent(full_Extent, isGeogCS);
511

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

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

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

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

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

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

    
568
            if (st == null) {
569
                    return new FNullGeometry();
570
            }
571
            
572
        Datum[] the_data = null;
573

    
574
        
575
        
576
        try {
577
            the_data = st.getOracleAttributes();
578
            
579
            /*
580
                if (rec_iter > 4) {
581
                        logger.error(lastGeom);
582
                        return new FNullGeometry();
583
                }
584
                */
585

    
586
            int full_gtype = ((NUMBER) the_data[0]).intValue();
587
            // int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
588
            int fshape_type = OracleSpatialUtils.oracleGTypeToFShapeType(full_gtype, complex);
589

    
590
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
591

    
592
            if (dim < 2) {
593
                dim = 2;
594
            }
595

    
596
            IGeometry ig = null;
597
            // ========================== collection issue with rects
598
            int collec_val = OracleSpatialUtils.isCollection(the_data);
599
            switch (collec_val) {
600
            case OracleSpatialUtils.COLLECTION_VALUE_YES_COLLECTION:
601
                    fshape_type = FShape.MULTI;
602
                    break;
603
            case OracleSpatialUtils.COLLECTION_VALUE_MERGE_COLLECTION_IN_POLYGON:
604
                    fshape_type = FShape.MULTI;
605
                    break;
606
            case OracleSpatialUtils.COLLECTION_VALUE_NOT_COLLECTION:
607
                    break;
608
            }
609
            // ========================================================
610

    
611
            switch (fshape_type) {
612
            case FShape.MULTI:
613
                ig = getFMapGeometryCollection(the_data, dim, rec_iter);
614
                    if (collec_val == OracleSpatialUtils.COLLECTION_VALUE_MERGE_COLLECTION_IN_POLYGON) {
615
                            ig = OracleSpatialUtils.mergePolygons((FGeometryCollection) ig);
616
                    }
617
                break;
618

    
619
            case FShape.POINT:
620
                ig = OracleSpatialUtils.getFMapGeometryPoint(the_data, dim);
621

    
622
                break;
623

    
624
            case FShape.LINE:
625
                ig = OracleSpatialUtils.getFMapGeometryMultiLineString(the_data, dim);
626

    
627
                break;
628

    
629
            case FShape.POLYGON:
630
                ig = OracleSpatialUtils.getFMapGeometryMultipolygon(the_data, dim);
631

    
632
                break;
633
            }
634

    
635
            return ig;
636
        }
637
        catch (Exception e) {
638
            logger.error(e);
639
        }
640

    
641
        return new FNullGeometry();
642
    }
643

    
644

    
645
        private static String printStruct(Datum[] datt) {
646
            
647
            String resp = "\n";
648
            resp = resp + "============= START === PRINTING STRUCT:\n";
649
            int sz = datt.length;
650
            for (int i=0; i<sz; i++) {
651
                    resp = resp + printDatum(i, datt[i]);
652
            }
653
            resp = resp + "============= END === PRINTING STRUCT\n";
654
            return resp;
655
        }
656
    
657
    
658

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

    
713
        private Rectangle2D getRectangle(double minx, double maxx, double miny,
714
        double maxy) {
715
        Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx,
716
                maxy - miny);
717
        return resp;
718
    }
719

    
720
    private void oneRowMetadata() {
721
        try {
722

    
723
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
724
                    ResultSet.CONCUR_READ_ONLY);
725
            
726
            ResultSet _rs = null;
727
            shapeType = guessShapeType();
728
            // -----------------------
729
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
730
            metaData = _rs.getMetaData(); 
731
            
732
            this.setAdaptedFetchSize(OracleSpatialUtils.estimateGoodFetchSize(metaData));
733
            
734
            userName = ((ConnectionJDBC)conn).getConnection().getMetaData().getUserName();
735

    
736
            // geoColInd = _rs.findColumn(geoColName);
737
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
738

    
739
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
740
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
741

    
742
            int cnt = metaData.getColumnCount();
743
            fieldNames = new String[cnt];
744

    
745
            for (int i = 0; i < cnt; i++) {
746
                fieldNames[i] = metaData.getColumnName(i + 1);
747
            }
748

    
749
            getIdFieldNames();
750
            adjustLyrDef();
751
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan
752
        }
753
        catch (SQLException se) {
754
            logger.error("While getting metadata. " + se.getMessage());
755
        }
756
    }
757

    
758
    private int guessShapeType() {
759

    
760
            int resp = FShape.MULTI;
761

    
762
        String _sql = "select " + getStandardSelectExpression() + ", c." +
763
        geoColName + " from " + getTableName() + " c ";
764

    
765
        ResultSet _rs = null;
766
        STRUCT sample_geo = null;
767
        
768
        try {
769
                _sql = _sql + " where c." + geoColName + " is not NULL AND "
770
                    + OracleSpatialUtils.EXPONENTIAL_INDICES_CONDITION;
771
                
772
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
773
                ResultSet.CONCUR_READ_ONLY);
774

    
775
            _rs = st.executeQuery(_sql);
776

    
777
            int aux = 0;
778
            ArrayList shptypes = new ArrayList();
779
            while (_rs.next()) {
780
                sample_geo = (STRUCT) _rs.getObject(geoColName);
781
                aux = OracleSpatialUtils.getShapeTypeOfStruct(sample_geo);
782
                shptypes.add(new Integer(aux));
783
            }
784
            if (shptypes.size() > 0) {
785
                    resp = getShapeTypeFromArray(shptypes);
786
            }
787
        } catch (Exception ex) {
788
                logger.error("While guessing shape type: " + ex.getMessage());
789
                logger.warn("Assumed MULTI");
790
        }
791
        
792
        return resp;
793
        }
794

    
795
        private int getShapeTypeFromArray(ArrayList arrlist) {
796
                
797
                int resp = ((Integer) arrlist.get(0)).intValue();
798
                
799
                int sz = arrlist.size();
800
                int aux = 0;
801
                for (int i=1; i<sz; i++) {
802
                        aux = ((Integer) arrlist.get(i)).intValue();
803
                        if (aux != resp) return FShape.MULTI;
804
                }
805
                return resp;
806
        }
807

    
808
        private String getIdFieldNames() {
809
        try {
810
            idFieldNames = "";
811

    
812
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
813
                idFieldNames = idFieldNames +
814
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
815
            }
816
        }
817
        catch (SQLException se) {
818
        }
819

    
820
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
821

    
822
        return idFieldNames;
823
    }
824

    
825
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
826
        int[] _res = new int[1];
827
        _res[0] = 1;
828

    
829
        return _res;
830
    }
831

    
832
    public String getSqlTotal() {
833
        // TODO Auto-generated method stub
834
        return "";
835
    }
836

    
837
    public String getCompleteWhere() {
838
        // TODO Auto-generated method stub
839
        return "";
840
    }
841

    
842
    /**
843
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
844
     * and uses directly that sentence to query the table).
845
     */
846
    public IFeatureIterator getFeatureIterator(String sql)
847
        throws ReadDriverException {
848
        if (isNotAvailableYet) {
849
                return new AnEmptyFeatureIterator();
850
            // return null;
851
        }
852

    
853
        singleCachedFeatureRowNum = -1;
854

    
855
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
856

    
857
        ResultSet localrs = (ResultSet) rs_st[0];
858
        Statement _st = (Statement) rs_st[1];
859

    
860
        return new OracleSpatialFeatureIterator(this, localrs, _st,
861
            oneBasedGeoColInd, use_geotools, false, null);
862
    }
863

    
864
    /**
865
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
866
     */
867
    public String getConnectionStringBeginning() {
868
        // oracle
869
        return CONN_STR_BEGIN;
870
    }
871

    
872
    public void open() { // throws DriverException {
873
    }
874

    
875
    /**
876
     * Gets Oracle's default port: 1521
877
     */
878
    public int getDefaultPort() {
879
        // oracle port
880
        return 1521;
881
    }
882

    
883
    /**
884
     * Gets the feature iterator for a given rectangle (the view's bounding box)
885
     * and a SRS.
886
     */
887
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
888
        throws ReadDriverException {
889
        if (isNotAvailableYet) {
890
                return new AnEmptyFeatureIterator();
891
            // return null;
892
        }
893

    
894
        singleCachedFeatureRowNum = -1;
895
        
896
        STRUCT local_st = shapeToStruct(r, FShape.NULL, tableHasSrid, false, true);
897
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
898
        ResultSet localrs = (ResultSet) rs_st[0];
899
        Statement _st = (Statement) rs_st[1];
900

    
901
        return new OracleSpatialFeatureIterator(this, localrs, _st,
902
            oneBasedGeoColInd, use_geotools, false, null);
903
    }
904

    
905
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
906
        if (workingAreaInTablesCS == null) return r;
907
        return OracleSpatialUtils.doIntersect(r, workingAreaInTablesCS);
908
    }
909

    
910
    /**
911
     * This method reverts to the one without the fields specification.
912
     * The fields have been selected from the start.
913
     */
914
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
915
        String[] alphaNumericFieldsNeeded) throws ReadDriverException {
916
            
917
        if (isNotAvailableYet) {
918
                return new AnEmptyFeatureIterator();
919
            // return null;
920
        }
921
        singleCachedFeatureRowNum = -1;
922

    
923
        if ((alphaNumericFieldsNeeded == null) || (alphaNumericFieldsNeeded.length == 0)) {
924
            return getFeatureIterator(r, strEPSG);
925
        } else {
926

    
927
            STRUCT local_st = shapeToStruct(r, FShape.NULL, tableHasSrid, false, true);
928
            Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
929
            ResultSet localrs = (ResultSet) rs_st[0];
930
            Statement _st = (Statement) rs_st[1];
931

    
932
            return new OracleSpatialFeatureIterator(this, localrs, _st,
933
                oneBasedGeoColInd, use_geotools, true, alphaNumericFieldsNeeded);
934
        }
935
    }
936

    
937
    private String getSqlFor(String[] alphaNumericFieldsNeeded, String sdo_inter) {
938
            
939
            String idswhere = getIdsQueryWhereClause(false);
940
        String custom_sel = getCustomSelect(alphaNumericFieldsNeeded, sdo_inter, idswhere);
941
                return custom_sel;
942
        }
943

    
944
        public String getGeometryField(String fieldName) {
945
        return fieldName;
946
    }
947

    
948
    public DriverAttributes getDriverAttributes() {
949
        return drvAtts;
950
    }
951

    
952
    /**
953
     * Gets the requested geometry. Always performs a new query in this case.
954
     * This should be a rare way to get the geometries. The standard way is by using
955
     * the iterators.
956
     */
957
    public IGeometry getShape(int _ind) throws ReadDriverException {
958
        if (isNotAvailableYet) {
959
            return OracleSpatialUtils.NULL_GEOM;
960
        }
961

    
962
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
963

    
964
        String _sql = "select " + geoColName + " from " + getTableName() +
965
            " where rowid = ?";
966

    
967
        try {
968
            java.sql.PreparedStatement ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(_sql);
969
            ps.setObject(1, r_id);
970

    
971
            // Statement stmnt = conn.createStatement();
972
            ps.execute();
973

    
974
            ResultSet _res = ps.getResultSet();
975

    
976
            if (_res.next()) {
977
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
978
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
979
                _res.close();
980
                ps.close();
981

    
982
                return theGeom;
983
            }
984
            else {
985
                logger.error("Unable to get shape: " + _ind +
986
                    " (probably due to edition)");
987
                
988

    
989
                return OracleSpatialUtils.NULL_GEOM;
990
            }
991
        }
992
        catch (SQLException se) {
993
            throw new ReadDriverException(getName(), se);
994
        }
995
    }
996

    
997
    public boolean isWritable() {
998
        return true;
999
    }
1000

    
1001
    public String getName() {
1002
        return NAME;
1003
    }
1004

    
1005
    public int[] getPrimaryKeys() throws ReadDriverException {
1006
        return pkOneBasedIndexes;
1007
    }
1008

    
1009

    
1010

    
1011

    
1012
    private void setIdRowTable(boolean only_test) throws SQLException  {
1013
        hashRelate = new Hashtable();
1014

    
1015
        java.sql.PreparedStatement ps = null;
1016

    
1017
        try {
1018
            String _sql = getIdAndElemInfoFullResulltSetQuery();
1019

    
1020
            logger.debug("SQL para leer ids: " + _sql);
1021
            Statement st = null;
1022
            st = ((ConnectionJDBC)conn).getConnection().createStatement(
1023
                            ResultSet.TYPE_FORWARD_ONLY,
1024
                            ResultSet.CONCUR_READ_ONLY);
1025

    
1026
             st.setFetchSize(getAdaptedFetchSize());
1027
             logger.info("FETCH_SIZE = " + getAdaptedFetchSize());
1028

    
1029
            ResultSet _r = null;
1030
            _r = st.executeQuery(_sql);
1031

    
1032
            ROWID ri = null;
1033

    
1034
            int row = 0;
1035
            String gid;
1036
            Value aux = null;
1037

    
1038
            // ----------------------------------- types init
1039
            ArrayList types = new ArrayList();
1040
            int types_aux = 0;
1041

    
1042
            ARRAY info_aux;
1043
            int[] info_aux_int;
1044
            int size;
1045

    
1046
            // ----------------------------------- types init
1047
            logger.debug("Beginning of result set:");
1048

    
1049
            while (_r.next()) {
1050
                // ---------------------------------------
1051
                ri = (ROWID) _r.getObject(1);
1052
                gid = ri.stringValue();
1053
                aux = ValueFactory.createValue(gid);
1054

    
1055
                Integer intobj = new Integer(row);
1056
                hashRelate.put(aux, intobj);
1057
                rowToId.put(intobj, ri);
1058

    
1059
                if ((row % 5000) == 0) {
1060
                    // ------------------------------------------- cancel load
1061
                    if (cancelIDLoad) {
1062
                        hashRelate.clear();
1063
                        rowToId.clear();
1064

    
1065
                        return;
1066
                    }
1067

    
1068
                    // -------------------------------------------
1069
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
1070
                    logger.info("IDs read: " + fmt);
1071
                }
1072

    
1073
                row++;
1074

    
1075
                // --------------------------------------- types
1076
                info_aux = (ARRAY) _r.getObject(2);
1077

    
1078
                if (info_aux == null) {
1079
                    // logger.debug("NULL info array found in record: " + row);
1080
                }
1081
                else {
1082
                    info_aux_int = info_aux.getIntArray();
1083
                    size = info_aux_int.length / 3;
1084

    
1085
                    for (int i = 0; i < size; i++) {
1086
                        types_aux = info_aux_int[(3 * i) + 1];
1087
                        types.add(new Integer(types_aux % 1000));
1088
                    }
1089
                }
1090

    
1091
                // --------------------------------------- types end
1092
            }
1093

    
1094
            _r.close();
1095
//            ps.close();
1096
            st.close();
1097
            numReg = row;
1098

    
1099
            needsCollectionLayer = OracleSpatialUtils.hasSeveralGeometryTypes(types, false);
1100

    
1101
            if (needsCollectionLayer) {
1102
                shapeType = FShape.MULTI;
1103
            }
1104
        }
1105
        catch (SQLException e) {
1106
                logger.error("While setting id-row hashmap: " + e.getMessage());
1107
                throw e;
1108
        }
1109
    }
1110

    
1111
    public int getFieldCount() throws ReadDriverException {
1112
        try {
1113
            return metaData.getColumnCount();
1114
        }
1115
        catch (SQLException e) {
1116
                logger.error("While getting field count: " + e.getMessage());
1117
            throw new ReadDriverException(getName(), e);
1118
        }
1119
    }
1120

    
1121
    public String[] getFieldNames() {
1122
        return fieldNames;
1123
    }
1124

    
1125
    public String getTotalFields() {
1126
        String strAux = "";
1127

    
1128
        for (int i = 0; i < fieldNames.length; i++) {
1129
            if (i == 0) {
1130
                strAux = fieldNames[i];
1131
            }
1132
            else {
1133
                strAux = strAux + ", " + fieldNames[i];
1134
            }
1135
        }
1136

    
1137
        return strAux;
1138
    }
1139

    
1140
    public int getFieldType(int idField) throws ReadDriverException {
1141
        int i = 0;
1142

    
1143
        try {
1144
            i = idField + 1; // idField viene basado en 0
1145

    
1146
            int __type = metaData.getColumnType(i);
1147
            
1148
            int size = 1;
1149
            // avoid exception
1150
            try { size = metaData.getPrecision(i); } catch (Exception ex) { }
1151
            
1152
            int dec_pos = metaData.getScale(i);
1153

    
1154
            // we must add this entry because we did not remove the 'geometry' column
1155
            if (__type == Types.STRUCT) {
1156
                return Types.VARCHAR; // .STRUCT;
1157
                // ----------------------------------------------------------------------
1158
            }
1159

    
1160
            if (__type == Types.VARCHAR) {
1161
                return Types.VARCHAR;
1162
            }
1163

    
1164
            if (__type == Types.FLOAT) {
1165
                return Types.FLOAT;
1166
            }
1167

    
1168
            if (__type == Types.DOUBLE) {
1169
                return Types.DOUBLE;
1170
            }
1171

    
1172
            if ((__type == Types.INTEGER)
1173
                            || (__type == Types.SMALLINT)
1174
                            || (__type == Types.TINYINT)
1175
                            || (__type == Types.BIGINT)
1176
                            || ((__type == Types.NUMERIC) && (dec_pos == 0))
1177
                            ) {
1178
                    
1179
                    if (size > 10) {
1180
                            return Types.BIGINT;
1181
                    } else {
1182
                            return Types.INTEGER;
1183
                    }
1184
            }
1185

    
1186
            if (__type == Types.BIT) {
1187
                return Types.BIT;
1188
            }
1189

    
1190
            if (__type == Types.DATE) {
1191
                return Types.DATE;
1192
            }
1193

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

    
1198
            if (__type == Types.NUMERIC) {
1199
                    return Types.DOUBLE;
1200
            }
1201

    
1202
            if (__type == Types.DATE) {
1203
                return Types.DATE;
1204
            }
1205

    
1206
            if (__type == Types.TIME) {
1207
                return Types.TIME;
1208
            }
1209

    
1210
            if (__type == Types.TIMESTAMP) {
1211
                return Types.TIMESTAMP;
1212
            }
1213
        }
1214
        catch (SQLException e) {
1215
            logger.error("Unknown field type of : " + i);
1216
            throw new ReadDriverException(getName(), e);
1217
        }
1218

    
1219
        return -1;
1220
    }
1221

    
1222

    
1223
    public String getFieldName(int fieldId) throws ReadDriverException {
1224
        return fieldNames[fieldId];
1225
    }
1226

    
1227
    public int getFieldWidth(int fieldId) {
1228
        int i = -1;
1229

    
1230
        try {
1231
            int aux = fieldId + 1; // fieldId viene basado en 0
1232
            int _type = metaData.getColumnType(aux);
1233
            if (NumberUtilities.isNumeric(_type)) {
1234
                i = metaData.getPrecision(aux);
1235
            } else {
1236
                i = metaData.getColumnDisplaySize(aux);
1237
            }
1238
        }
1239
        catch (SQLException e) {
1240
            logger.error("While getting field width: " + e.getMessage());
1241
        }
1242

    
1243
        if (i < 0) {
1244
            i = 255;
1245
        }
1246

    
1247
        return i;
1248
    }
1249

    
1250
    public Value getFieldValue(long rowIndex, int field_Id) throws ReadDriverException {
1251
        if (isNotAvailableYet) {
1252
            return nullVal;
1253
        }
1254

    
1255
        if ((singleCachedFeature != null) &&
1256
                (rowIndex == singleCachedFeatureRowNum)) {
1257
            return singleCachedFeature.getAttributes()[field_Id];
1258
        }
1259

    
1260
        // return ValueFactory.createNullValue();
1261
        ResultSet _r = null;
1262
        java.sql.PreparedStatement ps = null;
1263

    
1264
        try {
1265
            String rnq = getSearchId();
1266
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1267

    
1268
            ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(rnq);
1269
            ps.setObject(1, _id);
1270

    
1271
            ps.execute();
1272
            _r = ps.getResultSet();
1273
            
1274
            if (!_r.next()) {
1275
                _r.close();
1276
                ps.close();
1277
                    throw new SQLException("No row for ROWID: " + _id.toString() + ". Possibly deleted from another app.");
1278
            }
1279
            
1280
        } catch (SQLException se) {
1281
                logger.error("While getting row " + rowIndex + " : " + se.getMessage());
1282
                return ValueFactory.createNullValue();
1283
        }
1284

    
1285
        IFeature ife = null;
1286
        Value[] atts = null;
1287

    
1288
        try {
1289
            ROWID ri = (ROWID) _r.getObject(1);
1290
            atts = getAttributes(_r, true);
1291

    
1292
            String gid = ri.stringValue();
1293
            STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1294
            IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1295
            ife = new DefaultFeature(theGeom, atts, gid);
1296
            _r.close();
1297
            ps.close();
1298
        } catch (SQLException se) {
1299
            logger.error("Error while doing next(): " + se.getMessage(), se);
1300
            return ValueFactory.createNullValue();
1301
        }
1302

    
1303
        // -------------------------------
1304
        singleCachedFeature = ife;
1305
        singleCachedFeatureRowNum = rowIndex;
1306

    
1307
        // -------------------------------
1308
        if (atts == null) {
1309
            return ValueFactory.createNullValue();
1310
        } else {
1311
            return atts[field_Id];
1312
        }
1313
    }
1314

    
1315

    
1316

    
1317
    public Rectangle2D getFullExtent() {
1318
            return full_Extent;
1319
    }
1320

    
1321

    
1322

    
1323
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim, int reciter) {
1324
        // int __srid) {
1325

    
1326
            NUMBER _srid = new NUMBER(0);
1327
        NUMBER main_type = new NUMBER((dim * 1000) +
1328
                OracleSpatialUtils.getStructType(the_data));
1329

    
1330
        Datum[] all_info_array = null;
1331
        Object[] elems_info_aray = null;
1332
        Datum[] all_ords = null;
1333

    
1334
        Object[] ords_of_groups = null;
1335
        Object[] _elems_info_aray = null;
1336
        try {
1337
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1338
            elems_info_aray = OracleSpatialUtils.groupByElement(all_info_array);
1339
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1340

    
1341
            ords_of_groups = OracleSpatialUtils.getOrdOfGroups(all_ords, elems_info_aray);
1342
            _elems_info_aray = new Object[elems_info_aray.length];
1343
        }
1344
        catch (SQLException e) { 
1345
            logger.error("Unexpected error: " + e.getMessage());
1346
        }
1347

    
1348

    
1349
        for (int i = 0; i < elems_info_aray.length; i++) {
1350
            _elems_info_aray[i] = OracleSpatialUtils.updateIndexes((Datum[]) elems_info_aray[i]);
1351
        }
1352

    
1353
        // _elems_info_aray, ords_of_groups
1354
        int no_of_elems = ords_of_groups.length;
1355
        IGeometry[] geoms = new IGeometry[no_of_elems];
1356

    
1357
        for (int i = 0; i < no_of_elems; i++) {
1358
            Datum[] item_info_array = null;
1359
            Datum[] item_ords = null;
1360
            NUMBER gtype = null;
1361

    
1362
            try {
1363
                item_info_array = (Datum[]) _elems_info_aray[i];
1364
                item_ords = (Datum[]) ords_of_groups[i];
1365

    
1366
                gtype = new NUMBER((dim * 1000) +
1367
                        (item_info_array[1].intValue() % 1000));
1368

    
1369
                if (tableHasSrid) {
1370
                        _srid = new NUMBER(Integer.parseInt(oracleSRID));
1371
                }
1372
            }
1373
            catch (SQLException se) {
1374
                logger.error("Unexpected error: " + se.getMessage());
1375
            }
1376

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

    
1380
            STRUCT itemst = null;
1381

    
1382
            if (tableHasSrid) {
1383

    
1384
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1385
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1386
            }
1387
            else {
1388
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1389
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1390
            }
1391

    
1392
            geoms[i] = getFMapGeometry(itemst, true, reciter + 1);
1393
        }
1394

    
1395
        return new FGeometryCollection(geoms);
1396
    }
1397

    
1398

    
1399

    
1400

    
1401

    
1402

    
1403

    
1404

    
1405
    private void cleanWhereClause() {
1406
        emptyWhereClause = false;
1407

    
1408
        String aux = getWhereClauseWithoutWhere();
1409

    
1410
        for (int i = 0; i < aux.length(); i++)
1411
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
1412
                return;
1413
            }
1414

    
1415
        getLyrDef().setWhereClause("");
1416
        emptyWhereClause = true;
1417
    }
1418

    
1419

    
1420

    
1421
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
1422
        String resp = "";
1423

    
1424
        if (isGeogCS) {
1425
            String vport = "sdo_filter(" + geoColName +
1426
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
1427
                "), 'querytype=window') = 'TRUE'";
1428

    
1429
                resp = "select " + getStandardSelectExpression() + ", c." +
1430
                    geoColName + " from " + getTableName() + " c where ";
1431
                if (idsLoadWhere.length() > 0) {
1432
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1433
                }
1434
                resp = resp + "(" + vport + ")";
1435
        }
1436
        else {
1437
                resp = "select " + getStandardSelectExpression() + ", c." +
1438
                    geoColName + " from " + getTableName() + " c where ";
1439
                if (idsLoadWhere.length() > 0) {
1440
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1441
                }
1442
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
1443
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
1444
        }
1445

    
1446
//        return "select " + getStandardSelectExpression() + ", c." +
1447
//        geoColName + " from " + getTableName() + " c";
1448
        return resp;
1449
    }
1450
    
1451
    private String getCustomSelect(String[] atts, String viewsdo, String idsLoadWhere) {
1452
        String resp = "";
1453
        
1454
        String atts_enum = "";
1455
        if ((atts == null) || (atts.length == 0)) {
1456
                
1457
        } else {
1458
                atts_enum = " c.\"" + atts[0] + "\" ";
1459
            for (int i=1; i<atts.length; i++) {
1460
                    atts_enum = atts_enum + ", " + atts[1]; 
1461
            }
1462
        }
1463

    
1464
        if (isGeogCS) {
1465
            String vport = "sdo_filter(" + geoColName +
1466
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
1467
                "), 'querytype=window') = 'TRUE'";
1468

    
1469
                resp = "select " + atts_enum + " from " + getTableName() + " c where ";
1470
                if (idsLoadWhere.length() > 0) {
1471
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1472
                }
1473
                resp = resp + "(" + vport + ")";
1474
        } else {
1475
                resp = "select " + atts_enum + " from " + getTableName() + " c where ";
1476
                if (idsLoadWhere.length() > 0) {
1477
                        resp = resp + " (" + idsLoadWhere + ") AND ";
1478
                }
1479
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
1480
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
1481
        }
1482

    
1483
//        return "select " + getStandardSelectExpression() + ", c." +
1484
//        geoColName + " from " + getTableName() + " c";
1485
        return resp;
1486
    }    
1487

    
1488
    public void setWorkingArea(Rectangle2D rect) {
1489
    }
1490

    
1491
    private void setWAStructt() {
1492
    }
1493

    
1494

    
1495

    
1496
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
1497
        /*
1498
         * Tipos en Oracle Spatial usando JGeometry
1499
         *
1500
         * GTYPE_COLLECTION collection geometry type
1501
         * GTYPE_CURVE curve geoemtry type
1502
         * GTYPE_MULTICURVE multi-curve geometry type
1503
         * GTYPE_MULTIPOINT multi-point geometry type
1504
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
1505
         * GTYPE_POINT point geometry type
1506
         * GTYPE_POLYGON  polygon geometry type
1507
         *
1508
         * Tipos gvSIG FShape
1509
         *
1510
         * NULL = 0;
1511
         * POINT = 1;
1512
         * LINE = 2;
1513
         * POLYGON = 4;
1514
         * TEXT = 8;
1515
         * MULTI = 16;
1516
         * MULTIPOINT = 32;
1517
         * CIRCLE = 64;
1518
         * ARC = 128;
1519
         * ELLIPSE=256;
1520
         * Z=512
1521
         */
1522
        switch (type) {
1523
        case JGeometry_GTYPE_POLYGON:
1524
        case JGeometry_GTYPE_MULTIPOLYGON:
1525
            return FShape.POLYGON;
1526

    
1527
        case JGeometry_GTYPE_CURVE:
1528
        case JGeometry_GTYPE_MULTICURVE:
1529
            return FShape.LINE;
1530
        }
1531

    
1532
        logger.error("Unhandled Oracle Spatial geometry type: " + type +
1533
            " (conversion returned FShape.NULL)");
1534

    
1535
        return FShape.NULL;
1536
    }
1537
    
1538
    private String getValidViewConstructor(
1539
                    STRUCT _st,
1540
                    String ora_srid,
1541
                    boolean _hassrid,
1542
                    boolean _isgeocs) {
1543

    
1544
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
1545
            String resp = "";
1546
            if ((_hassrid) && (_isgeocs)) {
1547
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
1548
            } else {
1549
                    resp = sdo;
1550
            }
1551

    
1552
            return resp;
1553
    }
1554

    
1555

    
1556

    
1557
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
1558
        boolean hasSrid) throws ReadDriverException {
1559
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
1560
        String main_sel = "";
1561

    
1562
        if (fixsql == null) {
1563
            // main_sel = getMainSelect3(var_name);
1564
                String idswhere = getIdsQueryWhereClause(false);
1565
            main_sel = getMainSelect(sdo_intersect, idswhere);
1566
        }
1567
        else {
1568
            main_sel = fixsql;
1569
        }
1570

    
1571
        logger.debug("MAIN SEL = " + main_sel);
1572

    
1573
        ResultSet _rs = null;
1574
        Statement _stmnt = null;
1575
        Object[] _resp = new Object[2];
1576

    
1577
        try {
1578
            _stmnt = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_FORWARD_ONLY,
1579
                    ResultSet.CONCUR_READ_ONLY);
1580
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
1581
            _stmnt.setFetchSize(getAdaptedFetchSize());
1582

    
1583
            _rs = _stmnt.executeQuery(main_sel);
1584

    
1585
            // stmnt.close();
1586
        }
1587
        catch (SQLException se) {
1588
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
1589
                se);
1590
            throw new ReadDriverException(getName(), se);
1591
        }
1592

    
1593
        // this method returns the statement too, so that it can be closed afterwards
1594
        _resp[0] = _rs;
1595
        _resp[1] = _stmnt;
1596

    
1597
        return _resp;
1598
    }
1599

    
1600
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
1601
        String resp = "";
1602

    
1603
        try {
1604
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
1605
            String mdsys_sdo_ordinate_array = "";
1606
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
1607

    
1608
            for (int i = 0; i < vertices.length; i++) {
1609
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
1610
                    vertices[i].doubleValue() + ", ";
1611
            }
1612

    
1613
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
1614
                    mdsys_sdo_ordinate_array.length() - 2);
1615
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
1616
                mdsys_sdo_ordinate_array + ")";
1617

    
1618
            String aux = "";
1619

    
1620
            if (hasSrid) {
1621
                aux = oracleSRID;
1622

    
1623
                if (_isGeogCS) {
1624
                    aux = "0";
1625
                }
1626
            }
1627
            else {
1628
                aux = "null";
1629
            }
1630

    
1631
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
1632
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
1633
                ")";
1634
        }
1635
        catch (Exception ex) {
1636
                logger.error("While getting sdo contructor: " +
1637
                ex.getMessage());
1638
        }
1639

    
1640
        return resp;
1641
    }
1642

    
1643
    private String getIdsQueryWhereClause(boolean with_where) {
1644
                String resp = "";
1645

    
1646
                String _where = "";
1647
                if (with_where) _where = " where ";
1648

    
1649
                if (workingAreaInTablesCSStruct == null) {
1650
                        if (emptyWhereClause) {
1651
                                // return "select rowid from " + getTableName();
1652
                        } else {
1653
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
1654
                                                + ")";
1655
                        }
1656
                } else {
1657
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
1658
                                        oracleSRID, tableHasSrid, isGeogCS);
1659

    
1660
                        if (emptyWhereClause) {
1661
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
1662
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
1663
                        } else {
1664
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
1665
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
1666
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
1667
                        }
1668
                }
1669

    
1670
                // resp = resp + " order by rowid";
1671
                return resp;
1672
        }
1673

    
1674
    public String getIdAndElemInfoFullResulltSetQuery() {
1675
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
1676
            getTableName() + " c";
1677

    
1678
        resp = resp + getIdsQueryWhereClause(true);
1679
        return resp;
1680
    }
1681

    
1682
    private String getSearchId() {
1683
        if (emptyWhereClause) {
1684
            return "select " + getStandardSelectExpression() + ", c." +
1685
            geoColName + " from " + getTableName() + " c where rowid = ?";
1686
        }
1687
        else {
1688
            return "select " + getStandardSelectExpression() + ", c." +
1689
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
1690
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
1691
        }
1692
    }
1693

    
1694
    public int getShapeType() {
1695
        return shapeType;
1696
    }
1697

    
1698
    public void setShapeType(int t) {
1699
        shapeType = t;
1700
    }
1701
    
1702

    
1703
    private String getWhereClauseWithoutWhere() {
1704
        String resp = "";
1705
        String old = getLyrDef().getWhereClause();
1706
        resp = old;
1707

    
1708
        if (old.length() <= 6) {
1709
            return old;
1710
        }
1711

    
1712
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
1713
            resp = resp.substring(6, resp.length());
1714
        }
1715

    
1716
        return resp;
1717
    }
1718

    
1719

    
1720

    
1721
    public static String fieldTypeToSqlStringType(FieldDescription fd) {
1722
            
1723
        String aux = "VARCHAR2(" + VARCHAR2_MAX_SIZE + ")"; // Por defecto.
1724
        int the_type = fd.getFieldType();
1725
        
1726
        int _w = fd.getFieldLength();
1727
        int _dec = 0;
1728
        
1729
        if (NumberUtilities.isNumeric(the_type)) {
1730
                _dec = fd.getFieldDecimalCount(); 
1731
        }
1732
        
1733
        if (_w < (_dec + 1)) {
1734
                _w = Math.max(6+_dec,2*_dec);
1735
        }
1736

    
1737
        switch (the_type) {
1738
        case Types.SMALLINT:
1739
            aux = "NUMBER(" + _w + ", 0)";
1740
            break;
1741

    
1742
        case Types.INTEGER:
1743
            aux = "NUMBER(" + _w + ", 0)";
1744
            break;
1745

    
1746
        case Types.BIGINT:
1747
            aux = "NUMBER(" + _w + ", 0)";
1748
            break;
1749

    
1750
        case Types.BOOLEAN:
1751
            aux = "NUMBER(1, 0)";
1752
            break;
1753

    
1754
        case Types.DECIMAL:
1755
            aux = "NUMBER(" + _w + ", " + _dec + ")";
1756
            break;
1757

    
1758
        case Types.NUMERIC:
1759
            aux = "NUMBER(" + _w + ", " + _dec + ")";
1760
            break;
1761

    
1762
        case Types.DOUBLE:
1763
            aux = "NUMBER(" + _w + ", " + _dec + ")";
1764
            break;
1765

    
1766
        case Types.FLOAT:
1767
            aux = "NUMBER(" + _w + ", " + _dec + ")";
1768
            break;
1769

    
1770
        case Types.CHAR:
1771
            aux = "CHAR(1 BYTE)";
1772
            break;
1773

    
1774
        case Types.VARCHAR:
1775
            aux = "VARCHAR2(" + _w + ")";
1776
            break;
1777

    
1778
        case Types.LONGVARCHAR:
1779
            aux = "VARCHAR2(" + _w + ")";
1780
            break;
1781
            
1782
        case Types.DATE:
1783
            aux = "DATE";
1784
            break;
1785

    
1786
        }
1787

    
1788
        return aux;
1789
    }
1790

    
1791
    // -----------------------------------------------------------
1792
    // -----------------------------------------------------------
1793
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
1794
        return "DROP TABLE " + dbLayerDef.getTableName() +
1795
        " CASCADE CONSTRAINTS";
1796
    }
1797

    
1798
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
1799
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
1800

    
1801
        String type = "";
1802
        String name = "";
1803
        String table_name = dbLayerDef.getTableName().toUpperCase();
1804

    
1805
        String resp = "CREATE TABLE " + table_name + " ( ";
1806

    
1807
        for (int i = 0; i < flds.length; i++) {
1808
            name = flds[i].getFieldName();
1809

    
1810
            // -------------- FORBIDDEN FIELD NAMES -----------------
1811
            if (!isOracleAllowedFieldname(name)) {
1812
                continue;
1813
            }
1814

    
1815
            // ------------------------------------------------------
1816
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
1817
            }
1818
            else {
1819
                name = getValidOracleID(name, i, false);
1820
                resp = resp + "\"" + name + "\" ";
1821
                type = fieldTypeToSqlStringType(flds[i]);
1822
                resp = resp + type + ", ";
1823
            }
1824
        }
1825

    
1826
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
1827
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
1828
        resp = resp + ", ";
1829

    
1830
        String pk = "CONSTRAINT " + getDerivedNAme(table_name, "PK") +
1831
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD_CASE_SENSITIVE +
1832
            "\") ENABLE";
1833

    
1834
        resp = resp + pk + " )";
1835

    
1836
        return resp;
1837
    }
1838

    
1839
    private static String getDerivedNAme(String tname, String suffix) {
1840

    
1841
            int ind = tname.lastIndexOf(".");
1842
            if (ind == -1) {
1843

    
1844
                    int l = Math.min(28, tname.length());
1845
                    return tname.substring(0, l) + "_" + suffix;
1846

    
1847
            } else {
1848

    
1849
                    String pre = tname.substring(0, ind);
1850
                    String post = tname.substring(ind + 1, tname.length());
1851
                    int lpost = Math.min(24, post.length());
1852
                    int lpre = Math.min(3, pre.length());
1853
                    return pre.substring(0, lpre) + "_" + post.substring(0, lpost) + "_" + suffix;
1854
            }
1855

    
1856
    }
1857

    
1858
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
1859
        String resp = "CREATE INDEX " + getDerivedNAme(dbLayerDef.getTableName(), "SX") +
1860
            " ON " + dbLayerDef.getTableName() + " (\"" +
1861
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
1862
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
1863

    
1864
        return resp;
1865
    }
1866

    
1867
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
1868

    
1869
            String tname = dbLayerDef.getTableName();
1870
            int ind = tname.lastIndexOf(".");
1871
            if (ind != -1) {
1872
                    String schema = tname.substring(0, ind);
1873
                    tname = tname.substring(ind + 1, tname.length());
1874
            return "DELETE FROM " + USER_ORACLE_GEOMETADATA_VIEW +
1875
            " WHERE TABLE_NAME = '" + tname + "'";
1876

    
1877
            } else{
1878
            return "DELETE FROM " + USER_ORACLE_GEOMETADATA_VIEW +
1879
            " WHERE TABLE_NAME = '" + tname + "'";
1880
            }
1881
    }
1882

    
1883
    /**
1884
     * UTility method to get the SQL sentence needed to update the geographic metadata table
1885
     * with a new bounding box and SRS
1886
     *
1887
     * @param tName table name
1888
     * @param ora_srid new SRS
1889
     * @param bbox new bounding box
1890
     * @param dim geometries dimension
1891
     * @param withsrid False if the SRS is set to NULL. True otherwise.
1892
     * @return the SQL sentence to perform the update
1893
     */
1894
    public static String getMetadataUpdateSql(String schema, String tName, String ora_srid,
1895
        Rectangle2D bbox, int dim, boolean withsrid) {
1896
            
1897
        String[] dim_name = new String[dim];
1898

    
1899
        
1900
        String _ora_srid = ora_srid;
1901
        if (_ora_srid == null) _ora_srid = "NULL";
1902

    
1903
        if (_ora_srid.compareTo(GEODETIC_SRID) == 0) {
1904
            dim_name[0] = "LONGITUDE";
1905
            dim_name[1] = "LATITUDE";
1906
        }
1907
        else {
1908
            dim_name[0] = "X";
1909
            dim_name[1] = "Y";
1910

    
1911
            if (dim > 2) {
1912
                dim_name[2] = "Z";
1913

    
1914
                if (dim > 3) {
1915
                    dim_name[3] = "T";
1916
                }
1917
            }
1918
        }
1919
        
1920
        double minx = bbox.getMinX();
1921
        double miny = bbox.getMinY();
1922
        double maxx = bbox.getMaxX();
1923
        double maxy = bbox.getMaxY();
1924
        
1925
        String resp = "INSERT INTO " + USER_ORACLE_GEOMETADATA_VIEW + " " +
1926
            " ( TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
1927
            + "'" + tName + "', "
1928
            + "'" + DEFAULT_GEO_FIELD + "', " +
1929
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
1930
            minx + ", " + maxx + ", " + OracleSpatialUtils.ORACLE_GEOM_METADATA_TOLERANCE + " ), " +
1931
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + miny + ", " +
1932
            maxy + ", " + OracleSpatialUtils.ORACLE_GEOM_METADATA_TOLERANCE + " ))";
1933

    
1934
        if (dim > 2) {
1935
            resp = resp.substring(0, resp.length() - 1) + ",";
1936
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
1937
                "', 0.0, 100.0, " + OracleSpatialUtils.ORACLE_GEOM_METADATA_TOLERANCE + " ))";
1938

    
1939
            if (dim > 3) {
1940
                resp = resp.substring(0, resp.length() - 1) + ",";
1941
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
1942
                    "', 0.0, 100.0, " + OracleSpatialUtils.ORACLE_GEOM_METADATA_TOLERANCE + " ))";
1943
            }
1944
        }
1945

    
1946
        if (withsrid) {
1947
            resp = resp + ", " + _ora_srid + " )";
1948
        }
1949
        else {
1950
            resp = resp + ", NULL )";
1951
        }
1952

    
1953
        return resp;
1954
    }
1955

    
1956
    /**
1957
     * Gets the SQL sentence to perform an insertion.
1958
     *
1959
     * @param feat feature to be added
1960
     * @param dbLayerDef layer definition
1961
     * @param rowInd row index
1962
     * @param _geoColName geometry field name
1963
     * @return the SQL sentence to perform the insertion
1964
     */
1965
    public static String getRowInsertSql(IFeature feat,
1966
        DBLayerDefinition dbLayerDef, int rowInd,
1967
        String _geoColName,
1968
        String geo_val) {
1969
            
1970
        String name = "";
1971
        int ftype = -1;
1972
        String aux_orig = "";
1973
        String aux_limited = "";
1974
        String aux_quotes_ok = "";
1975

    
1976
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
1977

    
1978
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
1979

    
1980
        for (int i = 0; i < fieldsDescr.length; i++) {
1981
            name = fieldsDescr[i].getFieldName();
1982
            ftype = fieldsDescr[i].getFieldType();
1983

    
1984
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
1985
            if (!isOracleAllowedFieldname(name)) continue;
1986
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
1987
            // ------------------------------------------------------
1988
            if (name.compareToIgnoreCase(_geoColName) == 0) {
1989
            }
1990
            else {
1991
                name = getValidOracleID(name, i, false);
1992
                resp = resp + "\"" + name + "\"" + " , ";
1993
            }
1994
        }
1995

    
1996
        resp = resp + _geoColName + " ) VALUES ( ";
1997

    
1998
        for (int i = 0; i < fieldsDescr.length; i++) {
1999
            name = fieldsDescr[i].getFieldName();
2000
            ftype = fieldsDescr[i].getFieldType();
2001

    
2002
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2003
            if (!isOracleAllowedFieldname(name)) continue;
2004
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2005
            // ------------------------------------------------------
2006
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2007

    
2008
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2009
            }
2010
            else {
2011
                if (name.compareTo(OracleSpatialDriver.DEFAULT_ID_FIELD_CASE_SENSITIVE) == 0) {
2012
                    resp = resp + rowInd + " , ";
2013
                }
2014
                else {
2015
                    Value attValue = feat.getAttribute(i);
2016

    
2017
                    if (attValue.toString() == null) {
2018
                        resp = resp + "NULL , ";
2019
                    }
2020
                    else {
2021
                        if (sur.length() > 0) {
2022
                            aux_orig = attValue.toString();
2023
                            aux_limited = cropStringValue(aux_orig, i,
2024
                                    fieldsDescr);
2025
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
2026

    
2027
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
2028
                        }
2029
                        else {
2030
                            String _aux = attValue.toString();
2031

    
2032
                            if (_aux.length() == 0) {
2033
                                _aux = "NULL";
2034
                            }
2035

    
2036
                            resp = resp + _aux + " , ";
2037
                        }
2038
                    }
2039
                }
2040
            }
2041
        }
2042

    
2043
        resp = resp + " " + geo_val + " )";
2044
        /*
2045
        String test = "SDO_UTIL.APPEND(SDO_GEOMETRY("
2046
                        + "2002, NULL, NULL,"
2047
                        + "SDO_ELEM_INFO_ARRAY(1, 2, 2),"
2048
                        + "SDO_ORDINATE_ARRAY(500000, 4000000, 1000000, 5000000, 500000, 5000000)"
2049
                        + "), ? )";
2050

2051
        resp = resp + " " + test + " )";
2052
        */
2053
        return resp;
2054
    }
2055

    
2056
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
2057

    
2058
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
2059
                    return true;
2060
            }
2061

    
2062
            if ((ftype == Types.BINARY)
2063
                || (ftype == Types.ARRAY)
2064
                || (ftype == Types.BLOB)
2065
                || (ftype == Types.CLOB)
2066
                || (ftype == Types.STRUCT)
2067
            ) {
2068
                    return false;
2069
            }
2070
                return true;
2071
        }
2072

    
2073
        /**
2074
     * Gets the SQL sentence to perform an update.
2075
     *
2076
     * @param feat feature to be updated
2077
     * @param dbLayerDef layer definition
2078
     * @param rowInd row index
2079
     * @param geoFieldName geometry field name
2080
     * @return the SQL sentence to perform the update
2081
     */
2082
    public static String getRowUpdateSql(IFeature feat,
2083
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
2084
        String name = "";
2085
        String aux_orig = "";
2086
        String aux_limited = "";
2087
        String aux_quotes_ok = "";
2088

    
2089
        Value[] atts = feat.getAttributes();
2090
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
2091

    
2092
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
2093

    
2094
        for (int i = 0; i < _fieldsDescr.length; i++) {
2095
            name = _fieldsDescr[i].getFieldName();
2096

    
2097
            // -------------- FORBIDDEN FIELD NAMES -----------------
2098
            if (!isOracleAllowedFieldname(name)) {
2099
                logger.info("Field: " + name + " will not be updated.");
2100
                continue;
2101
            }
2102

    
2103
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
2104
                        geoFieldName)) {
2105
                logger.info("Field: " + name + " will not be updated (it's a struct).");
2106
                continue;
2107
            }
2108

    
2109
            // ------------------------------------------------------
2110
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
2111
                // resp = resp + "\"" + name + "\"" + " = ?, ";
2112
            }
2113
            else {
2114
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
2115
                aux_orig = atts[i].toString();
2116
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
2117
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
2118
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
2119
                    sur + ", ";
2120
            }
2121
        }
2122

    
2123
        resp = resp + "\"" + geoFieldName + "\" = ?";
2124
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
2125

    
2126
        return resp;
2127
    }
2128

    
2129
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
2130
        String geoname) {
2131
        if (ftype == Types.STRUCT) {
2132
            if (fldname.compareToIgnoreCase(geoname) != 0) {
2133
                return true;
2134
            }
2135
        }
2136

    
2137
        return false;
2138
    }
2139

    
2140
    /**
2141
     * Gets the SQL sentence to perform a deletion.
2142
     *
2143
     * @param dbLayerDef layer definition
2144
     * @param id ROWID of the record to be deleted
2145
     * @return the SQL sentence to perform the deletion
2146
     */
2147
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
2148
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
2149
        resp = resp + " WHERE ROWID ='" + id + "'";
2150

    
2151
        return resp;
2152
    }
2153

    
2154
    private static String cropStringValue(String orig_val, int i,
2155
        FieldDescription[] _flds) {
2156
            
2157
        if (orig_val == null) {
2158
            return "NULL";
2159
        }
2160
        
2161
        if (NumberUtilities.isNumeric(_flds[i].getFieldType())
2162
                    && (orig_val.length() == 0)) {
2163
                    return "NULL";
2164
        }
2165

    
2166
        int tpe = _flds[i].getFieldType();
2167
        int max_size = OracleSpatialUtils.maxSizeForFieldType(tpe);
2168

    
2169
        if (max_size == -1) {
2170
            return orig_val;
2171
        }
2172

    
2173
        int or_size = orig_val.length();
2174

    
2175
        if (or_size <= max_size) {
2176
            return orig_val;
2177
        }
2178

    
2179
        return orig_val.substring(0, max_size);
2180
    }
2181

    
2182
    private static String avoidQuoteProblem(String str) {
2183
        return str.replaceAll("'", "''");
2184
    }
2185

    
2186
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
2187
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
2188
            return "";
2189
        }
2190

    
2191
        return "'";
2192
    }
2193

    
2194
    /**
2195
     * Utility function to translate a SRS code from EPSG to Oracle.
2196
     * Uses a datasource based on a DBF file.
2197
     *
2198
     * @param epsg the EPSG code
2199
     * @return the Oracle code
2200
     */
2201
    public static String epsgSridToOracleSrid(String _epsg) throws Exception {
2202
            
2203
            String epsg = removePrefix(_epsg);
2204
            
2205
        String resp = "8307";
2206

    
2207
        // --------------------------------------------
2208
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
2209
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
2210
        DataSource ds = null;
2211

    
2212
        try {
2213
            ds = LayerFactory.getDataSourceFactory()
2214
                             .executeSQL(sql,
2215
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
2216

    
2217
            if (ds.getRowCount() == 0) {
2218
                logger.error("EPSG code not found in table: " + epsg);
2219
                throw new Exception("Unknown EPSG: " + epsg);
2220
            }
2221

    
2222
            if (ds.getRowCount() > 1) {
2223
                logger.error("===============");
2224
                logger.error(
2225
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
2226
                    epsg);
2227

    
2228
                for (int i = 0; i < ds.getRowCount(); i++) {
2229
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
2230

    
2231
                    if (i == 0) {
2232
                        resp = "" + aux;
2233
                    }
2234

    
2235
                    logger.error("" + aux);
2236
                }
2237

    
2238
                logger.error("===============");
2239

    
2240
                return resp;
2241
            }
2242

    
2243
            resp = "" +
2244
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
2245
        }
2246
        catch (Exception pe) {
2247
            logger.error("Error with SQL statement. " + pe.getMessage());
2248
        }
2249

    
2250
        return resp;
2251
    }
2252

    
2253
    /**
2254
     * Utility function to translate a SRS code from Oracle to EPSG.
2255
     * Uses a datasource based on a DBF file.
2256
     *
2257
     * @param ora the Oracle code
2258
     * @return the EPSG code
2259
     */
2260
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
2261
            
2262
            if (ora == null) return null;
2263
            
2264
        String resp = "4326";
2265

    
2266
        // --------------------------------------------
2267
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
2268
            " where ORACLE = " + ora + ";";
2269
        DataSource ds = null;
2270

    
2271
        try {
2272
            ds = LayerFactory.getDataSourceFactory()
2273
                             .executeSQL(sql,
2274
                    DataSourceFactory.AUTOMATIC_OPENING);
2275

    
2276
            if (ds.getRowCount() == 0) {
2277
                logger.error("Oracle Spatial code not found in table: " + ora);
2278
                throw new Exception("Unknown Oracle code: " + ora);
2279
            }
2280

    
2281
            if (ds.getRowCount() > 1) {
2282
                logger.error("===============");
2283
                logger.error(
2284
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
2285
                    ora);
2286

    
2287
                for (int i = 0; i < ds.getRowCount(); i++) {
2288
                    String aux = "" +
2289
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
2290

    
2291
                    if (i == 0) {
2292
                        resp = aux;
2293
                    }
2294

    
2295
                    logger.error("" + aux);
2296
                }
2297

    
2298
                logger.error("===============");
2299

    
2300
                return resp;
2301
            }
2302

    
2303
            resp = "" +
2304
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
2305
        }
2306
        catch (Exception pe) {
2307
            logger.error("Error with SQL statement. " + pe.getMessage());
2308
        }
2309

    
2310
        return resp;
2311
    }
2312

    
2313
    /**
2314
     * This methos creates the datasource used to translate the SRS codes:
2315
     * EPSG <--> Oracle.
2316
     *
2317
     * It's called from several places, so checks that the datasource does not exist.
2318
     */
2319

    
2320

    
2321
    /**
2322
     * Utility method to get a valid Oracle identifier (in terms of length)
2323
     *
2324
     * @param str Proposed string
2325
     * @param ind field index of the given field name (used by the method to
2326
     * improve the renaming)
2327
     * @return an acceptable oracle identifier.
2328
     */
2329
    public static String getValidOracleID(String _str, int ind, boolean force_uppercase) {
2330
            
2331
            String str = _str;
2332
            if (force_uppercase) str = _str.toUpperCase();
2333
            
2334
        if (str.length() <= MAX_ID_LENGTH) {
2335
            return str;
2336
        }
2337

    
2338
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
2339
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
2340
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
2341
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
2342
        resp = resp + "_" + (ind % 1000);
2343

    
2344
        return resp;
2345
    }
2346

    
2347
    private static ArrayList ensureSensibleShell(ArrayList cc) {
2348
        if (sameCoordinate((Coordinate) cc.get(0),
2349
                    (Coordinate) cc.get(cc.size() - 1))) {
2350
            if (cc.size() == 2) {
2351
                ArrayList resp = new ArrayList();
2352
                resp.add(cc.get(0));
2353

    
2354
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
2355
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
2356
                resp.add(newcoo);
2357

    
2358
                newcoo = new Coordinate((Coordinate) cc.get(0));
2359
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
2360
                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
2361
                resp.add(newcoo);
2362

    
2363
                resp.add(cc.get(0));
2364

    
2365
                return resp;
2366
            }
2367

    
2368
            if (cc.size() == 3) {
2369
                cc.remove(1);
2370

    
2371
                return ensureSensibleShell(cc);
2372
            }
2373

    
2374
            return cc;
2375
        }
2376
        else {
2377
            cc.add(cc.get(0));
2378

    
2379
            return cc;
2380
        }
2381
    }
2382

    
2383
    private static ArrayList ensureSensibleHole(ArrayList cc) {
2384
        if (sameCoordinate((Coordinate) cc.get(0),
2385
                    (Coordinate) cc.get(cc.size() - 1))) {
2386
            if (cc.size() == 2) {
2387
                ArrayList resp = new ArrayList();
2388
                resp.add(cc.get(0));
2389

    
2390
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
2391
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
2392
                resp.add(newcoo);
2393

    
2394
                newcoo = new Coordinate((Coordinate) cc.get(0));
2395
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
2396
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
2397
                resp.add(newcoo);
2398

    
2399
                resp.add(cc.get(0));
2400

    
2401
                return resp;
2402
            }
2403

    
2404
            if (cc.size() == 3) {
2405
                cc.remove(1);
2406

    
2407
                return ensureSensibleHole(cc);
2408
            }
2409

    
2410
            return cc;
2411
        }
2412
        else {
2413
            cc.add(cc.get(0));
2414

    
2415
            return cc;
2416
        }
2417
    }
2418

    
2419
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
2420
        if (cc.size() == 2) {
2421
            if (sameCoordinate((Coordinate) cc.get(0),
2422
                        (Coordinate) cc.get(cc.size() - 1))) {
2423
                ArrayList resp = new ArrayList();
2424
                resp.add(cc.get(0));
2425

    
2426
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
2427
                newc.x = newc.x + IRRELEVANT_DISTANCE;
2428
                resp.add(newc);
2429

    
2430
                return resp;
2431
            }
2432
        }
2433

    
2434
        return cc;
2435
    }
2436

    
2437
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
2438
        if (c1.x != c2.x) {
2439
            return false;
2440
        }
2441

    
2442
        if (c1.y != c2.y) {
2443
            return false;
2444
        }
2445

    
2446
        return true;
2447
    }
2448

    
2449
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
2450
        if (cc.size() == 2) {
2451
            return null;
2452
        }
2453

    
2454
        if (cc.size() == 3) {
2455
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
2456
                return null;
2457
            }
2458

    
2459
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
2460
                return null;
2461
            }
2462

    
2463
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
2464
                return null;
2465
            }
2466

    
2467
            cc.add(cc.get(0));
2468

    
2469
            return cc;
2470
        }
2471

    
2472
        if (!sameCoordinate((Coordinate) cc.get(0),
2473
                    (Coordinate) cc.get(cc.size() - 1))) {
2474
            cc.add(cc.get(0));
2475
        }
2476

    
2477
        return cc;
2478
    }
2479

    
2480
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
2481
        Coordinate[] p = new Coordinate[4];
2482
        p[0] = c;
2483

    
2484
        Coordinate nc = new Coordinate(c);
2485
        nc.x = nc.x + IRRELEVANT_DISTANCE;
2486

    
2487
        Coordinate nc2 = new Coordinate(nc);
2488
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
2489
        p[1] = nc;
2490
        p[2] = nc2;
2491
        p[3] = new Coordinate(c);
2492

    
2493
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
2494
        LinearRing ls = new LinearRing(cs, geomFactory);
2495
        Polygon po = new Polygon(ls, null, geomFactory);
2496
        Polygon[] pos = new Polygon[1];
2497
        pos[0] = po;
2498

    
2499
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
2500

    
2501
        return mpo;
2502
    }
2503

    
2504
    public String getSourceProjection(IConnection conn, DBLayerDefinition lyrDef) {
2505
            
2506
            String resp = null;
2507
        try {
2508
            Statement _st = ((ConnectionJDBC) conn).getConnection().createStatement();
2509
            String[] tokens = lyrDef.getName().split("\\u002E", 2);
2510
            String qry;
2511
            if (tokens.length > 1) {
2512
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2513
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
2514
                tokens[1] + "'";
2515
            } else {
2516
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
2517
                " where TABLE_NAME = " + "'" + lyrDef.getName() + "'";
2518
            }
2519
            ResultSet _rs = _st.executeQuery(qry);
2520

    
2521
            if (_rs.next()) {
2522
                String aux = getOracleSridFromCurrentRecord(_rs);
2523
                try {
2524
                                        resp = oracleSridToEpsgSrid(aux);
2525
                                } catch (Exception e) {
2526
                                        logger.error("Unknown oracle SRID: " + aux);
2527
                                }
2528
            } else {
2529
                    
2530
            }
2531
        } catch (Exception ex) {
2532
                logger.error("While getting Source Projection: " + ex.getMessage());
2533
        }
2534
        
2535
        if (resp != null) {
2536
                return resp;
2537
        } else {
2538
                return getDestProjection();
2539
        }
2540
        
2541
    }
2542

    
2543
    public String getDestProjection() {
2544
        return removePrefix(destProj);
2545
    }
2546

    
2547
    public void setDestProjection(String toEPSG) {
2548
        destProj = toEPSG;
2549
        try {
2550
                        destProjOracle = epsgSridToOracleSrid(destProj);
2551
                        isDestGeogCS = OracleSpatialUtils.getIsGCS(destProjOracle, true);
2552

    
2553
                } catch (Exception e) {
2554
                        logger.error("Unknown EPSG code: " + destProj);
2555
                        destProjOracle = oracleSRID;
2556
                        isDestGeogCS = false;
2557
                }
2558

    
2559
    }
2560

    
2561
    public String getDestProjectionOracleCode() {
2562
            return destProjOracle;
2563
    }
2564

    
2565
    public boolean getIsDestProjectionGeog() {
2566
            return isDestGeogCS;
2567
    }
2568

    
2569
    public String getTableProjectionOracleCode() {
2570
            return oracleSRID;
2571
    }
2572

    
2573
    public boolean canReproject(String toEPSGdestinyProjection) {
2574
        return false;
2575
    }
2576

    
2577
    /**
2578
     * Utility function. Says whether a given field name can be a user field name
2579
     * or not (for example, "ROWID" is not a valid one because it's a system
2580
     * reserved word).
2581
     *
2582
     * @param str proposed firld name
2583
     * @return whether it is valid or not for Oracle databases
2584
     */
2585
    private static boolean isOracleAllowedFieldname(String str) {
2586
        if (str.compareToIgnoreCase("rowid") == 0) {
2587
            return false;
2588
        }
2589

    
2590
        if (str.compareToIgnoreCase("rownum") == 0) {
2591
            return false;
2592
        }
2593

    
2594
        return true;
2595
    }
2596

    
2597
    public Hashtable getHashRelate() {
2598
        return hashRelate;
2599
    }
2600

    
2601
    public void setHashRelate(Hashtable m) {
2602
        hashRelate = m;
2603
    }
2604

    
2605
    public void setNumReg(int n) {
2606
        numReg = n;
2607
    }
2608

    
2609
    private int[] getRandomSample(int maxn_one_based, int n) {
2610
        int[] resp = new int[n];
2611

    
2612
        if (maxn_one_based <= n) {
2613
            resp = new int[maxn_one_based];
2614

    
2615
            for (int i = 0; i < maxn_one_based; i++) {
2616
                resp[i] = i;
2617
            }
2618
        }
2619
        else {
2620
            Random rnd = new Random();
2621

    
2622
            for (int i = 0; i < n; i++) {
2623
                resp[i] = rnd.nextInt(maxn_one_based);
2624
            }
2625
        }
2626

    
2627
        return resp;
2628
    }
2629

    
2630
    private String getRowIdRestrictionCondition(int nrecords) {
2631
        int[] zero_based_rows = getRandomSample(nrecords,
2632
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
2633
        String resp = "(";
2634
        Object aux = "";
2635
        ROWID riaux = null;
2636

    
2637
        for (int i = 0; i < zero_based_rows.length; i++) {
2638
            aux = rowToId.get(new Integer(zero_based_rows[i]));
2639
            riaux = (ROWID) aux;
2640
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
2641
        }
2642

    
2643
        resp = resp.substring(0, resp.length() - 4);
2644
        resp = resp + ")";
2645

    
2646
        return resp;
2647
    }
2648

    
2649
    private Rectangle2D getBoundingFromSample(int n_max) {
2650
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
2651
            " WHERE " + getRowIdRestrictionCondition(n_max);
2652
        STRUCT auxstr = null;
2653
        IGeometry theGeom = null;
2654
        Rectangle2D resp = null;
2655

    
2656
        try {
2657
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
2658
            ResultSet rs = st.executeQuery(_qry);
2659

    
2660
            if (rs.next()) {
2661
                auxstr = (STRUCT) rs.getObject(1);
2662

    
2663
                if (auxstr != null) {
2664
                    theGeom = getGeometryUsing(auxstr, use_geotools);
2665

    
2666
                    if (resp == null) {
2667
                        resp = theGeom.getBounds2D();
2668
                    }
2669
                    else {
2670
                        resp.add(theGeom.getBounds2D());
2671
                    }
2672
                }
2673

    
2674
                while (rs.next()) {
2675
                    auxstr = (STRUCT) rs.getObject(1);
2676

    
2677
                    if (auxstr != null) {
2678
                        theGeom = getGeometryUsing(auxstr, use_geotools);
2679

    
2680
                        if (resp == null) {
2681
                            resp = theGeom.getBounds2D();
2682
                        }
2683
                        else {
2684
                            resp.add(theGeom.getBounds2D());
2685
                        }
2686
                    }
2687
                }
2688

    
2689
                rs.close();
2690
                st.close();
2691
            }
2692
            else {
2693
                throw new SQLException("Empty resultset from this query: " +
2694
                    _qry);
2695
            }
2696
        }
2697
        catch (SQLException se) {
2698
                logger.error("While getting sample full extent: " +
2699
                se.getMessage());
2700
        }
2701

    
2702
        if (resp == null) {
2703
            logger.warn(
2704
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
2705

    
2706
            return new Rectangle2D.Double(-180, -90, 360, 180);
2707
        }
2708

    
2709
        return resp;
2710
    }
2711

    
2712
    /**
2713
     * Does what it says, puts the LinearRing in counter clock wise
2714
     * order.
2715
     * @param ls The ring to set.
2716
     * @param gf a GeometryFactory object
2717
     * @return A new ring in CCW order.
2718
     *
2719
     */
2720
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
2721
        Coordinate[] cc = ls.getCoordinates();
2722

    
2723
        if (CGAlgorithms.isCCW(cc)) {
2724
            return gf.createLinearRing(cc);
2725
        }
2726
        else {
2727
            if (ls instanceof LinearRing) {
2728
                return reverseRing((LinearRing) ls, gf);
2729
            }
2730
            else {
2731
                return reverseLineString(ls, gf);
2732
            }
2733
        }
2734
    }
2735

    
2736
    /**
2737
     * Does what it says, reverses the order of the Coordinates in the ring.
2738
     * @param lr The ring to reverse.
2739
     * @return A new ring with the reversed Coordinates.
2740
     *
2741
     */
2742
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
2743
        int numPoints = lr.getNumPoints() - 1;
2744
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
2745

    
2746
        for (int t = numPoints; t >= 0; t--) {
2747
            newCoords[t] = lr.getCoordinateN(numPoints - t);
2748
        }
2749

    
2750
        return gf.createLinearRing(newCoords);
2751
    }
2752

    
2753
    /**
2754
     * Does what it says, reverses the order of the Coordinates in the linestring.
2755
     * @param ls The ls to reverse.
2756
     * @param gf a GeometryFactory object
2757
     * @return A new ls with the reversed Coordinates.
2758
     *
2759
     */
2760
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
2761
        int numPoints = ls.getNumPoints() - 1;
2762
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
2763

    
2764
        for (int t = numPoints; t >= 0; t--) {
2765
            newCoords[t] = ls.getCoordinateN(numPoints - t);
2766
        }
2767

    
2768
        return gf.createLinearRing(newCoords);
2769
    }
2770

    
2771
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
2772
        if (ge instanceof MultiPolygon) {
2773
            MultiPolygon mp = (MultiPolygon) ge;
2774
            int size = ge.getNumGeometries();
2775
            Polygon[] pols = new Polygon[size];
2776

    
2777
            for (int i = 0; i < size; i++)
2778
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
2779
                        gf);
2780

    
2781
            return new MultiPolygon(pols, gf);
2782
        }
2783
        else {
2784
            if (ge instanceof Polygon) {
2785
                Polygon p = (Polygon) ge;
2786
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
2787
                int nholes = p.getNumInteriorRing();
2788

    
2789
                if (nholes > 0) {
2790
                    LinearRing[] holes = new LinearRing[nholes];
2791

    
2792
                    for (int i = 0; i < nholes; i++) {
2793
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
2794
                    }
2795

    
2796
                    return gf.createPolygon(exterior, holes);
2797
                }
2798
                else {
2799
                    return gf.createPolygon(exterior, null);
2800
                }
2801
            }
2802
            else {
2803
                return ge;
2804
            }
2805
        }
2806
    }
2807

    
2808
    /**
2809
     * Converts from IGeometry to STRUCT
2810
     *
2811
     * @param ig the geometry to convert
2812
     * @param _forced_type forced type to use
2813
     * @param _conn connection
2814
     * @param _o_srid  SRS (oracle code)
2815
     * @param withSrid whether this STRUCT has a non-NULL SRS
2816
     * @param agu_bien whether or not to check the correctness of the holes
2817
     * @param _isGeoCS whether the SRS is geodetic or not
2818
     * @return the generated STRUCT
2819
     */
2820
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
2821
        IConnection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
2822
        boolean _isGeoCS) {
2823
        if (ig instanceof FGeometryCollection) {
2824
            FGeometryCollection coll = (FGeometryCollection) ig;
2825

    
2826
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
2827
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
2828

    
2829
            // logger.error("Collections no soportadas por ahora.");
2830
            // return null;
2831
        }
2832
        else {
2833
            Shape shp = ig.getInternalShape();
2834

    
2835
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
2836
                agu_bien, false, _isGeoCS);
2837
        }
2838
    }
2839

    
2840
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
2841
        boolean agu_bien, boolean isView) {
2842

    
2843
            if (shp == null) return null;
2844
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
2845
            agu_bien, isView, isGeogCS);
2846
    }
2847

    
2848
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
2849
        IConnection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
2850
        boolean isView, boolean _isGeoCS) {
2851
        int _srid = -1;
2852

    
2853
        if ((o_srid != null) && (o_srid.length() > 0)) {
2854
            _srid = Integer.parseInt(o_srid);
2855
        }
2856

    
2857
        if (shp == null) {
2858
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
2859

    
2860
            return null;
2861
        }
2862

    
2863
        if (shp instanceof Rectangle2D) {
2864
            return OracleSpatialUtils.rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
2865
                _isGeoCS, o_srid, _conn);
2866
        }
2867

    
2868
        try {
2869
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
2870
                    _srid, agu_bien, hasSrid, _isGeoCS);
2871

    
2872
            return the_struct;
2873
        }
2874
        catch (SQLException ex) {
2875
            logger.error("While creating STRUCT: " + ex.getMessage());
2876

    
2877
            return null;
2878
        }
2879
    }
2880

    
2881
    // -------------------------- not ready yet ----------------
2882
    public int getRowIndexByFID(IFeature _fid) {
2883
        if (isNotAvailableYet) {
2884
            return -1;
2885
        }
2886
        else {
2887
            return super.getRowIndexByFID(_fid);
2888
        }
2889
    }
2890

    
2891
    public int getShapeCount() throws ReadDriverException { 
2892
        if (isNotAvailableYet) {
2893
            return 0;
2894
        }
2895
        else {
2896
            return numReg;
2897
        }
2898
    }
2899

    
2900
    public void setNotAvailableYet(boolean nav) {
2901
        isNotAvailableYet = nav;
2902
    }
2903

    
2904
    // -------------------------------------------------------
2905
    // -------------------------------------------------------
2906
    public String[] getTableNames(IConnection conn, String catalog)
2907
        throws DBException {
2908
        try{
2909
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
2910
        String[] types = { "TABLE", "VIEW" };
2911
        // String[] types = { "VIEW" };
2912

    
2913
        ResultSet rs = null;
2914
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
2915
                    ALL_ORACLE_GEOMETADATA_VIEW, types), ((ConnectionJDBC)conn).getConnection());
2916
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
2917
//                          ORACLE_GEOMETADATA_VIEW, types);
2918
        TreeMap ret = new TreeMap();
2919

    
2920
        while (rs.next()) {
2921
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
2922
            ret.put(nomCompleto, nomCompleto);
2923
        }
2924

    
2925
        return (String[]) ret.keySet().toArray(new String[0]);
2926
        }catch (SQLException e) {
2927
                        throw new DBException(e);
2928
                }
2929
    }
2930

    
2931
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
2932
        throws SQLException {
2933
        String tablename = "";
2934

    
2935
        if (res.next()) {
2936
            tablename = res.getString("TABLE_NAME");
2937

    
2938
            // debug
2939
            writeMetaTableToLog(con, tablename);
2940

    
2941
            Statement __st = con.createStatement();
2942

    
2943
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
2944
                "union (select VIEW_NAME from USER_VIEWS)) " +
2945
                "intersect (select TABLE_NAME from " + tablename + ")";
2946
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
2947
            ResultSet rs = __st.executeQuery(sql);
2948

    
2949
            return rs;
2950
        }
2951
        else {
2952
            logger.error("Error while getting geometry tables.");
2953

    
2954
            return null;
2955
        }
2956
    }
2957

    
2958
    private void writeMetaTableToLog(Connection con, String tname) {
2959

    
2960
            logger.debug("======================================================");
2961
            logger.debug("=     " + ALL_ORACLE_GEOMETADATA_VIEW + "  (1 EVERY 10 TABLES) ========");
2962
            logger.debug("======================================================");
2963

    
2964
            try {
2965
            Statement _stmt = con.createStatement();
2966
            String sql = "SELECT * FROM " + tname;
2967
            ResultSet res = _stmt.executeQuery(sql);
2968
            
2969
            int count = 0;
2970
            while (res.next()) {
2971
                    
2972
                    if ((count % 10) == 0) {
2973
                        logger.debug(
2974
                                        "OWNER: " + res.getString("OWNER")
2975
                                        + ", TABLE_NAME: " + res.getString("TABLE_NAME")
2976
                                        + ", COLUMN_NAME: " + res.getString("COLUMN_NAME")
2977
                                        + ", SRID: " + res.getString("SRID"));
2978
                        ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
2979
                        String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
2980
                        logger.debug("DIMINFO: " + dinfo);
2981
                        logger.debug("=========");
2982
                    }
2983
                    count++;
2984
                    
2985
            }
2986
            } catch (Throwable th) {
2987

    
2988
            }
2989
        }
2990

    
2991
        /**
2992
     * Gets the field names that can act as row id (always ROWID)
2993
     */
2994
    public String[] getIdFieldsCandidates(IConnection conn, String table_name)
2995
        throws DBException {
2996
            try{
2997
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
2998
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
2999
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
3000
            _rs.close();
3001
            _st.close();
3002

    
3003
            String[] resp = { "ROWID" };
3004
        return resp;
3005
            }catch (SQLException e) {
3006
                        throw new DBException(e);
3007
                }
3008
    }
3009

    
3010
    /**
3011
     * Gets the field names that can act as geometry fields
3012
     * (queries the user's geographic metadata).
3013
     */
3014
    public String[] getGeometryFieldsCandidates(IConnection conn,
3015
        String table_name) throws DBException {
3016
            try{
3017
        Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3018
        String[] tokens = table_name.split("\\u002E", 2);
3019
        String qry;
3020
        if (tokens.length > 1)
3021
        {
3022
                qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
3023
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
3024
            tokens[1] + "'";
3025
        }
3026
        else
3027
        {
3028
                qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
3029
            " where TABLE_NAME = " + "'" + table_name + "'";
3030

    
3031
        }
3032
        ResultSet _rs = _st.executeQuery(qry);
3033

    
3034
        ArrayList aux = new ArrayList();
3035

    
3036
        while (_rs.next()) {
3037
            String _geo = _rs.getString("COLUMN_NAME");
3038
            aux.add(_geo);
3039
        }
3040

    
3041
        _rs.close();
3042
        _st.close();
3043

    
3044
        String[] resp = (String[]) aux.toArray(new String[0]);
3045

    
3046
        return checkIndexes(conn, resp, table_name);
3047
            }catch (SQLException e) {
3048
                        throw new DBException(e);
3049
                }
3050
    }
3051

    
3052
    private String[] checkIndexes(IConnection c, String[] all, String long_table_name) throws DBException {
3053

    
3054
            ArrayList good_ones = new ArrayList();
3055
            try{
3056
            String t = long_table_name;
3057
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
3058

    
3059
            for (int i=0; i<all.length; i++) {
3060

    
3061
                String qry = "SELECT SRID, DIMINFO FROM " + ALL_ORACLE_GEOMETADATA_VIEW +
3062
            " WHERE TABLE_NAME = " + "'" + t.toUpperCase() +
3063
            "' AND COLUMN_NAME = '" + all[i].toUpperCase() + "'";
3064

    
3065
                Statement _st = ((ConnectionJDBC)c).getConnection().createStatement();
3066
                ResultSet _rs = _st.executeQuery(qry);
3067
                if (_rs.next()) {
3068
                        String _srid = toString((BigDecimal) _rs.getObject(1));
3069
                        ARRAY diminfo = (ARRAY) _rs.getObject(2);
3070
                        int len = diminfo.getOracleArray().length;
3071
                        if (allowsGeoQueries(((ConnectionJDBC)c).getConnection(), long_table_name, all[i], _srid, len)) {
3072
                                good_ones.add(all[i]);
3073
                        }
3074
                }
3075
                _rs.close();
3076
                _st.close();
3077
            }
3078

    
3079
            if (good_ones.size() == 0) {
3080
                    throw new SQLException("no_indexes_on_declared_geo_fields");
3081
            }
3082
            }catch (SQLException e) {
3083
                        throw new DBException(e);
3084
                }
3085
            return (String[]) good_ones.toArray(new String[0]);
3086
    }
3087

    
3088
    private String toString(BigDecimal number) {
3089

    
3090
            if (number == null) return "NULL";
3091
            return "" + number.intValue();
3092
        }
3093

    
3094
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
3095
            String p = getPointConstructor(dims, _srid);
3096
            String qry = "";
3097
            qry = "SELECT * FROM " + _t.toUpperCase()
3098
            + " WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'"
3099
            + " AND ROWNUM = 1";
3100

    
3101
            try {
3102
                        Statement _st = c.createStatement();
3103
                        ResultSet _rs = _st.executeQuery(qry);
3104
                        _rs.close();
3105
                        _st.close();
3106
                } catch (Exception ex) {
3107
                        return false;
3108
                }
3109
                return true;
3110
        }
3111

    
3112
        private String getPointConstructor(int dims, String _srid) {
3113

    
3114
                String coord = "";
3115
                for (int i=0; i<dims; i++) coord = coord + "0, ";
3116
                coord = coord.substring(0, coord.length() - 2);
3117

    
3118
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
3119
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
3120
        }
3121

    
3122
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
3123

    
3124
            if (l == null) return false;
3125
            if (str == null) return false;
3126

    
3127
            String item = "";
3128
            for (int i=0; i<l.size(); i++) {
3129
                    if (l.get(i) instanceof String) {
3130
                            item = (String) l.get(i);
3131
                            if (item.compareToIgnoreCase(str) == 0) return true;
3132
                    }
3133
            }
3134
            return false;
3135
    }
3136

    
3137
        /**
3138
     * Utility method to check if a given table is empty.
3139
     */
3140
    public boolean isEmptyTable(Connection conn, String tableName) {
3141
        boolean res = true;
3142

    
3143
        try {
3144
            Statement st = conn.createStatement();
3145
            ResultSet rs = null;
3146
            rs = st.executeQuery("select * from " + tableName +
3147
                    " where rownum = 1");
3148
            res = !rs.next();
3149
            rs.close();
3150
            st.close();
3151
        }
3152
        catch (Exception ex) {
3153
            res = true;
3154
        }
3155

    
3156
        return res;
3157
    }
3158

    
3159
    /**
3160
     * Gets all the fields from a table name.
3161
     */
3162
    public String[] getAllFields(IConnection conn, String table_name)
3163
        throws DBException {
3164
            try{
3165
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3166
        ResultSet rs = st.executeQuery("select * from " + table_name +
3167
                " where rownum = 1");
3168
        ResultSetMetaData rsmd = rs.getMetaData();
3169
        String[] ret = new String[rsmd.getColumnCount()];
3170

    
3171
        for (int i = 0; i < ret.length; i++) {
3172
            ret[i] = rsmd.getColumnName(i + 1);
3173
        }
3174

    
3175
        rs.close();
3176
        st.close();
3177

    
3178
        return ret;
3179
            }catch (SQLException e) {
3180
                        throw new DBException(e);
3181
                }
3182
    }
3183

    
3184
    /**
3185
     * Gets all field type names from a table.
3186
     */
3187
    public String[] getAllFieldTypeNames(IConnection conn, String table_name)
3188
        throws DBException {
3189
            try{
3190
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3191
        ResultSet rs = st.executeQuery("select * from " + table_name +
3192
                " where rownum = 1");
3193
        ResultSetMetaData rsmd = rs.getMetaData();
3194
        String[] ret = new String[rsmd.getColumnCount()];
3195

    
3196
        for (int i = 0; i < ret.length; i++) {
3197
            if (rsmd.getColumnType(i + 1) == Types.NUMERIC) {
3198
                    int scale = rsmd.getScale(i+1);
3199
                    if (scale >= 0) {
3200
                        String prec_dec = " (" + rsmd.getPrecision(i+1) + ", " + scale + ")";  
3201
                        ret[i] = rsmd.getColumnTypeName(i + 1) + prec_dec;
3202
                    } else {
3203
                            ret[i] = rsmd.getColumnTypeName(i + 1);
3204
                    }
3205
            } else {
3206
                ret[i] = rsmd.getColumnTypeName(i + 1);
3207
            }
3208
        }
3209

    
3210
        rs.close();
3211
        st.close();
3212

    
3213
        close();
3214

    
3215
        return ret;
3216
            }catch (SQLException e) {
3217
                        throw new DBException(e);
3218
                }
3219
    }
3220

    
3221
    /**
3222
     * Gets Oracle's specific connection string for the given parameters.
3223
     */
3224
    public String getConnectionString(String host, String port, String dbname,
3225
        String user, String pw) {
3226
        String _pw = pw;
3227

    
3228
        if (_pw == null) {
3229
            _pw = "null";
3230
        }
3231

    
3232
        String fullstr = CONN_STR_BEGIN;
3233
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
3234
        fullstr = fullstr + "@" + host.toLowerCase();
3235
        fullstr = fullstr + ":" + port;
3236
        fullstr = fullstr + ":" + dbname.toLowerCase();
3237

    
3238
        return fullstr;
3239
    }
3240

    
3241
    /**
3242
     * Gets the Pracle geometries writer associated with this driver.
3243
     */
3244
    public IWriter getWriter() {
3245
        // on(VectorialEditableDBAdapter.java:290)
3246
        if (writer == null) {
3247

    
3248
                long count = 0;
3249
                        try {
3250
                                count = getRowCount();
3251
                        } catch (ReadDriverException e1) {
3252
                                logger.error("While getting row count: " + e1.getMessage());
3253
                        }
3254
                
3255
            writer = new OracleSpatialWriter(count);
3256
            writer.setDriver(this);
3257
            writer.setLyrShapeType(getShapeType());
3258
            writer.setGeoCS(isGeogCS());
3259
            writer.setGeoColName(geoColName);
3260
            writer.setSRID(oracleSRID);
3261

    
3262
            try {
3263
                    DBLayerDefinition db_lyr_def = getLyrDef();
3264
                    if (db_lyr_def == null) {
3265
                            logger.warn("Found a null DB layer definition, method initialize of OracleWriter not called.");
3266
                    } else {
3267
                            writer.initialize(getLyrDef());
3268
                    }
3269
                
3270
            } catch (InitializeWriterException e) {
3271
                logger.error("While initializing OS Writer: " + e.getMessage(), e);
3272
            }
3273

    
3274
            writer.setStoreWithSrid(tableHasSrid);
3275
        }
3276

    
3277
        return writer;
3278
    }
3279

    
3280
    /**
3281
     * Tells whether the SRS is geodetic or not-
3282
     * @return whether the SRS is geodetic or not
3283
     */
3284
    public boolean isGeogCS() {
3285
        return isGeogCS;
3286
    }
3287

    
3288
    /**
3289
     * Adds a row id to the inner set od IDs.
3290
     * @param id
3291
     */
3292
    public void addRow(String id) {
3293
        Value aux = ValueFactory.createValue(id);
3294
        Integer intobj = new Integer(numReg);
3295
        hashRelate.put(aux, intobj);
3296
        rowToId.put(intobj, id);
3297

    
3298
        numReg++;
3299
    }
3300

    
3301
    /**
3302
     * Removes a row id to the inner set od IDs.
3303
     * @param id
3304
     */
3305
    public void deleteRow(String id) {
3306
        Value aux = ValueFactory.createValue(id);
3307
        Integer intobj = (Integer) hashRelate.get(aux);
3308
        hashRelate.remove(aux);
3309
        rowToId.remove(intobj);
3310

    
3311
        numReg--;
3312
    }
3313

    
3314
    private String getStandardSelectExpression() {
3315

    
3316
                String resp = "";
3317

    
3318
                String[] flds = getLyrDef().getFieldNames();
3319
                int size = flds.length;
3320

    
3321
                for (int i = 0; i < size; i++) {
3322
                        if (i > 0) {
3323
                                resp = resp + "c.\"" + flds[i] + "\", ";
3324
                        } else {
3325
                                resp = resp + flds[i] + ", ";
3326
                        }
3327
                }
3328

    
3329
                resp = resp.substring(0, resp.length() - 2);
3330
                return resp;
3331
        }
3332

    
3333
    /**
3334
         * Allows the method to decide what to do with the geometry field name
3335
         * (remove/add it from the user selected fields).
3336
         * 
3337
         * @param flds
3338
         * @param geof
3339
         * @return the possibly modified field names
3340
         */
3341
    public String[] manageGeometryField(String[] flds, String geof) {
3342
        return addEndIfNotContained(flds, geof);
3343
    }
3344

    
3345
    /**
3346
     * Allows the method to decide what to do with the ID field name
3347
     * (remove/add it from the user selected fields).
3348
     *
3349
     * @param flds
3350
     * @param idf
3351
     * @return the possibly modified field names
3352
     */
3353
    public String[] manageIdField(String[] flds, String idf) {
3354
        return addStartIfNotContained(flds, idf);
3355
    }
3356

    
3357
    private String[] addEndIfNotContained(String[] arr, String item) {
3358
        if (contains(arr, item)) {
3359
            return arr;
3360
        }
3361
        else {
3362
            int size = arr.length;
3363
            String[] resp = new String[size + 1];
3364

    
3365
            for (int i = 0; i < size; i++) {
3366
                resp[i] = arr[i];
3367
            }
3368

    
3369
            resp[size] = item;
3370

    
3371
            return resp;
3372
        }
3373
    }
3374

    
3375
    private String[] addStartIfNotContained(String[] arr, String item) {
3376
        if (contains(arr, item)) {
3377
            return arr;
3378
        }
3379
        else {
3380
            int size = arr.length;
3381
            String[] resp = new String[size + 1];
3382

    
3383
            for (int i = 1; i <= size; i++) {
3384
                resp[i] = arr[i];
3385
            }
3386

    
3387
            resp[0] = item;
3388

    
3389
            return resp;
3390
        }
3391
    }
3392

    
3393
    private boolean contains(String[] arr, String item) {
3394
        for (int i = 0; i < arr.length; i++) {
3395
            if (arr[i].compareTo(item) == 0) {
3396
                return true;
3397
            }
3398
        }
3399

    
3400
        return false;
3401
    }
3402

    
3403
    /**
3404
     * This method is called when the user removes the layer from the view.
3405
     * If the IDs were being loaded, the driver will check this field and will
3406
     * let the thread 'die' quietly.
3407
     *
3408
     */
3409
    public void remove() {
3410
        cancelIDLoad = true;
3411
    }
3412

    
3413
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
3414
            // if (!isgeodetic) return true;
3415
            if ((ext.getMinX() > -179.9) || (ext.getMinX() < -180.1)) return true;
3416
            if ((ext.getMinY() > -89.9) || (ext.getMinY() < -90.1)) return true;
3417
            if ((ext.getWidth() < 359.9) || (ext.getWidth() > 360.1)) return true;
3418
            if ((ext.getHeight() < 179.9) || (ext.getHeight() > 180.1)) return true;
3419
            return false;
3420
    }
3421

    
3422
    private Rectangle2D getFastEstimatedExtent(
3423
                    String tname,
3424
                    String gfield,
3425
                    IConnection c,
3426
                    int sample_size,
3427
                    double enlargement,
3428
                    boolean is_geo) {
3429

    
3430
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
3431
            Rectangle2D resp_aux = null;
3432
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
3433
            ResultSet _rs = null;
3434

    
3435
            try {
3436
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
3437
                        _rs = _st.executeQuery();
3438
                        while (_rs.next()) {
3439
                                STRUCT aux = (STRUCT) _rs.getObject(1);
3440
                                IGeometry ig = getGeometryUsing(aux, false);
3441

    
3442
                                if (ig == null) continue;
3443

    
3444
                                if (resp_aux == null) {
3445
                                        resp_aux = ig.getBounds2D();
3446
                                } else {
3447
                                        resp_aux.add(ig.getBounds2D());
3448
                                }
3449

    
3450
                        }
3451
                } catch (Exception ex) {
3452
                        logger.error("While getting random sample: " + ex.getMessage());
3453
                }
3454

    
3455
                if (resp_aux == null) {
3456
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
3457
                        return world;
3458
                }
3459
                
3460
                double w = resp_aux.getWidth();
3461
                double h = resp_aux.getHeight();
3462
                double x = resp_aux.getMinX();
3463
                double y = resp_aux.getMinY();
3464

    
3465
                // enlarge n times:
3466
                double newx = x - (0.5 * (enlargement - 1)) * w;
3467
                double newy = y - (0.5 * (enlargement - 1)) * h;
3468
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
3469
                                enlargement * w,
3470
                                enlargement * h);
3471

    
3472
                if (is_geo) {
3473
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
3474
                        logger.debug("FAST BB: " + resp_aux.toString());
3475
                        return resp_aux;
3476
                } else {
3477
                        logger.debug("FAST BB: " + resp_aux_large.toString());
3478
                        return resp_aux_large;
3479
                }
3480

    
3481
    }
3482

    
3483
    private Rectangle2D getEstimatedExtent(
3484
                    String tname,
3485
                    String gfield,
3486
                    IConnection c,
3487
                    int sample_size,
3488
                    double enlargement,
3489
                    boolean is_geo) {
3490

    
3491
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
3492
            
3493
            if (numReg == 0) {
3494
                    logger.warn("numReg is 0, returned worlld bbox in getEstimatedExtent(...).");
3495
                    return world;
3496
            }
3497

    
3498
            ArrayList ids = new ArrayList();
3499
            int _rnd_index = 0;
3500
            ROWID _id = null;
3501
            Random rnd = new Random(System.currentTimeMillis());
3502

    
3503
            for (int i=0; i<sample_size; i++) {
3504
                    _rnd_index = rnd.nextInt(numReg);
3505
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
3506
                    ids.add(_id.stringValue());
3507
            }
3508

    
3509
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
3510
            for (int i=0; i<ids.size(); i++) {
3511
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR ";
3512
            }
3513
            qry = qry.substring(0, qry.length() - 4) + ")";
3514

    
3515
            Rectangle2D resp_aux = null;
3516
            ResultSet _rs = null;
3517

    
3518
            try {
3519
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
3520
                        _rs = _st.executeQuery();
3521
                        while (_rs.next()) {
3522
                                STRUCT aux = (STRUCT) _rs.getObject(1);
3523
                                IGeometry ig = getGeometryUsing(aux, false);
3524

    
3525
                                if (ig == null) continue;
3526

    
3527
                                if (resp_aux == null) {
3528
                                        resp_aux = ig.getBounds2D();
3529
                                } else {
3530
                                        resp_aux.add(ig.getBounds2D());
3531
                                }
3532

    
3533
                        }
3534
                } catch (Exception ex) {
3535
                        logger.error("While getting random sample: " + ex.getMessage());
3536
                }
3537

    
3538
                if (resp_aux == null) {
3539
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
3540
                        return world;
3541
                }
3542
                
3543
                double w = resp_aux.getWidth();
3544
                double h = resp_aux.getHeight();
3545
                double x = resp_aux.getMinX();
3546
                double y = resp_aux.getMinY();
3547

    
3548
                // enlarge 10 times:
3549
                double newx = x - (0.5 * (enlargement - 1)) * w;
3550
                double newy = y - (0.5 * (enlargement - 1)) * h;
3551
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
3552
                                enlargement * w,
3553
                                enlargement * h);
3554

    
3555
                if (is_geo) {
3556
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
3557
                        logger.debug("ESTIMATED BB: " + resp_aux.toString());
3558
                        return resp_aux;
3559
                } else {
3560
                        logger.debug("ESTIMATED BB: " + resp_aux_large.toString());
3561
                        return resp_aux_large;
3562
                }
3563

    
3564
    }
3565

    
3566
    public void setUserName(String u) {
3567
            userName = u;
3568
    }
3569

    
3570
    public String getUserName() {
3571
            return userName;
3572
    }
3573

    
3574
    public static final int JGeometry_GTYPE_COLLECTION = 4;
3575
    public static final int JGeometry_GTYPE_CURVE = 2;
3576
    public static final int JGeometry_GTYPE_MULTICURVE = 6;
3577
    public static final int JGeometry_GTYPE_MULTIPOINT = 5;
3578
    public static final int JGeometry_GTYPE_MULTIPOLYGON = 7;
3579
    public static final int JGeometry_GTYPE_POINT = 1;
3580
    public static final int JGeometry_GTYPE_POLYGON = 3;
3581
        
3582

    
3583
    // ------------------------------
3584
    
3585
    public void setXMLEntity(XMLEntity xml) throws XMLException {
3586
            
3587
            super.setXMLEntity(xml);
3588
            workingAreaInTablesCS = workingArea;
3589
            
3590
            try {
3591
                    int[] ftypes = xml.getIntArrayProperty("fieldTypes");
3592
                    setLyrDefFieldTypes(ftypes);
3593
            } catch (Exception ex) {
3594
                    logger.warn("Apparently, an old GVP file has been opened," +
3595
                                    " field type values are not accurate after this point.");
3596
            }
3597
            
3598
    }
3599
    
3600
    public XMLEntity getXMLEntity() {
3601
                // ---------------------
3602

    
3603
                XMLEntity xml = new XMLEntity();
3604
                xml.putProperty("className", getClass().getName());
3605

    
3606
                xml.putProperty("catalog", getLyrDef().getCatalogName());
3607

    
3608
                int aux = userName.indexOf("@");
3609
                if (aux != -1)
3610
                        userName = userName.substring(0, aux);
3611
                xml.putProperty("username", userName);
3612

    
3613
                xml.putProperty("driverclass", ORACLE_JAR_FILE_NAME);
3614

    
3615
                xml.putProperty("tablename", getTableName());
3616
                xml.putProperty("fields", lyrDef.getFieldNames());
3617
                xml.putProperty("fieldTypes", getLyrDefFieldTypes());
3618
                xml.putProperty("FID", lyrDef.getFieldID());
3619
                xml.putProperty("THE_GEOM", lyrDef.getFieldGeometry());
3620
                xml.putProperty("whereclause", getWhereClause());
3621
                xml.putProperty("SRID", lyrDef.getSRID_EPSG());
3622

    
3623
                xml.putProperty("host", host);
3624
                xml.putProperty("port", port);
3625
                xml.putProperty("dbName", dbName);
3626
                xml.putProperty("connName", connName);
3627

    
3628
                if (workingAreaInTablesCS != null) {
3629
                        xml.putProperty("minXworkArea", workingAreaInTablesCS.getMinX());
3630
                        xml.putProperty("minYworkArea", workingAreaInTablesCS.getMinY());
3631
                        xml.putProperty("HworkArea", workingAreaInTablesCS.getHeight());
3632
                        xml.putProperty("WworkArea", workingAreaInTablesCS.getWidth());
3633
                }
3634

    
3635
                return xml;
3636
        }
3637
    
3638
    private int[] getLyrDefFieldTypes() {
3639
            FieldDescription[] fd = lyrDef.getFieldsDesc();
3640
            int sz = fd.length;
3641
            int[] resp = new int[sz];
3642
            for (int i=0; i<sz; i++) resp[i] = fd[i].getFieldType();
3643
                return resp;
3644
        }
3645
    
3646
    private void setLyrDefFieldTypes(int[] tt) {
3647
            FieldDescription[] fd = lyrDef.getFieldsDesc();
3648
            
3649
            int sz_fd = fd.length;
3650
            int sz_tt = tt.length;
3651
            int sz = sz_tt;
3652
            
3653
            if (sz_tt != sz_fd) {
3654
                    logger.error("Field count does not match. lyrDef has " + sz_fd + " fields," +
3655
                                    " but this method was called with " + sz_tt + " items (?)");
3656
                    sz = Math.min(sz_fd, sz_tt);
3657
            }
3658
            
3659
            for (int i=0; i<sz; i++) lyrDef.getFieldsDesc()[i].setFieldType(tt[i]);
3660
    }
3661

    
3662
        public String[] getTableFields(IConnection conex, String table) throws DBException {
3663
                try{
3664
                Statement st = ((ConnectionJDBC)conex).getConnection().createStatement();
3665
        // ResultSet rs = dbmd.getTables(catalog, null, dbLayerDefinition.getTable(), null);
3666
                ResultSet rs = st.executeQuery("select * from " + table + " LIMIT 1");
3667
                ResultSetMetaData rsmd = rs.getMetaData();
3668

    
3669
                String[] ret = new String[rsmd.getColumnCount()];
3670

    
3671
                for (int i = 0; i < ret.length; i++) {
3672
                        ret[i] = rsmd.getColumnName(i+1);
3673
                }
3674

    
3675
                return ret;
3676
                }catch (SQLException e) {
3677
                        throw new DBException(e);
3678
                }
3679
        }
3680

    
3681
    // Overwritten to keep old behavior: returns "schema.table_name" if
3682
    // schema is not current user
3683
        public String getTableName() {
3684
            return fullTableName; 
3685
        }
3686
        
3687
    private Timestamp flexibleTimeStamp(String s) {
3688
            
3689
            String aux = s.replace('-', ' ');
3690
            aux = aux.replace(':', ' ');
3691
            aux = aux.replace('.', ' ');
3692
            // sample: 2007 12 31 23 59 59 9999
3693
            String[] parts = aux.trim().split(" ");
3694
            
3695
            int year;
3696
            int month;
3697
            int day;
3698
            int hour;
3699
            int minute;
3700
            int second;
3701
            int a_nanos;
3702

    
3703
            if (parts.length == 7) {
3704

    
3705
                    try {
3706

    
3707
                            year = Integer.parseInt(parts[0]) - 1900;
3708
                            month = Integer.parseInt(parts[1]) - 1;
3709
                            day = Integer.parseInt(parts[2]);
3710
                            hour = Integer.parseInt(parts[3]);
3711
                            minute = Integer.parseInt(parts[4]);
3712
                            second = Integer.parseInt(parts[5]);
3713
                            a_nanos = Integer.parseInt(parts[6]);
3714
                            
3715
                    } catch (Exception ex) {
3716
                        logger.debug("Bad time stamp: " + ex.getMessage());
3717
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3718
                    }
3719

    
3720
            } else {
3721
                    
3722
                if (parts.length == 6) {
3723
                        
3724
                        try {
3725
                            year = Integer.parseInt(parts[0]) - 1900;
3726
                            month = Integer.parseInt(parts[1]) - 1;
3727
                            day = Integer.parseInt(parts[2]);
3728
                            hour = Integer.parseInt(parts[3]);
3729
                            minute = Integer.parseInt(parts[4]);
3730
                            second = Integer.parseInt(parts[5]);
3731
                            a_nanos = 0;
3732
                            
3733
                        } catch (Exception ex) {
3734
                                
3735
                            logger.debug("Bad time stamp: " + ex.getMessage());
3736
                            return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3737
                        }
3738

    
3739
                } else {
3740
                        
3741
                        logger.debug("Bad time stamp: " + s);
3742
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
3743
                        
3744
                }
3745
            }
3746
            
3747
            return new Timestamp(year, month, day, hour, minute, second, a_nanos);
3748
    }
3749

    
3750
        public void write(DataWare arg0) throws WriteDriverException, ReadDriverException {
3751
        }
3752
        
3753
        public static String removePrefix(String str) {
3754
                
3755
                int colon_ind = str.indexOf(":");
3756
                if (colon_ind != -1) {
3757
                        return str.substring(colon_ind + 1);
3758
                } else {
3759
                        return str;
3760
                }
3761
        }
3762

    
3763
    
3764
            
3765
            private class AnEmptyFeatureIterator implements IFeatureIterator {
3766
                public boolean hasNext() throws ReadDriverException { return false; }
3767
                public IFeature next() throws ReadDriverException { return null; }
3768
                public void closeIterator() throws ReadDriverException { }                
3769
        }
3770
            
3771
        private Value objToValue(Object obj, int idFld) {
3772
                
3773
            if (obj == null) {
3774
                    return ValueFactory.createNullValue();
3775
            } else {
3776
                    
3777
                    String objToString = obj.toString();
3778

    
3779
                if (obj instanceof String) {
3780
                    objToString = (String) obj;
3781
                    return ValueFactory.createValue(objToString);
3782
                } else {
3783
                    if (obj instanceof ROWID) {
3784
                        objToString = ((ROWID) obj).stringValue();
3785
                        return ValueFactory.createValue(objToString);
3786
                    } else {
3787
                        if (obj instanceof STRUCT) {
3788
                            objToString = "STRUCT";
3789
                            return ValueFactory.createValue(objToString);
3790
                        } else {
3791
                            if (obj instanceof TIMESTAMP) {
3792
                                    TIMESTAMP aux = (TIMESTAMP) obj;
3793
                                objToString = aux.stringValue();
3794
                                Timestamp ts = flexibleTimeStamp(objToString);
3795
                                return ValueFactory.createValue(ts);
3796

    
3797
                            } else {
3798

    
3799
                                    // last try
3800
                                    int _type = -1;
3801
                                                            try {
3802
                                                                    _type = getFieldType(idFld);
3803
                                        if (_type == Types.DATE) {
3804
                                                objToString = objToString.replace('-', '/');
3805
                                        }
3806
                                        return ValueFactory.createValueByType(objToString, _type);
3807
                                } catch (Exception ex) {
3808
                                        logger.debug("Failed to create Value: _type = "
3809
                                                        + _type + ", objToString = " + objToString);
3810
                                        return ValueFactory.createNullValue();
3811
                                }
3812
                                
3813
                            }
3814
                        }
3815
                    }
3816
                }
3817
            }
3818
        }
3819

    
3820
        public Value[] getAttributes(ResultSet rs, boolean use_main_metadata) {
3821
            Value[] res = null;
3822

    
3823
            int fcount = 0;
3824

    
3825
            try {
3826
                    if (use_main_metadata) {
3827
                            fcount = metaData.getColumnCount();
3828
                    } else {
3829
                            fcount = rs.getMetaData().getColumnCount();
3830
                    }
3831
                
3832
                res = new Value[fcount];
3833

    
3834
                for (int i = 0; i < fcount; i++) {
3835
                    Object obj = rs.getObject(i + 1);
3836
                    res[i] = objToValue(obj, i);
3837
                }
3838

    
3839
            } catch (Exception se) {
3840
                    logger.error("While getting resultset attribute values: " + se.getMessage());
3841
                    res = new Value[fcount];
3842
                    for (int i=0; i<fcount; i++) res[i] = ValueFactory.createNullValue();
3843
            }
3844

    
3845
            return res;
3846
        }            
3847
        
3848
        public boolean canWriteGeometry(int gvSIGgeometryType) {
3849
                if (writer == null) {
3850
                        return true;
3851
                } else {
3852
                        return writer.canWriteGeometry(gvSIGgeometryType);
3853
                }
3854
        }
3855

    
3856
        public static String getTableExistsSql(DBLayerDefinition dbLayerDef) {
3857
                
3858
        return "SELECT * FROM " + dbLayerDef.getTableName();
3859
        }
3860

    
3861
        public int getAdaptedFetchSize() {
3862
                return adaptedFetchSize;
3863
        }
3864

    
3865
        public void setAdaptedFetchSize(int v) {
3866
                adaptedFetchSize = v;
3867
        }
3868
        
3869
    
3870

    
3871
}
3872

    
3873
// [eiel-gestion-conexiones]
3874