gt:             for (GeographyPointValue pt : loops) {
context: /* This file is part of VoltDB.
   * Copyright (C) 2008-2018 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;
  
  import java.math.BigDecimal;
  import java.nio.ByteBuffer;
  import java.nio.charset.Charset;
  
  import org.json_voltpatches.JSONException;
  import org.json_voltpatches.JSONStringer;
  import org.voltdb.types.GeographyPointValue;
  import org.voltdb.types.GeographyValue;
  import org.voltdb.types.TimestampType;
  import org.voltdb.types.VoltDecimalHelper;
  import org.voltdb.utils.Encoder;
  import org.voltdb.utils.VoltTypeUtil;
  
  /**
   * <p>Represents the interface to a row in a VoltTable result set.</p>
   *
   * <h3>Accessing Row Fields</h3>
   *
   * <p>Row fields are acessed via methods of the form
   * <code>get</code><i>&lt;Type&gt;</i><code>(</code><i>col_index</i><code>|</code><i>col_name</i><code>)</code>.
   * Note: it is more performant to access rows by column index than by column name.</p>
   *
   * <h3>Advancing and Iterating through a Table</h3>
   *
   * <p>VoltTableRow represents both a row in a table and an iterator for all the
   * rows in the table. For a given table, each VoltTableRow instance has a position
   * value which represents the index represented in the table. To increment the
   * position, call {@link #advanceRow()}. To reset the position, call
   * {@link #resetRowPosition()}, which moves the position before the first row.
   * Note that before you can access fields after a call to resetRowPosition,
   * advanceRow must be called to move to the first row.</p>
   *
   * <h3>Example</h3>
   *
   * <code>
   * VoltTableRow row = table.fetchRow(5);<br>
   * System.out.println(row.getString("foo");<br>
   * row.resetRowPosition();<br>
   * while (row.advanceRow()) {<br>
   * &nbsp;&nbsp;&nbsp;&nbsp;System.out.println(row.getLong(7));<br>
   * }
   * </code>
   */
  public abstract class VoltTableRow {
  
      /**
       * Size in bytes of the maximum length for a VoltDB tuple.
       * This is inclusive of the 4-byte row length prefix.
       *
       * 2 megs to allow a max size string/varbinary + length prefix + some other stuff
       */
      public static final int MAX_TUPLE_LENGTH = 2097152;
      /**
       * String representation of <code>MAX_TUPLE_LENGTH</code>.
       */
      public static final String MAX_TUPLE_LENGTH_STR = String.valueOf(MAX_TUPLE_LENGTH / 1024) + "k";
  
      static final int ROW_HEADER_SIZE = Integer.SIZE/8;
      static final int ROW_COUNT_SIZE = Integer.SIZE/8;
      static final int STRING_LEN_SIZE = Integer.SIZE/8;
      static final int VARBINARY_LEN_SIZE = Integer.SIZE/8;
      static final int INVALID_ROW_INDEX = -1;
  
      /** Stores the row data (and possibly much more) */
      ByteBuffer m_buffer;
      /** Was the last value retrieved null? */
      boolean m_wasNull = false;
      /** Where in the buffer is the start of the active row's data */
      int m_position = -1;
      /** Offsets of each column in the buffer */
      int[] m_offsets;
      /** Have the offsets been calculated */
      boolean m_hasCalculatedOffsets = false;
  
      int m_activeRowIndex = INVALID_ROW_INDEX;
  
      VoltTableRow() {}
  
      /**
       * Return the {@link VoltType type} of the column with the specified index.
       * @param columnIndex Index of the column
       * @return {@link VoltType VoltType} of the column
       */
      abstract public VoltType getColumnType(int columnIndex);
  
      /**
       * Return the index of the column with the specified column name.
       * @param columnName Name of the column
       * @return Index of the column
       */
      abstract public int getColumnIndex(String columnName);
  
      /**
       * Returns the number of columns in the table schema
       * @return Number of columns in the table schema
       */
      abstract public int getColumnCount();
  
      /**
       * Returns the number of rows.
       * @return Number of rows in the table
       */
      abstract int getRowCount();
  
      abstract int getRowStart();
  
      /**
       * Provide a way to efficiently compare two schemas belonging to a table or row.
       * @return A byte string uniquely identifying the schema of the table.
       */
      abstract byte[] getSchemaString();
  
      /**
       * Clone a row. The new instance returned will have an independent
       * position from the original instance.
       * @return A deep copy of the current <tt>VoltTableRow</tt> instance.
       */
      public abstract VoltTableRow cloneRow();
  
      private final void ensureCalculatedOffsets() {
          if (m_hasCalculatedOffsets == true)
              return;
  
          m_offsets[0] = m_position;
          for (int i = 1; i < getColumnCount(); i++) {
              final VoltType type = getColumnType(i - 1);
              // handle variable length types specially
              if (type.isVariableLength()) {
                  final int len = m_buffer.getInt(m_offsets[i - 1]);
                  if (len == VoltTable.NULL_STRING_INDICATOR) {
                      m_offsets[i] = m_offsets[i - 1] + STRING_LEN_SIZE;
                  }
                  else if (len < 0) {
                      throw new RuntimeException("Invalid object length for column: " + i);
                  }
                  else {
                      m_offsets[i] = m_offsets[i - 1] + len + STRING_LEN_SIZE;
                  }
              }
              else {
                  m_offsets[i] = m_offsets[i - 1] + type.getLengthInBytesForFixedTypes();
              }
          }
          m_hasCalculatedOffsets = true;
      }
  
      public final int getOffset(int index) {
          ensureCalculatedOffsets();
          assert(index >= 0);
          assert(index < m_offsets.length);
          return m_offsets[index];
      }
  
      /**
       * Sets the active position indicator so that the next call
       * to {@link #advanceRow()} will make the first record active.
       * This never needs to be called if the table is only going to
       * be scanned once. After this call {@link #getActiveRowIndex()}
       * will return -1 until {@link #advanceRow()} is called.
       */
      public void resetRowPosition() {
          m_activeRowIndex = INVALID_ROW_INDEX;
      }
  
      /**
       * Get the position in the table of this row instance, starting
       * at zero for the first row.
       * @return The index of the active row or -1 if none.
       */
      public int getActiveRowIndex() {
          return m_activeRowIndex;
      }
  
      /**
       * Makes the next row active so calls to getXXX() will return
       * values from the current record. At initialization time, the
       * active row index is -1, which is invalid. If advanced past the
       * end of the resultset, {@link #resetRowPosition()} must be
       * called to re-iterate through the rows.
       * @return True if a valid row became active. False otherwise.
       */
      public boolean advanceRow() {
          return advanceToRow(m_activeRowIndex + 1);
      }
  
      /**
       * Advance to a specific row so calls to getXXX() will return values from
       * the current record. At initialization time, the active row index is -1,
       * which is invalid. If advanced past the end of the resultset,
       * {@link #resetRowPosition()} must be called to re-iterate through the
       * rows.
       *
       * @param rowIndex The row to jump to.
       * @return True if a valid row became active. False otherwise.
       */
      public boolean advanceToRow(int rowIndex) {
          int rows_to_move = rowIndex - m_activeRowIndex;
          m_activeRowIndex = rowIndex;
  
          if (m_activeRowIndex >= getRowCount()) {
              return false;
          }
          if (rows_to_move < 0) {// this is "advance" to row, don't move backwards
              return false;
          }
  
          m_hasCalculatedOffsets = false;
          if (m_offsets == null) {
              m_offsets = new int[getColumnCount()];
          }
  
          if (m_activeRowIndex == 0) {
              m_position = getRowStart() + ROW_COUNT_SIZE + ROW_HEADER_SIZE;
          }
          else {
              // Move n rows - this code assumes rows can be variable size, so we
              // have to fetch the size of each row in order to advance to the
              // next row
              if (rows_to_move > 0 && m_position < 0)
                  throw new RuntimeException(
                          "VoltTableRow is in an invalid state. Consider calling advanceRow().");
  
              for (int i = 0; i < rows_to_move; i++) {
                  int rowlength = m_buffer.getInt(m_position - ROW_HEADER_SIZE);
                  if (rowlength <= 0) {
                      throw new RuntimeException("Invalid row length.");
                  }
  
                  m_position += (rowlength + ROW_HEADER_SIZE);
              }
  
              if (m_position >= m_buffer.limit()) {
                  throw new RuntimeException("Row length exceeds table boundary.");
              }
          }
  
          return true;
      }
  
      /**
       * Retrieve a value from the row by specifying the column index and the {@link VoltType type}.
       * This method is slower then linking directly against the type specific getter. Prefer the
       * type specific getter methods where viable. Looking at the return value is not a reliable
       * way to check if the value is <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnIndex Index of the column
       * @param type {@link VoltType} of the value
       * @return The value or <tt>null</tt> if the value is not set.
       * @see #wasNull()
       */
      public final Object get(int columnIndex, VoltType type) {
          Object ret = null;
          switch (type) {
          case TINYINT:
              ret = new Byte((byte)getLong(columnIndex));
              break;
          case SMALLINT:
              ret = new Short((short)getLong(columnIndex));
              break;
          case INTEGER:
              ret = new Integer((int)getLong(columnIndex));
              break;
          case BIGINT:
              ret = getLong(columnIndex);
              break;
          case FLOAT:
              ret = getDouble(columnIndex);
              break;
          case STRING:
              ret = getString(columnIndex);
              break;
          case VARBINARY:
              ret = getVarbinary(columnIndex);
              break;
          case TIMESTAMP:
              ret = getTimestampAsTimestamp(columnIndex);
              break;
          case DECIMAL:
              ret = getDecimalAsBigDecimal(columnIndex);
              break;
          case GEOGRAPHY_POINT:
              ret = getGeographyPointValue(columnIndex);
              break;
          case GEOGRAPHY:
              ret = getGeographyValue(columnIndex);
              break;
          default:
              throw new IllegalArgumentException("Invalid type '" + type + "'");
          }
          return ret;
      }
  
      /**
       * Retrieve a value from the row by specifying the column name and the
       * {@link VoltType type}. This method is slower then linking directly
       * against the type specific getter. Prefer the type specific getter methods
       * where viable. Looking at the return value is not a reliable way to check
       * if the value is <tt>null</tt>. Use {@link #wasNull()} instead.
       *
       * @param columnName
       *            Name of the column
       * @param type
       *            {@link VoltType} of the value
       * @return The value or <tt>null</tt> if the value is not set.
       * @see #wasNull()
       */
      public final Object get(String columnName, VoltType type) {
          final int colIndex = getColumnIndex(columnName);
          return get(colIndex, type);
      }
  
      /**
       * Retrieve the <tt>long</tt> value stored in the column specified by index.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead.
       *
       * @param columnIndex
       *            Index of the column
       * @return <tt>long</tt> value stored in the specified column
       * @see #wasNull()
       */
      public final long getLong(int columnIndex) {
          if (columnIndex < 0) {
              throw new IndexOutOfBoundsException("Column index " + columnIndex + " is negative");
          }
          if (columnIndex >= getColumnCount()) {
              throw new IndexOutOfBoundsException("Column index " + columnIndex +
                      " is beyond number of columns " + getColumnCount());
          }
          final VoltType type = getColumnType(columnIndex);
          if (m_activeRowIndex == INVALID_ROW_INDEX)
              throw new RuntimeException("VoltTableRow.advanceRow() must be called to advance to the first row before any access.");
  
          switch (type) {
          case TINYINT:
              final byte value1 = m_buffer.get(getOffset(columnIndex));
              m_wasNull = (value1 == VoltType.NULL_TINYINT);
              return value1;
          case SMALLINT:
              final short value2 = m_buffer.getShort(getOffset(columnIndex));
              m_wasNull = (value2 == VoltType.NULL_SMALLINT);
              return value2;
          case INTEGER:
              final int value3 = m_buffer.getInt(getOffset(columnIndex));
              m_wasNull = (value3 == VoltType.NULL_INTEGER);
              return value3;
          case BIGINT:
              final long value4 = m_buffer.getLong(getOffset(columnIndex));
              m_wasNull = (value4 == VoltType.NULL_BIGINT);
              return value4;
          default:
              throw new IllegalArgumentException("getLong() called on non-integral column.");
          }
      }
  
      /**
       * Retrieve the <tt>long</tt> value stored in the column
       * specified by name. Avoid retrieving via this method as it is slower than specifying the
       * column by index. Use {@link #getLong(int)} instead.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnName Name of the column
       * @return <tt>long</tt> value stored in the specified column
       * @see #wasNull()
       * @see #getLong(int)
       */
      public final long getLong(String columnName) {
          final int colIndex = getColumnIndex(columnName);
          return getLong(colIndex);
      }
  
      /**
       * Returns whether last retrieved value was <tt>null</tt>.
       * Some special values that are NOT Java's NULL represents <tt>null</tt> the SQL notion of <tt>null</tt>
       * in our system.
       * @return <tt>true</tt> if the value was <tt>null</tt>, false otherwise.
       */
      public final boolean wasNull() {
          return m_wasNull;
      }
  
      /**
       * @return A slice of the underlying buffer containing the raw data of a row
       * in a format that can be blindly copied into a VoltDB with sufficient space
       * and the exact same schema.
       */
      final ByteBuffer getRawRow() {
          int rowSize = m_buffer.getInt(m_position - ROW_HEADER_SIZE);
          int pos = m_buffer.position();
          m_buffer.position(m_position - ROW_HEADER_SIZE);
          ByteBuffer retval = m_buffer.slice();
          m_buffer.position(pos);
          retval.limit(ROW_HEADER_SIZE + rowSize);
          return retval;
      }
  
      /**
       * A way to get a column value in raw byte form without doing any
       * expensive conversions, like date processing or string encoding.
       *
       * Next optimization is to do this without an allocation (maybe).
       *
       * @param columnIndex Index of the column
       * @return A byte string containing the raw byte value.
       */
      final byte[] getRaw(int columnIndex) {
          byte[] retval;
          int pos = m_buffer.position();
          int offset = getOffset(columnIndex);
          VoltType type = getColumnType(columnIndex);
  
          switch(type) {
          case TINYINT:
          case SMALLINT:
          case INTEGER:
          case BIGINT:
          case TIMESTAMP:
          case FLOAT:
          case DECIMAL:
          case GEOGRAPHY_POINT: {
              // all of these types are fixed length, so easy to get raw type
              int length = type.getLengthInBytesForFixedTypesWithoutCheck();
              retval = new byte[length];
              m_buffer.position(offset);
              m_buffer.get(retval);
              m_buffer.position(pos);
              return retval;
          }
          case STRING:
          case VARBINARY:
          case GEOGRAPHY: {
              // all of these types are variable length with a prefix
              int length = m_buffer.getInt(offset);
              if (length == VoltTable.NULL_STRING_INDICATOR) {
                  length = 0;
              }
              length += 4;
              retval = new byte[length];
              m_buffer.position(offset);
              m_buffer.get(retval);
              m_buffer.position(pos);
              return retval;
          }
          default:
              throw new RuntimeException("Unknown type");
          }
      }
  
      /**
       * Retrieve the <tt>double</tt> value stored in the column specified by index.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnIndex Index of the column
       * @return <tt>double</tt> value stored in the specified column
       * @see #wasNull()
       */
      public final double getDouble(int columnIndex) {
          validateColumnType(columnIndex, VoltType.FLOAT);
          final double value = m_buffer.getDouble(getOffset(columnIndex));
          m_wasNull = (value <= VoltType.NULL_FLOAT); // see value.h
          return value;
      }
  
      /**
       * Retrieve the <tt>double</tt> value stored in the column
       * specified by name. Avoid retrieving via this method as it is slower than specifying the
       * column by index. Use {@link #getDouble(int)} instead.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnName Name of the column
       * @return <tt>double</tt> value stored in the specified column
       * @see #wasNull()
       * @see #getDouble(int)
       */
      public final double getDouble(String columnName) {
          final int colIndex = getColumnIndex(columnName);
          return getDouble(colIndex);
      }
  
      /**
       * Retrieve the {@link java.lang.String String} value stored in the column specified by index.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead. If at all possible you should use {@link #getStringAsBytes(int)} instead
       * and avoid the overhead of constructing the {@link java.lang.String String} object.
       * @param columnIndex Index of the column
       * @return {@link java.lang.String String} value stored in the specified column
       * @see #wasNull()
       */
      public final String getString(int columnIndex) {
          validateColumnType(columnIndex, VoltType.STRING);
          String retval = readString(getOffset(columnIndex), VoltTable.ROWDATA_ENCODING);
          m_wasNull = (retval == null);
          return retval;
      }
  
      /**
       * Retrieve the {@link java.lang.String String} value stored in the column
       * specified by name. Avoid retrieving via this method as it is slower than specifying the
       * column by index. Use {@link #getString(int)} instead.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead. If at all possible you should use {@link #getStringAsBytes(int)} instead
       * and avoid the overhead of constructing the {@link java.lang.String String} object.
       * @param columnName Name of the column
       * @return {@link java.lang.String String} value stored in the specified column
       * @see #wasNull()
       * @see #getString(int)
       */
      public final String getString(String columnName) {
          final int colIndex = getColumnIndex(columnName);
          return getString(colIndex);
      }
  
      /**
       * Retrieve the <tt>string</tt> value stored in the column specified by index as
       * an array of bytes. Assume UTF-8 encoding for all string values in VoltDB.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnIndex Index of the column
       * @return <tt>string</tt> value stored in the specified column as a <tt>byte[]</tt>
       * @see #wasNull()
       */
      public final byte[] getStringAsBytes(int columnIndex) {
          validateColumnType(columnIndex, VoltType.STRING);
          int pos = m_buffer.position();
          m_buffer.position(getOffset(columnIndex));
          int len = m_buffer.getInt();
          if (len == VoltTable.NULL_STRING_INDICATOR) {
              m_wasNull = true;
              m_buffer.position(pos);
              return null;
          }
          m_wasNull = false;
          byte[] data = new byte[len];
          m_buffer.get(data);
          m_buffer.position(pos);
          return data;
      }
  
      /**
       * Retrieve the <tt>string</tt> value stored in the column
       * specified by name as an array of bytes. Assume UTF-8 encoding for all
       * string values in VoltDB.Avoid retrieving via this method as it is slower
       * than specifying the column by index. Use {@link #getStringAsBytes(int)} instead.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnName Name of the column
       * @return <tt>string</tt> value stored in the specified column as a <tt>byte[]</tt>
       * @see #wasNull()
       * @see #getStringAsBytes(int)
       */
      public final byte[] getStringAsBytes(String columnName) {
          final int colIndex = getColumnIndex(columnName);
          return getStringAsBytes(colIndex);
      }
  
      /**
       * Retrieve the varbinary value stored in the column specified by index.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnIndex Index of the column
       * @return Varbinary value stored in the specified column
       * @see #wasNull()
       */
      public final byte[] getVarbinary(int columnIndex) {
          validateColumnType(columnIndex, VoltType.VARBINARY);
          int pos = m_buffer.position();
          m_buffer.position(getOffset(columnIndex));
          // Sanity check the varbinary size int position.
          if (VARBINARY_LEN_SIZE > m_buffer.remaining()) {
              throw new RuntimeException(String.format(
                      "VoltTableRow::getVarbinary: Can't read varbinary size as %d byte integer " +
                      "from buffer with %d bytes remaining.",
                      VARBINARY_LEN_SIZE, m_buffer.remaining()));
          }
          int len = m_buffer.getInt();
          if (len == VoltTable.NULL_STRING_INDICATOR) {
              m_wasNull = true;
              m_buffer.position(pos);
              return null;
          }
          // Sanity check the size against the remaining buffer size.
          if (len > m_buffer.remaining()) {
              throw new RuntimeException(String.format(
                      "VoltTableRow::getVarbinary: Can't read %d byte varbinary " +
                      "from buffer with %d bytes remaining.", len, m_buffer.remaining()));
          }
          m_wasNull = false;
          byte[] data = new byte[len];
          m_buffer.get(data);
          m_buffer.position(pos);
          return data;
      }
  
      /**
       * Retrieve the varbinary value stored in the column
       * specified by name. Avoid retrieving via this method as it is slower than specifying the
       * column by index. Use {@link #getVarbinary(int)} instead.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnName Name of the column
       * @return Varbinary value stored in the specified column
       * @see #wasNull()
       * @see #getVarbinary(int)
       */
      public final byte[] getVarbinary(String columnName) {
          final int colIndex = getColumnIndex(columnName);
          return getVarbinary(colIndex);
      }
  
      /**
       * Retrieve the GeographyPointValue value stored in the column specified by index.
       * Looking at the return value is not a reliable way to check if the value is
       * <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnIndex Index of the column
       * @return GeographyPointValue value stored in the specified column
       * @see #wasNull()
       */
      public final GeographyPointValue getGeographyPointValue(int columnIndex) {
          validateColumnType(columnIndex, VoltType.GEOGRAPHY_POINT);
          GeographyPointValue pt = GeographyPointValue.unflattenFromBuffer(m_buffer, getOffset(columnIndex));
          m_wasNull = (pt == null);
          return pt;
      }
  
      /**
       * Retrieve the GeographyPointValue value stored in the column specified by name.
       * Avoid retrieving via this method as it is slower than specifying the column
       * by index. Use {@link #getGeographyPointValue(int)} instead.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnName Name of the column
       * @return GeographyPointValue value stored in the specified column
       * @see #wasNull()
       * @see #getGeographyPointValue(int)
       */
      public final GeographyPointValue getGeographyPointValue(String columnName) {
          final int colIndex = getColumnIndex(columnName);
          return getGeographyPointValue(colIndex);
      }
  
      /**
       * Retrieve the GeographyValue value stored in the column specified by index.
       * Looking at the return value is not a reliable way to check if the value is
       * <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnIndex Index of the column
       * @return GeographyValue value stored in the specified column
       * @see #wasNull()
       */
      public final GeographyValue getGeographyValue(int columnIndex) {
          validateColumnType(columnIndex, VoltType.GEOGRAPHY);
          int offset = getOffset(columnIndex);
          int len = m_buffer.getInt(offset);
          if (len == VoltTable.NULL_STRING_INDICATOR) {
              m_wasNull = true;
              return null;
          }
  
          m_wasNull = false;
          offset += 4;
          GeographyValue gv = GeographyValue.unflattenFromBuffer(m_buffer, offset);
          return gv;
      }
  
      /**
       * Retrieve the GeographyValue value stored in the column specified by name.
       * Avoid retrieving via this method as it is slower than specifying the column
       * by index. Use {@link #getGeographyValue(int)} instead.
       * Looking at the return value is not a reliable way to check if the value
       * is <tt>null</tt>. Use {@link #wasNull()} instead.
       * @param columnName Name of the column
       * @return GeographyValue value stored in the specified column
       * @see #wasNull()
       * @see #getGeographyPointValue(int)
       */
      public final GeographyValue getGeographyValue(String columnName) {
          final int colIndex = getColumnIndex(columnName);
          return getGeographyValue(colIndex);
      }
  
  
      /**
       * Retrieve the <tt>long</tt> timestamp stored in the column specified by index.
       * Note that VoltDB uses GMT universally within its process space. Date objects sent over
       * the wire from clients may seem to be different times because of this, but it is just
       * a time zone offset. Timestamps represent microseconds from epoch.
       * @param columnIndex Index of the column
       * @return <tt>long</tt> timestamp value stored in the specified column
       * @see #wasNull()
       * @see #getTimestampAsTimestamp(int)
       */
      public final long getTimestampAsLong(int columnIndex) {
          validateColumnType(columnIndex, VoltType.TIMESTAMP);
          final long value = m_buffer.getLong(getOffset(columnIndex));
          m_wasNull = (value == Long.MIN_VALUE); // see value.h
          return value;
      }
  
      /**
       * Retrieve the <tt>long</tt> timestamp value stored in the column
       * specified by name. Note that VoltDB uses GMT universally within its
       * process space. Date objects sent over the wire from clients may seem
       * to be different times because of this, but it is just a time zone offset.
       * Avoid retrieving via this method as it is slower than specifying the
       * column by index. Use {@link #getTimestampAsLong(int)} instead.
       * @param columnName Name of the column
       * @return <tt>long</tt> timestamp value stored in the specified column
       * @see #wasNull()
       * @see #getTimestampAsLong(int)
       * @see #getTimestampAsTimestamp(String)
       */
      public final long getTimestampAsLong(String columnName) {
          final int colIndex = getColumnIndex(columnName);
          return getTimestampAsLong(colIndex);
      }
  
      /**
       * Retrieve the {@link org.voltdb.types.TimestampType TimestampType}
       * value stored in the column specified by index.
       * Note that VoltDB uses GMT universally within its process space. Date objects sent over
       * the wire from clients may seem to be different times because of this, but it is just
       * a time zone offset.
       * @param columnIndex Index of the column
       * @return {@link org.voltdb.types.TimestampType TimestampType}
       * value stored in the specified column
       * @see #wasNull()
       */
      public final TimestampType getTimestampAsTimestamp(int columnIndex) {
          final long timestamp = getTimestampAsLong(columnIndex);
          if (m_wasNull) return null;
          return new TimestampType(timestamp);
      }
  
      /**
       * Retrieve the {@link org.voltdb.types.TimestampType TimestampType} value stored in the column
       * specified by name. Note that VoltDB uses GMT universally within its
       * process space. Date objects sent over the wire from clients may seem
       * to be different times because of this, but it is just a time zone offset.
       * Avoid retrieving via this method as it is slower than specifying the
       * column by index. Use {@link #getTimestampAsTimestamp(int)} instead.
       * @param columnName Name of the column
       * @return {@link org.voltdb.types.TimestampType TimestampType}
       * value stored in the specified column
       * @see #wasNull()
       * @see #getTimestampAsTimestamp(int)
       */
      public final TimestampType getTimestampAsTimestamp(String columnName) {
          final int colIndex = getColumnIndex(columnName);
          return getTimestampAsTimestamp(colIndex);
      }
  
      /**
       * Retrieve the <tt>java.sql.Timestamp</tt> equivalent to the value stored in the column specified by index.
       * Note that VoltDB uses GMT universally within its process space. Date objects sent over
       * the wire from clients may seem to be different times because of this, but it is just
       * a time zone offset. VoltDB Timestamps are stored as long integer microseconds from epoch.
       * The resulting value is accurate to no finer than microsecond granularity.
       * @param columnIndex Index of the column
       * @return the <tt>java.sql.Timestamp</tt> equivalent to the value stored in the specified column
       */
      public final java.sql.Timestamp getTimestampAsSqlTimestamp(int columnIndex) {
          final long timestamp = getTimestampAsLong(columnIndex);
          if (m_wasNull) return null;
  
          return VoltTypeUtil.getSqlTimestampFromMicrosSinceEpoch(timestamp);
      }
  
      /**
       * Retrieve the <tt>java.sql.Timestamp</tt> equivalent to the value stored in the column specified by name.
       * Note that VoltDB uses GMT universally within its process space. Date objects sent over
       * the wire from clients may seem to be different times because of this, but it is just
       * a time zone offset. VoltDB Timestamps are stored as long integer microseconds from epoch.
       * The resulting value is accurate to no finer than microsecond granularity.
       * Avoid retrieving via this method as it is slower than specifying the
       * column by index. Use {@link #getTimestampAsSqlTimestamp(int)} instead.
       * @param columnName name of the column
       * @return the <tt>java.sql.Timestamp</tt> equivalent to the value stored in the specified column
       */
      public java.sql.Timestamp getTimestampAsSqlTimestamp(String columnName) {
          final int colIndex = getColumnIndex(columnName);
          return getTimestampAsSqlTimestamp(colIndex);
      }
  
      /**
       * <p>Retrieve the {@link BigDecimal} value stored in the column
       * specified by the index. All DECIMAL types have a fixed
       * scale when represented as BigDecimals.</p>
       *
       * @param columnIndex Index of the column
       * @return BigDecimal representation.
       * @see #wasNull()
       */
      public final BigDecimal getDecimalAsBigDecimal(int columnIndex) {
          validateColumnType(columnIndex, VoltType.DECIMAL);
          final int position = m_buffer.position();
          m_buffer.position(getOffset(columnIndex));
          final BigDecimal bd = VoltDecimalHelper.deserializeBigDecimal(m_buffer);
          m_buffer.position(position);
          m_wasNull = bd == null ? true : false;
          return bd;
      }
  
      /**
       * Retrieve the {@link BigDecimal} value stored in the column
       * specified by columnName. All DECIMAL types have a
       * fixed scale when represented as BigDecimals.
       * @param columnName Name of the column
       * @return BigDecimal representation.
       * @see #wasNull()
       * @see #getDecimalAsBigDecimal(int)
       */
      public BigDecimal getDecimalAsBigDecimal(String columnName) {
          int colIndex = getColumnIndex(columnName);
          return getDecimalAsBigDecimal(colIndex);
      }
  
      static final String GEOJSON_TYPE_KEY           = "type";
      static final String GEOJSON_COORDS_KEY         = "coordinates";
      // This is not "GeographyPoint".  This is used in geojson syntax.
      static final String GEOJSON_POINT_TYPE_SIGIL   = "Point";
      static final String GEOJSON_POLYGON_TYPE_SIGIL = "Polygon";
      /**
       *
       * @param columnIndex
       * @param js
       * @throws JSONException
       */
      void putJSONRep(int columnIndex, JSONStringer js) throws JSONException {
          long value; double dvalue;
  
          VoltType columnType = getColumnType(columnIndex);
          switch (columnType) {
          case TINYINT:
              value = getLong(columnIndex);
              if (wasNull()) {
                  js.valueNull();
              }
              else {
                  js.value(value);
              }
              break;
          case SMALLINT:
              value = getLong(columnIndex);
              if (wasNull()) {
                  js.valueNull();
              }
              else {
                  js.value(value);
              }
              break;
          case INTEGER:
              value = getLong(columnIndex);
              if (wasNull()) {
                  js.valueNull();
              }
              else {
                  js.value(value);
              }
              break;
          case BIGINT:
              value = getLong(columnIndex);
              if (wasNull()) {
                  js.valueNull();
              }
              else {
                  js.value(value);
              }
              break;
          case TIMESTAMP:
              value = getTimestampAsLong(columnIndex);
              if (wasNull()) {
                  js.valueNull();
              }
              else {
                  js.value(value);
              }
              break;
          case FLOAT:
              dvalue = getDouble(columnIndex);
              if (wasNull()) {
                  js.valueNull();
              }
              else if (Double.isNaN(dvalue)) {
                  js.value(Double.toString(dvalue));
              }
              else if (Double.isInfinite(dvalue)) {
                  js.value(Double.toString(dvalue));
              }
              else {
                  js.value(dvalue);
              }
              break;
          case STRING:
              js.value(getString(columnIndex));
              break;
          case VARBINARY:
              byte[] bin = getVarbinary(columnIndex);
              js.value(Encoder.hexEncode(bin));
              break;
          case DECIMAL:
              Object dec = getDecimalAsBigDecimal(columnIndex);
              if (wasNull()) {
                  js.valueNull();
              }
              else {
                  js.value(dec.toString());
              }
              break;
          case GEOGRAPHY_POINT:
              GeographyPointValue pt = getGeographyPointValue(columnIndex);
              if (wasNull()) {
                  js.valueNull();
              }
              else {
                  js.value(pt.toString());
              }
              break;
          case GEOGRAPHY:
              GeographyValue gv = getGeographyValue(columnIndex);
              if (wasNull()) {
                  js.valueNull();
              }
              else {
                  js.value(gv.toString());
              }
              break;
          // VoltType includes a few values that aren't valid column value types
          case INVALID:
              break;
          case NULL:
              break;
          case NUMERIC:
              break;
          case BOOLEAN:
              break;
          case VOLTTABLE:
              break;
          }
      }
  
      /**
       * This converts a GeographyValue to GEOJSON. We currently don't use it
       * because the VMC does not know what to do with GEOJSON. But it's left here
       * in the hope that it will be useful in the future.
       *
       * @param gv
       * @param js
       * @throws JSONException
      @SuppressWarnings("unused")
      static private void geographyValueToJSON(GeographyValue gv, JSONStringer js) throws JSONException {
          js.object()
            .key(GEOJSON_TYPE_KEY)
            .value(GEOJSON_POLYGON_TYPE_SIGIL)
            .key(GEOJSON_COORDS_KEY)
            .array();
          for (List<GeographyPointValue> loops : gv.getLoops()) {
              js.array();
  