/** * Copyright (c) 2011-2014, OpenIoT * * This file is part of OpenIoT. * * OpenIoT is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, version 3 of the License. * * OpenIoT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with OpenIoT. If not, see <http://www.gnu.org/licenses/>. * * Contact: OpenIoT mailto: info@openiot.eu * @author Sofiane Sarni */ package org.openiot.gsn.storage.db; import org.openiot.gsn.beans.DataField; import org.openiot.gsn.beans.DataTypes; import org.openiot.gsn.storage.StorageManager; import org.apache.log4j.Logger; import java.sql.Connection; import java.sql.SQLException; import java.sql.Types; public class PostgresStorageManager extends StorageManager { private static final transient Logger logger = Logger.getLogger(PostgresStorageManager.class); public PostgresStorageManager() { super(); this.isPostgres = true; } @Override public byte convertLocalTypeToGSN(int jdbcType, int precision) { switch (jdbcType) { case Types.BIGINT: return DataTypes.BIGINT; case Types.INTEGER: return DataTypes.INTEGER; case Types.SMALLINT: return DataTypes.SMALLINT; case Types.TINYINT: return DataTypes.TINYINT; case Types.VARCHAR: return DataTypes.VARCHAR; case Types.CHAR: return DataTypes.CHAR; case Types.DOUBLE: case Types.DECIMAL: // This is needed for doing aggregates in datadownload servlet. return DataTypes.DOUBLE; case Types.BINARY: case Types.BLOB: case Types.VARBINARY: case Types.LONGVARBINARY: return DataTypes.BINARY; default: logger.error("The type can't be converted to GSN form : " + jdbcType); break; } return -100; } @Override public String getStatementDropIndex() { return "DROP TABLE IF EXISTS #NAME"; } @Override public String getStatementDropView() { return "DROP VIEW IF EXISTS #NAME"; } @Override public int getTableNotExistsErrNo() { return 0; //TODO: check error code in Postgres reference } @Override public String addLimit(String query, int limit, int offset) { return query + " LIMIT " + limit + " OFFSET " + offset; } @Override public StringBuilder getStatementUselessDataRemoval(String virtualSensorName, long storageSize) { return new StringBuilder() .append("delete from ") .append(virtualSensorName) .append(" where ") .append(virtualSensorName) .append(".timed <= ( SELECT * FROM ( SELECT timed FROM ") .append(virtualSensorName) .append(" group by ") .append(virtualSensorName) .append(".timed ORDER BY ") .append(virtualSensorName) .append(".timed DESC LIMIT 1 offset ") .append(storageSize) .append(" ) AS TMP)"); //TODO: verify } @Override public StringBuilder getStatementRemoveUselessDataCountBased(String virtualSensorName, long storageSize) { return new StringBuilder() .append("delete from ") .append(virtualSensorName) .append(" where ") .append(virtualSensorName) .append(".timed <= ( SELECT * FROM ( SELECT timed FROM ") .append(virtualSensorName) .append(" group by ") .append(virtualSensorName) .append(".timed ORDER BY ") .append(virtualSensorName) .append(".timed DESC LIMIT 1 offset ") .append(storageSize).append(" ) AS TMP)"); //TODO: verify } @Override public StringBuilder getStatementDropTable(CharSequence tableName, Connection conn) throws SQLException { StringBuilder sb = new StringBuilder("Drop table if exists "); sb.append(tableName); return sb; } @Override public StringBuilder getStatementCreateTable(String tableName, DataField[] structure) { StringBuilder result = new StringBuilder("CREATE TABLE ").append(tableName); result.append(" (PK serial PRIMARY KEY NOT NULL , timed BIGINT NOT NULL, "); //TODO: add auto increment AUTO_INCREMENT for (DataField field : structure) { if (field.getName().equalsIgnoreCase("pk") || field.getName().equalsIgnoreCase("timed")) continue; result.append(field.getName().toUpperCase()).append(' '); result.append(convertGSNTypeToLocalType(field)); result.append(" ,"); } result.delete(result.length() - 2, result.length()); result.append(")"); return result; } @Override public String getJDBCPrefix() { return "jdbc:postgresql:"; } @Override public String convertGSNTypeToLocalType(DataField gsnType) { String convertedType; switch (gsnType.getDataTypeID()) { case DataTypes.CHAR: case DataTypes.VARCHAR: // Because the parameter for the varchar is not // optional. if (gsnType.getType().trim().equalsIgnoreCase("string")) convertedType = "TEXT"; else convertedType = gsnType.getType(); break; case DataTypes.BINARY: convertedType = "BYTEA"; break; case DataTypes.DOUBLE: convertedType = "DOUBLE PRECISION"; break; default: convertedType = DataTypes.TYPE_NAMES[gsnType.getDataTypeID()]; break; } return convertedType; } @Override public String getStatementDifferenceTimeInMillis() { return "SELECT extract(epoch FROM now())*1000"; } }