Statistics
| Revision:

root / trunk / org.gvsig.mysql / org.gvsig.mysql.provider / src / main / java / org / gvsig / mysql / dal / MySQLSQLBuilder.java @ 120

History | View | Annotate | Download (9.01 KB)

1
package org.gvsig.mysql.dal;
2

    
3
import java.util.ArrayList;
4
import java.util.List;
5
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
6
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
7

    
8
public class MySQLSQLBuilder extends JDBCSQLBuilderBase {
9

    
10
    public MySQLSQLBuilder(MySQLHelper helper) {
11
        super(helper);
12
        
13
        //
14
        // MySQL 5.5, SQL functions reference list
15
        //
16
        // https://dev.mysql.com/doc/refman/5.5/en/sql-syntax.html
17
        // https://dev.mysql.com/doc/refman/5.5/en/using-spatial-data.html
18
        //
19
        // https://dev.mysql.com/doc/refman/5.7/en/spatial-function-reference.html
20
        //
21
        
22
        config.set(SQLConfig.default_schema, "");
23
        config.set(SQLConfig.quote_for_identifiers, "`");
24
        config.set(SQLConfig.allowAutomaticValues, true);
25
        config.set(SQLConfig.geometry_type_support, this.helper.getGeometrySupportType());
26
        config.set(SQLConfig.has_spatial_functions, this.helper.hasSpatialFunctions());
27

    
28
        config.remove_functionality(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table);
29
        config.remove_functionality(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_table);
30
         
31
        
32
        // MySQL no tiene funciones de agregado sobre geometrias.
33
        // Esto no es nada eficiente y fallara con tablas grandes.
34
        // https://forums.mysql.com/read.php?23,249284,249284#msg-249284
35
        config.set(SQLConfig.ST_ExtentAggregate, "ST_AsWKB(ST_Envelope(ST_GeomCollFromText(GROUP_CONCAT(ST_AsWKT({0})))))");
36
        config.set(SQLConfig.ST_UnionAggregate, "null");
37
        
38
        
39
                
40
        config.set(SQLConfig.UPDATE_TABLE_STATISTICS_table,"ANALYZE TABLE {0}");
41
        
42
        config.set(SQLConfig.lcase, "lower({0})");
43
        config.set(SQLConfig.ucase, "upper({0})");
44
        config.set(SQLConfig.operator_ILIKE, "lower({0}) LIKE lower({1})");
45
        config.set(SQLConfig.isNull, "( ({0}) IS NULL )");
46
        config.set(SQLConfig.notIsNull, "( ({0}) IS NOT NULL )");
47

    
48
        config.set(SQLConfig.type_boolean, "BIT");
49
        config.set(SQLConfig.type_byte, "TINYINT");
50
        config.set(SQLConfig.type_bytearray, "BINARY");
51
        config.set(SQLConfig.type_geometry, "GEOMETRY");
52
        config.set(SQLConfig.type_char, "TEXT");
53
        config.set(SQLConfig.type_date, "DATETIME");
54
        config.set(SQLConfig.type_double, "DOUBLE"); 
55
        config.set(SQLConfig.type_numeric_p, "DECIMAL({0})");
56
        config.set(SQLConfig.type_numeric_ps, "DECIMAL({0},{1})");
57
        config.set(SQLConfig.type_bigdecimal, "DECIMAL");
58
        config.set(SQLConfig.type_float, "FLOAT");
59
        config.set(SQLConfig.type_int, "INTEGER");
60
        config.set(SQLConfig.type_long, "BIGINT");
61
        config.set(SQLConfig.type_string, "CHAR");
62
        config.set(SQLConfig.type_string_p, "VARCHAR({0})");
63
        config.set(SQLConfig.type_time, "TIME");
64
        config.set(SQLConfig.type_timestamp, "TIMESTAMP");
65
        config.set(SQLConfig.type_version, "VARCHAR(45)");
66
        config.set(SQLConfig.type_URI, "TEXT");
67
        config.set(SQLConfig.type_URL, "TEXT");
68
        config.set(SQLConfig.type_FILE, "TEXT");
69
        config.set(SQLConfig.type_FOLDER, "TEXT");        
70
    }
71

    
72
    public MySQLHelper getHelper() {
73
        return (MySQLHelper) helper;
74
    }
75
    
76
    public class MySQLTableNameBuilderBase extends TableNameBuilderBase {
77

    
78
        @Override
79
        public boolean has_schema() {
80
            return false;
81
        }
82
        
83
    }
84
    
85
    protected class MySQLCreateTableBuilder extends CreateTableBuilderBase {
86

    
87
        @Override
88
        public List<String> toStrings() {
89

    
90
            List<String> sqls = new ArrayList<>();
91
            StringBuilder builder = new StringBuilder();
92

    
93
            builder.append("CREATE TABLE ");
94
            builder.append(this.table.toString());
95
            builder.append(" (");
96
            boolean first = true;
97
            for (ColumnDescriptorBuilder column : columns) {
98
                if (first) {
99
                    first = false;
100
                } else {
101
                    builder.append(", ");
102
                }
103
                builder.append(identifier(column.getName()));
104
                builder.append(" ");
105
                builder.append(sqltype(column.getType(), column.getPrecision(), column.getSize()));
106
                if (column.isPrimaryKey()) {
107
                    builder.append(" PRIMARY KEY");
108
                }
109
                if( column.isAutomatic() ) {
110
                    builder.append(" AUTO_INCREMENT");
111
                }
112
                if (column.getDefaultValue() == null) {
113
                    if (column.allowNulls()) {
114
                        builder.append(" DEFAULT NULL");
115
                    }
116
                } else {
117
                    builder.append(" DEFAULT '");
118
                    builder.append(column.getDefaultValue().toString());
119
                    builder.append("'");
120
                }
121
                if (column.allowNulls()) {
122
                    builder.append(" NULL");
123
                } else {
124
                    builder.append(" NOT NULL");
125
                }
126
            }
127
            builder.append(" )");
128
            sqls.add(builder.toString());
129

    
130
            return sqls;
131
        }
132
    }
133

    
134
    public class MySQLSelectBuilderBase extends SelectBuilderBase {
135
        
136
        @Override
137
        protected boolean isValid(StringBuilder message) {
138
            if( message == null ) {
139
                message = new StringBuilder();
140
            }
141
            if( this.has_offset() && !this.has_order_by() ) {
142
                // Algunos gestores de BBDD requieren que se especifique un
143
                // orden para poder usar OFFSET. Como eso parece buena idea para
144
                // asegurar que siempre tengamos los mismo resultados, lo exijimos
145
                // siempre.
146
                message.append("Can't use OFFSET without an ORDER BY.");
147
                return false;
148
            }
149
            return true;
150
        }        
151
        
152
        @Override
153
        public String toString() {
154
            // MySQL requiere que si se especifica OFFSET deba especificarse
155
            // LIMIT obligatoriamente. Se le puede poner un LIMIT -1 cuando 
156
            // queramos un OFFSET sin especificar un LIMIT.
157
            StringBuilder builder = new StringBuilder();
158
            if( !isValid(builder) ) {
159
                throw new IllegalStateException(builder.toString());
160
            }
161
            builder.append("SELECT ");
162
            if( this.distinct ) {
163
                builder.append("DISTINCT ");
164
            }
165
            boolean first = true;
166
            for (SelectColumnBuilder column : columns) {
167
                if (first) {
168
                    first = false;
169
                } else {
170
                    builder.append(", ");
171
                }
172
                builder.append(column.toString());
173
            }
174

    
175
            if ( this.has_from() ) {
176
                builder.append(" FROM ");
177
                builder.append(this.from.toString());
178
            }
179
            if ( this.has_where() ) {
180
                builder.append(" WHERE ");
181
                builder.append(this.where.toString());
182
            }
183
            
184
            if( this.has_order_by() ) {
185
                builder.append(" ORDER BY ");
186
                first = true;
187
                for (OrderByBuilder item : this.order_by) {
188
                    if (first) {
189
                        first = false;
190
                    } else {
191
                        builder.append(", ");
192
                    }
193
                    builder.append(item.toString());                    
194
                }   
195
            }
196
            
197
            if ( this.has_limit() && this.has_offset() ) {
198
                builder.append(" LIMIT ");
199
                builder.append(this.limit);
200
                builder.append(" OFFSET ");
201
                builder.append(this.offset);
202
                
203
            } else if ( this.has_limit()) {
204
                builder.append(" LIMIT ");
205
                builder.append(this.limit);
206

    
207
            } else if ( this.has_offset() ) {
208
                // See https://dev.mysql.com/doc/refman/5.7/en/select.html#idm140126933499488
209
                builder.append(" LIMIT 18446744073709551615 OFFSET ");
210
                builder.append(this.offset);    
211
            }
212
            return builder.toString();
213

    
214
        }
215
    }
216

    
217
    @Override
218
    public String bytearray(byte[] data) {
219
        // MySQL usa un formato diferencte para especificar un array de 
220
        // bytes. En lugar de 0x... usa x'...' .
221
        StringBuilder builder = new StringBuilder();
222
        builder.append("x'");
223
        for (byte abyte : data) {
224
            int v = abyte & 0xff;
225
            builder.append(String.format("%02x", v));
226
        }
227
        builder.append("'");
228
        return builder.toString();
229
    }
230
    
231
    @Override
232
    protected TableNameBuilder createTableNameBuilder() {
233
        return new MySQLTableNameBuilderBase();
234
    }
235
    
236
    @Override
237
    protected CreateTableBuilder createCreateTableBuilder() {
238
        return new MySQLCreateTableBuilder();
239
    }
240

    
241
    @Override
242
    protected SelectBuilder createSelectBuilder() {
243
        return new MySQLSelectBuilderBase();
244
    }
245

    
246
}