/** * @return Numeric meta data information for the channel or <code>null</code> * @throws Exception on error */ private Display determineDisplay() throws Exception { // Try numeric meta data final PreparedStatement statement = reader .getRDB() .getConnection() .prepareStatement(reader.getSQL().numeric_meta_sel_by_channel); try { statement.setInt(1, channel_id); final ResultSet result = statement.executeQuery(); if (result.next()) { final NumberFormat format = NumberFormats.format(result.getInt(7)); // prec return ValueFactory.newDisplay( result.getDouble(1), // lowerDisplayLimit result.getDouble(5), // lowerAlarmLimit result.getDouble(3), // lowerWarningLimit result.getString(8), // units format, // numberFormat result.getDouble(4), // upperWarningLimit result.getDouble(6), // upperAlarmLimit result.getDouble(2), // upperDisplayLimit result.getDouble(1), // lowerCtrlLimit result.getDouble(2)); // upperCtrlLimit } } finally { statement.close(); } // No numeric display meta data return null; }
/** * See if there are array elements. * * @param dbl0 Value of the first (maybe only) array element * @param result ResultSet for the sample table with blob * @return Array with given element and maybe more. * @throws Exception on error, including 'cancel' */ private double[] readBlobArrayElements(final double dbl0, final ResultSet result) throws Exception { final String datatype; if (reader.isOracle()) datatype = result.getString(7); else datatype = result.getString(8); // ' ' or NULL indicate: Scalar, not an array if (datatype == null || " ".equals(datatype) || result.wasNull()) return new double[] {dbl0}; // Decode BLOB final byte[] bytes = result.getBytes(reader.isOracle() ? 8 : 9); final ByteArrayInputStream stream = new ByteArrayInputStream(bytes); final DataInputStream data = new DataInputStream(stream); if ("d".equals(datatype)) { // Read Double typed array elements final int nelm = data.readInt(); final double[] array = new double[nelm]; for (int i = 0; i < nelm; i++) array[i] = data.readDouble(); data.close(); return array; } // TODO Decode 'l' Long and 'i' Integer? else { throw new Exception("Sample BLOBs of type '" + datatype + "' are not decoded"); } }
/** * @return Numeric meta data information for the channel or <code>null</code> * @throws Exception on error */ private List<String> determineLabels() throws Exception { // Try enumerated meta data List<String> labels = null; final PreparedStatement statement = reader .getRDB() .getConnection() .prepareStatement(reader.getSQL().enum_sel_num_val_by_channel); try { statement.setInt(1, channel_id); final ResultSet result = statement.executeQuery(); if (result.next()) { labels = new ArrayList<String>(); do { final int id = result.getInt(1); final String val = result.getString(2); // Expect vals for ids 0, 1, 2, ... if (id != labels.size()) throw new Exception( "Enum IDs for channel with ID " + channel_id + " not in sequential order"); labels.add(val); } while (result.next()); } } finally { statement.close(); } // Anything found? if (labels == null || labels.size() <= 0) return null; // Nothing found return labels; }
/** * Extract value from SQL result * * @param result ResultSet that must contain contain time, severity, ..., value * @param handle_array Try to read array elements, or only a scalar value? * @return IValue Decoded IValue * @throws Exception on error, including cancellation */ protected VType decodeSampleTableValue(final ResultSet result, final boolean handle_array) throws Exception { // Get time stamp final java.sql.Timestamp stamp = result.getTimestamp(1); // Oracle has nanoseconds in TIMESTAMP, other RDBs in separate column if (!reader.isOracle()) stamp.setNanos(result.getInt(7)); final Timestamp time = TimestampHelper.fromSQLTimestamp(stamp); // Get severity/status final String status = reader.getStatus(result.getInt(3)); final AlarmSeverity severity = filterSeverity(reader.getSeverity(result.getInt(2)), status); // Determine the value type // Try double final double dbl0 = result.getDouble(5); if (!result.wasNull()) { // Is it an error to have enumeration strings for double samples? // In here, we handle it by returning enumeration samples, // because the meta data would be wrong for double values. if (labels != null) return new ArchiveVEnum(time, severity, status, labels, (int) dbl0); // Double data. if (handle_array) { // Get array elements - if any. final double data[] = reader.useArrayBlob() ? readBlobArrayElements(dbl0, result) : readArrayElements(time, dbl0, severity); if (data.length == 1) return new ArchiveVNumber(time, severity, status, display, data[0]); else return new ArchiveVNumberArray(time, severity, status, display, data); } else return new ArchiveVNumber(time, severity, status, display, dbl0); } // Try integer final int num = result.getInt(4); if (!result.wasNull()) { // Enumerated integer? if (labels != null) return new ArchiveVEnum(time, severity, status, labels, num); return new ArchiveVNumber(time, severity, status, display, num); } // Default to string final String txt = result.getString(6); return new ArchiveVString(time, severity, status, txt); }
/** * Given the time and first element of the sample, see if there are more array elements. * * @param stamp Time stamp of the sample * @param dbl0 Value of the first (maybe only) array element * @param severity Severity of the sample * @return Array with given element and maybe more. * @throws Exception on error, including 'cancel' */ private double[] readArrayElements( final Timestamp stamp, final double dbl0, final AlarmSeverity severity) throws Exception { // For performance reasons, only look for array data until we hit a scalar sample. if (is_an_array == false) return new double[] {dbl0}; // See if there are more array elements if (sel_array_samples == null) { // Lazy initialization sel_array_samples = reader.getRDB().getConnection().prepareStatement(reader.getSQL().sample_sel_array_vals); } sel_array_samples.setInt(1, channel_id); sel_array_samples.setTimestamp(2, TimestampHelper.toSQLTimestamp(stamp)); // MySQL keeps nanoseconds in designated column, not TIMESTAMP if (!reader.isOracle()) sel_array_samples.setInt(3, stamp.getNanoSec()); // Assemble array of unknown size in ArrayList .... final ArrayList<Double> vals = new ArrayList<Double>(); reader.addForCancellation(sel_array_samples); try { final ResultSet res = sel_array_samples.executeQuery(); vals.add(new Double(dbl0)); while (res.next()) vals.add(res.getDouble(1)); res.close(); } finally { reader.removeFromCancellation(sel_array_samples); } // Convert to plain double array final int N = vals.size(); final double ret[] = new double[N]; for (int i = 0; i < N; i++) ret[i] = vals.get(i).doubleValue(); // Check if it's in fact just a scalar, and a valid one if (N == 1 && severity != AlarmSeverity.UNDEFINED) { // Found a perfect non-array sample: // Assume that the data is scalar, skip the array check from now on is_an_array = false; } return ret; }
/** * Initialize * * @param reader RDBArchiveReader * @param channel_id ID of channel * @param start Start time * @param end End time * @throws Exception on error */ public RawSampleIterator( final RDBArchiveReader reader, final int channel_id, final Timestamp start, final Timestamp end) throws Exception { super(reader, channel_id); try { determineInitialSample(start, end); } catch (Exception ex) { if (!RDBArchiveReader.isCancellation(ex)) throw ex; // Else: Not a real error; return empty iterator value = null; } }
/** * @param reader RDBArchiveReader * @param channel_id ID of channel * @throws Exception on error */ AbstractRDBValueIterator(final RDBArchiveReader reader, final int channel_id) throws Exception { this.reader = reader; this.channel_id = channel_id; try { this.display = determineDisplay(); this.labels = determineLabels(); } catch (final Exception ex) { // Set iterator to empty close(); if (!RDBArchiveReader.isCancellation(ex)) throw ex; // Else: Not a real error, return empty iterator } if (labels == null && display == null) display = ValueFactory.newDisplay( 0.0, 0.0, 0.0, "", NumberFormats.format(0), 0.0, 0.0, 10.0, 0.0, 10.0); }
/** {@inheritDoc} */ @Override @SuppressWarnings("nls") public VType next() throws Exception { // This should not happen... if (result_set == null) throw new Exception("RawSampleIterator.next(" + channel_id + ") called after end"); // Remember value to return... final VType result = value; // ... and prepare next value try { if (result_set.next()) value = decodeSampleTableValue(result_set, true); else close(); } catch (Exception ex) { close(); if (!RDBArchiveReader.isCancellation(ex)) throw ex; // Else: Not a real error; return empty iterator } return result; }