Mercurial > hg > monetdb-java
view src/main/java/nl/cwi/monetdb/mcl/responses/DataBlockResponse.java @ 98:c0ce1ea5075f embedded
Some documentation added.
author | Pedro Ferreira <pedro.ferreira@monetdbsolutions.com> |
---|---|
date | Wed, 11 Jan 2017 17:01:20 +0100 (2017-01-11) |
parents | e087be5c7225 |
children | 1dcb51573c89 |
line wrap: on
line source
/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 1997 - July 2008 CWI, August 2008 - 2017 MonetDB B.V. */ package nl.cwi.monetdb.mcl.responses; import nl.cwi.monetdb.jdbc.MonetBlob; import nl.cwi.monetdb.jdbc.MonetClob; import nl.cwi.monetdb.mcl.protocol.AbstractProtocol; import nl.cwi.monetdb.mcl.protocol.ProtocolException; import nl.cwi.monetdb.mcl.protocol.ServerResponses; import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Types; import java.util.Arrays; import java.util.Calendar; /** * The DataBlockResponse is tabular data belonging to a ResultSetResponse. On a MAPI connection, tabular data from the * server typically looks like: * <pre> * [ "value", 56 ] * </pre> * where each column is separated by ",\t" and each tuple surrounded by brackets ("[" and "]"). A DataBlockResponse * object holds the raw data as read from the server, in a parsed manner, ready for easy retrieval. Meanwhile on an * Embedded connection, the data is automatically parsed. * * This object is not intended to be queried by multiple threads synchronously. It is designed to work for one thread * retrieving rows from it. When multiple threads will retrieve rows from this object, it is possible for threads to * get the same data. */ public class DataBlockResponse implements IIncompleteResponse { /** The array to keep the data in */ private Object[] data; /** The counter which keeps the current position in the data array */ private int pos; /** The connection protocol to parse the tuple lines */ private final AbstractProtocol protocol; /** The JdbcSQLTypes mapping */ private final int[] jdbcSQLTypes; /** A 'pointer' to the current line */ private int blockLine; /** The number of rows in the block */ private final int rowcount; /** * Constructs a DataBlockResponse object. * * @param rowcount the number of rows * @param columncount the number of columns * @param protocol the underlying protocol * @param JdbcSQLTypes an array of the JDBC mappings of the columns */ DataBlockResponse(int rowcount, int columncount, AbstractProtocol protocol, int[] JdbcSQLTypes) { this.pos = -1; this.rowcount = rowcount; this.data = new Object[columncount]; this.protocol = protocol; this.jdbcSQLTypes = JdbcSQLTypes; } /** * addLines adds a batch of rows to the block. Before adding the first line, the column arrays are allocated. * * @param protocol The connection's protocol to fetch data from * @throws ProtocolException If the result line is not expected */ @Override public void addLines(AbstractProtocol protocol) throws ProtocolException { int csrh = protocol.getCurrentServerResponse(); if (csrh != ServerResponses.RESULT) { throw new ProtocolException("protocol violation: unexpected line in data block: " + protocol.getRemainingStringLine(0)); } if(this.pos == -1) { //if it's the first line, initialize the matrix int numberOfColumns = this.data.length; for (int i = 0 ; i < numberOfColumns ; i++) { switch (this.jdbcSQLTypes[i]) { case Types.BOOLEAN: case Types.TINYINT: this.data[i] = new byte[this.rowcount]; break; case Types.SMALLINT: this.data[i] = new short[this.rowcount]; break; case Types.INTEGER: this.data[i] = new int[this.rowcount]; break; case Types.BIGINT: this.data[i] = new long[this.rowcount]; break; case Types.REAL: this.data[i] = new float[this.rowcount]; break; case Types.DOUBLE: this.data[i] = new double[this.rowcount]; break; case Types.DECIMAL: this.data[i] = new BigDecimal[this.rowcount]; break; case Types.NUMERIC: this.data[i] = new BigInteger[this.rowcount]; break; case Types.BLOB: this.data[i] = new MonetBlob[this.rowcount]; break; case Types.CLOB: this.data[i] = new MonetClob[this.rowcount]; break; case Types.TIME: case Types.TIME_WITH_TIMEZONE: case Types.DATE: case Types.TIMESTAMP: case Types.TIMESTAMP_WITH_TIMEZONE: this.data[i] = new Calendar[this.rowcount]; break; case Types.LONGVARBINARY: this.data[i] = new byte[this.rowcount][]; break; default: //CHAR, VARCHAR, OTHER this.data[i] = new String[this.rowcount]; } } } // add to the backing array int nextPos = this.pos + 1; this.pos = this.protocol.parseTupleLines(nextPos, this.jdbcSQLTypes, this.data); } /** * Returns whether this Response expects more lines to be added to it. * * @return true if a next line should be added, false otherwise */ @Override public boolean wantsMore() { // remember: pos is the value already stored return (this.pos + 1) < this.rowcount; } /** * Instructs the Response implementation to close and do the necessary clean up procedures. */ @Override public void close() { // feed all rows to the garbage collector int numberOfColumns = this.data.length; for (int i = 0; i < numberOfColumns; i++) { data[i] = null; } data = null; } /* Methods to be called after the block construction has been completed */ /** * Sets the current line number on the block. * * @param blockLine the block line number */ void setBlockLine(int blockLine) { this.blockLine = blockLine; } /** * Sets the data on the block. * This method is called by the MonetVirtualResultSet class which should be eliminated on the future. * * @param data the data to set */ public void setData(Object[] data) { /* For VirtualResultSet :( */ this.data = data; } /** * Gets the data on the block. * This method is called by the MonetVirtualResultSet class which should be eliminated on the future. * * @return the result set data */ public Object[] getData() { /* For VirtualResultSet :( */ return this.data; } /** * Checks if a value in the current row is null. * * @param column The column index starting from 0 * @return If the value is null or not. */ public boolean checkValueIsNull(int column) { switch (this.jdbcSQLTypes[column]) { case Types.BOOLEAN: case Types.TINYINT: return ((byte[]) this.data[column])[this.blockLine] == Byte.MIN_VALUE; case Types.SMALLINT: return ((short[]) this.data[column])[this.blockLine] == Short.MIN_VALUE; case Types.INTEGER: return ((int[]) this.data[column])[this.blockLine] == Integer.MIN_VALUE; case Types.BIGINT: return ((long[]) this.data[column])[this.blockLine] == Long.MIN_VALUE; case Types.REAL: return ((float[]) this.data[column])[this.blockLine] == Float.MIN_VALUE; case Types.DOUBLE: return ((double[]) this.data[column])[this.blockLine] == Double.MIN_VALUE; default: return ((Object[]) this.data[column])[this.blockLine] == null; } } /** * Gets the current row value as a Java Boolean. * * @param column The column index starting from 0 * @return A Java Boolean if the column is a boolean, otherwise a ClassCastException is thrown */ public boolean getBooleanValue(int column) { return ((byte[]) this.data[column])[this.blockLine] == 1; } /** * Gets the current row value as a Java Byte. * * @param column The column index starting from 0 * @return A Java Byte if the column is a tinyint, otherwise a ClassCastException is thrown */ public byte getByteValue(int column) { return ((byte[]) this.data[column])[this.blockLine]; } /** * Gets the current row value as a Java Short. * * @param column The column index starting from 0 * @return A Java Short if the column is a smallint, otherwise a ClassCastException is thrown */ public short getShortValue(int column) { return ((short[]) this.data[column])[this.blockLine]; } /** * Gets the current row value as a Java Integer. * * @param column The column index starting from 0 * @return A Java Integer if the column is an integer or month_interval, otherwise a ClassCastException is thrown */ public int getIntValue(int column) { return ((int[]) this.data[column])[this.blockLine]; } /** * Gets the current row value as a Java Long. * * @param column The column index starting from 0 * @return A Java Long if the column is a bigint or second_interval, otherwise a ClassCastException is thrown */ public long getLongValue(int column) { return ((long[]) this.data[column])[this.blockLine]; } /** * Gets the current row value as a Java Float. * * @param column The column index starting from 0 * @return A Java Float if the column is a real, otherwise a ClassCastException is thrown */ public float getFloatValue(int column) { return ((float[]) this.data[column])[this.blockLine]; } /** * Gets the current row value as a Java Double. * * @param column The column index starting from 0 * @return A Java Double if the column is a double, otherwise a ClassCastException is thrown */ public double getDoubleValue(int column) { return ((double[]) this.data[column])[this.blockLine]; } /** * Gets the current row value as a Java Object. * * @param column The column index starting from 0 * @return A Java Object if the column is not a primitive type, otherwise a ClassCastException is thrown */ public Object getObjectValue(int column) { return ((Object[]) this.data[column])[this.blockLine]; } /** * Gets the current row value as a Java String. * * @param column The column index starting from 0 * @return The String representation of the data type */ public String getValueAsString(int column) { switch (this.jdbcSQLTypes[column]) { case Types.BOOLEAN: return ((byte[]) this.data[column])[this.blockLine] == 1 ? "true" : "false"; case Types.TINYINT: return Byte.toString(((byte[]) this.data[column])[this.blockLine]); case Types.SMALLINT: return Short.toString(((short[]) this.data[column])[this.blockLine]); case Types.INTEGER: return Integer.toString(((int[]) this.data[column])[this.blockLine]); case Types.BIGINT: return Long.toString(((long[]) this.data[column])[this.blockLine]); case Types.REAL: return Float.toString(((float[]) this.data[column])[this.blockLine]); case Types.DOUBLE: return Double.toString(((double[]) this.data[column])[this.blockLine]); case Types.LONGVARBINARY: return Arrays.toString(((byte[][]) this.data[column])[this.blockLine]); case Types.CHAR: case Types.VARCHAR: case Types.LONGVARCHAR: case Types.OTHER: return ((String[]) this.data[column])[this.blockLine]; default: //BLOB, CLOB, BigDecimal, BigInteger, Time, Timestamp and Date return ((Object[]) this.data[column])[this.blockLine].toString(); } } /** * Gets the current row value as a Java Object. * * @param column The column index starting from 0 * @return The Object representation of the data type */ public Object getValueAsObject(int column) { switch (this.jdbcSQLTypes[column]) { case Types.BOOLEAN: return ((byte[]) this.data[column])[this.blockLine] == 1; case Types.TINYINT: return ((byte[]) this.data[column])[this.blockLine]; case Types.SMALLINT: return ((short[]) this.data[column])[this.blockLine]; case Types.INTEGER: return ((int[]) this.data[column])[this.blockLine]; case Types.BIGINT: return ((long[]) this.data[column])[this.blockLine]; case Types.REAL: return ((float[]) this.data[column])[this.blockLine]; case Types.DOUBLE: return ((double[]) this.data[column])[this.blockLine]; default: return ((Object[]) this.data[column])[this.blockLine]; } } }