Statistics
| Revision:

root / trunk / org.gvsig.postgresql / org.gvsig.postgresql.provider / src / main / java / org / gvsig / postgresql / dal / PostgreSQLBuilder.java @ 464

History | View | Annotate | Download (12.1 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

    
25
package org.gvsig.postgresql.dal;
26

    
27
import java.sql.Connection;
28
import java.sql.DatabaseMetaData;
29
import java.text.MessageFormat;
30
import java.util.ArrayList;
31
import java.util.List;
32
import org.apache.commons.lang3.StringUtils;
33
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
34
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
35

    
36
public class PostgreSQLBuilder extends JDBCSQLBuilderBase {
37

    
38
    private int[] databaseVersion = null;
39
    
40
    protected int[] getDatabaseVersion() {
41
        if( databaseVersion == null ) {
42
            Connection conn;
43
            try {
44
                conn = this.getHelper().getConnection();
45
                DatabaseMetaData metadata = conn.getMetaData();
46
                databaseVersion =  new int[] {
47
                    metadata.getDatabaseMajorVersion(),
48
                    metadata.getDatabaseMinorVersion()
49
                };
50
            } catch (Exception ex) {
51
                databaseVersion = new int[] { 0,0 };
52
            }
53
        }
54
        return databaseVersion;
55
    }
56
    
57
    public PostgreSQLBuilder(JDBCHelper helper) {
58
        super(helper);
59
              
60
        config.set(SQLConfig.default_schema, "public");
61
        config.set(SQLConfig.allowAutomaticValues, true);
62
        config.set(SQLConfig.geometry_type_support, this.helper.getGeometrySupportType());
63
        config.set(SQLConfig.has_spatial_functions, this.helper.hasSpatialFunctions());
64
        config.set(SQLConfig.constant_true, "true");
65
        config.set(SQLConfig.constant_false, "false");
66
            
67
        config.remove_functionality(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table);
68
        config.remove_functionality(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_table);
69
         
70
        config.set(SQLConfig.UPDATE_TABLE_STATISTICS_table,"ANALYZE {0}");
71

    
72
        config.set(SQLConfig.ST_GeomFromEWKB, "ST_GeomFromEWKB({0}, {1})");
73
        config.set(SQLConfig.ST_AsEWKB, "ST_AsEWKB(({0}))");        
74
        config.set(SQLConfig.ST_ExtentAggregate, "ST_Extent({0})");        
75
        config.set(SQLConfig.ST_UnionAggregate, "ST_Union({0})");
76
        
77
        config.set(SQLConfig.lcase, "lower({0})");
78
        config.set(SQLConfig.ucase, "upper({0})");
79
        config.set(SQLConfig.operator_ILIKE, "({0}) ILIKE ({1})");
80
        config.set(SQLConfig.isNull, "( ({0}) ISNULL )");
81
        config.set(SQLConfig.notIsNull, "( ({0}) NOT NULL )");
82

    
83
    }
84
    
85
    public class PostgreSQLUpdateTableStatisticsBuilderBase extends UpdateTableStatisticsBuilderBase {
86
        @Override
87
        public List<String> toStrings() {
88
            List<String> sqls = new ArrayList<>();
89
            
90
            if( config.has_functionality(SQLConfig.UPDATE_TABLE_STATISTICS_table) ) {
91
                // In postGIS, UpdateLayerStatistics function, don't allow to 
92
                // use the database name in the table name.
93
                String name = identifier(this.table.getName());
94
                if( table.has_schema()) {
95
                    name = identifier(this.table.getSchema()) + "." + name;
96
                }
97
                String sql = MessageFormat.format(
98
                        config.getString(SQLConfig.UPDATE_TABLE_STATISTICS_table),
99
                        name
100
                    );
101
                if( !StringUtils.isEmpty(sql) ) {
102
                    sqls.add(sql);
103
                }
104
            }
105
            return sqls;
106
        }        
107
    }
108
    protected class PostgreSQLCreateIndexBuilder extends CreateIndexBuilderBase {
109

    
110
        @Override
111
        public List<String> toStrings() {
112
            StringBuilder builder = new StringBuilder();
113
            builder.append("CREATE ");
114
//            if( this.isUnique ) {
115
//                builder.append("UNIQUE ");
116
//            }
117
            builder.append("INDEX ");
118
            if( this.ifNotExist ) {
119
                int[] version = getDatabaseVersion();
120
                if( version[0]>=9 && version[1]>=5 ) {
121
                    builder.append("IF NOT EXISTS ");
122
                }
123
            }
124
            builder.append(identifier(this.indexName));
125
            builder.append(" ON ");
126
            builder.append(this.table.toString());
127
            if( this.isSpatial ) {
128
                builder.append(" USING GIST ");
129
            }
130
            builder.append(" ( ");
131
            boolean is_first_column = true;
132
            for( String column : this.columns) {
133
                if( is_first_column ) {
134
                    is_first_column = false;
135
                } else {
136
                    builder.append(", ");
137
                }
138
                builder.append(column);
139
            }
140
            builder.append(" )");
141
            
142
            List<String> sqls = new ArrayList<>();
143
            sqls.add(builder.toString());
144
            return sqls;
145
        }
146
        
147
    }
148
    
149
    protected class PostgreSQLCreateTableBuilder extends CreateTableBuilderBase {
150

    
151
        @Override
152
       public List<String> toStrings() {
153
           // 
154
           // https://www.postgresql.org/docs/9.1/static/sql-createtable.html
155
           //
156
            List<String> sqls = new ArrayList<>();
157
            StringBuilder builder = new StringBuilder();
158

    
159
            builder.append("CREATE TABLE ");
160
            builder.append(this.table.toString());
161
            builder.append(" (");
162
            boolean first = true;
163
            for (ColumnDescriptor column : columns) {
164
                if( column.isGeometry() ) {
165
                    continue;
166
                }
167
                if (first) {
168
                    first = false;
169
                } else {
170
                    builder.append(", ");
171
                }
172
                builder.append(identifier(column.getName()));
173
                builder.append(" ");
174
                if( column.isAutomatic() ) {
175
                    builder.append(" SERIAL");
176
                } else {
177
                    builder.append(sqltype(column.getType(), column.getPrecision(), column.getSize()));
178
                    if (column.getDefaultValue() == null) {
179
                        if (column.allowNulls()) {
180
                            builder.append(" DEFAULT NULL");
181
                        }
182
                    } else {
183
                        builder.append(" DEFAULT '");
184
                        builder.append(column.getDefaultValue().toString());
185
                        builder.append("'");
186
                    }
187
                    if (column.allowNulls()) {
188
                        builder.append(" NULL");
189
                    } else {
190
                        builder.append(" NOT NULL");
191
                    }
192
                }
193
                if (column.isPrimaryKey()) {
194
                    builder.append(" PRIMARY KEY");
195
                }
196
            }
197
            builder.append(" )");
198
            sqls.add(builder.toString());
199

    
200
            String AddGeometryColumn = "SELECT AddGeometryColumn({0} , {1} , {2}, {3,number,#######} , {4} , {5}, {6})";
201
            for (ColumnDescriptor column : columns) {
202
                if( column.isGeometry() ) {
203
                    String sql = MessageFormat.format(
204
                        AddGeometryColumn,
205
                        constant(this.table.getSchema()),
206
                        constant(this.table.getName()),
207
                        constant(column.getName()),
208
                        column.getGeometrySRSId(),
209
                        constant(sqlgeometrytype(column.getGeometryType(), column.getGeometrySubtype())),
210
                        constant(sqlgeometrydimension(column.getGeometryType(), column.getGeometrySubtype())),
211
                        constant(column.allowNulls())
212
                    );
213
                    sqls.add(sql);
214
                }
215
            }
216
            return sqls;
217
        }
218
    }
219

    
220
    public class PostgreSQLSelectBuilderBase extends SelectBuilderBase {
221
        
222
        @Override
223
        protected boolean isValid(StringBuilder message) {
224
            if( message == null ) {
225
                message = new StringBuilder();
226
            }
227
            if( this.has_offset() && !this.has_order_by() ) {
228
                // Algunos gestores de BBDD requieren que se especifique un
229
                // orden para poder usar OFFSET. Como eso parece buena idea para
230
                // asegurar que siempre tengamos los mismo resultados, lo exijimos
231
                // siempre.
232
                message.append("Can't use OFFSET without an ORDER BY.");
233
                return false;
234
            }
235
            return true;
236
        }        
237
        
238
        @Override
239
        public String toString() {
240
            //
241
            // https://www.postgresql.org/docs/9.1/static/sql-select.html
242
            //
243
            StringBuilder builder = new StringBuilder();
244
            if( !isValid(builder) ) {
245
                throw new IllegalStateException(builder.toString());
246
            }
247
            builder.append("SELECT ");
248
            if( this.distinct ) {
249
                builder.append("DISTINCT ");
250
            }
251
            boolean first = true;
252
            for (SelectColumnBuilder column : columns) {
253
                if (first) {
254
                    first = false;
255
                } else {
256
                    builder.append(", ");
257
                }
258
                builder.append(column.toString());
259
            }
260

    
261
            if ( this.has_from() ) {
262
                builder.append(" FROM ");
263
                builder.append(this.from.toString());
264
            }
265
            if ( this.has_where() ) {
266
                builder.append(" WHERE ");
267
                builder.append(this.where.toString());
268
            }
269
            
270
            if( this.has_order_by() ) {
271
                builder.append(" ORDER BY ");
272
                first = true;
273
                for (OrderByBuilder item : this.order_by) {
274
                    if (first) {
275
                        first = false;
276
                    } else {
277
                        builder.append(", ");
278
                    }
279
                    builder.append(item.toString());                    
280
                }   
281
            }
282
            
283
            if ( this.has_limit() && this.has_offset() ) {
284
                builder.append(" OFFSET ");
285
                builder.append(this.offset);
286
                builder.append(" FETCH NEXT ");
287
                builder.append(this.limit);
288
                builder.append(" ROWS ONLY");
289

    
290
            } else if ( this.has_limit()) {
291
                builder.append(" LIMIT ");
292
                builder.append(this.limit);
293

    
294
            } else if ( this.has_offset() ) {
295
                builder.append(" LIMIT ALL OFFSET ");
296
                builder.append(this.offset);    
297
            }
298
            return builder.toString();
299

    
300
        }
301
    }
302

    
303
    @Override
304
    public String bytearray(byte[] data) {
305
        return "decode('"+bytearray_hex(data)+"','hex')";
306
    }
307

    
308
    public PostgreSQLHelper getHelper() {
309
        return (PostgreSQLHelper) helper;
310
    }
311
    
312
    @Override
313
    protected CreateTableBuilder createCreateTableBuilder() {
314
        return new PostgreSQLCreateTableBuilder();
315
    }
316

    
317
    @Override
318
    protected CreateIndexBuilder createCreateIndexBuilder() {
319
        return new PostgreSQLCreateIndexBuilder();
320
    }
321

    
322
    @Override
323
    protected SelectBuilder createSelectBuilder() {
324
        return new PostgreSQLSelectBuilderBase();
325
    }
326

    
327
    @Override
328
    protected UpdateTableStatisticsBuilder createUpdateTableStatisticsBuilder() {
329
        return new PostgreSQLUpdateTableStatisticsBuilderBase();
330
    }       
331
   
332
}