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.postgresql.Driver;
23  import org.waarp.common.database.DbConstant;
24  import org.waarp.common.database.DbPreparedStatement;
25  import org.waarp.common.database.DbRequest;
26  import org.waarp.common.database.DbSession;
27  import org.waarp.common.database.data.DbDataModel;
28  import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
29  import org.waarp.common.database.exception.WaarpDatabaseNoDataException;
30  import org.waarp.common.database.exception.WaarpDatabaseSqlException;
31  import org.waarp.common.logging.SysErrLogger;
32  import org.waarp.common.logging.WaarpLogger;
33  import org.waarp.common.logging.WaarpLoggerFactory;
34  
35  import java.sql.DriverManager;
36  import java.sql.SQLException;
37  import java.sql.Types;
38  
39  /**
40   * PostGreSQL Database Model implementation
41   */
42  public abstract class DbModelPostgresql extends DbModelAbstract {
43    /**
44     * Internal Logger
45     */
46    private static final WaarpLogger logger =
47        WaarpLoggerFactory.getLogger(DbModelPostgresql.class);
48  
49    private static final DbType type = DbType.PostGreSQL;
50  
51    protected static class DbTypeResolverPostgreSQL
52        extends DbModelAbstract.DbTypeResolver {
53  
54      @Override
55      public final String getType(final int sqlType) {
56        return DBType.getType(sqlType);
57      }
58  
59      @Override
60      public final DbType getDbType() {
61        return type;
62      }
63    }
64  
65    static {
66      dbTypeResolver = new DbTypeResolverPostgreSQL();
67    }
68  
69    protected Boolean useIsValid;
70  
71    @Override
72    public final DbType getDbType() {
73      return type;
74    }
75  
76    /**
77     * Create the object and initialize if necessary the driver
78     *
79     * @throws WaarpDatabaseNoConnectionException
80     */
81    protected DbModelPostgresql() throws WaarpDatabaseNoConnectionException {
82      if (DbModelFactory.classLoaded.contains(type.name())) {
83        return;
84      }
85      try {
86        DriverManager.registerDriver(new Driver());
87        DbModelFactory.classLoaded.add(type.name());
88      } catch (final SQLException e) {
89        // SQLException
90        logger.error(
91            "Cannot register Driver " + type.name() + ' ' + e.getMessage());
92        DbConstant.error(e);
93        throw new WaarpDatabaseNoConnectionException(
94            "Cannot load database drive:" + type.name(), e);
95      }
96      // No pooling connection yet available through URL and not for production purpose
97      /*
98       * Quoting the PostgreSQL documentation: from http://jdbc.postgresql.org/documentation/head/ds-ds.html In
99       * general it is not recommended to use the PostgreSQLâ„¢ provided connection pool.
100      *
101      */
102     /*
103      * PGPoolingDataSource source = new PGPoolingDataSource(); source.setDataSourceName("A Data Source");
104      * source.setServerName("localhost"); source.setDatabaseName("test"); source.setUser("testuser");
105      * source.setPassword("testpassword"); source.setMaxConnections(10);
106      */
107   }
108 
109   protected enum DBType {
110     CHAR(Types.CHAR, " CHAR(3) "),
111     VARCHAR(Types.VARCHAR, " VARCHAR(" + MAX_VARCHAR + ") "),
112     NVARCHAR(Types.NVARCHAR, " VARCHAR(" + MAX_KEY_VARCHAR + ") "),
113     LONGVARCHAR(Types.LONGVARCHAR, " VARCHAR(" + MAX_LONGVARCHAR + ") "),
114     BIT(Types.BIT, " BOOLEAN "), TINYINT(Types.TINYINT, " INT2 "),
115     SMALLINT(Types.SMALLINT, " SMALLINT "), INTEGER(Types.INTEGER, " INTEGER "),
116     BIGINT(Types.BIGINT, " BIGINT "), REAL(Types.REAL, " REAL "),
117     DOUBLE(Types.DOUBLE, " DOUBLE PRECISION "),
118     VARBINARY(Types.VARBINARY, " BYTEA "), DATE(Types.DATE, " DATE "),
119     TIMESTAMP(Types.TIMESTAMP, " TIMESTAMP(3) ");
120 
121     public final int type;
122 
123     public final String constructor;
124 
125     DBType(final int type, final String constructor) {
126       this.type = type;
127       this.constructor = constructor;
128     }
129 
130     public static String getType(final int sqltype) {
131       switch (sqltype) {
132         case Types.CHAR:
133           return CHAR.constructor;
134         case Types.VARCHAR:
135           return VARCHAR.constructor;
136         case Types.NVARCHAR:
137           return NVARCHAR.constructor;
138         case Types.LONGVARCHAR:
139           return LONGVARCHAR.constructor;
140         case Types.BIT:
141           return BIT.constructor;
142         case Types.TINYINT:
143           return TINYINT.constructor;
144         case Types.SMALLINT:
145           return SMALLINT.constructor;
146         case Types.INTEGER:
147           return INTEGER.constructor;
148         case Types.BIGINT:
149           return BIGINT.constructor;
150         case Types.REAL:
151           return REAL.constructor;
152         case Types.DOUBLE:
153           return DOUBLE.constructor;
154         case Types.VARBINARY:
155           return VARBINARY.constructor;
156         case Types.DATE:
157           return DATE.constructor;
158         case Types.TIMESTAMP:
159           return TIMESTAMP.constructor;
160         default:
161           return null;
162       }
163     }
164   }
165 
166   @Override
167   public void resetSequence(final DbSession session, final long newvalue)
168       throws WaarpDatabaseNoConnectionException {
169     final String action =
170         "ALTER SEQUENCE " + DbDataModel.fieldseq + " MINVALUE " +
171         (DbConstant.ILLEGALVALUE + 1) + " RESTART WITH " + newvalue;
172     final DbRequest request = new DbRequest(session);
173     try {
174       request.query(action);
175     } catch (final WaarpDatabaseNoConnectionException e) {
176       SysErrLogger.FAKE_LOGGER.ignoreLog(e);
177     } catch (final WaarpDatabaseSqlException e) {
178       SysErrLogger.FAKE_LOGGER.ignoreLog(e);
179     } finally {
180       request.close();
181     }
182     logger.warn(action);
183   }
184 
185   @Override
186   public long nextSequence(final DbSession dbSession)
187       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException,
188              WaarpDatabaseNoDataException {
189     long result;
190     final String action = "SELECT NEXTVAL('" + DbDataModel.fieldseq + "')";
191     final DbPreparedStatement preparedStatement =
192         new DbPreparedStatement(dbSession);
193     try {
194       preparedStatement.createPrepareStatement(action);
195       // Limit the search
196       preparedStatement.executeQuery();
197       if (preparedStatement.getNext()) {
198         try {
199           result = preparedStatement.getResultSet().getLong(1);
200         } catch (final SQLException e) {
201           throw new WaarpDatabaseSqlException(e);
202         }
203         return result;
204       } else {
205         throw new WaarpDatabaseNoDataException(
206             "No sequence found. Must be initialized first");
207       }
208     } finally {
209       preparedStatement.realClose();
210     }
211   }
212 
213   @Override
214   protected final String validConnectionString() {
215     return "select 1";
216   }
217 
218   @Override
219   public final String limitRequest(final String allfields, final String request,
220                                    final int nb) {
221     if (nb == 0) {
222       return request;
223     }
224     return request + " LIMIT " + nb;
225   }
226 
227 }