Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

DefaultSQLGenerator.java 14KB

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