View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.common.database;
21  
22  import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
23  import org.waarp.common.database.exception.WaarpDatabaseNoDataException;
24  import org.waarp.common.database.exception.WaarpDatabaseSqlException;
25  import org.waarp.common.logging.WaarpLogger;
26  import org.waarp.common.logging.WaarpLoggerFactory;
27  
28  import java.sql.ResultSet;
29  import java.sql.SQLException;
30  import java.sql.Statement;
31  
32  /**
33   * Class to handle request
34   */
35  public class DbRequest {
36    /**
37     * Internal Logger
38     */
39    private static final WaarpLogger logger =
40        WaarpLoggerFactory.getLogger(DbRequest.class);
41    private static final String SQL_EXCEPTION_REQUEST = "SQL Exception Request:";
42    private static final String SQL_EXCEPTION_REQUEST1 = "SQL Exception Request:";
43  
44    /**
45     * Internal Statement
46     */
47    private Statement stmt;
48  
49    /**
50     * Internal Result Set
51     */
52    private ResultSet rs;
53  
54    /**
55     * Internal DB Session
56     */
57    private final DbSession ls;
58  
59    /**
60     * Create a new request from the DbSession
61     *
62     * @param ls
63     *
64     * @throws WaarpDatabaseNoConnectionException
65     */
66    public DbRequest(final DbSession ls)
67        throws WaarpDatabaseNoConnectionException {
68      if (ls.isDisActive()) {
69        ls.checkConnection();
70      }
71      this.ls = ls;
72    }
73  
74    /**
75     * Create a statement with some particular options
76     *
77     * @return the new Statement
78     *
79     * @throws WaarpDatabaseNoConnectionException
80     * @throws WaarpDatabaseSqlException
81     */
82    private Statement createStatement()
83        throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
84      if (ls == null) {
85        throw new WaarpDatabaseNoConnectionException("No connection");
86      }
87      if (ls.getConn() == null) {
88        throw new WaarpDatabaseNoConnectionException("No connection");
89      }
90      if (ls.isDisActive()) {
91        ls.checkConnection();
92      }
93      try {
94        return ls.getConn().createStatement();
95      } catch (final SQLException e) {
96        ls.checkConnection();
97        try {
98          return ls.getConn().createStatement();
99        } catch (final SQLException e1) {
100         throw new WaarpDatabaseSqlException("Error while Create Statement", e);
101       }
102     }
103   }
104 
105   /**
106    * Execute a SELECT statement and set of Result. The statement must not be
107    * an
108    * update/insert/delete. The
109    * previous statement and resultSet are closed.
110    *
111    * @param select
112    *
113    * @throws WaarpDatabaseSqlException
114    * @throws WaarpDatabaseNoConnectionException
115    */
116   public final void select(final String select)
117       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
118     close();
119     stmt = createStatement();
120     // or alternatively, if you don't know ahead of time that
121     // the query will be a SELECT...
122     try {
123       if (stmt.execute(select)) {
124         rs = stmt.getResultSet();
125       }
126     } catch (final SQLException e) {
127       logger.error(SQL_EXCEPTION_REQUEST + select + ' ' + e.getMessage());
128       DbConstant.error(e);
129       ls.checkConnectionNoException();
130       throw new WaarpDatabaseSqlException(SQL_EXCEPTION_REQUEST1 + select, e);
131     }
132   }
133 
134   /**
135    * Execute a SELECT statement and set of Result. The statement must not be
136    * an
137    * update/insert/delete. The
138    * previous statement and resultSet are closed. The timeout is applied if >
139    * 0.
140    *
141    * @param select
142    * @param timeout in seconds
143    *
144    * @throws WaarpDatabaseSqlException
145    * @throws WaarpDatabaseNoConnectionException
146    */
147   public final void select(final String select, final int timeout)
148       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
149     close();
150     stmt = createStatement();
151     if (timeout > 0) {
152       try {
153         stmt.setQueryTimeout(timeout);
154       } catch (final SQLException e1) {
155         // ignore
156       }
157     }
158     // or alternatively, if you don't know ahead of time that
159     // the query will be a SELECT...
160     try {
161       if (stmt.execute(select)) {
162         rs = stmt.getResultSet();
163       }
164     } catch (final SQLException e) {
165       logger.error(SQL_EXCEPTION_REQUEST1 + select + ' ' + e.getMessage());
166       DbConstant.error(e);
167       ls.checkConnectionNoException();
168       throw new WaarpDatabaseSqlException(SQL_EXCEPTION_REQUEST1 + select, e);
169     }
170   }
171 
172   /**
173    * Execute a UPDATE/INSERT/DELETE statement and returns the number of row.
174    * The
175    * previous statement and
176    * resultSet are closed.
177    *
178    * @param query
179    *
180    * @return the number of row in the query
181    *
182    * @throws WaarpDatabaseSqlException
183    * @throws WaarpDatabaseNoConnectionException
184    */
185   public final int query(final String query)
186       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
187     close();
188     stmt = createStatement();
189     try {
190       final int rowcount = stmt.executeUpdate(query);
191       logger.debug("QUERY({}): {}", rowcount, query);
192       return rowcount;
193     } catch (final SQLException e) {
194       logger.error(SQL_EXCEPTION_REQUEST1 + query + ' ' + e.getMessage());
195       DbConstant.error(e);
196       ls.checkConnectionNoException();
197       throw new WaarpDatabaseSqlException(SQL_EXCEPTION_REQUEST1 + query, e);
198     }
199   }
200 
201   /**
202    * Finished a Request (ready for a new one)
203    */
204   public final void close() {
205     // it is a good idea to release
206     // resources in a finally{} block
207     // in reverse-order of their creation
208     // if they are no-longer needed
209     if (rs != null) {
210       try {
211         rs.close();
212       } catch (final SQLException sqlEx) {
213         ls.checkConnectionNoException();
214       } // ignore
215       rs = null;
216     }
217     if (stmt != null) {
218       try {
219         stmt.close();
220       } catch (final SQLException sqlEx) {
221         ls.checkConnectionNoException();
222       } // ignore
223       stmt = null;
224     }
225   }
226 
227   /**
228    * Get the last ID autoincrement from the last request
229    *
230    * @return the long Id or DbConstant.ILLEGALVALUE (Long.MIN_VALUE) if an
231    *     error
232    *     occurs.
233    *
234    * @throws WaarpDatabaseNoDataException
235    */
236   public final long getLastId() throws WaarpDatabaseNoDataException {
237     ResultSet rstmp = null;
238     long result = DbConstant.ILLEGALVALUE;
239     try {
240       rstmp = stmt.getGeneratedKeys();
241       if (rstmp.next()) {
242         result = rstmp.getLong(1);
243       }
244     } catch (final SQLException e) {
245       DbConstant.error(e);
246       ls.checkConnectionNoException();
247       throw new WaarpDatabaseNoDataException("No data found", e);
248     } finally {
249       if (rstmp != null) {
250         try {
251           rstmp.close();
252         } catch (final SQLException e) {
253           // nothing
254         }
255       }
256     }
257     return result;
258   }
259 
260   /**
261    * Move the cursor to the next result
262    *
263    * @return True if there is a next result, else False
264    *
265    * @throws WaarpDatabaseNoConnectionException
266    * @throws WaarpDatabaseSqlException
267    */
268   public final boolean getNext()
269       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException {
270     if (rs == null) {
271       logger.error("SQL ResultSet is Null into getNext");
272       throw new WaarpDatabaseNoConnectionException(
273           "SQL ResultSet is Null into getNext");
274     }
275     if (ls.isDisActive()) {
276       ls.checkConnection();
277       throw new WaarpDatabaseSqlException(
278           "Request cannot be executed since connection was recreated between");
279     }
280     try {
281       return rs.next();
282     } catch (final SQLException e) {
283       logger.warn("SQL Exception to getNextRow" + ' ' + e.getMessage());
284       DbConstant.error(e);
285       ls.checkConnectionNoException();
286       throw new WaarpDatabaseSqlException("SQL Exception to getNextRow", e);
287     }
288   }
289 
290   /**
291    * @return The resultSet (can be used in conjunction of getNext())
292    *
293    * @throws WaarpDatabaseNoConnectionException
294    */
295   public final ResultSet getResultSet()
296       throws WaarpDatabaseNoConnectionException {
297     if (rs == null) {
298       throw new WaarpDatabaseNoConnectionException(
299           "SQL ResultSet is Null into getResultSet");
300     }
301     return rs;
302   }
303 
304   /**
305    * Test if value is null and create the string for insert/update
306    *
307    * @param value
308    *
309    * @return the string as result
310    */
311   public static String getIsNull(final String value) {
312     return value == null? " is NULL" : " = '" + value + '\'';
313   }
314 }