You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TableQuery.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. /*
  2. * Copyright 2011 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.data.util.sqlcontainer.query;
  17. import java.io.IOException;
  18. import java.sql.Connection;
  19. import java.sql.DatabaseMetaData;
  20. import java.sql.PreparedStatement;
  21. import java.sql.ResultSet;
  22. import java.sql.ResultSetMetaData;
  23. import java.sql.SQLException;
  24. import java.util.ArrayList;
  25. import java.util.Collections;
  26. import java.util.EventObject;
  27. import java.util.HashMap;
  28. import java.util.LinkedList;
  29. import java.util.List;
  30. import java.util.Map;
  31. import java.util.logging.Level;
  32. import java.util.logging.Logger;
  33. import com.vaadin.data.Container.Filter;
  34. import com.vaadin.data.util.filter.Compare.Equal;
  35. import com.vaadin.data.util.sqlcontainer.ColumnProperty;
  36. import com.vaadin.data.util.sqlcontainer.OptimisticLockException;
  37. import com.vaadin.data.util.sqlcontainer.RowId;
  38. import com.vaadin.data.util.sqlcontainer.RowItem;
  39. import com.vaadin.data.util.sqlcontainer.SQLUtil;
  40. import com.vaadin.data.util.sqlcontainer.TemporaryRowId;
  41. import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool;
  42. import com.vaadin.data.util.sqlcontainer.query.generator.DefaultSQLGenerator;
  43. import com.vaadin.data.util.sqlcontainer.query.generator.MSSQLGenerator;
  44. import com.vaadin.data.util.sqlcontainer.query.generator.SQLGenerator;
  45. import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper;
  46. @SuppressWarnings("serial")
  47. public class TableQuery implements QueryDelegate,
  48. QueryDelegate.RowIdChangeNotifier {
  49. /** Table name, primary key column name(s) and version column name */
  50. private String tableName;
  51. private List<String> primaryKeyColumns;
  52. private String versionColumn;
  53. /** Currently set Filters and OrderBys */
  54. private List<Filter> filters;
  55. private List<OrderBy> orderBys;
  56. /** SQLGenerator instance to use for generating queries */
  57. private SQLGenerator sqlGenerator;
  58. /** Fields related to Connection and Transaction handling */
  59. private JDBCConnectionPool connectionPool;
  60. private transient Connection activeConnection;
  61. private boolean transactionOpen;
  62. /** Row ID change listeners */
  63. private LinkedList<RowIdChangeListener> rowIdChangeListeners;
  64. /** Row ID change events, stored until commit() is called */
  65. private final List<RowIdChangeEvent> bufferedEvents = new ArrayList<RowIdChangeEvent>();
  66. /** Set to true to output generated SQL Queries to System.out */
  67. private boolean debug = false;
  68. /** Prevent no-parameters instantiation of TableQuery */
  69. @SuppressWarnings("unused")
  70. private TableQuery() {
  71. }
  72. /**
  73. * Creates a new TableQuery using the given connection pool, SQL generator
  74. * and table name to fetch the data from. All parameters must be non-null.
  75. *
  76. * @param tableName
  77. * Name of the database table to connect to
  78. * @param connectionPool
  79. * Connection pool for accessing the database
  80. * @param sqlGenerator
  81. * SQL query generator implementation
  82. */
  83. public TableQuery(String tableName, JDBCConnectionPool connectionPool,
  84. SQLGenerator sqlGenerator) {
  85. if (tableName == null || tableName.trim().length() < 1
  86. || connectionPool == null || sqlGenerator == null) {
  87. throw new IllegalArgumentException(
  88. "All parameters must be non-null and a table name must be given.");
  89. }
  90. this.tableName = tableName;
  91. this.sqlGenerator = sqlGenerator;
  92. this.connectionPool = connectionPool;
  93. fetchMetaData();
  94. }
  95. /**
  96. * Creates a new TableQuery using the given connection pool and table name
  97. * to fetch the data from. All parameters must be non-null. The default SQL
  98. * generator will be used for queries.
  99. *
  100. * @param tableName
  101. * Name of the database table to connect to
  102. * @param connectionPool
  103. * Connection pool for accessing the database
  104. */
  105. public TableQuery(String tableName, JDBCConnectionPool connectionPool) {
  106. this(tableName, connectionPool, new DefaultSQLGenerator());
  107. }
  108. /*
  109. * (non-Javadoc)
  110. *
  111. * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#getCount()
  112. */
  113. @Override
  114. public int getCount() throws SQLException {
  115. getLogger().log(Level.FINE, "Fetching count...");
  116. StatementHelper sh = sqlGenerator.generateSelectQuery(tableName,
  117. filters, null, 0, 0, "COUNT(*)");
  118. boolean shouldCloseTransaction = false;
  119. if (!transactionOpen) {
  120. shouldCloseTransaction = true;
  121. beginTransaction();
  122. }
  123. ResultSet r = executeQuery(sh);
  124. r.next();
  125. int count = r.getInt(1);
  126. r.getStatement().close();
  127. r.close();
  128. if (shouldCloseTransaction) {
  129. commit();
  130. }
  131. return count;
  132. }
  133. /*
  134. * (non-Javadoc)
  135. *
  136. * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#getResults(int,
  137. * int)
  138. */
  139. @Override
  140. public ResultSet getResults(int offset, int pagelength) throws SQLException {
  141. StatementHelper sh;
  142. /*
  143. * If no ordering is explicitly set, results will be ordered by the
  144. * first primary key column.
  145. */
  146. if (orderBys == null || orderBys.isEmpty()) {
  147. List<OrderBy> ob = new ArrayList<OrderBy>();
  148. ob.add(new OrderBy(primaryKeyColumns.get(0), true));
  149. sh = sqlGenerator.generateSelectQuery(tableName, filters, ob,
  150. offset, pagelength, null);
  151. } else {
  152. sh = sqlGenerator.generateSelectQuery(tableName, filters, orderBys,
  153. offset, pagelength, null);
  154. }
  155. return executeQuery(sh);
  156. }
  157. /*
  158. * (non-Javadoc)
  159. *
  160. * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#
  161. * implementationRespectsPagingLimits()
  162. */
  163. @Override
  164. public boolean implementationRespectsPagingLimits() {
  165. return true;
  166. }
  167. /*
  168. * (non-Javadoc)
  169. *
  170. * @see
  171. * com.vaadin.addon.sqlcontainer.query.QueryDelegate#storeRow(com.vaadin
  172. * .addon.sqlcontainer.RowItem)
  173. */
  174. @Override
  175. public int storeRow(RowItem row) throws UnsupportedOperationException,
  176. SQLException {
  177. if (row == null) {
  178. throw new IllegalArgumentException("Row argument must be non-null.");
  179. }
  180. StatementHelper sh;
  181. int result = 0;
  182. if (row.getId() instanceof TemporaryRowId) {
  183. setVersionColumnFlagInProperty(row);
  184. sh = sqlGenerator.generateInsertQuery(tableName, row);
  185. result = executeUpdateReturnKeys(sh, row);
  186. } else {
  187. setVersionColumnFlagInProperty(row);
  188. sh = sqlGenerator.generateUpdateQuery(tableName, row);
  189. result = executeUpdate(sh);
  190. }
  191. if (versionColumn != null && result == 0) {
  192. throw new OptimisticLockException(
  193. "Someone else changed the row that was being updated.",
  194. row.getId());
  195. }
  196. return result;
  197. }
  198. private void setVersionColumnFlagInProperty(RowItem row) {
  199. ColumnProperty versionProperty = (ColumnProperty) row
  200. .getItemProperty(versionColumn);
  201. if (versionProperty != null) {
  202. versionProperty.setVersionColumn(true);
  203. }
  204. }
  205. /**
  206. * Inserts the given row in the database table immediately. Begins and
  207. * commits the transaction needed. This method was added specifically to
  208. * solve the problem of returning the final RowId immediately on the
  209. * SQLContainer.addItem() call when auto commit mode is enabled in the
  210. * SQLContainer.
  211. *
  212. * @param row
  213. * RowItem to add to the database
  214. * @return Final RowId of the added row
  215. * @throws SQLException
  216. */
  217. public RowId storeRowImmediately(RowItem row) throws SQLException {
  218. beginTransaction();
  219. /* Set version column, if one is provided */
  220. setVersionColumnFlagInProperty(row);
  221. /* Generate query */
  222. StatementHelper sh = sqlGenerator.generateInsertQuery(tableName, row);
  223. PreparedStatement pstmt = activeConnection.prepareStatement(
  224. sh.getQueryString(), primaryKeyColumns.toArray(new String[0]));
  225. sh.setParameterValuesToStatement(pstmt);
  226. getLogger().log(Level.FINE, "DB -> " + sh.getQueryString());
  227. int result = pstmt.executeUpdate();
  228. if (result > 0) {
  229. /*
  230. * If affected rows exist, we'll get the new RowId, commit the
  231. * transaction and return the new RowId.
  232. */
  233. ResultSet generatedKeys = pstmt.getGeneratedKeys();
  234. RowId newId = getNewRowId(row, generatedKeys);
  235. generatedKeys.close();
  236. pstmt.clearParameters();
  237. pstmt.close();
  238. commit();
  239. return newId;
  240. } else {
  241. pstmt.clearParameters();
  242. pstmt.close();
  243. /* On failure return null */
  244. return null;
  245. }
  246. }
  247. /*
  248. * (non-Javadoc)
  249. *
  250. * @see
  251. * com.vaadin.addon.sqlcontainer.query.QueryDelegate#setFilters(java.util
  252. * .List)
  253. */
  254. @Override
  255. public void setFilters(List<Filter> filters)
  256. throws UnsupportedOperationException {
  257. if (filters == null) {
  258. this.filters = null;
  259. return;
  260. }
  261. this.filters = Collections.unmodifiableList(filters);
  262. }
  263. /*
  264. * (non-Javadoc)
  265. *
  266. * @see
  267. * com.vaadin.addon.sqlcontainer.query.QueryDelegate#setOrderBy(java.util
  268. * .List)
  269. */
  270. @Override
  271. public void setOrderBy(List<OrderBy> orderBys)
  272. throws UnsupportedOperationException {
  273. if (orderBys == null) {
  274. this.orderBys = null;
  275. return;
  276. }
  277. this.orderBys = Collections.unmodifiableList(orderBys);
  278. }
  279. /*
  280. * (non-Javadoc)
  281. *
  282. * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#beginTransaction()
  283. */
  284. @Override
  285. public void beginTransaction() throws UnsupportedOperationException,
  286. SQLException {
  287. if (transactionOpen && activeConnection != null) {
  288. throw new IllegalStateException();
  289. }
  290. getLogger().log(Level.FINE, "DB -> begin transaction");
  291. activeConnection = connectionPool.reserveConnection();
  292. activeConnection.setAutoCommit(false);
  293. transactionOpen = true;
  294. }
  295. /*
  296. * (non-Javadoc)
  297. *
  298. * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#commit()
  299. */
  300. @Override
  301. public void commit() throws UnsupportedOperationException, SQLException {
  302. if (transactionOpen && activeConnection != null) {
  303. getLogger().log(Level.FINE, "DB -> commit");
  304. activeConnection.commit();
  305. connectionPool.releaseConnection(activeConnection);
  306. } else {
  307. throw new SQLException("No active transaction");
  308. }
  309. transactionOpen = false;
  310. /* Handle firing row ID change events */
  311. RowIdChangeEvent[] unFiredEvents = bufferedEvents
  312. .toArray(new RowIdChangeEvent[] {});
  313. bufferedEvents.clear();
  314. if (rowIdChangeListeners != null && !rowIdChangeListeners.isEmpty()) {
  315. for (RowIdChangeListener r : rowIdChangeListeners) {
  316. for (RowIdChangeEvent e : unFiredEvents) {
  317. r.rowIdChange(e);
  318. }
  319. }
  320. }
  321. }
  322. /*
  323. * (non-Javadoc)
  324. *
  325. * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#rollback()
  326. */
  327. @Override
  328. public void rollback() throws UnsupportedOperationException, SQLException {
  329. if (transactionOpen && activeConnection != null) {
  330. getLogger().log(Level.FINE, "DB -> rollback");
  331. activeConnection.rollback();
  332. connectionPool.releaseConnection(activeConnection);
  333. } else {
  334. throw new SQLException("No active transaction");
  335. }
  336. transactionOpen = false;
  337. }
  338. /*
  339. * (non-Javadoc)
  340. *
  341. * @see
  342. * com.vaadin.addon.sqlcontainer.query.QueryDelegate#getPrimaryKeyColumns()
  343. */
  344. @Override
  345. public List<String> getPrimaryKeyColumns() {
  346. return Collections.unmodifiableList(primaryKeyColumns);
  347. }
  348. public String getVersionColumn() {
  349. return versionColumn;
  350. }
  351. public void setVersionColumn(String column) {
  352. versionColumn = column;
  353. }
  354. public String getTableName() {
  355. return tableName;
  356. }
  357. public SQLGenerator getSqlGenerator() {
  358. return sqlGenerator;
  359. }
  360. /**
  361. * Executes the given query string using either the active connection if a
  362. * transaction is already open, or a new connection from this query's
  363. * connection pool.
  364. *
  365. * @param sh
  366. * an instance of StatementHelper, containing the query string
  367. * and parameter values.
  368. * @return ResultSet of the query
  369. * @throws SQLException
  370. */
  371. private ResultSet executeQuery(StatementHelper sh) throws SQLException {
  372. Connection c = null;
  373. if (transactionOpen && activeConnection != null) {
  374. c = activeConnection;
  375. } else {
  376. throw new SQLException("No active transaction!");
  377. }
  378. PreparedStatement pstmt = c.prepareStatement(sh.getQueryString());
  379. sh.setParameterValuesToStatement(pstmt);
  380. getLogger().log(Level.FINE, "DB -> " + sh.getQueryString());
  381. return pstmt.executeQuery();
  382. }
  383. /**
  384. * Executes the given update query string using either the active connection
  385. * if a transaction is already open, or a new connection from this query's
  386. * connection pool.
  387. *
  388. * @param sh
  389. * an instance of StatementHelper, containing the query string
  390. * and parameter values.
  391. * @return Number of affected rows
  392. * @throws SQLException
  393. */
  394. private int executeUpdate(StatementHelper sh) throws SQLException {
  395. Connection c = null;
  396. PreparedStatement pstmt = null;
  397. try {
  398. if (transactionOpen && activeConnection != null) {
  399. c = activeConnection;
  400. } else {
  401. c = connectionPool.reserveConnection();
  402. }
  403. pstmt = c.prepareStatement(sh.getQueryString());
  404. sh.setParameterValuesToStatement(pstmt);
  405. getLogger().log(Level.FINE, "DB -> " + sh.getQueryString());
  406. int retval = pstmt.executeUpdate();
  407. return retval;
  408. } finally {
  409. if (pstmt != null) {
  410. pstmt.clearParameters();
  411. pstmt.close();
  412. }
  413. if (!transactionOpen) {
  414. connectionPool.releaseConnection(c);
  415. }
  416. }
  417. }
  418. /**
  419. * Executes the given update query string using either the active connection
  420. * if a transaction is already open, or a new connection from this query's
  421. * connection pool.
  422. *
  423. * Additionally adds a new RowIdChangeEvent to the event buffer.
  424. *
  425. * @param sh
  426. * an instance of StatementHelper, containing the query string
  427. * and parameter values.
  428. * @param row
  429. * the row item to update
  430. * @return Number of affected rows
  431. * @throws SQLException
  432. */
  433. private int executeUpdateReturnKeys(StatementHelper sh, RowItem row)
  434. throws SQLException {
  435. Connection c = null;
  436. PreparedStatement pstmt = null;
  437. ResultSet genKeys = null;
  438. try {
  439. if (transactionOpen && activeConnection != null) {
  440. c = activeConnection;
  441. } else {
  442. c = connectionPool.reserveConnection();
  443. }
  444. pstmt = c.prepareStatement(sh.getQueryString(),
  445. primaryKeyColumns.toArray(new String[0]));
  446. sh.setParameterValuesToStatement(pstmt);
  447. getLogger().log(Level.FINE, "DB -> " + sh.getQueryString());
  448. int result = pstmt.executeUpdate();
  449. genKeys = pstmt.getGeneratedKeys();
  450. RowId newId = getNewRowId(row, genKeys);
  451. bufferedEvents.add(new RowIdChangeEvent(row.getId(), newId));
  452. return result;
  453. } finally {
  454. if (genKeys != null) {
  455. genKeys.close();
  456. }
  457. if (pstmt != null) {
  458. pstmt.clearParameters();
  459. pstmt.close();
  460. }
  461. if (!transactionOpen) {
  462. connectionPool.releaseConnection(c);
  463. }
  464. }
  465. }
  466. /**
  467. * Fetches name(s) of primary key column(s) from DB metadata.
  468. *
  469. * Also tries to get the escape string to be used in search strings.
  470. */
  471. private void fetchMetaData() {
  472. Connection c = null;
  473. try {
  474. c = connectionPool.reserveConnection();
  475. DatabaseMetaData dbmd = c.getMetaData();
  476. if (dbmd != null) {
  477. tableName = SQLUtil.escapeSQL(tableName);
  478. ResultSet tables = dbmd.getTables(null, null, tableName, null);
  479. if (!tables.next()) {
  480. tables = dbmd.getTables(null, null,
  481. tableName.toUpperCase(), null);
  482. if (!tables.next()) {
  483. throw new IllegalArgumentException(
  484. "Table with the name \""
  485. + tableName
  486. + "\" was not found. Check your database contents.");
  487. } else {
  488. tableName = tableName.toUpperCase();
  489. }
  490. }
  491. tables.close();
  492. ResultSet rs = dbmd.getPrimaryKeys(null, null, tableName);
  493. List<String> names = new ArrayList<String>();
  494. while (rs.next()) {
  495. names.add(rs.getString("COLUMN_NAME"));
  496. }
  497. rs.close();
  498. if (!names.isEmpty()) {
  499. primaryKeyColumns = names;
  500. }
  501. if (primaryKeyColumns == null || primaryKeyColumns.isEmpty()) {
  502. throw new IllegalArgumentException(
  503. "Primary key constraints have not been defined for the table \""
  504. + tableName
  505. + "\". Use FreeFormQuery to access this table.");
  506. }
  507. for (String colName : primaryKeyColumns) {
  508. if (colName.equalsIgnoreCase("rownum")) {
  509. if (getSqlGenerator() instanceof MSSQLGenerator
  510. || getSqlGenerator() instanceof MSSQLGenerator) {
  511. throw new IllegalArgumentException(
  512. "When using Oracle or MSSQL, a primary key column"
  513. + " named \'rownum\' is not allowed!");
  514. }
  515. }
  516. }
  517. }
  518. } catch (SQLException e) {
  519. throw new RuntimeException(e);
  520. } finally {
  521. connectionPool.releaseConnection(c);
  522. }
  523. }
  524. private RowId getNewRowId(RowItem row, ResultSet genKeys) {
  525. try {
  526. /* Fetch primary key values and generate a map out of them. */
  527. Map<String, Object> values = new HashMap<String, Object>();
  528. ResultSetMetaData rsmd = genKeys.getMetaData();
  529. int colCount = rsmd.getColumnCount();
  530. if (genKeys.next()) {
  531. for (int i = 1; i <= colCount; i++) {
  532. values.put(rsmd.getColumnName(i), genKeys.getObject(i));
  533. }
  534. }
  535. /* Generate new RowId */
  536. List<Object> newRowId = new ArrayList<Object>();
  537. if (values.size() == 1) {
  538. if (primaryKeyColumns.size() == 1) {
  539. newRowId.add(values.get(values.keySet().iterator().next()));
  540. } else {
  541. for (String s : primaryKeyColumns) {
  542. if (!((ColumnProperty) row.getItemProperty(s))
  543. .isReadOnlyChangeAllowed()) {
  544. newRowId.add(values.get(values.keySet().iterator()
  545. .next()));
  546. } else {
  547. newRowId.add(values.get(s));
  548. }
  549. }
  550. }
  551. } else {
  552. for (String s : primaryKeyColumns) {
  553. newRowId.add(values.get(s));
  554. }
  555. }
  556. return new RowId(newRowId.toArray());
  557. } catch (Exception e) {
  558. getLogger().log(Level.FINE,
  559. "Failed to fetch key values on insert: " + e.getMessage());
  560. return null;
  561. }
  562. }
  563. /*
  564. * (non-Javadoc)
  565. *
  566. * @see
  567. * com.vaadin.addon.sqlcontainer.query.QueryDelegate#removeRow(com.vaadin
  568. * .addon.sqlcontainer.RowItem)
  569. */
  570. @Override
  571. public boolean removeRow(RowItem row) throws UnsupportedOperationException,
  572. SQLException {
  573. getLogger().log(Level.FINE,
  574. "Removing row with id: " + row.getId().getId()[0].toString());
  575. if (executeUpdate(sqlGenerator.generateDeleteQuery(getTableName(),
  576. primaryKeyColumns, versionColumn, row)) == 1) {
  577. return true;
  578. }
  579. if (versionColumn != null) {
  580. throw new OptimisticLockException(
  581. "Someone else changed the row that was being deleted.",
  582. row.getId());
  583. }
  584. return false;
  585. }
  586. /*
  587. * (non-Javadoc)
  588. *
  589. * @see
  590. * com.vaadin.addon.sqlcontainer.query.QueryDelegate#containsRowWithKey(
  591. * java.lang.Object[])
  592. */
  593. @Override
  594. public boolean containsRowWithKey(Object... keys) throws SQLException {
  595. ArrayList<Filter> filtersAndKeys = new ArrayList<Filter>();
  596. if (filters != null) {
  597. filtersAndKeys.addAll(filters);
  598. }
  599. int ix = 0;
  600. for (String colName : primaryKeyColumns) {
  601. filtersAndKeys.add(new Equal(colName, keys[ix]));
  602. ix++;
  603. }
  604. StatementHelper sh = sqlGenerator.generateSelectQuery(tableName,
  605. filtersAndKeys, orderBys, 0, 0, "*");
  606. boolean shouldCloseTransaction = false;
  607. if (!transactionOpen) {
  608. shouldCloseTransaction = true;
  609. beginTransaction();
  610. }
  611. ResultSet rs = null;
  612. try {
  613. rs = executeQuery(sh);
  614. boolean contains = rs.next();
  615. return contains;
  616. } finally {
  617. if (rs != null) {
  618. if (rs.getStatement() != null) {
  619. rs.getStatement().close();
  620. }
  621. rs.close();
  622. }
  623. if (shouldCloseTransaction) {
  624. commit();
  625. }
  626. }
  627. }
  628. /**
  629. * Custom writeObject to call rollback() if object is serialized.
  630. */
  631. private void writeObject(java.io.ObjectOutputStream out) throws IOException {
  632. try {
  633. rollback();
  634. } catch (SQLException ignored) {
  635. }
  636. out.defaultWriteObject();
  637. }
  638. /**
  639. * Simple RowIdChangeEvent implementation.
  640. */
  641. public static class RowIdChangeEvent extends EventObject implements
  642. QueryDelegate.RowIdChangeEvent {
  643. private final RowId oldId;
  644. private final RowId newId;
  645. private RowIdChangeEvent(RowId oldId, RowId newId) {
  646. super(oldId);
  647. this.oldId = oldId;
  648. this.newId = newId;
  649. }
  650. @Override
  651. public RowId getNewRowId() {
  652. return newId;
  653. }
  654. @Override
  655. public RowId getOldRowId() {
  656. return oldId;
  657. }
  658. }
  659. /**
  660. * Adds RowIdChangeListener to this query
  661. */
  662. @Override
  663. public void addRowIdChangeListener(RowIdChangeListener listener) {
  664. if (rowIdChangeListeners == null) {
  665. rowIdChangeListeners = new LinkedList<QueryDelegate.RowIdChangeListener>();
  666. }
  667. rowIdChangeListeners.add(listener);
  668. }
  669. /**
  670. * @deprecated As of 7.0, replaced by
  671. * {@link #addRowIdChangeListener(com.vaadin.data.util.sqlcontainer.query.QueryDelegate.RowIdChangeListener)}
  672. **/
  673. @Override
  674. @Deprecated
  675. public void addListener(RowIdChangeListener listener) {
  676. addRowIdChangeListener(listener);
  677. }
  678. /**
  679. * Removes the given RowIdChangeListener from this query
  680. */
  681. @Override
  682. public void removeRowIdChangeListener(RowIdChangeListener listener) {
  683. if (rowIdChangeListeners != null) {
  684. rowIdChangeListeners.remove(listener);
  685. }
  686. }
  687. /**
  688. * @deprecated As of 7.0, replaced by
  689. * {@link #removeRowIdChangeListener(com.vaadin.data.util.sqlcontainer.query.QueryDelegate.RowIdChangeListener)}
  690. **/
  691. @Override
  692. @Deprecated
  693. public void removeListener(RowIdChangeListener listener) {
  694. removeRowIdChangeListener(listener);
  695. }
  696. private static final Logger getLogger() {
  697. return Logger.getLogger(TableQuery.class.getName());
  698. }
  699. }