package org.postgresql.jdbc;
import org.postgresql.PGResultSetMetaData;
import org.postgresql.PGStatement;
import org.postgresql.core.BaseConnection;
import org.postgresql.core.BaseStatement;
import org.postgresql.core.Encoding;
import org.postgresql.core.Field;
import org.postgresql.core.Oid;
import org.postgresql.core.Query;
import org.postgresql.core.ResultCursor;
import org.postgresql.core.ResultHandlerBase;
import org.postgresql.core.TypeInfo;
import org.postgresql.core.Utils;
import org.postgresql.util.ByteConverter;
import org.postgresql.util.GT;
import org.postgresql.util.HStoreConverter;
import org.postgresql.util.PGbytea;
import org.postgresql.util.PGobject;
import org.postgresql.util.PGtokenizer;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;
import java.io.ByteArrayInputStream;
import java.io.CharArrayReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
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.sql.Types;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultSet {
private boolean updateable = false;
private boolean doingUpdates = false;
private HashMap<String, Object> updateValues = null;
private boolean usingOID = false;
private List<PrimaryKey> primaryKeys;
private boolean singleTable = false;
private String onlyTable = "";
private String tableName = null;
private PreparedStatement updateStatement = null;
private PreparedStatement insertStatement = null;
private PreparedStatement deleteStatement = null;
private PreparedStatement selectStatement = null;
private final int resultsettype;
private final int resultsetconcurrency;
private int fetchdirection = ResultSet.FETCH_UNKNOWN;
private TimeZone defaultTimeZone;
protected final BaseConnection connection;
protected final BaseStatement statement;
protected final Field[] fields;
protected final Query originalQuery;
protected final int maxRows;
protected final int maxFieldSize;
protected List<byte[][]> rows;
protected int currentRow = -1;
protected int rowOffset;
protected byte[][] thisRow;
protected SQLWarning warnings = null;
protected boolean wasNullFlag = false;
protected boolean onInsertRow = false;
private byte[][] rowBuffer = null;
protected int fetchSize;
protected ResultCursor cursor;
private Map<String, Integer> columnNameIndexMap;
private ResultSetMetaData rsMetaData;
protected ResultSetMetaData createMetaData() throws SQLException {
return new PgResultSetMetaData(connection, fields);
}
public ResultSetMetaData getMetaData() throws SQLException {
checkClosed();
if (rsMetaData == null) {
rsMetaData = createMetaData();
}
return rsMetaData;
}
PgResultSet(Query originalQuery, BaseStatement statement, Field[] fields, List<byte[][]> tuples,
ResultCursor cursor, int maxRows, int maxFieldSize, int rsType, int rsConcurrency,
int rsHoldability) throws SQLException {
if (tuples == null) {
throw new NullPointerException("tuples must be non-null");
}
if (fields == null) {
throw new NullPointerException("fields must be non-null");
}
this.originalQuery = originalQuery;
this.connection = (BaseConnection) statement.getConnection();
this.statement = statement;
this.fields = fields;
this.rows = tuples;
this.cursor = cursor;
this.maxRows = maxRows;
this.maxFieldSize = maxFieldSize;
this.resultsettype = rsType;
this.resultsetconcurrency = rsConcurrency;
}
public java.net.URL getURL(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getURL columnIndex: {0}", columnIndex);
checkClosed();
throw org.postgresql.Driver.notImplemented(this.getClass(), "getURL(int)");
}
public java.net.URL getURL(String columnName) throws SQLException {
return getURL(findColumn(columnName));
}
protected Object internalGetObject(int columnIndex, Field field) throws SQLException {
switch (getSQLType(columnIndex)) {
case Types.BOOLEAN:
case Types.BIT:
return getBoolean(columnIndex);
case Types.SQLXML:
return getSQLXML(columnIndex);
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
return getInt(columnIndex);
case Types.BIGINT:
return getLong(columnIndex);
case Types.NUMERIC:
case Types.DECIMAL:
return getNumeric(columnIndex,
(field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff), true);
case Types.REAL:
return getFloat(columnIndex);
case Types.FLOAT:
case Types.DOUBLE:
return getDouble(columnIndex);
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
return getString(columnIndex);
case Types.DATE:
return getDate(columnIndex);
case Types.TIME:
return getTime(columnIndex);
case Types.TIMESTAMP:
return getTimestamp(columnIndex, null);
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
return getBytes(columnIndex);
case Types.ARRAY:
return getArray(columnIndex);
case Types.CLOB:
return getClob(columnIndex);
case Types.BLOB:
return getBlob(columnIndex);
default:
String type = getPGType(columnIndex);
if (type.equals("unknown")) {
return getString(columnIndex);
}
if (type.equals("uuid")) {
if (isBinary(columnIndex)) {
return getUUID(thisRow[columnIndex - 1]);
}
return getUUID(getString(columnIndex));
}
if (type.equals("refcursor")) {
String cursorName = getString(columnIndex);
StringBuilder sb = new StringBuilder("FETCH ALL IN ");
Utils.escapeIdentifier(sb, cursorName);
ResultSet rs =
connection.execSQLQuery(sb.toString(), resultsettype, ResultSet.CONCUR_READ_ONLY);
sb.setLength(0);
sb.append("CLOSE ");
Utils.escapeIdentifier(sb, cursorName);
connection.execSQLUpdate(sb.toString());
((PgResultSet) rs).setRefCursor(cursorName);
return rs;
}
if ("hstore".equals(type)) {
if (isBinary(columnIndex)) {
return HStoreConverter.fromBytes(thisRow[columnIndex - 1], connection.getEncoding());
}
return HStoreConverter.fromString(getString(columnIndex));
}
return null;
}
}
private void checkScrollable() throws SQLException {
checkClosed();
if (resultsettype == ResultSet.TYPE_FORWARD_ONLY) {
throw new PSQLException(
GT.tr("Operation requires a scrollable ResultSet, but this ResultSet is FORWARD_ONLY."),
PSQLState.INVALID_CURSOR_STATE);
}
}
@Override
public boolean absolute(int index) throws SQLException {
checkScrollable();
int internalIndex;
if (index == 0) {
beforeFirst();
return false;
}
final int rows_size = rows.size();
if (index < 0) {
if (index >= -rows_size) {
internalIndex = rows_size + index;
} else {
beforeFirst();
return false;
}
} else {
if (index <= rows_size) {
internalIndex = index - 1;
} else {
afterLast();
return false;
}
}
currentRow = internalIndex;
initRowBuffer();
onInsertRow = false;
return true;
}
@Override
public void afterLast() throws SQLException {
checkScrollable();
final int rows_size = rows.size();
if (rows_size > 0) {
currentRow = rows_size;
}
onInsertRow = false;
thisRow = null;
rowBuffer = null;
}
@Override
public void beforeFirst() throws SQLException {
checkScrollable();
if (!rows.isEmpty()) {
currentRow = -1;
}
onInsertRow = false;
thisRow = null;
rowBuffer = null;
}
@Override
public boolean first() throws SQLException {
checkScrollable();
if (rows.size() <= 0) {
return false;
}
currentRow = 0;
initRowBuffer();
onInsertRow = false;
return true;
}
@Override
public Array getArray(String colName) throws SQLException {
return getArray(findColumn(colName));
}
protected Array makeArray(int oid, byte[] value) throws SQLException {
return new PgArray(connection, oid, value);
}
protected Array makeArray(int oid, String value) throws SQLException {
return new PgArray(connection, oid, value);
}
@Override
public Array getArray(int i) throws SQLException {
checkResultSet(i);
if (wasNullFlag) {
return null;
}
int oid = fields[i - 1].getOID();
if (isBinary(i)) {
return makeArray(oid, thisRow[i - 1]);
}
return makeArray(oid, getFixedString(i));
}
public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException {
return getBigDecimal(columnIndex, -1);
}
public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException {
return getBigDecimal(findColumn(columnName));
}
public Blob getBlob(String columnName) throws SQLException {
return getBlob(findColumn(columnName));
}
protected Blob makeBlob(long oid) throws SQLException {
return new PgBlob(connection, oid);
}
public Blob getBlob(int i) throws SQLException {
checkResultSet(i);
if (wasNullFlag) {
return null;
}
return makeBlob(getLong(i));
}
public java.io.Reader getCharacterStream(String columnName) throws SQLException {
return getCharacterStream(findColumn(columnName));
}
public java.io.Reader getCharacterStream(int i) throws SQLException {
checkResultSet(i);
if (wasNullFlag) {
return null;
}
return new CharArrayReader(getString(i).toCharArray());
}
public Clob getClob(String columnName) throws SQLException {
return getClob(findColumn(columnName));
}
protected Clob makeClob(long oid) throws SQLException {
return new PgClob(connection, oid);
}
public Clob getClob(int i) throws SQLException {
checkResultSet(i);
if (wasNullFlag) {
return null;
}
return makeClob(getLong(i));
}
public int getConcurrency() throws SQLException {
checkClosed();
return resultsetconcurrency;
}
@Override
public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException {
checkResultSet(i);
if (wasNullFlag) {
return null;
}
if (cal == null) {
cal = getDefaultCalendar();
}
if (isBinary(i)) {
int col = i - 1;
int oid = fields[col].getOID();
TimeZone tz = cal.getTimeZone();
if (oid == Oid.DATE) {
return connection.getTimestampUtils().toDateBin(tz, thisRow[col]);
} else if (oid == Oid.TIMESTAMP || oid == Oid.TIMESTAMPTZ) {
Timestamp timestamp = getTimestamp(i, cal);
return connection.getTimestampUtils().convertToDate(timestamp.getTime(), tz);
} else {
throw new PSQLException(
GT.tr("Cannot convert the column of type {0} to requested type {1}.",
Oid.toString(oid), "date"),
PSQLState.DATA_TYPE_MISMATCH);
}
}
return connection.getTimestampUtils().toDate(cal, getString(i));
}
@Override
public Time getTime(int i, java.util.Calendar cal) throws SQLException {
checkResultSet(i);
if (wasNullFlag) {
return null;
}
if (cal == null) {
cal = getDefaultCalendar();
}
if (isBinary(i)) {
int col = i - 1;
int oid = fields[col].getOID();
TimeZone tz = cal.getTimeZone();
if (oid == Oid.TIME || oid == Oid.TIMETZ) {
return connection.getTimestampUtils().toTimeBin(tz, thisRow[col]);
} else if (oid == Oid.TIMESTAMP || oid == Oid.TIMESTAMPTZ) {
Timestamp timestamp = getTimestamp(i, cal);
long timeMillis = timestamp.getTime();
if (oid == Oid.TIMESTAMPTZ) {
return new Time(timeMillis % TimeUnit.DAYS.toMillis(1));
}
return connection.getTimestampUtils().convertToTime(timeMillis, tz);
} else {
throw new PSQLException(
GT.tr("Cannot convert the column of type {0} to requested type {1}.",
Oid.toString(oid), "time"),
PSQLState.DATA_TYPE_MISMATCH);
}
}
String string = getString(i);
return connection.getTimestampUtils().toTime(cal, string);
}
private LocalTime getLocalTime(int i) throws SQLException {
checkResultSet(i);
if (wasNullFlag) {
return null;
}
if (isBinary(i)) {
int col = i - 1;
int oid = fields[col].getOID();
if (oid == Oid.TIME) {
return connection.getTimestampUtils().toLocalTimeBin(thisRow[col]);
} else {
throw new PSQLException(
GT.tr("Cannot convert the column of type {0} to requested type {1}.",
Oid.toString(oid), "time"),
PSQLState.DATA_TYPE_MISMATCH);
}
}
String string = getString(i);
return connection.getTimestampUtils().toLocalTime(string);
}
@Override
public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException {
checkResultSet(i);
if (wasNullFlag) {
return null;
}
if (cal == null) {
cal = getDefaultCalendar();
}
int col = i - 1;
int oid = fields[col].getOID();
if (isBinary(i)) {
if (oid == Oid.TIMESTAMPTZ || oid == Oid.TIMESTAMP) {
boolean hasTimeZone = oid == Oid.TIMESTAMPTZ;
TimeZone tz = cal.getTimeZone();
return connection.getTimestampUtils().toTimestampBin(tz, thisRow[col], hasTimeZone);
} else {
long millis;
if (oid == Oid.TIME || oid == Oid.TIMETZ) {
millis = getTime(i, cal).getTime();
} else if (oid == Oid.DATE) {
millis = getDate(i, cal).getTime();
} else {
throw new PSQLException(
GT.tr("Cannot convert the column of type {0} to requested type {1}.",
Oid.toString(oid), "timestamp"),
PSQLState.DATA_TYPE_MISMATCH);
}
return new Timestamp(millis);
}
}
String string = getString(i);
if (oid == Oid.TIME || oid == Oid.TIMETZ) {
return new Timestamp(connection.getTimestampUtils().toTime(cal, string).getTime());
}
return connection.getTimestampUtils().toTimestamp(cal, string);
}
private LocalDateTime getLocalDateTime(int i) throws SQLException {
checkResultSet(i);
if (wasNullFlag) {
return null;
}
int col = i - 1;
int oid = fields[col].getOID();
if (oid != Oid.TIMESTAMP) {
throw new PSQLException(
GT.tr("Cannot convert the column of type {0} to requested type {1}.",
Oid.toString(oid), "timestamp"),
PSQLState.DATA_TYPE_MISMATCH);
}
if (isBinary(i)) {
TimeZone timeZone = getDefaultCalendar().getTimeZone();
return connection.getTimestampUtils().toLocalDateTimeBin(timeZone, thisRow[col]);
}
String string = getString(i);
return connection.getTimestampUtils().toLocalDateTime(string);
}
public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException {
return getDate(findColumn(c), cal);
}
public Time getTime(String c, java.util.Calendar cal) throws SQLException {
return getTime(findColumn(c), cal);
}
public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException {
return getTimestamp(findColumn(c), cal);
}
public int getFetchDirection() throws SQLException {
checkClosed();
return fetchdirection;
}
public Object getObjectImpl(String columnName, Map<String, Class<?>> map) throws SQLException {
return getObjectImpl(findColumn(columnName), map);
}
public Object getObjectImpl(int i, Map<String, Class<?>> map) throws SQLException {
checkClosed();
if (map == null || map.isEmpty()) {
return getObject(i);
}
throw org.postgresql.Driver.notImplemented(this.getClass(), "getObjectImpl(int,Map)");
}
public Ref getRef(String columnName) throws SQLException {
return getRef(findColumn(columnName));
}
public Ref getRef(int i) throws SQLException {
checkClosed();
throw org.postgresql.Driver.notImplemented(this.getClass(), "getRef(int)");
}
@Override
public int getRow() throws SQLException {
checkClosed();
if (onInsertRow) {
return 0;
}
final int rows_size = rows.size();
if (currentRow < 0 || currentRow >= rows_size) {
return 0;
}
return rowOffset + currentRow + 1;
}
public Statement getStatement() throws SQLException {
checkClosed();
return statement;
}
public int getType() throws SQLException {
checkClosed();
return resultsettype;
}
@Override
public boolean isAfterLast() throws SQLException {
checkClosed();
if (onInsertRow) {
return false;
}
final int rows_size = rows.size();
if (rowOffset + rows_size == 0) {
return false;
}
return (currentRow >= rows_size);
}
@Override
public boolean isBeforeFirst() throws SQLException {
checkClosed();
if (onInsertRow) {
return false;
}
return ((rowOffset + currentRow) < 0 && !rows.isEmpty());
}
@Override
public boolean isFirst() throws SQLException {
checkClosed();
if (onInsertRow) {
return false;
}
final int rows_size = rows.size();
if (rowOffset + rows_size == 0) {
return false;
}
return ((rowOffset + currentRow) == 0);
}
@Override
public boolean isLast() throws SQLException {
checkClosed();
if (onInsertRow) {
return false;
}
final int rows_size = rows.size();
if (rows_size == 0) {
return false;
}
if (currentRow != (rows_size - 1)) {
return false;
}
if (cursor == null) {
return true;
}
if (maxRows > 0 && rowOffset + currentRow == maxRows) {
return true;
}
rowOffset += rows_size - 1;
int fetchRows = fetchSize;
if (maxRows != 0) {
if (fetchRows == 0 || rowOffset + fetchRows > maxRows) {
fetchRows = maxRows - rowOffset;
}
}
connection.getQueryExecutor().fetch(cursor, new CursorResultHandler(), fetchRows);
rows.add(0, thisRow);
currentRow = 0;
return (rows.size() == 1);
}
@Override
public boolean last() throws SQLException {
checkScrollable();
final int rows_size = rows.size();
if (rows_size <= 0) {
return false;
}
currentRow = rows_size - 1;
initRowBuffer();
onInsertRow = false;
return true;
}
@Override
public boolean previous() throws SQLException {
checkScrollable();
if (onInsertRow) {
throw new PSQLException(GT.tr("Can''t use relative move methods while on the insert row."),
PSQLState.INVALID_CURSOR_STATE);
}
if (currentRow - 1 < 0) {
currentRow = -1;
thisRow = null;
rowBuffer = null;
return false;
} else {
currentRow--;
}
initRowBuffer();
return true;
}
@Override
public boolean relative(int rows) throws SQLException {
checkScrollable();
if (onInsertRow) {
throw new PSQLException(GT.tr("Can''t use relative move methods while on the insert row."),
PSQLState.INVALID_CURSOR_STATE);
}
int index = currentRow + 1 + rows;
if (index < 0) {
beforeFirst();
return false;
}
return absolute(index);
}
public void setFetchDirection(int direction) throws SQLException {
checkClosed();
switch (direction) {
case ResultSet.FETCH_FORWARD:
break;
case ResultSet.FETCH_REVERSE:
case ResultSet.FETCH_UNKNOWN:
checkScrollable();
break;
default:
throw new PSQLException(GT.tr("Invalid fetch direction constant: {0}.", direction),
PSQLState.INVALID_PARAMETER_VALUE);
}
this.fetchdirection = direction;
}
public synchronized void cancelRowUpdates() throws SQLException {
checkClosed();
if (onInsertRow) {
throw new PSQLException(GT.tr("Cannot call cancelRowUpdates() when on the insert row."),
PSQLState.INVALID_CURSOR_STATE);
}
if (doingUpdates) {
doingUpdates = false;
clearRowBuffer(true);
}
}
public synchronized void deleteRow() throws SQLException {
checkUpdateable();
if (onInsertRow) {
throw new PSQLException(GT.tr("Cannot call deleteRow() when on the insert row."),
PSQLState.INVALID_CURSOR_STATE);
}
if (isBeforeFirst()) {
throw new PSQLException(
GT.tr(
"Currently positioned before the start of the ResultSet. You cannot call deleteRow() here."),
PSQLState.INVALID_CURSOR_STATE);
}
if (isAfterLast()) {
throw new PSQLException(
GT.tr(
"Currently positioned after the end of the ResultSet. You cannot call deleteRow() here."),
PSQLState.INVALID_CURSOR_STATE);
}
if (rows.isEmpty()) {
throw new PSQLException(GT.tr("There are no rows in this ResultSet."),
PSQLState.INVALID_CURSOR_STATE);
}
int numKeys = primaryKeys.size();
if (deleteStatement == null) {
StringBuilder deleteSQL =
new StringBuilder("DELETE FROM ").append(onlyTable).append(tableName).append(" where ");
for (int i = 0; i < numKeys; i++) {
Utils.escapeIdentifier(deleteSQL, primaryKeys.get(i).name);
deleteSQL.append(" = ?");
if (i < numKeys - 1) {
deleteSQL.append(" and ");
}
}
deleteStatement = connection.prepareStatement(deleteSQL.toString());
}
deleteStatement.clearParameters();
for (int i = 0; i < numKeys; i++) {
deleteStatement.setObject(i + 1, primaryKeys.get(i).getValue());
}
deleteStatement.executeUpdate();
rows.remove(currentRow);
currentRow--;
moveToCurrentRow();
}
@Override
public synchronized void insertRow() throws SQLException {
checkUpdateable();
if (!onInsertRow) {
throw new PSQLException(GT.tr("Not on the insert row."), PSQLState.INVALID_CURSOR_STATE);
} else if (updateValues.isEmpty()) {
throw new PSQLException(GT.tr("You must specify at least one column value to insert a row."),
PSQLState.INVALID_PARAMETER_VALUE);
} else {
StringBuilder insertSQL = new StringBuilder("INSERT INTO ").append(tableName).append(" (");
StringBuilder paramSQL = new StringBuilder(") values (");
Iterator<String> columnNames = updateValues.keySet().iterator();
int numColumns = updateValues.size();
for (int i = 0; columnNames.hasNext(); i++) {
String columnName = columnNames.next();
Utils.escapeIdentifier(insertSQL, columnName);
if (i < numColumns - 1) {
insertSQL.append(", ");
paramSQL.append("?,");
} else {
paramSQL.append("?)");
}
}
insertSQL.append(paramSQL.toString());
insertStatement = connection.prepareStatement(insertSQL.toString());
Iterator<Object> values = updateValues.values().iterator();
for (int i = 1; values.hasNext(); i++) {
insertStatement.setObject(i, values.next());
}
insertStatement.executeUpdate();
if (usingOID) {
long insertedOID = ((PgStatement) insertStatement).getLastOID();
updateValues.put("oid", insertedOID);
}
updateRowBuffer();
rows.add(rowBuffer);
thisRow = rowBuffer;
clearRowBuffer(false);
}
}
@Override
public synchronized void moveToCurrentRow() throws SQLException {
checkUpdateable();
if (currentRow < 0 || currentRow >= rows.size()) {
thisRow = null;
rowBuffer = null;
} else {
initRowBuffer();
}
onInsertRow = false;
doingUpdates = false;
}
@Override
public synchronized void moveToInsertRow() throws SQLException {
checkUpdateable();
if (insertStatement != null) {
insertStatement = null;
}
clearRowBuffer(false);
onInsertRow = true;
doingUpdates = false;
}
private synchronized void clearRowBuffer(boolean copyCurrentRow) throws SQLException {
rowBuffer = new byte[fields.length][];
if (copyCurrentRow) {
System.arraycopy(thisRow, 0, rowBuffer, 0, thisRow.length);
}
updateValues.clear();
}
public boolean rowDeleted() throws SQLException {
checkClosed();
return false;
}
public boolean rowInserted() throws SQLException {
checkClosed();
return false;
}
public boolean rowUpdated() throws SQLException {
checkClosed();
return false;
}
public synchronized void updateAsciiStream(int columnIndex, java.io.InputStream x, int length)
throws SQLException {
if (x == null) {
updateNull(columnIndex);
return;
}
try {
InputStreamReader reader = new InputStreamReader(x, "ASCII");
char[] data = new char[length];
int numRead = 0;
while (true) {
int n = reader.read(data, numRead, length - numRead);
if (n == -1) {
break;
}
numRead += n;
if (numRead == length) {
break;
}
}
updateString(columnIndex, new String(data, 0, numRead));
} catch (UnsupportedEncodingException uee) {
throw new PSQLException(GT.tr("The JVM claims not to support the encoding: {0}", "ASCII"),
PSQLState.UNEXPECTED_ERROR, uee);
} catch (IOException ie) {
throw new PSQLException(GT.tr("Provided InputStream failed."), null, ie);
}
}
public synchronized void updateBigDecimal(int columnIndex, java.math.BigDecimal x)
throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateBinaryStream(int columnIndex, java.io.InputStream x, int length)
throws SQLException {
if (x == null) {
updateNull(columnIndex);
return;
}
byte[] data = new byte[length];
int numRead = 0;
try {
while (true) {
int n = x.read(data, numRead, length - numRead);
if (n == -1) {
break;
}
numRead += n;
if (numRead == length) {
break;
}
}
} catch (IOException ie) {
throw new PSQLException(GT.tr("Provided InputStream failed."), null, ie);
}
if (numRead == length) {
updateBytes(columnIndex, data);
} else {
byte[] data2 = new byte[numRead];
System.arraycopy(data, 0, data2, 0, numRead);
updateBytes(columnIndex, data2);
}
}
public synchronized void updateBoolean(int columnIndex, boolean x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateByte(int columnIndex, byte x) throws SQLException {
updateValue(columnIndex, String.valueOf(x));
}
public synchronized void updateBytes(int columnIndex, byte[] x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateCharacterStream(int columnIndex, java.io.Reader x, int length)
throws SQLException {
if (x == null) {
updateNull(columnIndex);
return;
}
try {
char[] data = new char[length];
int numRead = 0;
while (true) {
int n = x.read(data, numRead, length - numRead);
if (n == -1) {
break;
}
numRead += n;
if (numRead == length) {
break;
}
}
updateString(columnIndex, new String(data, 0, numRead));
} catch (IOException ie) {
throw new PSQLException(GT.tr("Provided Reader failed."), null, ie);
}
}
public synchronized void updateDate(int columnIndex, java.sql.Date x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateDouble(int columnIndex, double x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateFloat(int columnIndex, float x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateInt(int columnIndex, int x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateLong(int columnIndex, long x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateNull(int columnIndex) throws SQLException {
checkColumnIndex(columnIndex);
String columnTypeName = getPGType(columnIndex);
updateValue(columnIndex, new NullObject(columnTypeName));
}
public synchronized void updateObject(int columnIndex, Object x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateObject(int columnIndex, Object x, int scale) throws SQLException {
this.updateObject(columnIndex, x);
}
@Override
public void refreshRow() throws SQLException {
checkUpdateable();
if (onInsertRow) {
throw new PSQLException(GT.tr("Can''t refresh the insert row."),
PSQLState.INVALID_CURSOR_STATE);
}
if (isBeforeFirst() || isAfterLast() || rows.isEmpty()) {
return;
}
StringBuilder selectSQL = new StringBuilder("select ");
ResultSetMetaData rsmd = getMetaData();
PGResultSetMetaData pgmd = (PGResultSetMetaData) rsmd;
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
if (i > 1) {
selectSQL.append(", ");
}
selectSQL.append(pgmd.getBaseColumnName(i));
}
selectSQL.append(" from ").append(onlyTable).append(tableName).append(" where ");
int numKeys = primaryKeys.size();
for (int i = 0; i < numKeys; i++) {
PrimaryKey primaryKey = primaryKeys.get(i);
selectSQL.append(primaryKey.name).append("= ?");
if (i < numKeys - 1) {
selectSQL.append(" and ");
}
}
String sqlText = selectSQL.toString();
if (connection.getLogger().isLoggable(Level.FINE)) {
connection.getLogger().log(Level.FINE, "selecting {0}", sqlText);
}
selectStatement = connection.prepareStatement(sqlText,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
for (int j = 0, i = 1; j < numKeys; j++, i++) {
selectStatement.setObject(i, primaryKeys.get(j).getValue());
}
PgResultSet rs = (PgResultSet) selectStatement.executeQuery();
if (rs.next()) {
rowBuffer = rs.thisRow;
}
rows.set(currentRow, rowBuffer);
thisRow = rowBuffer;
connection.getLogger().log(Level.FINE, "done updates");
rs.close();
selectStatement.close();
selectStatement = null;
}
@Override
public synchronized void updateRow() throws SQLException {
checkUpdateable();
if (onInsertRow) {
throw new PSQLException(GT.tr("Cannot call updateRow() when on the insert row."),
PSQLState.INVALID_CURSOR_STATE);
}
if (isBeforeFirst() || isAfterLast() || rows.isEmpty()) {
throw new PSQLException(
GT.tr(
"Cannot update the ResultSet because it is either before the start or after the end of the results."),
PSQLState.INVALID_CURSOR_STATE);
}
if (!doingUpdates) {
return;
}
StringBuilder updateSQL = new StringBuilder("UPDATE " + onlyTable + tableName + " SET ");
int numColumns = updateValues.size();
Iterator<String> columns = updateValues.keySet().iterator();
for (int i = 0; columns.hasNext(); i++) {
String column = columns.next();
Utils.escapeIdentifier(updateSQL, column);
updateSQL.append(" = ?");
if (i < numColumns - 1) {
updateSQL.append(", ");
}
}
updateSQL.append(" WHERE ");
int numKeys = primaryKeys.size();
for (int i = 0; i < numKeys; i++) {
PrimaryKey primaryKey = primaryKeys.get(i);
Utils.escapeIdentifier(updateSQL, primaryKey.name);
updateSQL.append(" = ?");
if (i < numKeys - 1) {
updateSQL.append(" and ");
}
}
String sqlText = updateSQL.toString();
if (connection.getLogger().isLoggable(Level.FINE)) {
connection.getLogger().log(Level.FINE, "updating {0}", sqlText);
}
updateStatement = connection.prepareStatement(sqlText);
int i = 0;
Iterator<Object> iterator = updateValues.values().iterator();
for (; iterator.hasNext(); i++) {
Object o = iterator.next();
updateStatement.setObject(i + 1, o);
}
for (int j = 0; j < numKeys; j++, i++) {
updateStatement.setObject(i + 1, primaryKeys.get(j).getValue());
}
updateStatement.executeUpdate();
updateStatement.close();
updateStatement = null;
updateRowBuffer();
connection.getLogger().log(Level.FINE, "copying data");
System.arraycopy(rowBuffer, 0, thisRow, 0, rowBuffer.length);
rows.set(currentRow, rowBuffer);
connection.getLogger().log(Level.FINE, "done updates");
updateValues.clear();
doingUpdates = false;
}
public synchronized void updateShort(int columnIndex, short x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateString(int columnIndex, String x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateTime(int columnIndex, Time x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
updateValue(columnIndex, x);
}
public synchronized void updateNull(String columnName) throws SQLException {
updateNull(findColumn(columnName));
}
public synchronized void updateBoolean(String columnName, boolean x) throws SQLException {
updateBoolean(findColumn(columnName), x);
}
public synchronized void updateByte(String columnName, byte x) throws SQLException {
updateByte(findColumn(columnName), x);
}
public synchronized void updateShort(String columnName, short x) throws SQLException {
updateShort(findColumn(columnName), x);
}
public synchronized void updateInt(String columnName, int x) throws SQLException {
updateInt(findColumn(columnName), x);
}
public synchronized void updateLong(String columnName, long x) throws SQLException {
updateLong(findColumn(columnName), x);
}
public synchronized void updateFloat(String columnName, float x) throws SQLException {
updateFloat(findColumn(columnName), x);
}
public synchronized void updateDouble(String columnName, double x) throws SQLException {
updateDouble(findColumn(columnName), x);
}
public synchronized void updateBigDecimal(String columnName, BigDecimal x) throws SQLException {
updateBigDecimal(findColumn(columnName), x);
}
public synchronized void updateString(String columnName, String x) throws SQLException {
updateString(findColumn(columnName), x);
}
public synchronized void updateBytes(String columnName, byte[] x) throws SQLException {
updateBytes(findColumn(columnName), x);
}
public synchronized void updateDate(String columnName, java.sql.Date x) throws SQLException {
updateDate(findColumn(columnName), x);
}
public synchronized void updateTime(String columnName, java.sql.Time x) throws SQLException {
updateTime(findColumn(columnName), x);
}
public synchronized void updateTimestamp(String columnName, java.sql.Timestamp x)
throws SQLException {
updateTimestamp(findColumn(columnName), x);
}
public synchronized void updateAsciiStream(String columnName, java.io.InputStream x, int length)
throws SQLException {
updateAsciiStream(findColumn(columnName), x, length);
}
public synchronized void updateBinaryStream(String columnName, java.io.InputStream x, int length)
throws SQLException {
updateBinaryStream(findColumn(columnName), x, length);
}
public synchronized void updateCharacterStream(String columnName, java.io.Reader reader,
int length) throws SQLException {
updateCharacterStream(findColumn(columnName), reader, length);
}
public synchronized void updateObject(String columnName, Object x, int scale)
throws SQLException {
updateObject(findColumn(columnName), x);
}
public synchronized void updateObject(String columnName, Object x) throws SQLException {
updateObject(findColumn(columnName), x);
}
boolean isUpdateable() throws SQLException {
checkClosed();
if (resultsetconcurrency == ResultSet.CONCUR_READ_ONLY) {
throw new PSQLException(
GT.tr("ResultSets with concurrency CONCUR_READ_ONLY cannot be updated."),
PSQLState.INVALID_CURSOR_STATE);
}
if (updateable) {
return true;
}
connection.getLogger().log(Level.FINE, "checking if rs is updateable");
parseQuery();
if (!singleTable) {
connection.getLogger().log(Level.FINE, "not a single table");
return false;
}
connection.getLogger().log(Level.FINE, "getting primary keys");
primaryKeys = new ArrayList<PrimaryKey>();
usingOID = false;
int oidIndex = findColumnIndex("oid");
int i = 0;
int numPKcolumns = 0;
if (oidIndex > 0) {
i++;
numPKcolumns++;
primaryKeys.add(new PrimaryKey(oidIndex, "oid"));
usingOID = true;
} else {
String[] s = quotelessTableName(tableName);
String quotelessTableName = s[0];
String quotelessSchemaName = s[1];
java.sql.ResultSet rs = connection.getMetaData().getPrimaryKeys("",
quotelessSchemaName, quotelessTableName);
while (rs.next()) {
numPKcolumns++;
String columnName = rs.getString(4);
int index = findColumnIndex(columnName);
if (index > 0) {
i++;
primaryKeys.add(new PrimaryKey(index, columnName));
}
}
rs.close();
}
connection.getLogger().log(Level.FINE, "no of keys={0}", i);
if (i < 1) {
throw new PSQLException(GT.tr("No primary key found for table {0}.", tableName),
PSQLState.DATA_ERROR);
}
updateable = (i == numPKcolumns);
connection.getLogger().log(Level.FINE, "checking primary key {0}", updateable);
return updateable;
}
public static String[] quotelessTableName(String fullname) {
String[] parts = new String[]{null, ""};
StringBuilder acc = new StringBuilder();
boolean betweenQuotes = false;
for (int i = 0; i < fullname.length(); i++) {
char c = fullname.charAt(i);
switch (c) {
case '"':
if ((i < fullname.length() - 1) && (fullname.charAt(i + 1) == '"')) {
i++;
acc.append(c);
} else {
betweenQuotes = !betweenQuotes;
}
break;
case '.':
if (betweenQuotes) {
acc.append(c);
} else {
parts[1] = acc.toString();
acc = new StringBuilder();
}
break;
default:
acc.append((betweenQuotes) ? c : Character.toLowerCase(c));
break;
}
}
parts[0] = acc.toString();
return parts;
}
private void parseQuery() {
String sql = originalQuery.toString(null);
StringTokenizer st = new StringTokenizer(sql, " \r\t\n");
boolean tableFound = false;
boolean tablesChecked = false;
String name = "";
singleTable = true;
while (!tableFound && !tablesChecked && st.hasMoreTokens()) {
name = st.nextToken();
if ("from".equalsIgnoreCase(name)) {
tableName = st.nextToken();
if ("only".equalsIgnoreCase(tableName)) {
tableName = st.nextToken();
onlyTable = "ONLY ";
}
tableFound = true;
}
}
}
private void updateRowBuffer() throws SQLException {
for (Map.Entry<String, Object> entry : updateValues.entrySet()) {
int columnIndex = findColumn(entry.getKey()) - 1;
Object valueObject = entry.getValue();
if (valueObject instanceof PGobject) {
String value = ((PGobject) valueObject).getValue();
rowBuffer[columnIndex] = (value == null) ? null : connection.encodeString(value);
} else {
switch (getSQLType(columnIndex + 1)) {
case Types.DATE:
rowBuffer[columnIndex] = connection
.encodeString(
connection.getTimestampUtils().toString(
getDefaultCalendar(), (Date) valueObject));
break;
case Types.TIME:
rowBuffer[columnIndex] = connection
.encodeString(
connection.getTimestampUtils().toString(
getDefaultCalendar(), (Time) valueObject));
break;
case Types.TIMESTAMP:
rowBuffer[columnIndex] = connection.encodeString(
connection.getTimestampUtils().toString(
getDefaultCalendar(), (Timestamp) valueObject));
break;
case Types.NULL:
break;
case Types.BINARY:
case Types.LONGVARBINARY:
case Types.VARBINARY:
if (isBinary(columnIndex + 1)) {
rowBuffer[columnIndex] = (byte[]) valueObject;
} else {
try {
rowBuffer[columnIndex] =
PGbytea.toPGString((byte[]) valueObject).getBytes("ISO-8859-1");
} catch (UnsupportedEncodingException e) {
throw new PSQLException(
GT.tr("The JVM claims not to support the encoding: {0}", "ISO-8859-1"),
PSQLState.UNEXPECTED_ERROR, e);
}
}
break;
default:
rowBuffer[columnIndex] = connection.encodeString(String.valueOf(valueObject));
break;
}
}
}
}
public class CursorResultHandler extends ResultHandlerBase {
public void handleResultRows(Query fromQuery, Field[] fields, List<byte[][]> tuples,
ResultCursor cursor) {
PgResultSet.this.rows = tuples;
PgResultSet.this.cursor = cursor;
}
public void handleCommandStatus(String status, int updateCount, long insertOID) {
handleError(new PSQLException(GT.tr("Unexpected command status: {0}.", status),
PSQLState.PROTOCOL_VIOLATION));
}
public void handleCompletion() throws SQLException {
SQLWarning warning = getWarning();
if (warning != null) {
PgResultSet.this.addWarning(warning);
}
super.handleCompletion();
}
}
public BaseStatement getPGStatement() {
return statement;
}
private String refCursorName;
public String getRefCursor() {
return refCursorName;
}
private void setRefCursor(String refCursorName) {
this.refCursorName = refCursorName;
}
public void setFetchSize(int rows) throws SQLException {
checkClosed();
if (rows < 0) {
throw new PSQLException(GT.tr("Fetch size must be a value greater to or equal to 0."),
PSQLState.INVALID_PARAMETER_VALUE);
}
fetchSize = rows;
}
public int getFetchSize() throws SQLException {
checkClosed();
return fetchSize;
}
@Override
public boolean next() throws SQLException {
checkClosed();
if (onInsertRow) {
throw new PSQLException(GT.tr("Can''t use relative move methods while on the insert row."),
PSQLState.INVALID_CURSOR_STATE);
}
if (currentRow + 1 >= rows.size()) {
if (cursor == null || (maxRows > 0 && rowOffset + rows.size() >= maxRows)) {
currentRow = rows.size();
thisRow = null;
rowBuffer = null;
return false;
}
rowOffset += rows.size();
int fetchRows = fetchSize;
if (maxRows != 0) {
if (fetchRows == 0 || rowOffset + fetchRows > maxRows) {
fetchRows = maxRows - rowOffset;
}
}
connection.getQueryExecutor().fetch(cursor, new CursorResultHandler(), fetchRows);
currentRow = 0;
if (rows.isEmpty()) {
thisRow = null;
rowBuffer = null;
return false;
}
} else {
currentRow++;
}
initRowBuffer();
return true;
}
public void close() throws SQLException {
try {
rows = null;
if (cursor != null) {
cursor.close();
cursor = null;
}
} finally {
((PgStatement) statement).checkCompletion();
}
}
public boolean wasNull() throws SQLException {
checkClosed();
return wasNullFlag;
}
@Override
public String getString(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getString columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return null;
}
if (isBinary(columnIndex) && getSQLType(columnIndex) != Types.VARCHAR) {
Field field = fields[columnIndex - 1];
Object obj = internalGetObject(columnIndex, field);
if (obj == null) {
obj = getObject(columnIndex);
if (obj == null) {
return null;
}
return obj.toString();
}
if (obj instanceof java.util.Date) {
int oid = field.getOID();
return connection.getTimestampUtils().timeToString((java.util.Date) obj,
oid == Oid.TIMESTAMPTZ || oid == Oid.TIMETZ);
}
if ("hstore".equals(getPGType(columnIndex))) {
return HStoreConverter.toString((Map<?, ?>) obj);
}
return trimString(columnIndex, obj.toString());
}
Encoding encoding = connection.getEncoding();
try {
return trimString(columnIndex, encoding.decode(thisRow[columnIndex - 1]));
} catch (IOException ioe) {
throw new PSQLException(
GT.tr(
"Invalid character data was found. This is most likely caused by stored data containing characters that are invalid for the character set the database was created in. The most common example of this is storing 8bit data in a SQL_ASCII database."),
PSQLState.DATA_ERROR, ioe);
}
}
@Override
public boolean getBoolean(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getBoolean columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return false;
}
int col = columnIndex - 1;
if (Oid.BOOL == fields[col].getOID()) {
final byte[] v = thisRow[col];
return (1 == v.length) && (116 == v[0]);
}
if (isBinary(columnIndex)) {
return BooleanTypeUtil.castToBoolean(readDoubleValue(thisRow[col], fields[col].getOID(), "boolean"));
}
return BooleanTypeUtil.castToBoolean(getString(columnIndex));
}
private static final BigInteger BYTEMAX = new BigInteger(Byte.toString(Byte.MAX_VALUE));
private static final BigInteger BYTEMIN = new BigInteger(Byte.toString(Byte.MIN_VALUE));
@Override
public byte getByte(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getByte columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return 0;
}
if (isBinary(columnIndex)) {
int col = columnIndex - 1;
return (byte) readLongValue(thisRow[col], fields[col].getOID(), Byte.MIN_VALUE,
Byte.MAX_VALUE, "byte");
}
String s = getString(columnIndex);
if (s != null) {
s = s.trim();
if (s.isEmpty()) {
return 0;
}
try {
return Byte.parseByte(s);
} catch (NumberFormatException e) {
try {
BigDecimal n = new BigDecimal(s);
BigInteger i = n.toBigInteger();
int gt = i.compareTo(BYTEMAX);
int lt = i.compareTo(BYTEMIN);
if (gt > 0 || lt < 0) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "byte", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
return i.byteValue();
} catch (NumberFormatException ex) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "byte", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
}
}
return 0;
}
@Override
public short getShort(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getShort columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return 0;
}
if (isBinary(columnIndex)) {
int col = columnIndex - 1;
int oid = fields[col].getOID();
if (oid == Oid.INT2) {
return ByteConverter.int2(thisRow[col], 0);
}
return (short) readLongValue(thisRow[col], oid, Short.MIN_VALUE, Short.MAX_VALUE, "short");
}
return toShort(getFixedString(columnIndex));
}
@Override
public int getInt(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getInt columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return 0;
}
if (isBinary(columnIndex)) {
int col = columnIndex - 1;
int oid = fields[col].getOID();
if (oid == Oid.INT4) {
return ByteConverter.int4(thisRow[col], 0);
}
return (int) readLongValue(thisRow[col], oid, Integer.MIN_VALUE, Integer.MAX_VALUE, "int");
}
Encoding encoding = connection.getEncoding();
if (encoding.hasAsciiNumbers()) {
try {
return getFastInt(columnIndex);
} catch (NumberFormatException ex) {
}
}
return toInt(getFixedString(columnIndex));
}
@Override
public long getLong(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getLong columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return 0;
}
if (isBinary(columnIndex)) {
int col = columnIndex - 1;
int oid = fields[col].getOID();
if (oid == Oid.INT8) {
return ByteConverter.int8(thisRow[col], 0);
}
return readLongValue(thisRow[col], oid, Long.MIN_VALUE, Long.MAX_VALUE, "long");
}
Encoding encoding = connection.getEncoding();
if (encoding.hasAsciiNumbers()) {
try {
return getFastLong(columnIndex);
} catch (NumberFormatException ex) {
}
}
return toLong(getFixedString(columnIndex));
}
private static final NumberFormatException FAST_NUMBER_FAILED = new NumberFormatException() {
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
};
private long getFastLong(int columnIndex) throws SQLException, NumberFormatException {
byte[] bytes = thisRow[columnIndex - 1];
if (bytes.length == 0) {
throw FAST_NUMBER_FAILED;
}
long val = 0;
int start;
boolean neg;
if (bytes[0] == '-') {
neg = true;
start = 1;
if (bytes.length == 1 || bytes.length > 19) {
throw FAST_NUMBER_FAILED;
}
} else {
start = 0;
neg = false;
if (bytes.length > 18) {
throw FAST_NUMBER_FAILED;
}
}
while (start < bytes.length) {
byte b = bytes[start++];
if (b < '0' || b > '9') {
throw FAST_NUMBER_FAILED;
}
val *= 10;
val += b - '0';
}
if (neg) {
val = -val;
}
return val;
}
private int getFastInt(int columnIndex) throws SQLException, NumberFormatException {
byte[] bytes = thisRow[columnIndex - 1];
if (bytes.length == 0) {
throw FAST_NUMBER_FAILED;
}
int val = 0;
int start;
boolean neg;
if (bytes[0] == '-') {
neg = true;
start = 1;
if (bytes.length == 1 || bytes.length > 10) {
throw FAST_NUMBER_FAILED;
}
} else {
start = 0;
neg = false;
if (bytes.length > 9) {
throw FAST_NUMBER_FAILED;
}
}
while (start < bytes.length) {
byte b = bytes[start++];
if (b < '0' || b > '9') {
throw FAST_NUMBER_FAILED;
}
val *= 10;
val += b - '0';
}
if (neg) {
val = -val;
}
return val;
}
private BigDecimal getFastBigDecimal(int columnIndex) throws SQLException, NumberFormatException {
byte[] bytes = thisRow[columnIndex - 1];
if (bytes.length == 0) {
throw FAST_NUMBER_FAILED;
}
int scale = 0;
long val = 0;
int start;
boolean neg;
if (bytes[0] == '-') {
neg = true;
start = 1;
if (bytes.length == 1 || bytes.length > 19) {
throw FAST_NUMBER_FAILED;
}
} else {
start = 0;
neg = false;
if (bytes.length > 18) {
throw FAST_NUMBER_FAILED;
}
}
int periodsSeen = 0;
while (start < bytes.length) {
byte b = bytes[start++];
if (b < '0' || b > '9') {
if (b == '.') {
scale = bytes.length - start;
periodsSeen++;
continue;
} else {
throw FAST_NUMBER_FAILED;
}
}
val *= 10;
val += b - '0';
}
int numNonSignChars = neg ? bytes.length - 1 : bytes.length;
if (periodsSeen > 1 || periodsSeen == numNonSignChars) {
throw FAST_NUMBER_FAILED;
}
if (neg) {
val = -val;
}
return BigDecimal.valueOf(val, scale);
}
@Override
public float getFloat(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getFloat columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return 0;
}
if (isBinary(columnIndex)) {
int col = columnIndex - 1;
int oid = fields[col].getOID();
if (oid == Oid.FLOAT4) {
return ByteConverter.float4(thisRow[col], 0);
}
return (float) readDoubleValue(thisRow[col], oid, "float");
}
return toFloat(getFixedString(columnIndex));
}
@Override
public double getDouble(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getDouble columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return 0;
}
if (isBinary(columnIndex)) {
int col = columnIndex - 1;
int oid = fields[col].getOID();
if (oid == Oid.FLOAT8) {
return ByteConverter.float8(thisRow[col], 0);
}
return readDoubleValue(thisRow[col], oid, "double");
}
return toDouble(getFixedString(columnIndex));
}
public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
connection.getLogger().log(Level.FINEST, " getBigDecimal columnIndex: {0}", columnIndex);
return (BigDecimal) getNumeric(columnIndex, scale, false);
}
private Number getNumeric(int columnIndex, int scale, boolean allowNaN) throws SQLException {
checkResultSet(columnIndex);
if (wasNullFlag) {
return null;
}
if (isBinary(columnIndex)) {
int sqlType = getSQLType(columnIndex);
if (sqlType != Types.NUMERIC && sqlType != Types.DECIMAL) {
Object obj = internalGetObject(columnIndex, fields[columnIndex - 1]);
if (obj == null) {
return null;
}
if (obj instanceof Long || obj instanceof Integer || obj instanceof Byte) {
BigDecimal res = BigDecimal.valueOf(((Number) obj).longValue());
res = scaleBigDecimal(res, scale);
return res;
}
return toBigDecimal(trimMoney(String.valueOf(obj)), scale);
}
}
Encoding encoding = connection.getEncoding();
if (encoding.hasAsciiNumbers()) {
try {
BigDecimal res = getFastBigDecimal(columnIndex);
res = scaleBigDecimal(res, scale);
return res;
} catch (NumberFormatException ignore) {
}
}
String stringValue = getFixedString(columnIndex);
if (allowNaN && "NaN".equalsIgnoreCase(stringValue)) {
return Double.NaN;
}
return toBigDecimal(stringValue, scale);
}
@Override
public byte[] getBytes(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getBytes columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return null;
}
if (isBinary(columnIndex)) {
return thisRow[columnIndex - 1];
}
if (fields[columnIndex - 1].getOID() == Oid.BYTEA) {
return trimBytes(columnIndex, PGbytea.toBytes(thisRow[columnIndex - 1]));
} else {
return trimBytes(columnIndex, thisRow[columnIndex - 1]);
}
}
public java.sql.Date getDate(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getDate columnIndex: {0}", columnIndex);
return getDate(columnIndex, null);
}
public Time getTime(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getTime columnIndex: {0}", columnIndex);
return getTime(columnIndex, null);
}
public Timestamp getTimestamp(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getTimestamp columnIndex: {0}", columnIndex);
return getTimestamp(columnIndex, null);
}
public InputStream getAsciiStream(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getAsciiStream columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return null;
}
try {
return new ByteArrayInputStream(getString(columnIndex).getBytes("ASCII"));
} catch (UnsupportedEncodingException l_uee) {
throw new PSQLException(GT.tr("The JVM claims not to support the encoding: {0}", "ASCII"),
PSQLState.UNEXPECTED_ERROR, l_uee);
}
}
public InputStream getUnicodeStream(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getUnicodeStream columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return null;
}
try {
return new ByteArrayInputStream(getString(columnIndex).getBytes("UTF-8"));
} catch (UnsupportedEncodingException l_uee) {
throw new PSQLException(GT.tr("The JVM claims not to support the encoding: {0}", "UTF-8"),
PSQLState.UNEXPECTED_ERROR, l_uee);
}
}
public InputStream getBinaryStream(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getBinaryStream columnIndex: {0}", columnIndex);
checkResultSet(columnIndex);
if (wasNullFlag) {
return null;
}
byte[] b = getBytes(columnIndex);
if (b != null) {
return new ByteArrayInputStream(b);
}
return null;
}
public String getString(String columnName) throws SQLException {
return getString(findColumn(columnName));
}
@Override
public boolean getBoolean(String columnName) throws SQLException {
return getBoolean(findColumn(columnName));
}
public byte getByte(String columnName) throws SQLException {
return getByte(findColumn(columnName));
}
public short getShort(String columnName) throws SQLException {
return getShort(findColumn(columnName));
}
public int getInt(String columnName) throws SQLException {
return getInt(findColumn(columnName));
}
public long getLong(String columnName) throws SQLException {
return getLong(findColumn(columnName));
}
public float getFloat(String columnName) throws SQLException {
return getFloat(findColumn(columnName));
}
public double getDouble(String columnName) throws SQLException {
return getDouble(findColumn(columnName));
}
public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException {
return getBigDecimal(findColumn(columnName), scale);
}
public byte[] getBytes(String columnName) throws SQLException {
return getBytes(findColumn(columnName));
}
public java.sql.Date getDate(String columnName) throws SQLException {
return getDate(findColumn(columnName), null);
}
public Time getTime(String columnName) throws SQLException {
return getTime(findColumn(columnName), null);
}
public Timestamp getTimestamp(String columnName) throws SQLException {
return getTimestamp(findColumn(columnName), null);
}
public InputStream getAsciiStream(String columnName) throws SQLException {
return getAsciiStream(findColumn(columnName));
}
public InputStream getUnicodeStream(String columnName) throws SQLException {
return getUnicodeStream(findColumn(columnName));
}
public InputStream getBinaryStream(String columnName) throws SQLException {
return getBinaryStream(findColumn(columnName));
}
public SQLWarning getWarnings() throws SQLException {
checkClosed();
return warnings;
}
public void clearWarnings() throws SQLException {
checkClosed();
warnings = null;
}
protected void addWarning(SQLWarning warnings) {
if (this.warnings != null) {
this.warnings.setNextWarning(warnings);
} else {
this.warnings = warnings;
}
}
public String getCursorName() throws SQLException {
checkClosed();
return null;
}
@Override
public Object getObject(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getObject columnIndex: {0}", columnIndex);
Field field;
checkResultSet(columnIndex);
if (wasNullFlag) {
return null;
}
field = fields[columnIndex - 1];
if (field == null) {
wasNullFlag = true;
return null;
}
Object result = internalGetObject(columnIndex, field);
if (result != null) {
return result;
}
if (isBinary(columnIndex)) {
return connection.getObject(getPGType(columnIndex), null, thisRow[columnIndex - 1]);
}
return connection.getObject(getPGType(columnIndex), getString(columnIndex), null);
}
public Object getObject(String columnName) throws SQLException {
return getObject(findColumn(columnName));
}
public int findColumn(String columnName) throws SQLException {
checkClosed();
int col = findColumnIndex(columnName);
if (col == 0) {
throw new PSQLException(
GT.tr("The column name {0} was not found in this ResultSet.", columnName),
PSQLState.UNDEFINED_COLUMN);
}
return col;
}
public static Map<String, Integer> createColumnNameIndexMap(Field[] fields,
boolean isSanitiserDisabled) {
Map<String, Integer> columnNameIndexMap = new HashMap<String, Integer>(fields.length * 2);
for (int i = fields.length - 1; i >= 0; i--) {
String columnLabel = fields[i].getColumnLabel();
if (isSanitiserDisabled) {
columnNameIndexMap.put(columnLabel, i + 1);
} else {
columnNameIndexMap.put(columnLabel.toLowerCase(Locale.US), i + 1);
}
}
return columnNameIndexMap;
}
private int findColumnIndex(String columnName) {
if (columnNameIndexMap == null) {
if (originalQuery != null) {
columnNameIndexMap = originalQuery.getResultSetColumnNameIndexMap();
}
if (columnNameIndexMap == null) {
columnNameIndexMap = createColumnNameIndexMap(fields, connection.isColumnSanitiserDisabled());
}
}
Integer index = columnNameIndexMap.get(columnName);
if (index != null) {
return index;
}
index = columnNameIndexMap.get(columnName.toLowerCase(Locale.US));
if (index != null) {
columnNameIndexMap.put(columnName, index);
return index;
}
index = columnNameIndexMap.get(columnName.toUpperCase(Locale.US));
if (index != null) {
columnNameIndexMap.put(columnName, index);
return index;
}
return 0;
}
public int getColumnOID(int field) {
return fields[field - 1].getOID();
}
public String getFixedString(int col) throws SQLException {
return trimMoney(getString(col));
}
private String trimMoney(String s) {
if (s == null) {
return null;
}
if (s.length() < 2) {
return s;
}
char ch = s.charAt(0);
if (ch > '-') {
return s;
}
if (ch == '(') {
s = "-" + PGtokenizer.removePara(s).substring(1);
} else if (ch == '$') {
s = s.substring(1);
} else if (ch == '-' && s.charAt(1) == '$') {
s = "-" + s.substring(2);
}
return s;
}
protected String getPGType(int column) throws SQLException {
Field field = fields[column - 1];
initSqlType(field);
return field.getPGType();
}
protected int getSQLType(int column) throws SQLException {
Field field = fields[column - 1];
initSqlType(field);
return field.getSQLType();
}
private void initSqlType(Field field) throws SQLException {
if (field.isTypeInitialized()) {
return;
}
TypeInfo typeInfo = connection.getTypeInfo();
int oid = field.getOID();
String pgType = typeInfo.getPGType(oid);
int sqlType = typeInfo.getSQLType(pgType);
field.setSQLType(sqlType);
field.setPGType(pgType);
}
private void checkUpdateable() throws SQLException {
checkClosed();
if (!isUpdateable()) {
throw new PSQLException(
GT.tr(
"ResultSet is not updateable. The query that generated this result set must select only one table, and must select all primary keys from that table. See the JDBC 2.1 API Specification, section 5.6 for more details."),
PSQLState.INVALID_CURSOR_STATE);
}
if (updateValues == null) {
updateValues = new HashMap<String, Object>((int) (fields.length / 0.75), 0.75f);
}
}
protected void checkClosed() throws SQLException {
if (rows == null) {
throw new PSQLException(GT.tr("This ResultSet is closed."), PSQLState.OBJECT_NOT_IN_STATE);
}
}
protected boolean isResultSetClosed() {
return rows == null;
}
protected void checkColumnIndex(int column) throws SQLException {
if (column < 1 || column > fields.length) {
throw new PSQLException(
GT.tr("The column index is out of range: {0}, number of columns: {1}.",
column, fields.length),
PSQLState.INVALID_PARAMETER_VALUE);
}
}
protected void checkResultSet(int column) throws SQLException {
checkClosed();
if (thisRow == null) {
throw new PSQLException(
GT.tr("ResultSet not positioned properly, perhaps you need to call next."),
PSQLState.INVALID_CURSOR_STATE);
}
checkColumnIndex(column);
wasNullFlag = (thisRow[column - 1] == null);
}
protected boolean isBinary(int column) {
return fields[column - 1].getFormat() == Field.BINARY_FORMAT;
}
private static final BigInteger SHORTMAX = new BigInteger(Short.toString(Short.MAX_VALUE));
private static final BigInteger SHORTMIN = new BigInteger(Short.toString(Short.MIN_VALUE));
public static short toShort(String s) throws SQLException {
if (s != null) {
try {
s = s.trim();
return Short.parseShort(s);
} catch (NumberFormatException e) {
try {
BigDecimal n = new BigDecimal(s);
BigInteger i = n.toBigInteger();
int gt = i.compareTo(SHORTMAX);
int lt = i.compareTo(SHORTMIN);
if (gt > 0 || lt < 0) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "short", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
return i.shortValue();
} catch (NumberFormatException ne) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "short", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
}
}
return 0;
}
private static final BigInteger INTMAX = new BigInteger(Integer.toString(Integer.MAX_VALUE));
private static final BigInteger INTMIN = new BigInteger(Integer.toString(Integer.MIN_VALUE));
public static int toInt(String s) throws SQLException {
if (s != null) {
try {
s = s.trim();
return Integer.parseInt(s);
} catch (NumberFormatException e) {
try {
BigDecimal n = new BigDecimal(s);
BigInteger i = n.toBigInteger();
int gt = i.compareTo(INTMAX);
int lt = i.compareTo(INTMIN);
if (gt > 0 || lt < 0) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "int", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
return i.intValue();
} catch (NumberFormatException ne) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "int", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
}
}
return 0;
}
private static final BigInteger LONGMAX = new BigInteger(Long.toString(Long.MAX_VALUE));
private static final BigInteger LONGMIN = new BigInteger(Long.toString(Long.MIN_VALUE));
public static long toLong(String s) throws SQLException {
if (s != null) {
try {
s = s.trim();
return Long.parseLong(s);
} catch (NumberFormatException e) {
try {
BigDecimal n = new BigDecimal(s);
BigInteger i = n.toBigInteger();
int gt = i.compareTo(LONGMAX);
int lt = i.compareTo(LONGMIN);
if (gt > 0 || lt < 0) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "long", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
return i.longValue();
} catch (NumberFormatException ne) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "long", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
}
}
return 0;
}
public static BigDecimal toBigDecimal(String s) throws SQLException {
if (s == null) {
return null;
}
try {
s = s.trim();
return new BigDecimal(s);
} catch (NumberFormatException e) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "BigDecimal", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
}
public BigDecimal toBigDecimal(String s, int scale) throws SQLException {
if (s == null) {
return null;
}
BigDecimal val = toBigDecimal(s);
return scaleBigDecimal(val, scale);
}
private BigDecimal scaleBigDecimal(BigDecimal val, int scale) throws PSQLException {
if (scale == -1) {
return val;
}
try {
return val.setScale(scale);
} catch (ArithmeticException e) {
throw new PSQLException(
GT.tr("Bad value for type {0} : {1}", "BigDecimal", val),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
}
public static float toFloat(String s) throws SQLException {
if (s != null) {
try {
s = s.trim();
return Float.parseFloat(s);
} catch (NumberFormatException e) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "float", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
}
return 0;
}
public static double toDouble(String s) throws SQLException {
if (s != null) {
try {
s = s.trim();
return Double.parseDouble(s);
} catch (NumberFormatException e) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", "double", s),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
}
return 0;
}
private void initRowBuffer() {
thisRow = rows.get(currentRow);
if (resultsetconcurrency == ResultSet.CONCUR_UPDATABLE) {
rowBuffer = new byte[thisRow.length][];
System.arraycopy(thisRow, 0, rowBuffer, 0, thisRow.length);
} else {
rowBuffer = null;
}
}
private boolean isColumnTrimmable(int columnIndex) throws SQLException {
switch (getSQLType(columnIndex)) {
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
return true;
}
return false;
}
private byte[] trimBytes(int columnIndex, byte[] bytes) throws SQLException {
if (maxFieldSize > 0 && bytes.length > maxFieldSize && isColumnTrimmable(columnIndex)) {
byte[] newBytes = new byte[maxFieldSize];
System.arraycopy(bytes, 0, newBytes, 0, maxFieldSize);
return newBytes;
} else {
return bytes;
}
}
private String trimString(int columnIndex, String string) throws SQLException {
if (maxFieldSize > 0 && string.length() > maxFieldSize && isColumnTrimmable(columnIndex)) {
return string.substring(0, maxFieldSize);
} else {
return string;
}
}
private double readDoubleValue(byte[] bytes, int oid, String targetType) throws PSQLException {
switch (oid) {
case Oid.INT2:
return ByteConverter.int2(bytes, 0);
case Oid.INT4:
return ByteConverter.int4(bytes, 0);
case Oid.INT8:
return ByteConverter.int8(bytes, 0);
case Oid.FLOAT4:
return ByteConverter.float4(bytes, 0);
case Oid.FLOAT8:
return ByteConverter.float8(bytes, 0);
}
throw new PSQLException(GT.tr("Cannot convert the column of type {0} to requested type {1}.",
Oid.toString(oid), targetType), PSQLState.DATA_TYPE_MISMATCH);
}
private long readLongValue(byte[] bytes, int oid, long minVal, long maxVal, String targetType)
throws PSQLException {
long val;
switch (oid) {
case Oid.INT2:
val = ByteConverter.int2(bytes, 0);
break;
case Oid.INT4:
val = ByteConverter.int4(bytes, 0);
break;
case Oid.INT8:
val = ByteConverter.int8(bytes, 0);
break;
case Oid.FLOAT4:
val = (long) ByteConverter.float4(bytes, 0);
break;
case Oid.FLOAT8:
val = (long) ByteConverter.float8(bytes, 0);
break;
default:
throw new PSQLException(
GT.tr("Cannot convert the column of type {0} to requested type {1}.",
Oid.toString(oid), targetType),
PSQLState.DATA_TYPE_MISMATCH);
}
if (val < minVal || val > maxVal) {
throw new PSQLException(GT.tr("Bad value for type {0} : {1}", targetType, val),
PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
}
return val;
}
protected void updateValue(int columnIndex, Object value) throws SQLException {
checkUpdateable();
if (!onInsertRow && (isBeforeFirst() || isAfterLast() || rows.isEmpty())) {
throw new PSQLException(
GT.tr(
"Cannot update the ResultSet because it is either before the start or after the end of the results."),
PSQLState.INVALID_CURSOR_STATE);
}
checkColumnIndex(columnIndex);
doingUpdates = !onInsertRow;
if (value == null) {
updateNull(columnIndex);
} else {
PGResultSetMetaData md = (PGResultSetMetaData) getMetaData();
updateValues.put(md.getBaseColumnName(columnIndex), value);
}
}
protected Object getUUID(String data) throws SQLException {
UUID uuid;
try {
uuid = UUID.fromString(data);
} catch (IllegalArgumentException iae) {
throw new PSQLException(GT.tr("Invalid UUID data."), PSQLState.INVALID_PARAMETER_VALUE, iae);
}
return uuid;
}
protected Object getUUID(byte[] data) throws SQLException {
return new UUID(ByteConverter.int8(data, 0), ByteConverter.int8(data, 8));
}
private class PrimaryKey {
int index;
String name;
PrimaryKey(int index, String name) {
this.index = index;
this.name = name;
}
Object getValue() throws SQLException {
return getObject(index);
}
}
static class NullObject extends PGobject {
NullObject(String type) {
setType(type);
}
public String getValue() {
return null;
}
}
void addRows(List<byte[][]> tuples) {
rows.addAll(tuples);
}
public void updateRef(int columnIndex, Ref x) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateRef(int,Ref)");
}
public void updateRef(String columnName, Ref x) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateRef(String,Ref)");
}
public void updateBlob(int columnIndex, Blob x) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateBlob(int,Blob)");
}
public void updateBlob(String columnName, Blob x) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateBlob(String,Blob)");
}
public void updateClob(int columnIndex, Clob x) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateClob(int,Clob)");
}
public void updateClob(String columnName, Clob x) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateClob(String,Clob)");
}
public void updateArray(int columnIndex, Array x) throws SQLException {
updateObject(columnIndex, x);
}
public void updateArray(String columnName, Array x) throws SQLException {
updateArray(findColumn(columnName), x);
}
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
if (type == null) {
throw new SQLException("type is null");
}
int sqlType = getSQLType(columnIndex);
if (type == BigDecimal.class) {
if (sqlType == Types.NUMERIC || sqlType == Types.DECIMAL) {
return type.cast(getBigDecimal(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == String.class) {
if (sqlType == Types.CHAR || sqlType == Types.VARCHAR) {
return type.cast(getString(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Boolean.class) {
if (sqlType == Types.BOOLEAN || sqlType == Types.BIT) {
boolean booleanValue = getBoolean(columnIndex);
if (wasNull()) {
return null;
}
return type.cast(booleanValue);
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Short.class) {
if (sqlType == Types.SMALLINT) {
short shortValue = getShort(columnIndex);
if (wasNull()) {
return null;
}
return type.cast(shortValue);
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Integer.class) {
if (sqlType == Types.INTEGER || sqlType == Types.SMALLINT) {
int intValue = getInt(columnIndex);
if (wasNull()) {
return null;
}
return type.cast(intValue);
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Long.class) {
if (sqlType == Types.BIGINT) {
long longValue = getLong(columnIndex);
if (wasNull()) {
return null;
}
return type.cast(longValue);
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == BigInteger.class) {
if (sqlType == Types.BIGINT) {
long longValue = getLong(columnIndex);
if (wasNull()) {
return null;
}
return type.cast(BigInteger.valueOf(longValue));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Float.class) {
if (sqlType == Types.REAL) {
float floatValue = getFloat(columnIndex);
if (wasNull()) {
return null;
}
return type.cast(floatValue);
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Double.class) {
if (sqlType == Types.FLOAT || sqlType == Types.DOUBLE) {
double doubleValue = getDouble(columnIndex);
if (wasNull()) {
return null;
}
return type.cast(doubleValue);
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Date.class) {
if (sqlType == Types.DATE) {
return type.cast(getDate(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Time.class) {
if (sqlType == Types.TIME) {
return type.cast(getTime(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Timestamp.class) {
if (sqlType == Types.TIMESTAMP
|| sqlType == Types.TIMESTAMP_WITH_TIMEZONE
) {
return type.cast(getTimestamp(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Calendar.class) {
if (sqlType == Types.TIMESTAMP
|| sqlType == Types.TIMESTAMP_WITH_TIMEZONE
) {
Timestamp timestampValue = getTimestamp(columnIndex);
if (wasNull()) {
return null;
}
Calendar calendar = Calendar.getInstance(getDefaultCalendar().getTimeZone());
calendar.setTimeInMillis(timestampValue.getTime());
return type.cast(calendar);
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Blob.class) {
if (sqlType == Types.BLOB || sqlType == Types.BINARY || sqlType == Types.BIGINT) {
return type.cast(getBlob(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Clob.class) {
if (sqlType == Types.CLOB || sqlType == Types.BIGINT) {
return type.cast(getClob(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == java.util.Date.class) {
if (sqlType == Types.TIMESTAMP) {
Timestamp timestamp = getTimestamp(columnIndex);
if (wasNull()) {
return null;
}
return type.cast(new java.util.Date(timestamp.getTime()));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == Array.class) {
if (sqlType == Types.ARRAY) {
return type.cast(getArray(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == SQLXML.class) {
if (sqlType == Types.SQLXML) {
return type.cast(getSQLXML(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == UUID.class) {
return type.cast(getObject(columnIndex));
} else if (type == InetAddress.class) {
Object addressString = getObject(columnIndex);
if (addressString == null) {
return null;
}
try {
return type.cast(InetAddress.getByName(((PGobject) addressString).getValue()));
} catch (UnknownHostException e) {
throw new SQLException("could not create inet address from string '" + addressString + "'");
}
} else if (type == LocalDate.class) {
if (sqlType == Types.DATE) {
Date dateValue = getDate(columnIndex);
if (wasNull()) {
return null;
}
long time = dateValue.getTime();
if (time == PGStatement.DATE_POSITIVE_INFINITY) {
return type.cast(LocalDate.MAX);
}
if (time == PGStatement.DATE_NEGATIVE_INFINITY) {
return type.cast(LocalDate.MIN);
}
return type.cast(dateValue.toLocalDate());
} else if (sqlType == Types.TIMESTAMP) {
LocalDateTime localDateTimeValue = getLocalDateTime(columnIndex);
if (wasNull()) {
return null;
}
return type.cast(localDateTimeValue.toLocalDate());
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == LocalTime.class) {
if (sqlType == Types.TIME) {
return type.cast(getLocalTime(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == LocalDateTime.class) {
if (sqlType == Types.TIMESTAMP) {
return type.cast(getLocalDateTime(columnIndex));
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (type == OffsetDateTime.class) {
if (sqlType == Types.TIMESTAMP_WITH_TIMEZONE || sqlType == Types.TIMESTAMP) {
Timestamp timestampValue = getTimestamp(columnIndex);
if (wasNull()) {
return null;
}
long time = timestampValue.getTime();
if (time == PGStatement.DATE_POSITIVE_INFINITY) {
return type.cast(OffsetDateTime.MAX);
}
if (time == PGStatement.DATE_NEGATIVE_INFINITY) {
return type.cast(OffsetDateTime.MIN);
}
OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(timestampValue.toInstant(), ZoneOffset.UTC);
return type.cast(offsetDateTime);
} else {
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
} else if (PGobject.class.isAssignableFrom(type)) {
Object object;
if (isBinary(columnIndex)) {
object = connection.getObject(getPGType(columnIndex), null, thisRow[columnIndex - 1]);
} else {
object = connection.getObject(getPGType(columnIndex), getString(columnIndex), null);
}
return type.cast(object);
}
throw new PSQLException(GT.tr("conversion to {0} from {1} not supported", type, getPGType(columnIndex)),
PSQLState.INVALID_PARAMETER_VALUE);
}
public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
return getObject(findColumn(columnLabel), type);
}
public Object getObject(String s, Map<String, Class<?>> map) throws SQLException {
return getObjectImpl(s, map);
}
public Object getObject(int i, Map<String, Class<?>> map) throws SQLException {
return getObjectImpl(i, map);
}
public void updateObject(int columnIndex, Object x, java.sql.SQLType targetSqlType,
int scaleOrLength) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateObject");
}
public void updateObject(String columnLabel, Object x, java.sql.SQLType targetSqlType,
int scaleOrLength) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateObject");
}
public void updateObject(int columnIndex, Object x, java.sql.SQLType targetSqlType)
throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateObject");
}
public void updateObject(String columnLabel, Object x, java.sql.SQLType targetSqlType)
throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateObject");
}
public RowId getRowId(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getRowId columnIndex: {0}", columnIndex);
throw org.postgresql.Driver.notImplemented(this.getClass(), "getRowId(int)");
}
public RowId getRowId(String columnName) throws SQLException {
return getRowId(findColumn(columnName));
}
public void updateRowId(int columnIndex, RowId x) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateRowId(int, RowId)");
}
public void updateRowId(String columnName, RowId x) throws SQLException {
updateRowId(findColumn(columnName), x);
}
public int getHoldability() throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "getHoldability()");
}
public boolean isClosed() throws SQLException {
return (rows == null);
}
public void updateNString(int columnIndex, String nString) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateNString(int, String)");
}
public void updateNString(String columnName, String nString) throws SQLException {
updateNString(findColumn(columnName), nString);
}
public void updateNClob(int columnIndex, NClob nClob) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateNClob(int, NClob)");
}
public void updateNClob(String columnName, NClob nClob) throws SQLException {
updateNClob(findColumn(columnName), nClob);
}
public void updateNClob(int columnIndex, Reader reader) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateNClob(int, Reader)");
}
public void updateNClob(String columnName, Reader reader) throws SQLException {
updateNClob(findColumn(columnName), reader);
}
public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateNClob(int, Reader, long)");
}
public void updateNClob(String columnName, Reader reader, long length) throws SQLException {
updateNClob(findColumn(columnName), reader, length);
}
public NClob getNClob(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getNClob columnIndex: {0}", columnIndex);
throw org.postgresql.Driver.notImplemented(this.getClass(), "getNClob(int)");
}
public NClob getNClob(String columnName) throws SQLException {
return getNClob(findColumn(columnName));
}
public void updateBlob(int columnIndex, InputStream inputStream, long length)
throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(),
"updateBlob(int, InputStream, long)");
}
public void updateBlob(String columnName, InputStream inputStream, long length)
throws SQLException {
updateBlob(findColumn(columnName), inputStream, length);
}
public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateBlob(int, InputStream)");
}
public void updateBlob(String columnName, InputStream inputStream) throws SQLException {
updateBlob(findColumn(columnName), inputStream);
}
public void updateClob(int columnIndex, Reader reader, long length) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateClob(int, Reader, long)");
}
public void updateClob(String columnName, Reader reader, long length) throws SQLException {
updateClob(findColumn(columnName), reader, length);
}
public void updateClob(int columnIndex, Reader reader) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(), "updateClob(int, Reader)");
}
public void updateClob(String columnName, Reader reader) throws SQLException {
updateClob(findColumn(columnName), reader);
}
public SQLXML getSQLXML(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getSQLXML columnIndex: {0}", columnIndex);
String data = getString(columnIndex);
if (data == null) {
return null;
}
return new PgSQLXML(connection, data);
}
public SQLXML getSQLXML(String columnName) throws SQLException {
return getSQLXML(findColumn(columnName));
}
public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException {
updateValue(columnIndex, xmlObject);
}
public void updateSQLXML(String columnName, SQLXML xmlObject) throws SQLException {
updateSQLXML(findColumn(columnName), xmlObject);
}
public String getNString(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getNString columnIndex: {0}", columnIndex);
throw org.postgresql.Driver.notImplemented(this.getClass(), "getNString(int)");
}
public String getNString(String columnName) throws SQLException {
return getNString(findColumn(columnName));
}
public Reader getNCharacterStream(int columnIndex) throws SQLException {
connection.getLogger().log(Level.FINEST, " getNCharacterStream columnIndex: {0}", columnIndex);
throw org.postgresql.Driver.notImplemented(this.getClass(), "getNCharacterStream(int)");
}
public Reader getNCharacterStream(String columnName) throws SQLException {
return getNCharacterStream(findColumn(columnName));
}
public void updateNCharacterStream(int columnIndex, Reader x, int length) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(),
"updateNCharacterStream(int, Reader, int)");
}
public void updateNCharacterStream(String columnName, Reader x, int length) throws SQLException {
updateNCharacterStream(findColumn(columnName), x, length);
}
public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(),
"updateNCharacterStream(int, Reader)");
}
public void updateNCharacterStream(String columnName, Reader x) throws SQLException {
updateNCharacterStream(findColumn(columnName), x);
}
public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(),
"updateNCharacterStream(int, Reader, long)");
}
public void updateNCharacterStream(String columnName, Reader x, long length) throws SQLException {
updateNCharacterStream(findColumn(columnName), x, length);
}
public void updateCharacterStream(int columnIndex, Reader reader, long length)
throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(),
"updateCharaceterStream(int, Reader, long)");
}
public void updateCharacterStream(String columnName, Reader reader, long length)
throws SQLException {
updateCharacterStream(findColumn(columnName), reader, length);
}
public void updateCharacterStream(int columnIndex, Reader reader) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(),
"updateCharaceterStream(int, Reader)");
}
public void updateCharacterStream(String columnName, Reader reader) throws SQLException {
updateCharacterStream(findColumn(columnName), reader);
}
public void updateBinaryStream(int columnIndex, InputStream inputStream, long length)
throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(),
"updateBinaryStream(int, InputStream, long)");
}
public void updateBinaryStream(String columnName, InputStream inputStream, long length)
throws SQLException {
updateBinaryStream(findColumn(columnName), inputStream, length);
}
public void updateBinaryStream(int columnIndex, InputStream inputStream) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(),
"updateBinaryStream(int, InputStream)");
}
public void updateBinaryStream(String columnName, InputStream inputStream) throws SQLException {
updateBinaryStream(findColumn(columnName), inputStream);
}
public void updateAsciiStream(int columnIndex, InputStream inputStream, long length)
throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(),
"updateAsciiStream(int, InputStream, long)");
}
public void updateAsciiStream(String columnName, InputStream inputStream, long length)
throws SQLException {
updateAsciiStream(findColumn(columnName), inputStream, length);
}
public void updateAsciiStream(int columnIndex, InputStream inputStream) throws SQLException {
throw org.postgresql.Driver.notImplemented(this.getClass(),
"updateAsciiStream(int, InputStream)");
}
public void updateAsciiStream(String columnName, InputStream inputStream) throws SQLException {
updateAsciiStream(findColumn(columnName), inputStream);
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return iface.isAssignableFrom(getClass());
}
public <T> T unwrap(Class<T> iface) throws SQLException {
if (iface.isAssignableFrom(getClass())) {
return iface.cast(this);
}
throw new SQLException("Cannot unwrap to " + iface.getName());
}
private Calendar getDefaultCalendar() {
TimestampUtils timestampUtils = connection.getTimestampUtils();
if (timestampUtils.hasFastDefaultTimeZone()) {
return timestampUtils.getSharedCalendar(null);
}
Calendar sharedCalendar = timestampUtils.getSharedCalendar(defaultTimeZone);
if (defaultTimeZone == null) {
defaultTimeZone = sharedCalendar.getTimeZone();
}
return sharedCalendar;
}
}