]> source.dussan.org Git - vaadin-framework.git/blob
c82af96b79a668336fa3238dbbce8ddc13f5d8b9
[vaadin-framework.git] /
1 /*
2  * Copyright 2000-2018 Vaadin Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 package com.vaadin.v7.data.util.sqlcontainer.query.generator;
17
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.Map;
21
22 import com.vaadin.v7.data.Container.Filter;
23 import com.vaadin.v7.data.util.sqlcontainer.ColumnProperty;
24 import com.vaadin.v7.data.util.sqlcontainer.RowItem;
25 import com.vaadin.v7.data.util.sqlcontainer.SQLUtil;
26 import com.vaadin.v7.data.util.sqlcontainer.TemporaryRowId;
27 import com.vaadin.v7.data.util.sqlcontainer.query.OrderBy;
28 import com.vaadin.v7.data.util.sqlcontainer.query.generator.filter.QueryBuilder;
29 import com.vaadin.v7.data.util.sqlcontainer.query.generator.filter.StringDecorator;
30
31 /**
32  * Generates generic SQL that is supported by HSQLDB, MySQL and PostgreSQL.
33  *
34  * @author Jonatan Kronqvist / Vaadin Ltd
35  *
36  * @deprecated As of 8.0, no replacement available.
37  */
38 @SuppressWarnings("serial")
39 @Deprecated
40 public class DefaultSQLGenerator implements SQLGenerator {
41
42     private Class<? extends StatementHelper> statementHelperClass = null;
43
44     public DefaultSQLGenerator() {
45
46     }
47
48     /**
49      * Create a new DefaultSqlGenerator instance that uses the given
50      * implementation of {@link StatementHelper}.
51      *
52      * @param statementHelper
53      */
54     public DefaultSQLGenerator(
55             Class<? extends StatementHelper> statementHelperClazz) {
56         this();
57         statementHelperClass = statementHelperClazz;
58     }
59
60     /**
61      * Construct a DefaultSQLGenerator with the specified identifiers for start
62      * and end of quoted strings. The identifiers may be different depending on
63      * the database engine and it's settings.
64      *
65      * @param quoteStart
66      *            the identifier (character) denoting the start of a quoted
67      *            string
68      * @param quoteEnd
69      *            the identifier (character) denoting the end of a quoted string
70      */
71     public DefaultSQLGenerator(String quoteStart, String quoteEnd) {
72         QueryBuilder
73                 .setStringDecorator(new StringDecorator(quoteStart, quoteEnd));
74     }
75
76     /**
77      * Same as {@link #DefaultSQLGenerator(String, String)} but with support for
78      * custom {@link StatementHelper} implementation.
79      *
80      * @param quoteStart
81      * @param quoteEnd
82      * @param statementHelperClazz
83      */
84     public DefaultSQLGenerator(String quoteStart, String quoteEnd,
85             Class<? extends StatementHelper> statementHelperClazz) {
86         this(quoteStart, quoteEnd);
87         statementHelperClass = statementHelperClazz;
88     }
89
90     /*
91      * (non-Javadoc)
92      *
93      * @see com.vaadin.addon.sqlcontainer.query.generator.SQLGenerator#
94      * generateSelectQuery(java.lang.String, java.util.List, java.util.List,
95      * int, int, java.lang.String)
96      */
97     @Override
98     public StatementHelper generateSelectQuery(String tableName,
99             List<Filter> filters, List<OrderBy> orderBys, int offset,
100             int pagelength, String toSelect) {
101         if (tableName == null || tableName.trim().equals("")) {
102             throw new IllegalArgumentException("Table name must be given.");
103         }
104         toSelect = toSelect == null ? "*" : toSelect;
105         StatementHelper sh = getStatementHelper();
106         StringBuffer query = new StringBuffer();
107         query.append("SELECT " + toSelect + " FROM ")
108                 .append(SQLUtil.escapeSQL(tableName));
109         if (filters != null) {
110             query.append(QueryBuilder.getWhereStringForFilters(filters, sh));
111         }
112         if (orderBys != null) {
113             for (OrderBy o : orderBys) {
114                 generateOrderBy(query, o, orderBys.indexOf(o) == 0);
115             }
116         }
117         if (pagelength != 0) {
118             generateLimits(query, offset, pagelength);
119         }
120         sh.setQueryString(query.toString());
121         return sh;
122     }
123
124     /*
125      * (non-Javadoc)
126      *
127      * @see com.vaadin.addon.sqlcontainer.query.generator.SQLGenerator#
128      * generateUpdateQuery(java.lang.String,
129      * com.vaadin.addon.sqlcontainer.RowItem)
130      */
131     @Override
132     public StatementHelper generateUpdateQuery(String tableName, RowItem item) {
133         if (tableName == null || tableName.trim().equals("")) {
134             throw new IllegalArgumentException("Table name must be given.");
135         }
136         if (item == null) {
137             throw new IllegalArgumentException("Updated item must be given.");
138         }
139         StatementHelper sh = getStatementHelper();
140         StringBuilder query = new StringBuilder();
141         query.append("UPDATE ").append(tableName).append(" SET");
142
143         /* Generate column<->value and rowidentifiers map */
144         Map<String, Object> columnToValueMap = generateColumnToValueMap(item);
145         Map<String, Object> rowIdentifiers = generateRowIdentifiers(item);
146         /* Generate columns and values to update */
147         boolean first = true;
148         for (String column : columnToValueMap.keySet()) {
149             if (first) {
150                 query.append(" " + QueryBuilder.quote(column) + " = ?");
151             } else {
152                 query.append(", " + QueryBuilder.quote(column) + " = ?");
153             }
154             sh.addParameterValue(columnToValueMap.get(column),
155                     item.getItemProperty(column).getType());
156             first = false;
157         }
158         /* Generate identifiers for the row to be updated */
159         first = true;
160         for (String column : rowIdentifiers.keySet()) {
161             if (first) {
162                 query.append(" WHERE " + QueryBuilder.quote(column) + " = ?");
163             } else {
164                 query.append(" AND " + QueryBuilder.quote(column) + " = ?");
165             }
166             sh.addParameterValue(rowIdentifiers.get(column),
167                     item.getItemProperty(column).getType());
168             first = false;
169         }
170         sh.setQueryString(query.toString());
171         return sh;
172     }
173
174     /*
175      * (non-Javadoc)
176      *
177      * @see com.vaadin.addon.sqlcontainer.query.generator.SQLGenerator#
178      * generateInsertQuery(java.lang.String,
179      * com.vaadin.addon.sqlcontainer.RowItem)
180      */
181     @Override
182     public StatementHelper generateInsertQuery(String tableName, RowItem item) {
183         if (tableName == null || tableName.trim().equals("")) {
184             throw new IllegalArgumentException("Table name must be given.");
185         }
186         if (item == null) {
187             throw new IllegalArgumentException("New item must be given.");
188         }
189         if (!(item.getId() instanceof TemporaryRowId)) {
190             throw new IllegalArgumentException(
191                     "Cannot generate an insert query for item already in database.");
192         }
193         StatementHelper sh = getStatementHelper();
194         StringBuilder query = new StringBuilder();
195         query.append("INSERT INTO ").append(tableName).append(" (");
196
197         /* Generate column<->value map */
198         Map<String, Object> columnToValueMap = generateColumnToValueMap(item);
199         /* Generate column names for insert query */
200         boolean first = true;
201         for (String column : columnToValueMap.keySet()) {
202             if (!first) {
203                 query.append(", ");
204             }
205             query.append(QueryBuilder.quote(column));
206             first = false;
207         }
208
209         /* Generate values for insert query */
210         query.append(") VALUES (");
211         first = true;
212         for (String column : columnToValueMap.keySet()) {
213             if (!first) {
214                 query.append(", ");
215             }
216             query.append('?');
217             sh.addParameterValue(columnToValueMap.get(column),
218                     item.getItemProperty(column).getType());
219             first = false;
220         }
221         query.append(')');
222         sh.setQueryString(query.toString());
223         return sh;
224     }
225
226     /*
227      * (non-Javadoc)
228      *
229      * @see com.vaadin.addon.sqlcontainer.query.generator.SQLGenerator#
230      * generateDeleteQuery(java.lang.String,
231      * com.vaadin.addon.sqlcontainer.RowItem)
232      */
233     @Override
234     public StatementHelper generateDeleteQuery(String tableName,
235             List<String> primaryKeyColumns, String versionColumn,
236             RowItem item) {
237         if (tableName == null || tableName.trim().equals("")) {
238             throw new IllegalArgumentException("Table name must be given.");
239         }
240         if (item == null) {
241             throw new IllegalArgumentException(
242                     "Item to be deleted must be given.");
243         }
244         if (primaryKeyColumns == null || primaryKeyColumns.isEmpty()) {
245             throw new IllegalArgumentException(
246                     "Valid keyColumnNames must be provided.");
247         }
248         StatementHelper sh = getStatementHelper();
249         StringBuilder query = new StringBuilder();
250         query.append("DELETE FROM ").append(tableName).append(" WHERE ");
251         int count = 1;
252         for (String keyColName : primaryKeyColumns) {
253             if ((this instanceof MSSQLGenerator
254                     || this instanceof OracleGenerator)
255                     && keyColName.equalsIgnoreCase("rownum")) {
256                 count++;
257                 continue;
258             }
259             if (count > 1) {
260                 query.append(" AND ");
261             }
262             if (item.getItemProperty(keyColName).getValue() != null) {
263                 query.append(QueryBuilder.quote(keyColName) + " = ?");
264                 sh.addParameterValue(
265                         item.getItemProperty(keyColName).getValue(),
266                         item.getItemProperty(keyColName).getType());
267             }
268             count++;
269         }
270         if (versionColumn != null) {
271             if (!item.getItemPropertyIds().contains(versionColumn)) {
272                 throw new IllegalArgumentException(String.format(
273                         "Table '%s' does not contain version column '%s'.",
274                         tableName, versionColumn));
275             }
276
277             query.append(String.format(" AND %s = ?",
278                     QueryBuilder.quote(versionColumn)));
279             sh.addParameterValue(item.getItemProperty(versionColumn).getValue(),
280                     item.getItemProperty(versionColumn).getType());
281         }
282
283         sh.setQueryString(query.toString());
284         return sh;
285     }
286
287     /**
288      * Generates sorting rules as an ORDER BY -clause.
289      *
290      * @param sb
291      *            StringBuffer to which the clause is appended.
292      * @param o
293      *            OrderBy object to be added into the sb.
294      * @param firstOrderBy
295      *            If true, this is the first OrderBy.
296      * @return
297      */
298     protected StringBuffer generateOrderBy(StringBuffer sb, OrderBy o,
299             boolean firstOrderBy) {
300         if (firstOrderBy) {
301             sb.append(" ORDER BY ");
302         } else {
303             sb.append(", ");
304         }
305         sb.append(QueryBuilder.quote(o.getColumn()));
306         if (o.isAscending()) {
307             sb.append(" ASC");
308         } else {
309             sb.append(" DESC");
310         }
311         return sb;
312     }
313
314     /**
315      * Generates the LIMIT and OFFSET clause.
316      *
317      * @param sb
318      *            StringBuffer to which the clause is appended.
319      * @param offset
320      *            Value for offset.
321      * @param pagelength
322      *            Value for pagelength.
323      * @return StringBuffer with LIMIT and OFFSET clause added.
324      */
325     protected StringBuffer generateLimits(StringBuffer sb, int offset,
326             int pagelength) {
327         sb.append(" LIMIT ").append(pagelength).append(" OFFSET ")
328                 .append(offset);
329         return sb;
330     }
331
332     protected Map<String, Object> generateColumnToValueMap(RowItem item) {
333         Map<String, Object> columnToValueMap = new HashMap<String, Object>();
334         for (Object id : item.getItemPropertyIds()) {
335             ColumnProperty cp = (ColumnProperty) item.getItemProperty(id);
336             /* Prevent "rownum" usage as a column name if MSSQL or ORACLE */
337             if ((this instanceof MSSQLGenerator
338                     || this instanceof OracleGenerator)
339                     && cp.getPropertyId().equalsIgnoreCase("rownum")) {
340                 continue;
341             }
342             if (cp.isPersistent()) {
343                 columnToValueMap.put(cp.getPropertyId(), cp.getValue());
344             }
345         }
346         return columnToValueMap;
347     }
348
349     protected Map<String, Object> generateRowIdentifiers(RowItem item) {
350         Map<String, Object> rowIdentifiers = new HashMap<String, Object>();
351         for (Object id : item.getItemPropertyIds()) {
352             ColumnProperty cp = (ColumnProperty) item.getItemProperty(id);
353             /* Prevent "rownum" usage as a column name if MSSQL or ORACLE */
354             if ((this instanceof MSSQLGenerator
355                     || this instanceof OracleGenerator)
356                     && cp.getPropertyId().equalsIgnoreCase("rownum")) {
357                 continue;
358             }
359
360             if (cp.isRowIdentifier()) {
361                 Object value;
362                 if (cp.isPrimaryKey()) {
363                     // If the value of a primary key has changed, its old value
364                     // should be used to identify the row (#9145)
365                     value = cp.getOldValue();
366                 } else {
367                     value = cp.getValue();
368                 }
369                 rowIdentifiers.put(cp.getPropertyId(), value);
370             }
371         }
372         return rowIdentifiers;
373     }
374
375     /**
376      * Returns the statement helper for the generator. Override this to handle
377      * platform specific data types.
378      *
379      * @see http://dev.vaadin.com/ticket/9148
380      * @return a new instance of the statement helper
381      */
382     protected StatementHelper getStatementHelper() {
383         if (statementHelperClass == null) {
384             return new StatementHelper();
385         }
386
387         try {
388             return statementHelperClass.newInstance();
389         } catch (InstantiationException e) {
390             throw new RuntimeException(
391                     "Unable to instantiate custom StatementHelper", e);
392         } catch (IllegalAccessException e) {
393             throw new RuntimeException(
394                     "Unable to instantiate custom StatementHelper", e);
395         }
396     }
397
398 }