gt:             return table.getLong(columnIndex - 1);
context: /* This file is part of VoltDB.
   * Copyright (C) 2008-2015 VoltDB Inc.
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Affero General Public License as
   * published by the Free Software Foundation, either version 3 of the
   * License, or (at your option) any later version.
   *
   * This program 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 Affero General Public License for more details.
   *
   * You should have received a copy of the GNU Affero General Public License
   * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  package org.voltdb.jdbc;
  
  import java.io.ByteArrayInputStream;
  import java.io.InputStream;
  import java.io.Reader;
  import java.io.StringReader;
  import java.math.BigDecimal;
  import java.net.URL;
  import java.sql.Array;
  import java.sql.Blob;
  import java.sql.Clob;
  import java.sql.Date;
  import java.sql.NClob;
  import java.sql.Ref;
  import java.sql.ResultSetMetaData;
  import java.sql.RowId;
  import java.sql.SQLException;
  import java.sql.SQLWarning;
  import java.sql.SQLXML;
  import java.sql.Statement;
  import java.sql.Time;
  import java.sql.Timestamp;
  import java.util.Calendar;
  import java.util.Map;
  
  import javax.sql.rowset.serial.SerialBlob;
  import javax.sql.rowset.serial.SerialClob;
  
  import org.voltdb.VoltTable;
  import org.voltdb.VoltType;
  
  // TODO: NString, (N)Clob, AsciiStream, (N)CharacterStream all feel dubious to me.  VoltDB stores data in UTF-8 - somewhere along the lines there should be a conversion.
  // TODO: Blob, Bytes, BinaryStream are debatable.  Here as well, I merely grab a varchar field's binary data.  With the internal conversion to UTF-8, this isn't going to work very well... Maybe embed Base64 encoding until binary field support is available?
  
  // The ResultSet 'cursorPosition' is made consistent with the enum 'Position' defined in this class
  // Initially the cursor points to beforeFirst position (activeRowIndex = -1) and hence cursorPosition is initialized with the beforeFirst enum value
  // beforeFirst method sets the cursorPosition to beforeFirst enum value and Resets the activeRowIndex value to -1
  // afterLast method sets the cursorPosition to afterLast enum value BUT does not change the activeRowIndex value
  // calling previous at first row sets the cursorPosition to beforeFirst enum value and activeRowIndex value to -1
  // calling next at last row sets the cursorPosition to afterLast enum value and sets the activeRowIndex value equal to table 'rowCount'
  
  public class JDBC4ResultSet implements java.sql.ResultSet {
      private final Statement statement;
      protected VoltTable table;
      protected int columnCount;
      private int fetchDirection = FETCH_FORWARD;
      private int fetchSize = 0;
      private int rowCount;
      private Position cursorPosition = Position.beforeFirst;
      private enum Position {
                  beforeFirst, middle, afterLast
      }
  
      public JDBC4ResultSet(Statement sourceStatement, VoltTable sourceTable)
              throws SQLException {
          statement = sourceStatement;
          table = sourceTable;
          rowCount = table.getRowCount();
  
          try {
              columnCount = table.getColumnCount();
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      protected final void checkClosed() throws SQLException {
          if (this.isClosed())
              throw SQLError.get(SQLError.CONNECTION_CLOSED);
      }
  
      protected synchronized final void checkColumnBounds(int columnIndex)
              throws SQLException {
          checkClosed();
          if ((columnIndex < 1) || (columnIndex > columnCount))
              throw SQLError.get(SQLError.COLUMN_NOT_FOUND, columnIndex,
                      columnCount);
      }
  
      // Moves the cursor to the given row number in this ResultSet object.
      @Override
      public boolean absolute(int row) throws SQLException {
          checkClosed();
          if (rowCount == 0) {
              if (row == 0) {
                 return true;
              }
              return false;
          }
          if (row == 0) {
              beforeFirst();
              return true;
          }
          if (rowCount + row < 0) {
              beforeFirst();
              return false;
          }
          if (row > rowCount) {
              cursorPosition = Position.afterLast;
              if(row == rowCount+1) {
                  return true;
              }
              else {
                  return false;
              }
          }
          try {
              // for negative row numbers or row numbers lesser then activeRowIndex, resetRowPosition
              // method is called and the cursor advances to the desired row from top of the table
              if(row < 0) {
                  row += rowCount;
                  row++;
              }
              if(table.getActiveRowIndex() > row || cursorPosition != Position.middle) {
                  table.resetRowPosition();
                  table.advanceToRow(0);
              }
              cursorPosition = Position.middle;
              return table.advanceToRow(row-1);
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Moves the cursor to the end of this ResultSet object, just after the last
      // row.
      @Override
      public void afterLast() throws SQLException {
          checkClosed();
          cursorPosition = Position.afterLast;
      }
  
      // Moves the cursor to the front of this ResultSet object, just before the
      // first row.
      @Override
      public void beforeFirst() throws SQLException {
          checkClosed();
          cursorPosition = Position.beforeFirst;
          table.resetRowPosition();
      }
  
      // Cancels the updates made to the current row in this ResultSet object.
      @Override
      public void cancelRowUpdates() throws SQLException {
          throw SQLError.noSupport();
      }
  
      // Clears all warnings reported on this ResultSet object.
      @Override
      public void clearWarnings() throws SQLException {
          throw SQLError.noSupport();
      }
  
      // Releases this ResultSet object's database and JDBC resources immediately
      // instead of waiting for this to happen when it is automatically closed.
      @Override
      public void close() throws SQLException {
          table = null;
      }
  
      // Deletes the current row from this ResultSet object and from the
      // underlying database.
      @Override
      public void deleteRow() throws SQLException {
          throw SQLError.noSupport();
      }
  
      // Maps the given ResultSet column label to its ResultSet column index.
      @Override
      public int findColumn(String columnLabel) throws SQLException {
          checkClosed();
          try {
              return table.getColumnIndex(columnLabel) + 1;
          } catch (IllegalArgumentException iax) {
              throw SQLError.get(iax, SQLError.COLUMN_NOT_FOUND, columnLabel);
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Moves the cursor to the first row in this ResultSet object.
      @Override
      public boolean first() throws SQLException {
          checkClosed();
          if (rowCount == 0) {
              return false;
          }
          if (cursorPosition != Position.middle) {
              cursorPosition = Position.middle;
          }
          try {
              if (table.getActiveRowIndex() != 0){
                  table.resetRowPosition();
              }
              return table.advanceToRow(0);
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as an Array object in the Java programming language.
      @Override
      public Array getArray(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          throw SQLError.noSupport();
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as an Array object in the Java programming language.
      @Override
      public Array getArray(String columnLabel) throws SQLException {
          return getArray(findColumn(columnLabel));
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a stream of ASCII characters.
      @Override
      public InputStream getAsciiStream(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              return new ByteArrayInputStream(
                      table.getStringAsBytes(columnIndex - 1));
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a stream of ASCII characters.
      @Override
      public InputStream getAsciiStream(String columnLabel) throws SQLException {
          return getAsciiStream(findColumn(columnLabel));
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a java.math.BigDecimal with full precision.
      @Override
      public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              return table.getDecimalAsBigDecimal(columnIndex - 1);
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Deprecated.
      @Override
      @Deprecated
      public BigDecimal getBigDecimal(int columnIndex, int scale)
              throws SQLException {
          checkColumnBounds(columnIndex);
          throw SQLError.noSupport();
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a java.math.BigDecimal with full precision.
      @Override
      public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
          return getBigDecimal(findColumn(columnLabel));
      }
  
      // Deprecated.
      @Override
      @Deprecated
      public BigDecimal getBigDecimal(String columnLabel, int scale)
              throws SQLException {
          return getBigDecimal(findColumn(columnLabel), scale);
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a stream of uninterpreted bytes.
      @Override
      public InputStream getBinaryStream(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              return new ByteArrayInputStream(
                      table.getStringAsBytes(columnIndex - 1));
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a stream of uninterpreted bytes.
      @Override
      public InputStream getBinaryStream(String columnLabel) throws SQLException {
          return getBinaryStream(findColumn(columnLabel));
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a Blob object in the Java programming language.
      @Override
      public Blob getBlob(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              return new SerialBlob(table.getStringAsBytes(columnIndex - 1));
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a Blob object in the Java programming language.
      @Override
      public Blob getBlob(String columnLabel) throws SQLException {
          return getBlob(findColumn(columnLabel));
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a boolean in the Java programming language.
      @Override
      public boolean getBoolean(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          // TODO: Tempting to apply a != 0 operation on numbers and
          // .equals("true") on strings, but... hacky
          try {
              return (new Long(table.getLong(columnIndex - 1))).intValue() == 1;
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a boolean in the Java programming language.
      @Override
      public boolean getBoolean(String columnLabel) throws SQLException {
          return getBoolean(findColumn(columnLabel));
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a byte in the Java programming language.
      @Override
      public byte getByte(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              return (new Long(table.getLong(columnIndex - 1))).byteValue();
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a byte in the Java programming language.
      @Override
      public byte getByte(String columnLabel) throws SQLException {
          return getByte(findColumn(columnLabel));
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a byte array in the Java programming language.
      @Override
      public byte[] getBytes(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              if (table.getColumnType(columnIndex - 1) == VoltType.STRING)
                  return table.getStringAsBytes(columnIndex - 1);
              else
                  throw SQLError.get(SQLError.CONVERSION_NOT_FOUND,
                          table.getColumnType(columnIndex - 1), "byte[]");
          } catch (SQLException x) {
              throw x;
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a byte array in the Java programming language.
      @Override
      public byte[] getBytes(String columnLabel) throws SQLException {
          return getBytes(findColumn(columnLabel));
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a java.io.Reader object.
      @Override
      public Reader getCharacterStream(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              String value = table.getString(columnIndex - 1);
              if (!wasNull())
                  return new StringReader(value);
              return null;
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a java.io.Reader object.
      @Override
      public Reader getCharacterStream(String columnLabel) throws SQLException {
          return getCharacterStream(findColumn(columnLabel));
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a Clob object in the Java programming language.
      @Override
      public Clob getClob(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              return new SerialClob(table.getString(columnIndex - 1)
                      .toCharArray());
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a Clob object in the Java programming language.
      @Override
      public Clob getClob(String columnLabel) throws SQLException {
          return getClob(findColumn(columnLabel));
      }
  
      // Retrieves the concurrency mode of this ResultSet object.
      @Override
      public int getConcurrency() throws SQLException {
          return CONCUR_READ_ONLY;
      }
  
      // Retrieves the name of the SQL cursor used by this ResultSet object.
      @Override
      public String getCursorName() throws SQLException {
          throw SQLError.noSupport();
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a java.sql.Date object in the Java programming
      // language.
      @Override
      public Date getDate(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              Timestamp ts = table.getTimestampAsSqlTimestamp(columnIndex - 1);
              Date result = null;
              if (ts != null) {
                  result = new Date(ts.getTime());
              }
              return result;
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a java.sql.Date object in the Java programming
      // language.
      @Override
      public Date getDate(int columnIndex, Calendar cal) throws SQLException {
          // TODO: Not sure what to do here... Dates are stored however given.
          // Need to try different TZs to see what happens when retrieving the
          // data
          checkColumnBounds(columnIndex);
          throw SQLError.noSupport();
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a java.sql.Date object in the Java programming
      // language.
      @Override
      public Date getDate(String columnLabel) throws SQLException {
          return getDate(findColumn(columnLabel));
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a java.sql.Date object in the Java programming
      // language.
      @Override
      public Date getDate(String columnLabel, Calendar cal) throws SQLException {
          return getDate(findColumn(columnLabel), cal);
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a double in the Java programming language.
      @Override
      public double getDouble(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              return table.getDouble(columnIndex - 1);
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a double in the Java programming language.
      @Override
      public double getDouble(String columnLabel) throws SQLException {
          return getDouble(findColumn(columnLabel));
      }
  
      // Retrieves the fetch direction for this ResultSet object.
      @Override
      public int getFetchDirection() throws SQLException {
          return this.fetchDirection;
      }
  
      // Retrieves the fetch size for this ResultSet object.
      @Override
      public int getFetchSize() throws SQLException {
          return this.fetchSize;
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a float in the Java programming language.
      @Override
      public float getFloat(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              return (new Double(table.getDouble(columnIndex - 1))).floatValue();
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a float in the Java programming language.
      @Override
      public float getFloat(String columnLabel) throws SQLException {
          return getFloat(findColumn(columnLabel));
      }
  
      // Retrieves the holdability of this ResultSet object
      @Override
      public int getHoldability() throws SQLException {
          throw SQLError.noSupport();
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as an int in the Java programming language.
      @Override
      public int getInt(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
              return (new Long(table.getLong(columnIndex - 1))).intValue();
          } catch (Exception x) {
              throw SQLError.get(x);
          }
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as an int in the Java programming language.
      @Override
      public int getInt(String columnLabel) throws SQLException {
          return getInt(findColumn(columnLabel));
      }
  
      // Retrieves the value of the designated column in the current row of this
      // ResultSet object as a long in the Java programming language.
      @Override
      public long getLong(int columnIndex) throws SQLException {
          checkColumnBounds(columnIndex);
          try {
  