Statistics
| Revision:

root / trunk / extensions / extJDBC / src / com / iver / cit / gvsig / fmap / drivers / jdbc / postgis / PostGisDriver.java @ 38057

History | View | Annotate | Download (48.2 KB)

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

    
46
import java.awt.geom.Rectangle2D;
47
import java.math.BigDecimal;
48
import java.math.BigInteger;
49
import java.nio.ByteBuffer;
50
import java.sql.Connection;
51
import java.sql.PreparedStatement;
52
import java.sql.ResultSet;
53
import java.sql.ResultSetMetaData;
54
import java.sql.SQLException;
55
import java.sql.Statement;
56
import java.sql.Timestamp;
57
import java.sql.Types;
58
import java.util.ArrayList;
59
import java.util.Calendar;
60
import java.util.GregorianCalendar;
61
import java.util.HashMap;
62
import java.util.Hashtable;
63
import java.util.Map;
64
import java.util.Random;
65

    
66
import org.apache.log4j.Logger;
67
import org.joda.time.DateTime;
68
import org.postgis.PGbox2d;
69
import org.postgis.PGbox3d;
70
import org.postgresql.util.PSQLException;
71
import org.postgresql.util.PSQLState;
72

    
73
import com.hardcode.gdbms.driver.exceptions.InitializeWriterException;
74
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
75
import com.hardcode.gdbms.engine.data.edition.DataWare;
76
import com.hardcode.gdbms.engine.values.Value;
77
import com.hardcode.gdbms.engine.values.ValueFactory;
78
import com.iver.andami.PluginServices;
79
import com.iver.cit.gvsig.fmap.core.FShape;
80
import com.iver.cit.gvsig.fmap.core.ICanReproject;
81
import com.iver.cit.gvsig.fmap.core.IGeometry;
82
import com.iver.cit.gvsig.fmap.drivers.ConnectionJDBC;
83
import com.iver.cit.gvsig.fmap.drivers.DBException;
84
import com.iver.cit.gvsig.fmap.drivers.DBLayerDefinition;
85
import com.iver.cit.gvsig.fmap.drivers.DefaultJDBCDriver;
86
import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
87
import com.iver.cit.gvsig.fmap.drivers.FieldDescription;
88
import com.iver.cit.gvsig.fmap.drivers.IConnection;
89
import com.iver.cit.gvsig.fmap.drivers.IFeatureIterator;
90
import com.iver.cit.gvsig.fmap.drivers.WKBParser3;
91
import com.iver.cit.gvsig.fmap.drivers.XTypes;
92
import com.iver.cit.gvsig.fmap.edition.IWriteable;
93
import com.iver.cit.gvsig.fmap.edition.IWriter;
94

    
95
/**
96
 * @author FJP
97
 */
98
public class PostGisDriver extends DefaultJDBCDriver implements ICanReproject,
99
                IWriteable {
100

    
101

    
102
        private static Logger logger = Logger.getLogger(PostGisDriver.class
103
                        .getName());
104

    
105
        private static int FETCH_SIZE = 5000;
106

    
107
        // To avoid problems when using wkb_cursor with same layer.
108
        // I mean, when you add twice or more the same layer using
109
        // the same connection
110

    
111
        private static int CURSOR_ID = 0;
112

    
113
        private int myCursorId;
114

    
115
        private PostGISWriter writer = new PostGISWriter();
116

    
117
        private WKBParser3 parser = new WKBParser3();
118

    
119
        private int fetch_min = -1;
120

    
121
        private int fetch_max = -1;
122

    
123
        private String sqlOrig;
124

    
125
        /**
126
         * Used by setAbsolutePosition
127
         */
128
        private String sqlTotal;
129

    
130
        private String strEPSG = null;
131

    
132
        private String originalEPSG = null;
133

    
134
        private Rectangle2D fullExtent = null;
135

    
136
        private String completeWhere;
137

    
138
        boolean bShapeTypeRevised = false;
139

    
140

    
141
        /**
142
         * It stores all schemas privileges, in order to avoid checking it everytime
143
         * canRead() is called.
144
         */
145
        private Map<String, Boolean> schemasUsage = new HashMap<String, Boolean>();
146

    
147
        private String cursorName;
148

    
149
        private static final BigInteger _nbase = new BigInteger("10000");
150

    
151
        private static final BigInteger _nbasePow2 = _nbase.pow(2);
152

    
153
        private static final BigInteger _nbasePow4 = _nbase.pow(4);
154

    
155
        private static final long nbaseLong = _nbase.longValue();
156

    
157
        private static final long nbaseLongPow2 = nbaseLong * nbaseLong;
158

    
159
        private static final int nbaseInt = (int) nbaseLong;
160

    
161
        public static final String NAME = "PostGIS JDBC Driver";
162

    
163
        protected static BigInteger getNBase() {
164
                return _nbase;
165
        }
166

    
167
        protected static BigInteger getNBasePow2() {
168
                return _nbasePow2;
169
        }
170

    
171
        protected static BigInteger getNBasePow4() {
172
                return _nbasePow4;
173
        }
174

    
175
        static {
176
                try {
177
                        Class.forName("org.postgresql.Driver");
178
                } catch (ClassNotFoundException e) {
179
                        throw new RuntimeException(e);
180
                }
181
        }
182

    
183
        /**
184
         *
185
         */
186
        public PostGisDriver() {
187
                // To avoid problems when using wkb_cursor with same layer.
188
                // I mean, when you add twice or more the same layer using
189
                // the same connection
190
                CURSOR_ID++;
191
                myCursorId = CURSOR_ID;
192
        }
193

    
194
        /*
195
         * (non-Javadoc)
196
         *
197
         * @see
198
         * com.iver.cit.gvsig.fmap.drivers.VectorialDriver#getDriverAttributes()
199
         */
200
        public DriverAttributes getDriverAttributes() {
201
                return null;
202
        }
203

    
204
        /*
205
         * (non-Javadoc)
206
         *
207
         * @see com.hardcode.driverManager.Driver#getName()
208
         */
209
        public String getName() {
210
                return NAME;
211
        }
212

    
213
        /**
214
         * @throws ReadDriverException
215
         * @see com.iver.cit.gvsig.fmap.layers.ReadableVectorial#getShape(int)
216
         */
217
        public IGeometry getShape(int index) throws ReadDriverException {
218
                IGeometry geom = null;
219
                try {
220
                        setAbsolutePosition(index);
221
                        // strAux = rs.getString(1);
222
                        // geom = parser.read(strAux);
223
                        if (rs != null) {
224
                                byte[] data = rs.getBytes(1);
225
                                if (data == null) {
226
                                    return null;
227
                                }
228
                                geom = parser.parse(data);
229
                        }
230
                } catch (SQLException e) {
231
                        throw new ReadDriverException(this.getName(), e);
232
                }
233

    
234
                return geom;
235
        }
236

    
237
        /**
238
         * First, the geometry field. After, the rest of fields
239
         *
240
         * @return
241
         */
242
        /*
243
         * public String getTotalFields() { String strAux = "AsBinary(" +
244
         * getLyrDef().getFieldGeometry() + ")"; String[] fieldNames =
245
         * getLyrDef().getFieldNames(); for (int i=0; i< fieldNames.length; i++) {
246
         * strAux = strAux + ", " + fieldNames[i]; } return strAux; }
247
         */
248

    
249
        /**
250
         * Antes de llamar a esta funci?n hay que haber fijado el workingArea si se
251
         * quiere usar.
252
         *
253
         * @param conn
254
         * @throws DBException
255
         */
256
        public void setData(IConnection conn, DBLayerDefinition lyrDef)
257
                        throws DBException {
258
                this.conn = conn;
259
                // TODO: Deber?amos poder quitar Conneciton de la llamada y meterlo
260
                // en lyrDef desde el principio.
261

    
262
                lyrDef.setConnection(conn);
263
                setLyrDef(lyrDef);
264

    
265
                getTableEPSG_and_shapeType(conn, lyrDef);
266

    
267
                getLyrDef().setSRID_EPSG(originalEPSG);
268

    
269
                try {
270
                        ((ConnectionJDBC) conn).getConnection().setAutoCommit(false);
271
                        sqlOrig = "SELECT " + getTotalFields() + " FROM "
272
                        + getLyrDef().getComposedTableName() + " ";
273

    
274
                        if (canReproject(strEPSG)) {
275
                                completeWhere = getCompoundWhere(sqlOrig, workingArea, strEPSG);
276
                        } else {
277
                                completeWhere = getCompoundWhere(sqlOrig, workingArea,
278
                                                originalEPSG);
279
                        }
280

    
281
                        sqlTotal = sqlOrig + completeWhere + " ORDER BY " + getLyrDef().getFieldID();
282

    
283
                        logger.info("Cadena SQL:" + sqlTotal);
284
                        Statement st = ((ConnectionJDBC) conn).getConnection().createStatement(
285
                                        ResultSet.TYPE_SCROLL_INSENSITIVE,
286
                                        ResultSet.CONCUR_READ_ONLY);
287

    
288
                        myCursorId++;
289
                        cursorName = "wkb_cursor_" + myCursorId + getTableName();
290

    
291
                        st.execute("declare " + cursorName + " binary scroll cursor with hold for " + sqlTotal);
292

    
293
                        rs = st.executeQuery("fetch forward " + FETCH_SIZE + " in " + cursorName);
294
                        fetch_min = 0;
295
                        fetch_max = FETCH_SIZE - 1;
296
                        metaData = rs.getMetaData();
297
                        doRelateID_FID();
298

    
299
                        writer.setCreateTable(false);
300
                        writer.setWriteAll(false);
301
                        writer.initialize(lyrDef);
302

    
303
                } catch (SQLException e) {
304

    
305
                        try {
306
                                ((ConnectionJDBC) conn).getConnection().rollback();
307
                        } catch (SQLException e1) {
308
                                logger.warn("Unable to rollback connection after problem (" + e.getMessage() + ") in setData()");
309
                        }
310

    
311
                        try {
312
                                if (rs != null) { rs.close(); }
313
                        } catch (SQLException e1) {
314
                                throw new DBException(e);
315
                        }
316
                        throw new DBException(e);
317
                } catch (InitializeWriterException e) {
318
                        throw new DBException(e);
319
                }
320
        }
321

    
322
        /**
323
         * @see com.iver.cit.gvsig.fmap.layers.ReadableVectorial#getFullExtent()
324
         */
325
        public Rectangle2D getFullExtent() throws ReadDriverException {
326
                if (fullExtent == null) {
327
                        try {
328
                                Statement s = ((ConnectionJDBC) conn).getConnection()
329
                                                .createStatement();
330
                                String query = "SELECT extent(\""
331
                                    + getLyrDef().getFieldGeometry()
332
                                    + "\") AS FullExtent FROM " + getLyrDef().getComposedTableName()
333
                                    + " " + getCompleteWhere();
334
                                ResultSet r = s.executeQuery(query);
335
                                r.next();
336
                                String strAux = r.getString(1);
337
                                System.out.println("fullExtent = " + strAux);
338
                                if (strAux == null) {
339
                                        logger.debug("La capa " + getLyrDef().getName()
340
                                                        + " no tiene FULLEXTENT");
341
                                        return null;
342
                                }
343
                                if (strAux.startsWith("BOX3D")) {
344
                                        PGbox3d regeom = new PGbox3d(strAux);
345
                                        double x = regeom.getLLB().x;
346
                                        double y = regeom.getLLB().y;
347
                                        double w = regeom.getURT().x - x;
348
                                        double h = regeom.getURT().y - y;
349
                                        fullExtent = new Rectangle2D.Double(x, y, w, h);
350
                                } else {
351
                                        PGbox2d regeom = new PGbox2d(strAux);
352
                                        double x = regeom.getLLB().x;
353
                                        double y = regeom.getLLB().y;
354
                                        double w = regeom.getURT().x - x;
355
                                        double h = regeom.getURT().y - y;
356
                                        fullExtent = new Rectangle2D.Double(x, y, w, h);
357
                                }
358
                        } catch (SQLException e) {
359
                                throw new ReadDriverException(this.getName(), e);
360
                        }
361

    
362
                }
363

    
364
                return fullExtent;
365
        }
366

    
367
        /*
368
         * (non-Javadoc)
369
         *
370
         * @see
371
         * com.iver.cit.gvsig.fmap.drivers.VectorialDatabaseDriver#getGeometryIterator
372
         * (java.lang.String)
373
         */
374
        public IFeatureIterator getFeatureIterator(String sql)
375
                        throws ReadDriverException {
376
                PostGisFeatureIterator geomIterator = null;
377
                geomIterator = myGetFeatureIterator(sql);
378
                geomIterator.setLyrDef(getLyrDef());
379

    
380
                return geomIterator;
381
        }
382

    
383
    private PostGisFeatureIterator myGetFeatureIterator(String sql)
384
            throws ReadDriverException {
385
        PostGisFeatureIterator geomIterator = null;
386
        try {
387
            String provCursorName = "wkb_cursor_prov_"
388
                    + Long.toString(Math.abs(new Random().nextLong()))
389
                    + getTableName();
390
            // jlopez: if the cursor is longer than 64 chars, we strip it to
391
            // that length. We should use a different name convention which
392
            // avoids this kind of problems.
393
            if (provCursorName.length() > 64) {
394
                provCursorName = provCursorName.substring(0, 63);
395
            }
396

    
397
            bCursorActivo = true;
398
            geomIterator = new PostGisFeatureIterator(
399
                    ((ConnectionJDBC) conn).getConnection(), provCursorName,
400
                    sql);
401
        } catch (SQLException e) {
402
            throw new ReadDriverException("PostGIS Driver", e);
403
                }
404
        return geomIterator;
405
    }
406

    
407
        public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
408
        throws ReadDriverException {
409
                if (workingArea != null) {
410
                    r = r.createIntersection(workingArea);
411
                }
412

    
413
                String sqlAux;
414
                if (canReproject(strEPSG)) {
415
                        sqlAux = sqlOrig + getCompoundWhere(sqlOrig, r, strEPSG);
416
                } else {
417
                        sqlAux = sqlOrig + getCompoundWhere(sqlOrig, r, originalEPSG);
418
                }
419

    
420
                System.out.println("SqlAux getFeatureIterator = " + sqlAux);
421

    
422
                return getFeatureIterator(sqlAux);
423
        }
424

    
425
        /**
426
         * Le pasas el rect?ngulo que quieres pedir. La primera vez es el
427
         * workingArea, y las siguientes una interseccion de este rectangulo con el
428
         * workingArea
429
         *
430
         * @param r
431
         * @param strEPSG
432
         * @return
433
         */
434
        private String getCompoundWhere(String sql, Rectangle2D r, String strEPSG) {
435
                if (r == null) {
436
                    return getWhereClause();
437
                }
438

    
439
                double xMin = r.getMinX();
440
                double yMin = r.getMinY();
441
                double xMax = r.getMaxX();
442
                double yMax = r.getMaxY();
443
                String wktBox = "GeometryFromText('LINESTRING(" + xMin + " " + yMin
444
                + ", " + xMax + " " + yMin + ", " + xMax + " " + yMax + ", "
445
                + xMin + " " + yMax + ")', " + strEPSG + ")";
446
                String sqlAux;
447
                if (getWhereClause().toUpperCase().indexOf("WHERE") != -1) {
448
                    sqlAux = getWhereClause() + " AND \"" + getLyrDef().getFieldGeometry() + "\" && " + wktBox;
449
                } else {
450
                    sqlAux = "WHERE \"" + getLyrDef().getFieldGeometry() + "\" && "
451
                        + wktBox;
452
                }
453
                return sqlAux;
454
        }
455

    
456
        /**
457
         * @see com.iver.cit.gvsig.fmap.drivers.IVectorialDatabaseDriver#getConnectionStringBeginning()
458
         */
459
        public String getConnectionStringBeginning() {
460
                return "jdbc:postgresql:";
461
        }
462

    
463
        /*
464
         * (non-Javadoc)
465
         *
466
         * @see com.iver.cit.gvsig.fmap.drivers.DefaultDBDriver#getFieldValue(long,
467
         * int)
468
         */
469
        @Override
470
        public Value getFieldValue(long rowIndex, int idField)
471
        throws ReadDriverException {
472
                // EL ABSOLUTE NO HACE QUE SE VUELVAN A LEER LAS
473
                // FILAS, ASI QUE MONTAMOS ESTA HISTORIA PARA QUE
474
                // LO HAGA
475
                int index = (int) (rowIndex);
476
                try {
477
                        setAbsolutePosition(index);
478
                        int fieldId = idField + 2;
479
                        return getFieldValue(rs, fieldId);
480

    
481
                } catch (SQLException e) {
482
                        throw new ReadDriverException("PostGIS Driver", e);
483
                }
484
        }
485

    
486
        static Value getFieldValue(ResultSet aRs, int fieldId) throws SQLException {
487
                ResultSetMetaData metaData = aRs.getMetaData();
488
                byte[] byteBuf = aRs.getBytes(fieldId);
489
                if (byteBuf == null) {
490
                    return ValueFactory.createNullValue();
491
                } else {
492
                        ByteBuffer buf = ByteBuffer.wrap(byteBuf);
493
                        if (metaData.getColumnType(fieldId) == Types.VARCHAR) {
494
                            return ValueFactory.createValue(aRs.getString(fieldId));
495
                        }
496
                        if (metaData.getColumnType(fieldId) == Types.CHAR){
497
                                String character = aRs.getString(fieldId);
498
                                if (character != null){
499
                                        return ValueFactory.createValue(character.trim());
500
                                }else{
501
                                        return ValueFactory.createValue(character);
502
                                }
503
                        }
504
                        if (metaData.getColumnType(fieldId) == Types.FLOAT) {
505
                            return ValueFactory.createValue(buf.getFloat());
506
                        }
507
                        if (metaData.getColumnType(fieldId) == Types.DOUBLE) {
508
                            return ValueFactory.createValue(buf.getDouble());
509
                        }
510
                        if (metaData.getColumnType(fieldId) == Types.REAL) {
511
                            return ValueFactory.createValue(buf.getFloat());
512
                        }
513
                        if (metaData.getColumnType(fieldId) == Types.INTEGER) {
514
                            return ValueFactory.createValue(buf.getInt());
515
                        }
516
                        if (metaData.getColumnType(fieldId) == Types.SMALLINT) {
517
                            return ValueFactory.createValue(buf.getShort());
518
                        }
519
                        if (metaData.getColumnType(fieldId) == Types.BIGINT) {
520
                            return ValueFactory.createValue(buf.getLong());
521
                        }
522
                        if (metaData.getColumnType(fieldId) == Types.BIT) {
523
                            return ValueFactory.createValue((byteBuf[0] == 1));
524
                        }
525
                        if (metaData.getColumnType(fieldId) == Types.BOOLEAN) {
526
                            return ValueFactory.createValue(aRs.getBoolean(fieldId));
527
                        }
528
                        if (metaData.getColumnType(fieldId) == Types.DATE) {
529
                                long daysAfter2000 = buf.getInt();
530
                                DateTime year2000 = new DateTime(2000, 1,1,0,0,0);
531
                                DateTime dt = year2000.plusDays((int)daysAfter2000);
532
                                Calendar cal = GregorianCalendar.getInstance();
533
                                cal.set(dt.getYear(), dt.getMonthOfYear()-1, dt.getDayOfMonth());
534
//                                System.out.println(dt + " convertido:" + cal.getTime());
535
                                return ValueFactory.createValue(cal.getTime());
536
                        }
537
                        if (metaData.getColumnType(fieldId) == Types.TIME) {
538
                                // TODO:
539
                                // throw new RuntimeException("TIME type not implemented yet");
540
                                return ValueFactory.createValue("NOT IMPLEMENTED YET");
541
                        }
542
                        if (metaData.getColumnType(fieldId) == Types.TIMESTAMP) {
543
                                double segsReferredTo2000 = buf.getDouble();
544
                                long real_msecs = (long) (XTypes.NUM_msSecs2000 + segsReferredTo2000 * 1000);
545
                                Timestamp valTimeStamp = new Timestamp(real_msecs);
546
                                return ValueFactory.createValue(valTimeStamp);
547
                        }
548

    
549
                        if (metaData.getColumnType(fieldId) == Types.NUMERIC) {
550
                                // System.out.println(metaData.getColumnName(fieldId) + " "
551
                                // + metaData.getColumnClassName(fieldId));
552
                                // short ndigits = buf.getShort();
553
                                // short weight = buf.getShort();
554
                                // short sign = buf.getShort();
555
                                // short dscale = buf.getShort();
556
                                // String strAux;
557
                                // if (sign == 0)
558
                                // strAux = "+";
559
                                // else
560
                                // strAux = "-";
561
                                //
562
                                // for (int iDigit = 0; iDigit < ndigits; iDigit++) {
563
                                // short digit = buf.getShort();
564
                                // strAux = strAux + digit;
565
                                // if (iDigit == weight)
566
                                // strAux = strAux + ".";
567
                                //
568
                                // }
569
                                // strAux = strAux + "0";
570

    
571
                                BigDecimal dec;
572
                                dec = getBigDecimal(buf.array());
573
                                // dec = new BigDecimal(strAux);
574
                                // System.out.println(ndigits + "_" + weight + "_" + dscale
575
                                // + "_" + strAux);
576
                                // System.out.println(strAux + " Big= " + dec);
577
                                return ValueFactory.createValue(dec.doubleValue());
578
                        }
579

    
580
                }
581

    
582
                return ValueFactory.createNullValue();
583

    
584
        }
585

    
586
        private static BigDecimal getBigDecimal(byte[] number) throws SQLException {
587

    
588
                short ndigits = (short) (((number[0] & 0xff) << 8) | (number[1] & 0xff));
589
                short weight = (short) (((number[2] & 0xff) << 8) | (number[3] & 0xff));
590
                short sign = (short) (((number[4] & 0xff) << 8) | (number[5] & 0xff));
591
                short dscale = (short) (((number[6] & 0xff) << 8) | (number[7] & 0xff));
592

    
593
                if (sign == (short) 0xC000) {
594
                        // Numeric NaN - BigDecimal doesn't support this
595
                        throw new PSQLException(
596
                                        "The numeric value is NaN - can't convert to BigDecimal",
597
                                        PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
598
                }
599

    
600
                final int bigDecimalSign = sign == 0x4000 ? -1 : 1;
601

    
602
                // System.out.println("ndigits=" + ndigits
603
                // +",\n wieght=" + weight
604
                // +",\n sign=" + sign
605
                // +",\n dscale=" + dscale);
606
                // // for (int i=8; i < number.length; i++) {
607
                // System.out.println("numer[i]=" + (int) (number[i] & 0xff));
608
                // }
609

    
610
                int tail = ndigits % 4;
611
                int bytesToParse = (ndigits - tail) * 2 + 8;
612
                // System.out.println("numberParseLength="+numberParseLength);
613
                int i;
614
                BigInteger unscaledValue = BigInteger.ZERO;
615
                final BigInteger nbase = getNBase();
616
                final BigInteger nbasePow2 = getNBasePow2();
617
                final BigInteger nbasePow4 = getNBasePow4();
618

    
619

    
620
                byte[] buffer = new byte[8];
621

    
622
                // System.out.println("tail = " + tail + " bytesToParse = " +
623
                // bytesToParse);
624

    
625
                for (i = 8; i < bytesToParse; i += 8) {
626
                        // This Hi and Lo aren't bytes Hi Li, but decimal Hi Lo!! (Big &
627
                        // Small)
628
                        long valHi = (((number[i] & 0xff) << 8) | (number[i + 1] & 0xff))
629
                                        * 10000
630
                                        + (((number[i + 2] & 0xff) << 8) | (number[i + 3] & 0xff));
631
                        long valLo = (((number[i + 4] & 0xff) << 8) | (number[i + 5] & 0xff))
632
                                        * 10000
633
                                        + (((number[i + 6] & 0xff) << 8) | (number[i + 7] & 0xff));
634
                        long val = valHi * nbaseLongPow2 + valLo;
635
                        buffer[0] = (byte) (val >>> 56);
636
                        buffer[1] = (byte) (val >>> 48);
637
                        buffer[2] = (byte) (val >>> 40);
638
                        buffer[3] = (byte) (val >>> 32);
639
                        buffer[4] = (byte) (val >>> 24);
640
                        buffer[5] = (byte) (val >>> 16);
641
                        buffer[6] = (byte) (val >>> 8);
642
                        buffer[7] = (byte) (val >>> 0);
643

    
644
                        BigInteger valBigInteger = new BigInteger(bigDecimalSign, buffer);
645
                        unscaledValue = unscaledValue.multiply(nbasePow4)
646
                                        .add(valBigInteger);
647
                }
648
                tail = tail % 2;
649
                bytesToParse = (ndigits - tail) * 2 + 8;
650
                // System.out.println("tail = " + tail + " bytesToParse = " +
651
                // bytesToParse);
652

    
653
                buffer = new byte[4];
654
                for (; i < bytesToParse; i += 4) {
655
                        int val = (((number[i] & 0xff) << 8) | (number[i + 1] & 0xff))
656
                                        * nbaseInt
657
                                        + (((number[i + 2] & 0xff) << 8) | (number[i + 3] & 0xff));
658
                        buffer[0] = (byte) (val >>> 24);
659
                        buffer[1] = (byte) (val >>> 16);
660
                        buffer[2] = (byte) (val >>> 8);
661
                        buffer[3] = (byte) val;
662
                        BigInteger valBigInteger = new BigInteger(bigDecimalSign, buffer);
663
                        unscaledValue = unscaledValue.multiply(nbasePow2)
664
                                        .add(valBigInteger);
665
                }
666

    
667
                // Add the rest of number
668
                if (tail % 2 == 1) {
669
                        buffer = new byte[2];
670
                        buffer[0] = number[number.length - 2];
671
                        buffer[1] = number[number.length - 1];
672
                        BigInteger valBigInteger = new BigInteger(bigDecimalSign, buffer);
673
                        unscaledValue = unscaledValue.multiply(nbase).add(valBigInteger);
674
                        // System.out.println("Value (2)  unscaled =" + unscaledValue
675
                        // +", valBI = "+ valBigInteger);
676
                }
677

    
678

    
679
                // Calculate scale offset
680
                final int databaseScale = (ndigits - weight - 1) * 4; // Number of
681
                                                                                                                                // digits in
682
                                                                                                                                // nbase
683
                // TODO This number of digits should be calculeted depending on nbase
684
                // (getNbase());
685

    
686
                BigDecimal result = new BigDecimal(unscaledValue, databaseScale);
687
                return result;
688

    
689
        }
690

    
691
        public void open() {
692
                /*
693
                 * try { st = conn.createStatement(); st.setFetchSize(2000); if
694
                 * (bCursorActivo) close(); st.execute("declare wkb_cursor binary cursor
695
                 * for " + sqlOrig); rs = st.executeQuery("fetch forward all in
696
                 * wkb_cursor"); // st.execute("BEGIN"); bCursorActivo = true; } catch
697
                 * (SQLException e) { e.printStackTrace(); throw new
698
                 * com.iver.cit.gvsig.fmap.DriverException(e); }
699
                 */
700

    
701
        }
702

    
703
        private void setAbsolutePosition(int index) throws SQLException {
704
                // TODO: USAR LIMIT Y ORDER BY, Y HACERLO TAMBI?N PARA
705
                // MYSQL
706

    
707
                if (rs == null) {
708
                        // ha habido un error previo. Es mejor poner un error y no seguir.
709
                        try {
710
                                reload();
711
                        }
712
                        catch (Exception e) {
713
                                e.printStackTrace();
714
                                throw new SQLException(e);
715
                        }
716
                }
717

    
718
                // EL ABSOLUTE NO HACE QUE SE VUELVAN A LEER LAS
719
                // FILAS, ASI QUE MONTAMOS ESTA HISTORIA PARA QUE
720
                // LO HAGA
721

    
722
                if ((index >= fetch_min) && (index <= fetch_max)) {
723
                        // Est? en el intervalo, as? que lo podemos posicionar
724

    
725
                } else {
726
                        // calculamos el intervalo correcto
727
                        fetch_min = (index / FETCH_SIZE) * FETCH_SIZE;
728
                        fetch_max = fetch_min + FETCH_SIZE - 1;
729
                        // y cogemos ese cacho
730
                        rs.close();
731

    
732
                        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
733
                        ResultSet.CONCUR_READ_ONLY);
734

    
735
//                        myCursorId++;
736
//                        st.execute("declare "
737
//                                        + getTableName()
738
//                                        + myCursorId
739
//                                        + "_wkb_cursorAbsolutePosition binary scroll cursor with hold for "
740
//                                        + sqlTotal);
741
                        st.executeQuery("fetch absolute " + fetch_min + " in " + cursorName);
742
//                                        + getTableName() + myCursorId
743
//                                        + "_wkb_cursorAbsolutePosition");
744

    
745
                        rs = st.executeQuery("fetch forward " + FETCH_SIZE + " in " + cursorName);
746
//                                        + getTableName() + myCursorId
747
//                                        + "_wkb_cursorAbsolutePosition");
748

    
749

    
750
                }
751
                rs.absolute(index - fetch_min + 1);
752

    
753
        }
754

    
755
        /**
756
         * @see com.iver.cit.gvsig.fmap.drivers.IVectorialDatabaseDriver#getGeometryField(java.lang.String)
757
         */
758
        public String getGeometryField(String fieldName) {
759
            return "AsEWKB(\"" + fieldName + "\", 'XDR')";
760
        }
761

    
762
        /**
763
         * @see com.hardcode.gdbms.engine.data.driver.ObjectDriver#getPrimaryKeys()
764
         */
765
        public int[] getPrimaryKeys() {
766
                // TODO Auto-generated method stub
767
                return null;
768
        }
769

    
770
        /**
771
         * @see com.iver.cit.gvsig.fmap.drivers.IVectorialJDBCDriver#getDefaultPort()
772
         */
773
        public int getDefaultPort() {
774
                return 5432;
775
        }
776

    
777
        /**
778
         * @see com.hardcode.gdbms.engine.data.driver.ObjectDriver#write(com.hardcode.gdbms.engine.data.edition.DataWare)
779
         */
780
        public void write(DataWare arg0) {
781
                // TODO Auto-generated method stub
782

    
783
        }
784

    
785
        /*
786
         * (non-Javadoc)
787
         *
788
         * @see com.iver.cit.gvsig.fmap.core.ICanReproject#getSourceProjection()
789
         */
790
        public String getSourceProjection(IConnection conn, DBLayerDefinition dbld) {
791
                if (originalEPSG == null) {
792
                    getTableEPSG_and_shapeType(conn, dbld);
793
                }
794
                return originalEPSG;
795
        }
796

    
797
        /**
798
         * Las tablas con geometr?as est?n en la tabla GEOMETRY_COLUMNS y de ah?
799
         * sacamos en qu? proyecci?n est?n. El problema es que si el usuario hace
800
         * una vista de esa tabla, no estar? dada de alta aqu? y entonces gvSIG no
801
         * se entera en qu? proyecci?n est? trabajando (y le ponemos un -1 como mal
802
         * menor). El -1 implica que luego no podremos reproyectar al vuelo desde la
803
         * base de datos. OJO: ES SENSIBLE A MAYUSCULAS / MINUSCULAS!!!
804
         */
805
        private void getTableEPSG_and_shapeType(IConnection conn,
806
                        DBLayerDefinition dbld) {
807
                try {
808
                        Statement stAux = ((ConnectionJDBC) conn).getConnection()
809
                                        .createStatement();
810

    
811
                        // String sql =
812
                        // "SELECT * FROM GEOMETRY_COLUMNS WHERE F_TABLE_NAME = '"
813
                        // + getTableName() + "' AND F_GEOMETRY_COLUMN = '" +
814
                        // getLyrDef().getFieldGeometry() + "'";
815
                        String sql;
816
                        if (dbld.getSchema() == null || dbld.getSchema().equals("")) {
817
                                sql = "SELECT * FROM GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = current_schema() AND F_TABLE_NAME = '"
818
                                                + dbld.getTableName()
819
                                                + "' AND F_GEOMETRY_COLUMN = '"
820
                                                + dbld.getFieldGeometry() + "'";
821
                        } else {
822
                                sql = "SELECT * FROM GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = '"
823
                                                + dbld.getSchema() + "' AND F_TABLE_NAME = '"
824
                                                + dbld.getTableName() + "' AND F_GEOMETRY_COLUMN = '"
825
                                                + dbld.getFieldGeometry() + "'";
826
                        }
827

    
828
                        ResultSet rs = stAux.executeQuery(sql);
829
                        if (rs.next()) {
830
                                originalEPSG = "" + rs.getInt("SRID");
831
                                String geometryType = rs.getString("TYPE");
832
                                int shapeType = FShape.MULTI;
833
                                if (geometryType.compareToIgnoreCase("POINT") == 0) {
834
                                    shapeType = FShape.POINT;
835
                                } else if (geometryType.compareToIgnoreCase("LINESTRING") == 0) {
836
                                    shapeType = FShape.LINE;
837
                                } else if (geometryType.compareToIgnoreCase("POLYGON") == 0) {
838
                                    shapeType = FShape.POLYGON;
839
                                } else if (geometryType.compareToIgnoreCase("MULTIPOINT") == 0) {
840
                                    shapeType = FShape.MULTIPOINT;
841
                                } else if (geometryType.compareToIgnoreCase("MULTILINESTRING") == 0) {
842
                                    shapeType = FShape.LINE;
843
                                } else if (geometryType.compareToIgnoreCase("MULTILINESTRINGM") == 0) {
844
                                    shapeType = FShape.LINE | FShape.M;
845
                                } else if (geometryType.compareToIgnoreCase("MULTIPOLYGON") == 0) {
846
                                    shapeType = FShape.POLYGON;
847
                                }
848
                                dbld.setShapeType(shapeType);
849

    
850
                                //jomarlla
851
                                int dimension  = rs.getInt("COORD_DIMENSION");
852
                                dbld.setDimension(dimension);
853

    
854
                        } else {
855
                                originalEPSG = "-1";
856
                        }
857

    
858
                        rs.close();
859
                } catch (SQLException e) {
860
                        // TODO Auto-generated catch block
861
                        originalEPSG = "-1";
862
                        logger.error(e);
863
                        e.printStackTrace();
864
                }
865

    
866
        }
867

    
868
        /*
869
         * (non-Javadoc)
870
         *
871
         * @see com.iver.cit.gvsig.fmap.core.ICanReproject#getDestProjection()
872
         */
873
        public String getDestProjection() {
874
                return strEPSG;
875
        }
876

    
877
        /*
878
         * (non-Javadoc)
879
         *
880
         * @see
881
         * com.iver.cit.gvsig.fmap.core.ICanReproject#setDestProjection(java.lang
882
         * .String)
883
         */
884
        public void setDestProjection(String toEPSG) {
885
                this.strEPSG = toEPSG;
886
        }
887

    
888
        /*
889
         * (non-Javadoc)
890
         *
891
         * @see
892
         * com.iver.cit.gvsig.fmap.core.ICanReproject#canReproject(java.lang.String)
893
         */
894
        public boolean canReproject(String toEPSGdestinyProjection) {
895
                // TODO POR AHORA, REPROYECTA SIEMPRE gvSIG.
896
                return false;
897
        }
898

    
899
        /*
900
         * (non-Javadoc)
901
         *
902
         * @see com.iver.cit.gvsig.fmap.drivers.DefaultDBDriver#doRelateID_FID()
903
         */
904
        protected void doRelateID_FID() throws DBException {
905
                hashRelate = new Hashtable();
906
                try {
907
                        String strSQL = "SELECT " + getLyrDef().getFieldID() + " FROM "
908
                        + getLyrDef().getComposedTableName() + " ";
909
                        // + getLyrDef().getWhereClause();
910
                        if (canReproject(strEPSG)) {
911
                                strSQL = strSQL
912
                                + getCompoundWhere(strSQL, workingArea, strEPSG);
913
                        } else {
914
                                strSQL = strSQL
915
                                + getCompoundWhere(strSQL, workingArea, originalEPSG);
916
                        }
917
                        strSQL = strSQL + " ORDER BY " + getLyrDef().getFieldID();
918
                        Statement s = ((ConnectionJDBC) getConnection()).getConnection()
919
                                        .createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
920
                                                        ResultSet.CONCUR_READ_ONLY);
921
                        int fetchSize = 5000;
922
                        ResultSet r = s.executeQuery(strSQL);
923
                        int id = 0;
924
                        String gid;
925
                        while (r.next()) {
926
                                gid = r.getString(1);
927

    
928
                                if (gid == null) {
929
                                        throw new SQLException(
930
                                                        PluginServices.getText(null, "Found_null_id_in_table") + ": " +
931
                                                        getLyrDef().getComposedTableName());
932
                                }
933

    
934
                                Value aux = ValueFactory.createValue(gid);
935
                                hashRelate.put(aux, new Integer(id));
936
                                // System.out.println("ASOCIANDO CLAVE " + aux + " CON VALOR " +
937
                                // id);
938
                                id++;
939
                                // System.out.println("Row " + id + ":" + strAux);
940
                        }
941
                        s.close();
942
                        numReg = id;
943

    
944
                        /*
945
                         * for (int index = 0; index < getShapeCount(); index++) { Value aux
946
                         * = getFieldValue(index, idFID_FieldName-2); hashRelate.put(aux,
947
                         * new Integer(index)); // System.out.println("Row " + index +
948
                         * " clave=" + aux); }
949
                         */
950
                        /*
951
                         * int index = 0;
952
                         *
953
                         * while (rs.next()) { Value aux = getFieldValue(index,
954
                         * idFID_FieldName-2); hashRelate.put(aux, new Integer(index));
955
                         * index++; System.out.println("Row " + index + " clave=" + aux); }
956
                         * numReg = index;
957
                         */
958
                        // rs.beforeFirst();
959
                        /*
960
                         * } catch (com.hardcode.gdbms.engine.data.driver.DriverException e)
961
                         * { // TODO Auto-generated catch block e.printStackTrace();
962
                         */
963
                } catch (SQLException e) {
964
                        throw new DBException(e);
965
                }
966
        }
967

    
968
        public String getSqlTotal() {
969
                return sqlTotal;
970
        }
971

    
972
        /**
973
         * @return Returns the completeWhere.
974
         */
975
        public String getCompleteWhere() {
976
                return completeWhere;
977
        }
978

    
979
        /*
980
         * (non-Javadoc)
981
         *
982
         * @see com.iver.cit.gvsig.fmap.drivers.DefaultDBDriver#close()
983
         */
984
        public void close() {
985
                super.close();
986
                /*
987
                 * if (bCursorActivo) { try { // st =
988
                 * conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
989
                 * ResultSet.CONCUR_READ_ONLY); st.execute("CLOSE wkb_cursor_prov"); //
990
                 * st.close(); } catch (SQLException e) { // TODO Auto-generated catch
991
                 * block e.printStackTrace(); } bCursorActivo = false; }
992
                 */
993

    
994
        }
995

    
996
        /*
997
         * (non-Javadoc)
998
         *
999
         * @see
1000
         * com.iver.cit.gvsig.fmap.drivers.VectorialDatabaseDriver#getFeatureIterator
1001
         * (java.awt.geom.Rectangle2D, java.lang.String, java.lang.String[])
1002
         */
1003
        public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
1004
                        String[] alphaNumericFieldsNeeded) throws ReadDriverException {
1005
                String sqlAux = null;
1006
                DBLayerDefinition lyrDef = getLyrDef();
1007
                DBLayerDefinition clonedLyrDef = cloneLyrDef(lyrDef);
1008
                ArrayList<FieldDescription> myFieldsDesc = new ArrayList<FieldDescription>(); // =
1009
                                                                                                                                                                                // new
1010
                                                                                                                                                                                // FieldDescription[alphaNumericFieldsNeeded.length+1];
1011
                try {
1012
                        if (workingArea != null) {
1013
                            r = r.createIntersection(workingArea);
1014
                        }
1015
                        // if (getLyrDef()==null){
1016
                        // load();
1017
                        // throw new DriverException("Fallo de la conexi?n");
1018
                        // }
1019
                        String strAux = getGeometryField(lyrDef.getFieldGeometry());
1020

    
1021
                        boolean found = false;
1022
                        int fieldIndex = -1;
1023
                        if (alphaNumericFieldsNeeded != null) {
1024
                                FieldDescription[] fieldsDesc = lyrDef.getFieldsDesc();
1025

    
1026
                                for (int i = 0; i < alphaNumericFieldsNeeded.length; i++) {
1027
                                        fieldIndex = lyrDef
1028
                                                        .getFieldIdByName(alphaNumericFieldsNeeded[i]);
1029
                                        if (fieldIndex < 0) {
1030
                                                throw new RuntimeException(
1031
                                                                "No se ha encontrado el nombre de campo "
1032
                                                                                + metaData.getColumnName(i));
1033
                                        }
1034
                                        strAux = strAux
1035
                                                        + ", "
1036
                                                        + PostGIS
1037
                                                                        .escapeFieldName(lyrDef.getFieldNames()[fieldIndex]);
1038
                                        if (alphaNumericFieldsNeeded[i].equalsIgnoreCase(lyrDef
1039
                                                        .getFieldID())) {
1040
                                                found = true;
1041
                                                clonedLyrDef.setIdFieldID(i);
1042
                                        }
1043

    
1044
                                        myFieldsDesc.add(fieldsDesc[fieldIndex]);
1045
                                }
1046
                        }
1047
                        // Nos aseguramos de pedir siempre el campo ID
1048
                        if (found == false) {
1049
                                strAux = strAux + ", " + lyrDef.getFieldID();
1050
                                myFieldsDesc.add(lyrDef.getFieldsDesc()[lyrDef
1051
                                                .getIdField(lyrDef.getFieldID())]);
1052
                                clonedLyrDef.setIdFieldID(myFieldsDesc.size() - 1);
1053
                        }
1054
                        clonedLyrDef.setFieldsDesc((FieldDescription[]) myFieldsDesc
1055
                                        .toArray(new FieldDescription[] {}));
1056

    
1057
                        String sqlProv = "SELECT " + strAux + " FROM "
1058
                        + lyrDef.getComposedTableName() + " ";
1059
                        // + getLyrDef().getWhereClause();
1060

    
1061
                        if (canReproject(strEPSG)) {
1062
                                sqlAux = sqlProv + getCompoundWhere(sqlProv, r, strEPSG);
1063
                        } else {
1064
                                sqlAux = sqlProv + getCompoundWhere(sqlProv, r, originalEPSG);
1065
                        }
1066

    
1067
                        System.out.println("SqlAux getFeatureIterator = " + sqlAux);
1068
                        PostGisFeatureIterator geomIterator = null;
1069
                        geomIterator = myGetFeatureIterator(sqlAux);
1070
                        geomIterator.setLyrDef(clonedLyrDef);
1071
                        return geomIterator;
1072
                } catch (Exception e) {
1073
                        // e.printStackTrace();
1074
                        // SqlDriveExceptionType type = new SqlDriveExceptionType();
1075
                        // type.setDriverName("PostGIS Driver");
1076
                        // type.setSql(sqlAux);
1077
                        // type.setLayerName(getTableName());
1078
                        // type.setSchema(null);
1079
                        throw new ReadDriverException("PostGIS Driver", e);
1080

    
1081
                        // throw new DriverException(e);
1082
                }
1083
        }
1084

    
1085
        /*
1086
         * public void preProcess() throws EditionException { writer.preProcess(); }
1087
         *
1088
         * public void process(IRowEdited row) throws EditionException {
1089
         * writer.process(row); }
1090
         *
1091
         * public void postProcess() throws EditionException { writer.postProcess();
1092
         * }
1093
         *
1094
         * public String getCapability(String capability) { return
1095
         * writer.getCapability(capability); }
1096
         *
1097
         * public void setCapabilities(Properties capabilities) {
1098
         * writer.setCapabilities(capabilities); }
1099
         *
1100
         * public boolean canWriteAttribute(int sqlType) { return
1101
         * writer.canWriteAttribute(sqlType); }
1102
         *
1103
         * public boolean canWriteGeometry(int gvSIGgeometryType) { return
1104
         * writer.canWriteGeometry(gvSIGgeometryType); }
1105
         *
1106
         * public void initialize(ITableDefinition layerDef) throws EditionException
1107
         * { writer.setCreateTable(false); writer.setWriteAll(false); // Obtenemos
1108
         * el DBLayerDefinition a partir del driver
1109
         *
1110
         * DBLayerDefinition dbLyrDef = getLyrDef();
1111
         *
1112
         *
1113
         * writer.initialize(dbLyrDef); }
1114
         */
1115
        public boolean isWritable() {
1116
                // CHANGE FROM CARTOLAB
1117
                // return true;
1118
                return writer.canSaveEdits();
1119
                // END CHANGE CARTOLAB
1120
        }
1121

    
1122
        public IWriter getWriter() {
1123
                return writer;
1124
        }
1125

    
1126
        public String[] getGeometryFieldsCandidates(IConnection conn,
1127
                        String table_name) throws DBException {
1128
                ArrayList list = new ArrayList();
1129
                try {
1130
                        Statement stAux = ((ConnectionJDBC) conn).getConnection()
1131
                                        .createStatement();
1132
                        String[] tokens = table_name.split("\\u002E", 2);
1133
                        String sql;
1134
                        if (tokens.length > 1) {
1135
                                sql = "select * from GEOMETRY_COLUMNS WHERE F_TABLE_SCHEMA = '"
1136
                                                + tokens[0] + "' AND F_TABLE_NAME = '" + tokens[1]
1137
                                                + "'";
1138
                        } else {
1139
                                sql = "select * from GEOMETRY_COLUMNS"
1140
                                                + " where F_TABLE_SCHEMA = current_schema() AND F_TABLE_NAME = '"
1141
                                                + table_name + "'";
1142

    
1143
                        }
1144

    
1145
                        // String sql =
1146
                        // "SELECT * FROM GEOMETRY_COLUMNS WHERE F_TABLE_NAME = '"
1147
                        // + table_name + "'";
1148

    
1149
                        ResultSet rs = stAux.executeQuery(sql);
1150
                        while (rs.next()) {
1151
                                String geomCol = rs.getString("F_GEOMETRY_COLUMN");
1152
                                list.add(geomCol);
1153
                        }
1154
                        rs.close();
1155
                        stAux.close();
1156
                } catch (SQLException e) {
1157
                        closeConnection(conn);
1158
                        throw new DBException(e);
1159
                }
1160
                return (String[]) list.toArray(new String[0]);
1161
        }
1162

    
1163
        // public String[] getTableFields(IConnection conex, String table) throws
1164
        // DBException {
1165
        // try{
1166
        // Statement st = ((ConnectionJDBC)conex).getConnection().createStatement();
1167
        // // ResultSet rs = dbmd.getTables(catalog, null,
1168
        // dbLayerDefinition.getTable(), null);
1169
        // ResultSet rs = st.executeQuery("select * from " + table + " LIMIT 1");
1170
        // ResultSetMetaData rsmd = rs.getMetaData();
1171
        //
1172
        // String[] ret = new String[rsmd.getColumnCount()];
1173
        //
1174
        // for (int i = 0; i < ret.length; i++) {
1175
        // ret[i] = rsmd.getColumnName(i+1);
1176
        // }
1177
        //
1178
        // return ret;
1179
        // }catch (SQLException e) {
1180
        // throw new DBException(e);
1181
        // }
1182
        // }
1183

    
1184
        private DBLayerDefinition cloneLyrDef(DBLayerDefinition lyrDef) {
1185
                DBLayerDefinition clonedLyrDef = new DBLayerDefinition();
1186

    
1187
                clonedLyrDef.setName(lyrDef.getName());
1188
                clonedLyrDef.setFieldsDesc(lyrDef.getFieldsDesc());
1189

    
1190
                clonedLyrDef.setShapeType(lyrDef.getShapeType());
1191
                clonedLyrDef.setProjection(lyrDef.getProjection());
1192

    
1193
                clonedLyrDef.setConnection(lyrDef.getConnection());
1194
                clonedLyrDef.setCatalogName(lyrDef.getCatalogName());
1195
                clonedLyrDef.setSchema(lyrDef.getSchema());
1196
                clonedLyrDef.setTableName(lyrDef.getTableName());
1197

    
1198
                clonedLyrDef.setFieldID(lyrDef.getFieldID());
1199
                clonedLyrDef.setFieldGeometry(lyrDef.getFieldGeometry());
1200
                clonedLyrDef.setWhereClause(lyrDef.getWhereClause());
1201
                clonedLyrDef.setWorkingArea(lyrDef.getWorkingArea());
1202
                clonedLyrDef.setSRID_EPSG(lyrDef.getSRID_EPSG());
1203
                clonedLyrDef.setClassToInstantiate(lyrDef.getClassToInstantiate());
1204

    
1205
                clonedLyrDef.setIdFieldID(lyrDef.getIdFieldID());
1206
                clonedLyrDef.setDimension(lyrDef.getDimension());
1207
                clonedLyrDef.setHost(lyrDef.getHost());
1208
                clonedLyrDef.setPort(lyrDef.getPort());
1209
                clonedLyrDef.setDataBase(lyrDef.getDataBase());
1210
                clonedLyrDef.setUser(lyrDef.getUser());
1211
                clonedLyrDef.setPassword(lyrDef.getPassword());
1212
                clonedLyrDef.setConnectionName(lyrDef.getConnectionName());
1213
                return clonedLyrDef;
1214
        }
1215

    
1216
        public String getTotalFields() {
1217
                StringBuilder strAux = new StringBuilder();
1218
                strAux.append(getGeometryField(getLyrDef().getFieldGeometry()));
1219
                String[] fieldNames = getLyrDef().getFieldNames();
1220
                for (int i = 0; i < fieldNames.length; i++) {
1221
                        strAux.append(", " + PostGIS.escapeFieldName(fieldNames[i]));
1222
                }
1223
                return strAux.toString();
1224
        }
1225

    
1226

    
1227
        /**
1228
         * Gets all field names of a given table.
1229
         *
1230
         * This method comes from DefaultJDBC.java class. Postgis driver has no method to check
1231
         *  the status of the connection -if it is valid or not. So, as it's not possible to assure
1232
         *  its status, close the connection when an exception happens and re-open it on demand
1233
         *  on the proper method will solve the problems related to an invalid status.
1234
         *
1235
         * @param conn connection object
1236
         * @param table_name table name
1237
         * @return all field names of the given table
1238
         * @throws SQLException
1239
         */
1240
        @Override
1241
        public String[] getAllFields(IConnection conn, String table_name) throws DBException {
1242
                Statement st = null;
1243
                ResultSet rs = null;
1244
                table_name = tableNameToComposedTableName(table_name);
1245

    
1246
                try {
1247
                        st = ((ConnectionJDBC)conn).getConnection().createStatement();
1248
                        rs = st.executeQuery("SELECT * FROM " + table_name + " LIMIT 1");
1249
                        ResultSetMetaData rsmd = rs.getMetaData();
1250
                        String[] ret = new String[rsmd.getColumnCount()];
1251

    
1252
                        for (int i = 0; i < ret.length; i++) {
1253
                                ret[i] = rsmd.getColumnName(i+1);
1254
                        }
1255

    
1256
                        return ret;
1257
                } catch (SQLException e) {
1258
                        // Next time  getConnection() method is called it will be re-opened.
1259
                        // @see com.iver.cit.gvsig.fmap.drivers.ConnectionJDBC.java;
1260
                        closeConnection(conn);
1261
                        throw new DBException(e);
1262
                }
1263
                finally {
1264
                        closeResultSet(rs);
1265
                        closeStatement(st);
1266
                }
1267
        }
1268

    
1269
        /**
1270
         * Gets all field type names of a given table.
1271
         *
1272
         * This method comes from DefaultJDBC.java class. Postgis driver has no method to check
1273
         *  the status of the connection -if it is valid or not. So, as it's not possible to assure
1274
         *  its status, close the connection when an exception happens and re-open it on demand
1275
         *  on the proper method will solve the problems related to an invalid status.
1276
         *
1277
         * @param conn connection object
1278
         * @param table_name table name
1279
         * @return all field type names of the given table
1280
         * @throws SQLException
1281
         */
1282
        public String[] getAllFieldTypeNames(IConnection conn, String table_name) throws DBException {
1283
            Statement st = null;
1284
            ResultSet rs = null;
1285
            table_name = tableNameToComposedTableName(table_name);
1286
                try {
1287
                        st = ((ConnectionJDBC)conn).getConnection().createStatement();
1288
                        rs = st.executeQuery("SELECT * FROM " + table_name + " LIMIT 1");
1289
                        ResultSetMetaData rsmd = rs.getMetaData();
1290
                        String[] ret = new String[rsmd.getColumnCount()];
1291

    
1292
                        for (int i = 0; i < ret.length; i++) {
1293
                                ret[i] = rsmd.getColumnTypeName(i+1);
1294
                        }
1295
                        return ret;
1296
                } catch (SQLException e) {
1297
                        // Next time  getConnection() method is called it will be re-opened.
1298
                        // @see com.iver.cit.gvsig.fmap.drivers.ConnectionJDBC.java;
1299
                        closeConnection(conn);
1300
                        throw new DBException(e);
1301
                }
1302
                finally{
1303
                        closeStatement(st);
1304
                        closeResultSet(rs);
1305
                }
1306
        }
1307

    
1308
        /**
1309
         *
1310
         * @param tableName
1311
         * @return a string with the schema and the tableName quoted
1312
         */
1313
        private String tableNameToComposedTableName(String tableName) {
1314
                String composedTableName = null;
1315
                // \u002E = unicode character for .
1316
                String[] tokens = tableName.trim().replace("\"", "").split("\\u002E");
1317

    
1318
                if (tokens.length == 1) {
1319
                        composedTableName = "\"" + tokens[0] + "\"";
1320

    
1321
                } else if (tokens.length == 2) {
1322
                        composedTableName = "\"" + tokens[0] + "\".\"" + tokens[1] + "\"";
1323
                } else {
1324
                        // this is a not predictable case, so we return the same
1325
                        composedTableName = tableName;
1326
                }
1327

    
1328
                return composedTableName;
1329
        }
1330

    
1331
        /**
1332
         * Close a ResultSet
1333
         * @param rs, the resultset to be closed
1334
         * @return true if the resulset was correctly closed. false in any other case
1335
         */
1336
        public boolean closeResultSet(ResultSet rs) {
1337
                boolean error = false;
1338

    
1339
                if (rs != null) {
1340
                        try {
1341
                                rs.close();
1342
                                error = true;
1343
                        } catch (SQLException e) {
1344
                                logger.error(e.getMessage(), e);
1345
                        }
1346
                }
1347

    
1348
                return error;
1349
        }
1350

    
1351
        /**
1352
         * Close a Statement
1353
         * @param st, the statement to be closed
1354
         * @return true if the  statement was correctly closed, false in any other case
1355
         */
1356
        public boolean closeStatement(Statement st) {
1357
                boolean error = false;
1358

    
1359
                if (st != null) {
1360
                        try {
1361
                                st.close();
1362
                                error = true;
1363
                        } catch (SQLException e) {
1364
                                logger.error(e.getMessage(), e);
1365
                        }
1366
                }
1367

    
1368
                return error;
1369
        }
1370

    
1371
        /**
1372
         * Close a Connection
1373
         * @param conn, the  connection to be closed
1374
         * @return true if the connection was correctly closed, false in any other case
1375
         */
1376
        public boolean closeConnection(IConnection conn) {
1377
                boolean error = false;
1378

    
1379
                if (conn != null) {
1380
                        try {
1381
                                conn.close();
1382
                                error = true;
1383
                        } catch (DBException e) {
1384
                                logger.error(e.getMessage(), e);
1385
                        }
1386
                }
1387

    
1388
                return error;
1389
        }
1390

    
1391
        /**
1392
         * Tells if user can read contents of the table.
1393
         *
1394
         *  @param iconn connection with the database where the user is connected
1395
         *  @param tablename to get the permissions over
1396
         *  @return true if can read, either false
1397
         *  @throws SQLException
1398
         */
1399
        public boolean canRead(IConnection iconn, String tablename) throws SQLException {
1400
                String schema = null;
1401
                int dotPos = tablename.indexOf(".");
1402
                if (dotPos > -1) {
1403
                        schema = tablename.substring(0, dotPos);
1404
                }
1405
                tablename = tableNameToComposedTableName(tablename);
1406
                Connection conn = ((ConnectionJDBC) iconn).getConnection();
1407
                boolean checkTable = true;
1408
                if (schema != null) {
1409
                        if (!schemasUsage.containsKey(schema)) {
1410
                                String query = "SELECT has_schema_privilege('" + schema + "', 'USAGE') AS usg";
1411
                                Statement st = conn.createStatement();
1412
                                ResultSet rs = st.executeQuery(query);
1413
                                if (rs.next()) {
1414
                                        schemasUsage.put(schema, rs.getBoolean("usg"));
1415
                                } else {
1416
                                        //this sentence should never be executed...
1417
                                        schemasUsage.put(schema, false);
1418
                                }
1419
                                rs.close();
1420
                                st.close();
1421
                        }
1422
                        checkTable = schemasUsage.get(schema);
1423
                }
1424
                if (checkTable) {
1425
                        String query = "SELECT has_table_privilege('" + tablename + "', 'SELECT') as selct";
1426
                        Statement st = conn.createStatement();
1427
                        ResultSet rs = st.executeQuery(query);
1428
                        if (rs.next()) {
1429
                                return rs.getBoolean("selct");
1430
                        } else {
1431
                                return false;
1432
                        }
1433
                } else {
1434
                    return false;
1435
                }
1436
        }
1437

    
1438

    
1439
        private Integer getGidFieldIndex(String ret[]){
1440
            for (int i=0; i<ret.length; i++) {
1441
                if (ret[i].equalsIgnoreCase("gid")) {
1442
                    return new Integer(i);
1443
                }
1444
            }
1445
            return null;
1446
        }
1447

    
1448
        private void swapIndexes(String[] ret, int i, int j){
1449
            if(i!=j && i>=0 && i<ret.length && j>=0 && j<ret.length){
1450
                String aux = ret[i];
1451
                ret[i] = ret[j];
1452
                ret[j] = aux;
1453
            }
1454
        }
1455

    
1456
        public String[] getIdFieldsCandidates(IConnection conn, String table_name) throws DBException {
1457

    
1458
            String[] ret = getAllFields(conn, table_name);
1459

    
1460
            String pk = getPrimaryKey(conn, table_name);
1461

    
1462
            if (!pk.equals("")){
1463
                for (int i = 0; i < ret.length; i++) {
1464
                    if (pk.equals(ret[i])) {
1465
                            //swap possible gid col with the first element
1466
                            //in order to make it the default selection on
1467
                            //combobox
1468
                            swapIndexes(ret, i, 0);
1469
                            break;
1470
                    }
1471
                }
1472
            } else {
1473
                Integer gidFieldIndex = getGidFieldIndex(ret);
1474
                if (gidFieldIndex!=null){
1475
                    //swap possible gid col with the first element
1476
                    //in order to make it the default selection on
1477
                    //combobox
1478
                    int index = gidFieldIndex.intValue();
1479
                    swapIndexes(ret, index, 0);
1480
                } else {
1481
                    for (int i = 0; i < ret.length; i++) {
1482
                        if (isAutoIncrement(conn, table_name, ret[i])) {
1483
                            //swap possible gid col with the first element
1484
                            //in order to make it the default selection on
1485
                            //combobox
1486
                            swapIndexes(ret, i, 0);
1487
                            break;
1488
                        }
1489
                    }
1490
                }
1491
            }
1492
            return ret;
1493
        }
1494

    
1495
        private boolean isAutoIncrement(IConnection con, String table_name, String colName) {
1496

    
1497
                String query = "SELECT column_default SIMILAR TO 'nextval%regclass%' AS isautoincremental "
1498
                        + "FROM information_schema.columns "
1499
                        + "WHERE table_name = ? AND table_schema=? "
1500
                        + "AND column_name=?";
1501

    
1502
                try {
1503
                        // get schema and table from the composed tablename
1504
                        String[] tokens = table_name.split("\\u002E", 2);
1505
                        String schema = "";
1506
                        String tableName = "";
1507
                        if (tokens.length == 1) {
1508
                                tableName = tokens[0];
1509
                        } else {
1510
                                schema = tokens[0];
1511
                                tableName = tokens[1];
1512
                        }
1513

    
1514

    
1515
                        Connection c = ((ConnectionJDBC)con).getConnection();
1516
                        PreparedStatement st = c.prepareStatement(query);
1517
                        st.setString(1, tableName);
1518
                        st.setString(2, schema);
1519
                        st.setString(3, colName);
1520

    
1521
                        ResultSet rs = st.executeQuery();
1522
                        boolean isAutoincrement = false;
1523
                        if (rs.next()) {
1524
                                isAutoincrement = rs.getBoolean("isautoincremental");
1525
                        }
1526

    
1527
                        rs.close();
1528
                        st.close();
1529

    
1530
                        return isAutoincrement;
1531
                } catch (SQLException e) {
1532
                        try {
1533
                                con.close();
1534
                        } catch (DBException e2) {
1535
                                // TODO Auto-generated catch block
1536
                                e.printStackTrace();
1537
                        }
1538
                        return false;
1539

    
1540
                }
1541

    
1542

    
1543
        }
1544

    
1545
           private String getPrimaryKey(IConnection con, String table_name) {
1546

    
1547
               String query = "SELECT column_name FROM information_schema.key_column_usage" +
1548
                               " WHERE table_name=? AND table_schema=? AND constraint_name=?";
1549

    
1550
                try {
1551
                    // get schema and table from the composed tablename
1552
                    String[] tokens = table_name.split("\\u002E", 2);
1553
                    String schema = "";
1554
                    String tableName = "";
1555
                    if (tokens.length == 1) {
1556
                        tableName = tokens[0];
1557
                    } else {
1558
                        schema = tokens[0];
1559
                        tableName = tokens[1];
1560
                    }
1561

    
1562

    
1563
                    Connection c = ((ConnectionJDBC)con).getConnection();
1564
                    PreparedStatement st = c.prepareStatement(query);
1565
                    st.setString(1, tableName);
1566
                    st.setString(2, schema);
1567
                    st.setString(3, tableName+"_pkey");
1568

    
1569
                    ResultSet rs = st.executeQuery();
1570

    
1571
                    String primaryKey = "";
1572
                    if (rs.next()) {
1573
                        primaryKey = rs.getString("column_name");
1574
                    }
1575

    
1576
                    rs.close();
1577
                    st.close();
1578

    
1579
                    return primaryKey;
1580
                } catch (SQLException e) {
1581
                    try {
1582
                        con.close();
1583
                    } catch (DBException e2) {
1584
                        // TODO Auto-generated catch block
1585
                        e.printStackTrace();
1586
                    }
1587
                    return "";
1588
                }
1589
            }
1590

    
1591

    
1592
                public void validateData(IConnection _conn, DBLayerDefinition lyrDef) throws DBException {
1593

    
1594
                        this.conn = _conn;
1595
                        lyrDef.setConnection(conn);
1596
                        setLyrDef(lyrDef);
1597

    
1598
                        getTableEPSG_and_shapeType(conn, lyrDef);
1599

    
1600
                        getLyrDef().setSRID_EPSG(originalEPSG);
1601

    
1602
                        try {
1603
                                ((ConnectionJDBC) conn).getConnection().setAutoCommit(false);
1604
                                sqlOrig = "SELECT " + getTotalFields() + " FROM "
1605
                                + getLyrDef().getComposedTableName() + " ";
1606
                                // + getLyrDef().getWhereClause();
1607
                                if (canReproject(strEPSG)) {
1608
                                        completeWhere = getCompoundWhere(sqlOrig, workingArea, strEPSG);
1609
                                } else {
1610
                                        completeWhere = getCompoundWhere(sqlOrig, workingArea,
1611
                                                        originalEPSG);
1612
                                }
1613
                                // completeWhere = getLyrDef().getWhereClause() + completeWhere;
1614

    
1615
                                String sqlAux = sqlOrig + completeWhere + " ORDER BY "
1616
                                                + getLyrDef().getFieldID();
1617

    
1618
                                sqlTotal = sqlAux;
1619
                                logger.info("Cadena SQL:" + sqlAux);
1620
                                Statement st = ((ConnectionJDBC) conn).getConnection().createStatement(
1621
                                                ResultSet.TYPE_SCROLL_INSENSITIVE,
1622
                                                ResultSet.CONCUR_READ_ONLY);
1623
                                // st.setFetchSize(FETCH_SIZE);
1624
                                // myCursorId++;
1625
                                String temp_index_name = getTableName() + "_temp_wkb_cursor";
1626
                                st.execute("declare " + temp_index_name + " binary scroll cursor with hold for "
1627
                                                + sqlAux);
1628
                                rs = st.executeQuery("fetch forward 50 in " + temp_index_name);
1629
                                rs.close();
1630
                                st.execute("close " + temp_index_name);
1631
                                st.close();
1632

    
1633
                        } catch (SQLException e) {
1634

    
1635
                                try {
1636
                                        ((ConnectionJDBC) conn).getConnection().rollback();
1637
                                } catch (SQLException e1) {
1638
                                        logger.warn("Unable to rollback connection after problem (" + e.getMessage() + ") in setData()");
1639
                                }
1640

    
1641
                                try {
1642
                                        if (rs != null) { rs.close(); }
1643
                                } catch (SQLException e1) {
1644
                                        throw new DBException(e);
1645
                                }
1646
                                throw new DBException(e);
1647
                        }
1648
                }
1649
}
1650

    
1651
// [eiel-gestion-conexiones]
1652
// [eiel-postgis-3d]
1653