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.model;
21  
22  import org.waarp.common.database.DbPreparedStatement;
23  import org.waarp.common.database.DbRequest;
24  import org.waarp.common.database.DbSession;
25  import org.waarp.common.database.data.DbDataModel;
26  import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
27  import org.waarp.common.database.exception.WaarpDatabaseNoDataException;
28  import org.waarp.common.database.exception.WaarpDatabaseSqlException;
29  import org.waarp.common.logging.SysErrLogger;
30  import org.waarp.common.logging.WaarpLogger;
31  import org.waarp.common.logging.WaarpLoggerFactory;
32  
33  import java.sql.SQLException;
34  import java.sql.Types;
35  import java.util.concurrent.locks.ReentrantLock;
36  
37  /**
38   * MariaDB/MySQL common Database Model implementation
39   */
40  public abstract class DbModelCommonMariadbMySql extends DbModelAbstract {
41    /**
42     * Internal Logger
43     */
44    private static final WaarpLogger logger =
45        WaarpLoggerFactory.getLogger(DbModelCommonMariadbMySql.class);
46  
47    protected enum DBType {
48      CHAR(Types.CHAR, " CHAR(3) "),
49      VARCHAR(Types.VARCHAR, " VARCHAR(" + MAX_VARCHAR + ") "),
50      /**
51       * Used in replacement of VARCHAR for MYSQL/MARIADB (limitation of size
52       * if
53       * in Primary Key)
54       */
55      NVARCHAR(Types.VARCHAR, " VARCHAR(" + MAX_KEY_VARCHAR + ") "),
56      LONGVARCHAR(Types.LONGVARCHAR, " TEXT "), BIT(Types.BIT, " " + "BOOLEAN "),
57      TINYINT(Types.TINYINT, " TINYINT "), SMALLINT(Types.SMALLINT, " SMALLINT "),
58      INTEGER(Types.INTEGER, " INTEGER "), BIGINT(Types.BIGINT, " BIGINT "),
59      REAL(Types.REAL, " FLOAT "), DOUBLE(Types.DOUBLE, " DOUBLE "),
60      VARBINARY(Types.VARBINARY, " VARBINARY(" + (MAX_BINARY * 2) + ") "),
61      DATE(Types.DATE, " " + "DATE "),
62      TIMESTAMP(Types.TIMESTAMP, " TIMESTAMP(3) ");
63  
64      public final int type;
65  
66      public final String constructor;
67  
68      DBType(final int type, final String constructor) {
69        this.type = type;
70        this.constructor = constructor;
71      }
72  
73      public static String getType(final int sqltype) {
74        switch (sqltype) {
75          case Types.CHAR:
76            return CHAR.constructor;
77          case Types.VARCHAR:
78            return VARCHAR.constructor;
79          case Types.NVARCHAR:
80            return NVARCHAR.constructor;
81          case Types.LONGVARCHAR:
82            return LONGVARCHAR.constructor;
83          case Types.BIT:
84            return BIT.constructor;
85          case Types.TINYINT:
86            return TINYINT.constructor;
87          case Types.SMALLINT:
88            return SMALLINT.constructor;
89          case Types.INTEGER:
90            return INTEGER.constructor;
91          case Types.BIGINT:
92            return BIGINT.constructor;
93          case Types.REAL:
94            return REAL.constructor;
95          case Types.DOUBLE:
96            return DOUBLE.constructor;
97          case Types.VARBINARY:
98            return VARBINARY.constructor;
99          case Types.DATE:
100           return DATE.constructor;
101         case Types.TIMESTAMP:
102           return TIMESTAMP.constructor;
103         default:
104           return null;
105       }
106     }
107   }
108 
109   private final ReentrantLock lock = new ReentrantLock();
110 
111   @Override
112   public void resetSequence(final DbSession session, final long newvalue)
113       throws WaarpDatabaseNoConnectionException {
114     final String action =
115         "UPDATE Sequences SET seq = " + newvalue + " WHERE name = '" +
116         DbDataModel.fieldseq + '\'';
117     final DbRequest request = new DbRequest(session);
118     try {
119       request.query(action);
120     } catch (final WaarpDatabaseNoConnectionException e) {
121       logger.warn("ResetSequence Error", e);
122     } catch (final WaarpDatabaseSqlException e) {
123       logger.warn("ResetSequence Error", e);
124     } finally {
125       request.close();
126     }
127     logger.warn(action);
128   }
129 
130   @Override
131   public long nextSequence(final DbSession dbSession)
132       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException,
133              WaarpDatabaseNoDataException {
134     lock.lock();
135     try {
136       long result;
137       String action =
138           "SELECT seq FROM Sequences WHERE name = '" + DbDataModel.fieldseq +
139           "' FOR UPDATE";
140       final DbPreparedStatement preparedStatement =
141           new DbPreparedStatement(dbSession);
142       try {
143         dbSession.getConn().setAutoCommit(false);
144       } catch (final SQLException ignored) {
145         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
146       }
147       try {
148         preparedStatement.createPrepareStatement(action);
149         // Limit the search
150         preparedStatement.executeQuery();
151         if (preparedStatement.getNext()) {
152           try {
153             result = preparedStatement.getResultSet().getLong(1);
154           } catch (final SQLException e) {
155             throw new WaarpDatabaseSqlException(e);
156           }
157         } else {
158           throw new WaarpDatabaseNoDataException(
159               "No sequence found. Must be initialized first");
160         }
161       } finally {
162         preparedStatement.realClose();
163       }
164       action =
165           "UPDATE Sequences SET seq = " + (result + 1) + " WHERE name = '" +
166           DbDataModel.fieldseq + '\'';
167       try {
168         preparedStatement.createPrepareStatement(action);
169         // Limit the search
170         preparedStatement.executeUpdate();
171       } finally {
172         preparedStatement.realClose();
173       }
174       return result;
175     } finally {
176       try {
177         dbSession.getConn().setAutoCommit(true);
178       } catch (final SQLException ignored) {
179         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
180       } finally {
181         lock.unlock();
182       }
183     }
184   }
185 
186   @Override
187   protected final String validConnectionString() {
188     return "select 1 from dual";
189   }
190 
191   @Override
192   public final String limitRequest(final String allfields, final String request,
193                                    final int nb) {
194     if (nb == 0) {
195       return request;
196     }
197     return request + " LIMIT " + nb;
198   }
199 
200 }