diff --git a/src/main/java/org/tango/jhdb/PostgreSQLSchema.java b/src/main/java/org/tango/jhdb/PostgreSQLSchema.java index 8516713..3384dbd 100644 --- a/src/main/java/org/tango/jhdb/PostgreSQLSchema.java +++ b/src/main/java/org/tango/jhdb/PostgreSQLSchema.java @@ -38,8 +38,10 @@ import java.sql.*; import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; import java.util.Properties; import java.util.List; +import java.util.SortedSet; /** * PostgreSQL database access @@ -274,28 +276,163 @@ public HdbSigInfo getSigInfo(String attName) throws HdbFailed { } + /** + * Build the aggragate list for the query, and store the column indexes for later processing.. + */ + private String getAggregateQueryList(SignalInfo sigInfo, Map indexes) { + int idx = 0; + int nbAggregates = sigInfo.aggregates.size(); + StringBuffer queryList = new StringBuffer(); + + if(indexes == null) + { + indexes = new HashMap<>(); + } + + for(HdbData.Aggregate agg : sigInfo.aggregates) + { + queryList.append(agg.toString()); + + if(idx != nbAggregates - 1) + { + queryList.append(", "); + } + + indexes.put(agg, idx); + ++idx; + } + + return queryList.toString(); + } + + + private String buildQuery(SignalInfo sigInfo, String tablename, SortedSet ranges, Map> agg_idxes, boolean isAggregate, boolean isRW, boolean isWO) + { + String query; + if(isAggregate) + { + int idx = 0; + if( agg_idxes == null) + { + agg_idxes = new HashMap<>(); + } + + StringBuilder queryBuilder = new StringBuilder(); + queryBuilder.append("SELECT data_time"); + + // special cases for count_rows and count_errors, as they are never arrrays. + if(sigInfo.aggregates.contains(HdbData.Aggregate.ROWS_COUNT)) + { + queryBuilder.append(", "); + queryBuilder.append(HdbData.Aggregate.ROWS_COUNT.toString()); + Map ret = new HashMap<>(); + ret.put(idx++, false); + agg_idxes.put(HdbData.Aggregate.ROWS_COUNT, ret); + } + if(sigInfo.aggregates.contains(HdbData.Aggregate.ERRORS_COUNT)) + { + queryBuilder.append(", "); + queryBuilder.append(HdbData.Aggregate.ERRORS_COUNT.toString()); + Map ret = new HashMap<>(); + ret.put(idx++, false); + agg_idxes.put(HdbData.Aggregate.ERRORS_COUNT, ret); + } + + for(SignalInfo.Range r : ranges) + { + for(HdbData.Aggregate agg : sigInfo.aggregates) + { + // Do not treat rows and error count + if(agg == HdbData.Aggregate.ROWS_COUNT || agg == HdbData.Aggregate.ERRORS_COUNT) + continue; + + queryBuilder.append(", "); + queryBuilder.append(agg.toString()); + queryBuilder.append(r.toString()); + if(!agg_idxes.containsKey(agg)) + { + agg_idxes.put(agg, new HashMap<>()); + } + boolean isArray = (sigInfo.isArray() && r == SignalInfo.Range.FULL_RANGE) || r.size() > 1; + agg_idxes.get(agg).put(idx++, isArray); + } + } + + queryBuilder.append(" FROM " + tablename + + " WHERE att_conf_id= ?" + + " AND data_time>= ?" + + " AND data_time<= ?" + + " ORDER BY data_time ASC"); + + query = queryBuilder.toString(); + } + else + { + if(ranges.isEmpty()) + { + String rwField = (isRW | isWO) ? ",value_w" : ""; + query = "SELECT data_time,att_error_desc.error_desc as error_desc,quality,value_r" + rwField + + " FROM " + tablename + + " left outer join att_error_desc on " + tablename + ".att_error_desc_id = att_error_desc.att_error_desc_id" + + " WHERE att_conf_id= ?" + + " AND data_time>= ?" + + " AND data_time<= ?" + + " ORDER BY data_time ASC"; + } + else + { + StringBuilder queryBuilder = new StringBuilder(); + queryBuilder.append("SELECT data_time, att_error_desc.error_desc as error_desc, quality"); + for(SignalInfo.Range i : ranges) + { + queryBuilder.append(", value_r"); + queryBuilder.append(i); + if(isRW | isWO) + { + queryBuilder.append(", value_w"); + queryBuilder.append(i); + } + } + queryBuilder.append(" FROM "); + queryBuilder.append(tablename); + queryBuilder.append(" left outer join att_error_desc on "); + queryBuilder.append(tablename); + queryBuilder.append(".att_error_desc_id = att_error_desc.att_error_desc_id"); + queryBuilder.append(" WHERE att_conf_id=? AND data_time>= ? AND data_time<= ? ORDER BY data_time ASC"); + + query = queryBuilder.toString(); + } + } + + return query; + } + HdbDataSet getDataFromDB(SignalInfo sigInfo, - String start_date, - String stop_date) throws HdbFailed { + String start_date, + String stop_date) throws HdbFailed { - if (sigInfo == null) - throw new HdbFailed("sigInfo input parameters is null"); + if (sigInfo == null) + throw new HdbFailed("sigInfo input parameters is null"); - checkDates(start_date, stop_date); + checkDates(start_date, stop_date); - boolean isRW = sigInfo.isRW(); - boolean isWO = sigInfo.access == SignalInfo.Access.WO; - boolean isAggregate = sigInfo.isAggregate(); + boolean isRW = sigInfo.isRW(); + boolean isWO = sigInfo.access == SignalInfo.Access.WO; + boolean isAggregate = sigInfo.isAggregate(); + SortedSet ranges = sigInfo.getRanges(); + + // Cache the prepared statement only for not aggregates quries that target a full range. + boolean isCacheable = !isAggregate && ranges.contains(SignalInfo.Range.FULL_RANGE); - String query; - int queryCount = 0; + String query; + int queryCount = 0; - connectionCheck(); + connectionCheck(); - String tablename; - if(isAggregate) - { - tablename = "cagg_" + sigInfo.tableName.substring(4) + "_" + sigInfo.interval.toString(); + String tablename; + if(isAggregate) + { + tablename = "cagg_" + sigInfo.tableName.substring(4) + "_" + sigInfo.interval.toString(); } else { @@ -327,125 +464,102 @@ HdbDataSet getDataFromDB(SignalInfo sigInfo, // Fetch data PreparedStatement statement; - if(!prepQueries.containsKey(sigInfo)) { - if(isAggregate) { - switch (sigInfo.dataType) { - case DOUBLE: - case FLOAT: - query = "SELECT data_time, count_rows, count_errors, count_r, count_nan_r, mean_r, min_r, max_r, stddev_r" + - ", count_w, count_nan_w, mean_w, min_w, max_w, stddev_w" + - " FROM " + tablename + - " WHERE att_conf_id= ?" + - " AND data_time>= ?" + - " AND data_time<= ?" + - " ORDER BY data_time ASC"; - break; - case LONG: - case ULONG: - case LONG64: - case ULONG64: - case SHORT: - case USHORT: - query = "SELECT data_time, count_rows, count_errors, count_r, mean_r, min_r, max_r, stddev_r" + - ", count_w, mean_w, min_w, max_w, stddev_w" + - " FROM " + tablename + - " WHERE att_conf_id= ?" + - " AND data_time>= ?" + - " AND data_time<= ?" + - " ORDER BY data_time ASC"; - break; - default: - throw new HdbFailed("Aggregates are not supported for type: " + sigInfo.dataType); + + Map> agg_idxes = new HashMap<>(); + if(isCacheable) + { + if(!prepQueries.containsKey(sigInfo)) { + + query = buildQuery(sigInfo, tablename, ranges, agg_idxes, isAggregate, isRW, isWO); + + try { + prepQueries.put(sigInfo, connection.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)); + } catch (SQLException e) { + throw new HdbFailed("An error occurred upon query preparation for query: " + query); + } } - } - else - { - String rwField = (isRW | isWO) ? ",value_w" : ""; - query = "SELECT data_time,att_error_desc.error_desc as error_desc,quality,value_r" + rwField + - " FROM " + tablename + - " left outer join att_error_desc on " + sigInfo.tableName + ".att_error_desc_id = att_error_desc.att_error_desc_id" + - " WHERE att_conf_id= ?" + - " AND data_time>= ?" + - " AND data_time<= ?" + - " ORDER BY data_time ASC"; - } - try { - prepQueries.put(sigInfo, connection.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)); - } catch (SQLException e) { - throw new HdbFailed("An error occurred upon query preparation for query: " + query); - } + //retrieve prepared statement + statement = prepQueries.get(sigInfo); + + } + else + { + query = buildQuery(sigInfo, tablename, ranges, agg_idxes, isAggregate, isRW, isWO); + try + { + statement = connection.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + } catch (SQLException e) { + throw new HdbFailed("An error occurred upon query preparation for query: " + query); + } } ArrayList ret = new ArrayList<>(); - - //retrieve prepared statement - statement = prepQueries.get(sigInfo); try { - - //fill the placeholders - statement.setInt(1, Integer.parseInt(sigInfo.sigId)); - statement.setTimestamp(2, Timestamp.valueOf(toDBDate(start_date))); - statement.setTimestamp(3, Timestamp.valueOf(toDBDate(stop_date))); - - if(sigInfo.isArray()) - statement.setFetchSize(arrayFetchSize); - else - statement.setFetchSize(fetchSize); + + //fill the placeholders + statement.setInt(1, Integer.parseInt(sigInfo.sigId)); + statement.setTimestamp(2, Timestamp.valueOf(toDBDate(start_date))); + statement.setTimestamp(3, Timestamp.valueOf(toDBDate(stop_date))); + + if(sigInfo.isArray()) + statement.setFetchSize(arrayFetchSize); + else + statement.setFetchSize(fetchSize); //execute query ResultSet rs = statement.executeQuery(); if(isAggregate) { - extractAggregateData(rs, sigInfo, isRW, isWO, queryCount, ret); + extractAggregateData(rs, sigInfo, ranges, isRW, isWO, queryCount, agg_idxes, ret); + // For aggregates we do not cache the statement, so we have to close it. + statement.close(); } else { - extractRawData(rs, sigInfo, isRW, isWO, queryCount, ret); + extractRawData(rs, sigInfo, ranges, isRW, isWO, queryCount, ret); + + if(!isCacheable) + statement.close(); } } catch (SQLException e) { - throw new HdbFailed("Failed to get data: " + e.getMessage()); + throw new HdbFailed("Failed to get data for query:\n" + statement.toString() + "\n" + e.getMessage()); } return new HdbDataSet(ret); } - private void extractRawData(ResultSet rs, SignalInfo sigInfo, boolean isRW, boolean isWO, int queryCount, List data) throws SQLException, HdbFailed + private void extractValue(SignalInfo sigInfo, ResultSet rs, int idx, List value, List wvalue, boolean isWO, boolean isW) throws SQLException { - long dTime = 0; - String errorMsg = null; - int quality = 0; - int nbRow = 0; - - ArrayList value = new ArrayList<>(); - ArrayList wvalue = new ArrayList<>(); - - boolean isW = isRW | isWO; - while (rs.next()) { + extractValue(sigInfo, rs, idx, value, wvalue, isWO, isW, false); + } - dTime = timeValue(rs.getTimestamp(1)); - errorMsg = rs.getString(2); - quality = rs.getInt(3); - value.clear(); - if(isW) - wvalue.clear(); - if(sigInfo.isArray()) - { - if(!isWO) - convertArray(value, rs.getArray(4)); - if(isW) convertArray(wvalue, rs.getArray(5)); - } - else - { + private int extractValue(SignalInfo sigInfo, ResultSet rs, int idx, List value, List wvalue, boolean isWO, boolean isW, boolean increment) throws SQLException + { + int ret_idx = idx; switch(sigInfo.dataType) { case BOOLEAN: if(!isWO) - value.add(rs.getBoolean(4)); - if(isW) wvalue.add(rs.getBoolean(5)); + { + value.add(rs.getBoolean(idx)); + ++ret_idx; + } + if(isW) + { + if(increment) + { + wvalue.add(rs.getBoolean(ret_idx)); + ++ret_idx; + } + else + { + wvalue.add(rs.getBoolean(idx + 1)); + } + } break; case SHORT: case UCHAR: @@ -455,23 +569,312 @@ private void extractRawData(ResultSet rs, SignalInfo sigInfo, boolean isRW, bool case LONG64: case ULONG: if(!isWO) - value.add(rs.getLong(4)); - if(isW) wvalue.add(rs.getLong(5)); + { + value.add(rs.getLong(idx)); + ++ret_idx; + } + if(isW) + { + if(increment) + { + wvalue.add(rs.getLong(ret_idx)); + ++ret_idx; + } + else + { + wvalue.add(rs.getLong(idx + 1)); + } + } break; case DOUBLE: if(!isWO) - value.add(rs.getDouble(4)); - if(isW) wvalue.add(rs.getDouble(5)); + { + value.add(rs.getDouble(idx)); + ++ret_idx; + } + if(isW) + { + if(increment) + { + wvalue.add(rs.getDouble(ret_idx)); + ++ret_idx; + } + else + { + wvalue.add(rs.getDouble(idx + 1)); + } + } break; case FLOAT: - if(!isWO) value.add(rs.getFloat(4)); - if(isW) wvalue.add(rs.getFloat(5)); + if(!isWO) + { + value.add(rs.getFloat(idx)); + ++ret_idx; + } + if(isW) + { + if(increment) + { + wvalue.add(rs.getFloat(ret_idx)); + ++ret_idx; + } + else + { + wvalue.add(rs.getFloat(idx + 1)); + } + } break; case STRING: - if(!isWO) value.add(rs.getString(4)); - if(isW) wvalue.add(rs.getString(5)); + if(!isWO) + { + value.add(rs.getString(idx)); + ++ret_idx; + } + if(isW) + { + if(increment) + { + wvalue.add(rs.getString(ret_idx)); + ++ret_idx; + } + else + { + wvalue.add(rs.getString(idx + 1)); + } + } break; } + return ret_idx; + } + + private void extractAggregates(Map> indexes, ResultSet rs, SignalInfo.Type dataType, List count_rows, List count_errors, List count_r, List count_nan_r, List mean_r, List min_r, List max_r, List stddev_r, List count_w, List count_nan_w, List mean_w, List min_w, List max_w, List stddev_w) throws SQLException + { + for(Map.Entry> agg_idx : indexes.entrySet()) + { + HdbData.Aggregate agg = agg_idx.getKey(); + for(Map.Entry i : agg_idx.getValue().entrySet()) + { + // We add 2 because indexing start at 1 for sql result + // and the first one is always the timestamp. + int idx = i.getKey() + 2; + boolean isArray = i.getValue(); + switch(agg) + { + case ROWS_COUNT: + { + count_rows.add(rs.getLong(idx)); + break; + } + case ERRORS_COUNT: + { + count_errors.add(rs.getLong(idx)); + break; + } + case COUNT_R: + { + if(isArray) + { + convertLongArray(count_r, rs.getArray(idx)); + } + else + { + count_r.add(rs.getLong(idx)); + } + break; + } + case NAN_COUNT_R: + { + if(isArray) + { + convertLongArray(count_nan_r, rs.getArray(idx)); + } + else + { + count_nan_r.add(rs.getLong(idx)); + } + break; + } + case MEAN_R: + { + if(isArray) + { + convertDoubleArray(mean_r, rs.getArray(idx)); + } + else + { + mean_r.add(rs.getDouble(idx)); + } + break; + } + case MIN_R: + { + if(isArray) + { + convertNumberArray(min_r, rs.getArray(idx), dataType); + } + else + { + min_r.add(extractNumber(rs, idx, dataType)); + } + break; + } + case MAX_R: + { + if(isArray) + { + convertNumberArray(max_r, rs.getArray(idx), dataType); + } + else + { + max_r.add(extractNumber(rs, idx, dataType)); + } + break; + } + case STDDEV_R: + { + if(isArray) + { + convertDoubleArray(stddev_r, rs.getArray(idx)); + } + else + { + stddev_r.add(rs.getDouble(idx)); + } + break; + } + case COUNT_W: + { + if(isArray) + { + convertLongArray(count_w, rs.getArray(idx)); + } + else + { + count_w.add(rs.getLong(idx)); + } + break; + } + case NAN_COUNT_W: + { + if(isArray) + { + convertLongArray(count_nan_w, rs.getArray(idx)); + } + else + { + count_nan_w.add(rs.getLong(idx)); + } + break; + } + case MEAN_W: + { + if(isArray) + { + convertDoubleArray(mean_w, rs.getArray(idx)); + } + else + { + mean_w.add(rs.getDouble(idx)); + } + break; + } + case MIN_W: + { + if(isArray) + { + convertNumberArray(min_w, rs.getArray(idx), dataType); + } + else + { + min_w.add(extractNumber(rs, idx, dataType)); + } + break; + } + case MAX_W: + { + if(isArray) + { + convertNumberArray(max_w, rs.getArray(idx), dataType); + } + else + { + max_w.add(extractNumber(rs, idx, dataType)); + } + break; + } + case STDDEV_W: + { + if(isArray) + { + convertDoubleArray(stddev_w, rs.getArray(idx)); + } + else + { + stddev_w.add(rs.getDouble(idx)); + } + break; + } + } + } + } + } + + private void extractRawData(ResultSet rs, SignalInfo sigInfo, SortedSet ranges, boolean isRW, boolean isWO, int queryCount, List data) throws SQLException, HdbFailed + { + long dTime = 0; + String errorMsg = null; + int quality = 0; + int nbRow = 0; + + ArrayList value = new ArrayList<>(); + ArrayList wvalue = new ArrayList<>(); + + boolean isW = isRW | isWO; + while (rs.next()) { + + dTime = timeValue(rs.getTimestamp(1)); + errorMsg = rs.getString(2); + quality = rs.getInt(3); + value.clear(); + if(isW) + wvalue.clear(); + if(sigInfo.isArray()) + { + if(ranges.contains(SignalInfo.Range.FULL_RANGE)) + { + if(!isWO) + convertArray(value, rs.getArray(4)); + if(isW) convertArray(wvalue, rs.getArray(5)); + } + else + { + int idx = 4; + for(SignalInfo.Range r : ranges) + { + if(r.size() > 1) + { + if(!isWO) + { + convertArray(value, rs.getArray(idx)); + ++idx; + } + if(isW) + { + convertArray(wvalue, rs.getArray(idx)); + ++idx; + } + } + else + { + idx = extractValue(sigInfo, rs, idx, value, wvalue, isWO, isW, true); + } + + } + } + } + else + { + extractValue(sigInfo, rs, 4, value, wvalue, isWO, isW); } // Write only attribute, copy write data to read data @@ -499,24 +902,15 @@ private void extractRawData(ResultSet rs, SignalInfo sigInfo, boolean isRW, bool } } - private void extractAggregateData(ResultSet rs, SignalInfo info, boolean isRW, boolean isWO, int queryCount, List data) throws SQLException, HdbFailed + private void extractAggregateData(ResultSet rs, SignalInfo info, SortedSet ranges, boolean isRW, boolean isWO, int queryCount, Map> indexes, List data) throws SQLException, HdbFailed { int nbRow = 0; - boolean isFloating = info.dataType == HdbSigInfo.Type.DOUBLE || info.dataType == HdbSigInfo.Type.FLOAT; - boolean isArray = info.isArray(); - int floatingOffset1 = 0; - int floatingOffset2 = 0; - if(!isFloating) - { - floatingOffset1 = 1; - floatingOffset2 = 2; - } long dTime = 0; - long count_rows; - long count_errors; while (rs.next()) { + ArrayList count_rows = new ArrayList<>(); + ArrayList count_errors = new ArrayList<>(); ArrayList count_r = new ArrayList<>(); ArrayList count_nan_r = new ArrayList<>(); ArrayList mean_r = new ArrayList<>(); @@ -530,49 +924,23 @@ private void extractAggregateData(ResultSet rs, SignalInfo info, boolean isRW, b ArrayList max_w = new ArrayList<>(); ArrayList stddev_w = new ArrayList<>(); dTime = timeValue(rs.getTimestamp(1)); - count_rows = rs.getLong(2); - count_errors = rs.getLong(3); - if (isArray) { - convertLongArray(count_r, rs.getArray(4)); - convertDoubleArray(mean_r, rs.getArray(6 - floatingOffset1)); - convertNumberArray(min_r, rs.getArray(7 - floatingOffset1), info.dataType); - convertNumberArray(max_r, rs.getArray(8 - floatingOffset1), info.dataType); - convertDoubleArray(stddev_r, rs.getArray(9 - floatingOffset1)); - convertLongArray(count_w, rs.getArray(10 - floatingOffset1)); - convertDoubleArray(mean_w, rs.getArray(12 - floatingOffset2)); - convertNumberArray(min_w, rs.getArray(13 - floatingOffset2), info.dataType); - convertNumberArray(max_w, rs.getArray(14 - floatingOffset2), info.dataType); - convertDoubleArray(stddev_w, rs.getArray(15 - floatingOffset2)); - if(isFloating) - { - convertLongArray(count_nan_r, rs.getArray(5)); - convertLongArray(count_nan_w, rs.getArray(11)); - } - } - else - { - count_r.add(rs.getLong(4)); - mean_r.add(rs.getDouble(6 - floatingOffset1)); - min_r.add(extractNumber(rs, 7 - floatingOffset1, info.dataType)); - max_r.add(extractNumber(rs, 8 - floatingOffset1, info.dataType)); - stddev_r.add(rs.getDouble(9 - floatingOffset1)); - count_w.add(rs.getLong(10 - floatingOffset1)); - mean_w.add(rs.getDouble(12 - floatingOffset2)); - min_w.add(extractNumber(rs, 13-floatingOffset2, info.dataType)); - max_w.add(extractNumber(rs, 14-floatingOffset2, info.dataType)); - stddev_w.add(rs.getDouble(15 - floatingOffset2)); - if(isFloating) { - count_nan_r.add(rs.getLong(5)); - count_nan_w.add(rs.getLong(11)); - } - } + + extractAggregates(indexes, rs, info.dataType, count_rows, count_errors, count_r, count_nan_r, mean_r, min_r, max_r, stddev_r, count_w, count_nan_w, mean_w, min_w, max_w, stddev_w); + + long count_rows_l = 0; + long count_errors_l = 0; + + if(!count_rows.isEmpty()) + count_rows_l = count_rows.get(0); + if(!count_errors.isEmpty()) + count_errors_l = count_errors.get(0); HdbData hd = HdbData.createData(info); hd.parseAggregate( dTime, //Tango timestamp - count_rows, - count_errors, + count_rows_l, + count_errors_l, count_r, count_nan_r, mean_r, @@ -720,7 +1088,7 @@ public HdbDataSet findErrors(String attName, // --------------------------------------------------------------------------------------- - private void convertArray(ArrayList v,Array a) throws SQLException { + private void convertArray(List v,Array a) throws SQLException { if(a!=null) { Object[] objects = (Object[]) a.getArray(); @@ -730,7 +1098,7 @@ private void convertArray(ArrayList v,Array a) throws SQLException { } - private void convertDoubleArray(ArrayList v,Array a) throws SQLException { + private void convertDoubleArray(List v,Array a) throws SQLException { if(a!=null) { Double[] objects = (Double[]) a.getArray(); @@ -741,7 +1109,7 @@ private void convertDoubleArray(ArrayList v,Array a) throws SQLException } - private void convertNumberArray(ArrayList v,Array a, HdbSigInfo.Type type) throws SQLException { + private void convertNumberArray(List v,Array a, HdbSigInfo.Type type) throws SQLException { if(a!=null) { Number[] numbers; switch(type) { @@ -764,7 +1132,7 @@ private void convertNumberArray(ArrayList v,Array a, HdbSigInfo.Type typ } } - private void convertLongArray(ArrayList v,Array a) throws SQLException { + private void convertLongArray(List v,Array a) throws SQLException { if(a!=null) { Long[] objects = (Long[]) a.getArray(); diff --git a/src/main/java/org/tango/jhdb/SignalInfo.java b/src/main/java/org/tango/jhdb/SignalInfo.java index 3c949b1..df1876e 100644 --- a/src/main/java/org/tango/jhdb/SignalInfo.java +++ b/src/main/java/org/tango/jhdb/SignalInfo.java @@ -35,6 +35,10 @@ import org.tango.jhdb.data.HdbData; import java.util.Set; +import java.util.Map; +import java.util.HashMap; +import java.util.SortedSet; +import java.util.TreeSet; /** * Signal info structure @@ -186,6 +190,45 @@ public String toString() } } + public static class Range implements Comparable + { + int start_idx; + int end_idx; + + public static Range FULL_RANGE = new Range(Integer.MIN_VALUE, Integer.MAX_VALUE); + + public Range(int start, int end) + { + start_idx = start; + end_idx = end; + } + + public String toString() + { + if(this == FULL_RANGE) + return ""; + // We set +1 as is postgres indexing starts at 1, it should be done differently. + if(start_idx == end_idx) + return "[" + (start_idx+1) + "]"; + return "[" + (start_idx+1) + ":" + (end_idx+1) + "]"; + } + + public int size() + { + return end_idx - start_idx + 1; + } + + @Override + public int compareTo(Range o) + { + if(start_idx != o.start_idx) + { + return start_idx - o.start_idx; + } + return end_idx - o.end_idx; + } + } + public String name; // Attribute name public String sigId; // Identifier public Format format; // Data type @@ -196,6 +239,7 @@ public String toString() public Access access; // Write only flag public Interval interval = Interval.NONE; // interval, for aggregates public Set aggregates; + public SortedSet indexes; // For arrays, indexes to be extracted public SignalInfo() { @@ -213,6 +257,7 @@ public SignalInfo(SignalInfo parent) this.access = parent.access; this.interval = parent.interval; this.aggregates = parent.aggregates; + this.indexes = parent.indexes; } protected SignalInfo(Type type, Format fmt, Access acc) @@ -340,13 +385,48 @@ public boolean isState() { * Returns true if this signal is aggregated data, false if it is raw. */ public boolean isAggregate() { - return Interval.isAggregate(interval); - } + return Interval.isAggregate(interval); + } public String toString() { return "Id=" + sigId + ", Type=" + dataType.toString() + ", Format=" + format.toString() + ", Access=" + access.toString()+ ", Interval=" + interval.toString(); } + public SortedSet getRanges() + { + SortedSet ret = new TreeSet<>(); + if(indexes == null || indexes.isEmpty()) + { + ret.add(Range.FULL_RANGE); + } + else + { + int start = -2; + int prev = -2; + boolean inRange = false; + for(int idx : indexes) + { + if(idx - prev > 1) + { + if(inRange) + { + ret.add(new Range(start, prev)); + start = idx; + } + else + { + inRange = true; + start = idx; + } + } + prev = idx; + } + if(inRange) + ret.add(new Range(start, prev)); + } + return ret; + } + @Override public boolean equals(Object info) { diff --git a/src/main/java/org/tango/jhdb/data/HdbData.java b/src/main/java/org/tango/jhdb/data/HdbData.java index f3c134c..6ad9525 100644 --- a/src/main/java/org/tango/jhdb/data/HdbData.java +++ b/src/main/java/org/tango/jhdb/data/HdbData.java @@ -46,20 +46,32 @@ public abstract class HdbData { public static enum Aggregate { - ROWS_COUNT, - ERRORS_COUNT, - COUNT_R, - NAN_COUNT_R, - MEAN_R, - MIN_R, - MAX_R, - STDDEV_R, - COUNT_W, - NAN_COUNT_W, - MEAN_W, - MIN_W, - MAX_W, - STDDEV_W, + ROWS_COUNT("count_rows"), + ERRORS_COUNT("count_errors"), + COUNT_R("count_r"), + NAN_COUNT_R("count_nan_r"), + MEAN_R("mean_r"), + MIN_R("min_r"), + MAX_R("max_r"), + STDDEV_R("stddev_r"), + COUNT_W("count_w"), + NAN_COUNT_W("count_nan_w"), + MEAN_W("mean_w"), + MIN_W("min_w"), + MAX_W("max_w"), + STDDEV_W("stddev_w"); + + String description; + + private Aggregate(String desc) + { + description = desc; + } + + public String toString() + { + return description; + } } final protected static Map> EMPTY_AGGREGATE = new EnumMap<>(Aggregate.class);