ShopChest/libs/org/sqlite/RS.java
2015-09-06 11:58:25 +02:00

541 lines
16 KiB
Java

/*
* Copyright (c) 2007 David Crawshaw <david@zentus.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package org.sqlite;
import java.io.Reader;
import java.io.StringReader;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Calendar;
/**
* Implements a JDBC ResultSet.
*/
final class RS extends Unused implements ResultSet, ResultSetMetaData, Codes
{
private final Stmt stmt;
private final DB db;
boolean open = false; // true means have results and can iterate them
int maxRows; // max. number of rows as set by a Statement
String[] cols = null; // if null, the RS is closed()
String[] colsMeta = null; // same as cols, but used by Meta interface
boolean[][] meta = null;
private int limitRows; // 0 means no limit, must check against maxRows
private int row = 0; // number of current row, starts at 1 (0 is for before loading data)
private int lastCol; // last column accessed, for wasNull(). -1 if none
RS(Stmt stmt) {
this.stmt = stmt;
this.db = stmt.db;
}
// INTERNAL FUNCTIONS ///////////////////////////////////////////
boolean isOpen() {
return open;
}
/* Throws SQLException if ResultSet is not open. */
void checkOpen() throws SQLException {
if (!open)
throw new SQLException("ResultSet closed");
}
// takes col in [1,x] form, returns in [0,x-1] form
private int checkCol(int col) throws SQLException {
if (colsMeta == null)
throw new IllegalStateException("SQLite JDBC: inconsistent internal state");
if (col < 1 || col > colsMeta.length)
throw new SQLException("column " + col + " out of bounds [1," + colsMeta.length + "]");
return --col;
}
// takes col in [1,x] form, marks it as last accessed and returns [0,x-1]
private int markCol(int col) throws SQLException {
checkOpen();
checkCol(col);
lastCol = col;
return --col;
}
private void checkMeta() throws SQLException {
checkCol(1);
if (meta == null)
meta = db.column_metadata(stmt.pointer);
}
// ResultSet Functions //////////////////////////////////////////
public void close() throws SQLException {
cols = null;
colsMeta = null;
meta = null;
open = false;
limitRows = 0;
row = 0;
lastCol = -1;
if (stmt == null)
return;
if (stmt != null && stmt.pointer != 0)
db.reset(stmt.pointer);
}
// returns col in [1,x] form
public int findColumn(String col) throws SQLException {
checkOpen();
int c = -1;
for (int i = 0; i < cols.length; i++) {
if (col.equalsIgnoreCase(cols[i])
|| (cols[i].toUpperCase().endsWith(col.toUpperCase()) && cols[i].charAt(cols[i].length()
- col.length()) == '.')) {
if (c == -1)
c = i;
else
throw new SQLException("ambiguous column: '" + col + "'");
}
}
if (c == -1)
throw new SQLException("no such column: '" + col + "'");
else
return c + 1;
}
public boolean next() throws SQLException {
if (!open)
return false; // finished ResultSet
lastCol = -1;
// first row is loaded by execute(), so do not step() again
if (row == 0) {
row++;
return true;
}
// check if we are row limited by the statement or the ResultSet
if (maxRows != 0 && row > maxRows)
return false;
// do the real work
int statusCode = db.step(stmt.pointer);
switch (statusCode) {
case SQLITE_DONE:
close(); // agressive closing to avoid writer starvation
return false;
case SQLITE_ROW:
row++;
return true;
case SQLITE_BUSY:
default:
db.throwex(statusCode);
return false;
}
}
public int getType() throws SQLException {
return TYPE_FORWARD_ONLY;
}
public int getFetchSize() throws SQLException {
return limitRows;
}
public void setFetchSize(int rows) throws SQLException {
if (0 > rows || (maxRows != 0 && rows > maxRows))
throw new SQLException("fetch size " + rows + " out of bounds " + maxRows);
limitRows = rows;
}
public int getFetchDirection() throws SQLException {
checkOpen();
return ResultSet.FETCH_FORWARD;
}
public void setFetchDirection(int d) throws SQLException {
checkOpen();
if (d != ResultSet.FETCH_FORWARD)
throw new SQLException("only FETCH_FORWARD direction supported");
}
public boolean isAfterLast() throws SQLException {
return !open;
}
public boolean isBeforeFirst() throws SQLException {
return open && row == 0;
}
public boolean isFirst() throws SQLException {
return row == 1;
}
public boolean isLast() throws SQLException { // FIXME
throw new SQLException("function not yet implemented for SQLite");
}
@Override
protected void finalize() throws SQLException {
close();
}
public int getRow() throws SQLException {
return row;
}
public boolean wasNull() throws SQLException {
return db.column_type(stmt.pointer, markCol(lastCol)) == SQLITE_NULL;
}
// DATA ACCESS FUNCTIONS ////////////////////////////////////////
public boolean getBoolean(int col) throws SQLException {
return getInt(col) == 0 ? false : true;
}
public boolean getBoolean(String col) throws SQLException {
return getBoolean(findColumn(col));
}
public byte getByte(int col) throws SQLException {
return (byte) getInt(col);
}
public byte getByte(String col) throws SQLException {
return getByte(findColumn(col));
}
public byte[] getBytes(int col) throws SQLException {
return db.column_blob(stmt.pointer, markCol(col));
}
public byte[] getBytes(String col) throws SQLException {
return getBytes(findColumn(col));
}
public Reader getCharacterStream(int col) throws SQLException {
return new StringReader(getString(col));
}
public Reader getCharacterStream(String col) throws SQLException {
return getCharacterStream(findColumn(col));
}
public Date getDate(int col) throws SQLException {
if (db.column_type(stmt.pointer, markCol(col)) == SQLITE_NULL)
return null;
return new Date(db.column_long(stmt.pointer, markCol(col)));
}
public Date getDate(int col, Calendar cal) throws SQLException {
if (db.column_type(stmt.pointer, markCol(col)) == SQLITE_NULL)
return null;
if (cal == null)
return getDate(col);
cal.setTimeInMillis(db.column_long(stmt.pointer, markCol(col)));
return new Date(cal.getTime().getTime());
}
public Date getDate(String col) throws SQLException {
return getDate(findColumn(col), Calendar.getInstance());
}
public Date getDate(String col, Calendar cal) throws SQLException {
return getDate(findColumn(col), cal);
}
public double getDouble(int col) throws SQLException {
if (db.column_type(stmt.pointer, markCol(col)) == SQLITE_NULL)
return 0;
return db.column_double(stmt.pointer, markCol(col));
}
public double getDouble(String col) throws SQLException {
return getDouble(findColumn(col));
}
public float getFloat(int col) throws SQLException {
if (db.column_type(stmt.pointer, markCol(col)) == SQLITE_NULL)
return 0;
return (float) db.column_double(stmt.pointer, markCol(col));
}
public float getFloat(String col) throws SQLException {
return getFloat(findColumn(col));
}
public int getInt(int col) throws SQLException {
return db.column_int(stmt.pointer, markCol(col));
}
public int getInt(String col) throws SQLException {
return getInt(findColumn(col));
}
public long getLong(int col) throws SQLException {
return db.column_long(stmt.pointer, markCol(col));
}
public long getLong(String col) throws SQLException {
return getLong(findColumn(col));
}
public short getShort(int col) throws SQLException {
return (short) getInt(col);
}
public short getShort(String col) throws SQLException {
return getShort(findColumn(col));
}
public String getString(int col) throws SQLException {
return db.column_text(stmt.pointer, markCol(col));
}
public String getString(String col) throws SQLException {
return getString(findColumn(col));
}
public Time getTime(int col) throws SQLException {
if (db.column_type(stmt.pointer, markCol(col)) == SQLITE_NULL)
return null;
return new Time(db.column_long(stmt.pointer, markCol(col)));
}
public Time getTime(int col, Calendar cal) throws SQLException {
if (cal == null)
return getTime(col);
if (db.column_type(stmt.pointer, markCol(col)) == SQLITE_NULL)
return null;
cal.setTimeInMillis(db.column_long(stmt.pointer, markCol(col)));
return new Time(cal.getTime().getTime());
}
public Time getTime(String col) throws SQLException {
return getTime(findColumn(col));
}
public Time getTime(String col, Calendar cal) throws SQLException {
return getTime(findColumn(col), cal);
}
public Timestamp getTimestamp(int col) throws SQLException {
if (db.column_type(stmt.pointer, markCol(col)) == SQLITE_NULL)
return null;
return new Timestamp(db.column_long(stmt.pointer, markCol(col)));
}
public Timestamp getTimestamp(int col, Calendar cal) throws SQLException {
if (cal == null)
return getTimestamp(col);
if (db.column_type(stmt.pointer, markCol(col)) == SQLITE_NULL)
return null;
cal.setTimeInMillis(db.column_long(stmt.pointer, markCol(col)));
return new Timestamp(cal.getTime().getTime());
}
public Timestamp getTimestamp(String col) throws SQLException {
return getTimestamp(findColumn(col));
}
public Timestamp getTimestamp(String c, Calendar ca) throws SQLException {
return getTimestamp(findColumn(c), ca);
}
public Object getObject(int col) throws SQLException {
switch (db.column_type(stmt.pointer, checkCol(col))) {
case SQLITE_INTEGER:
long val = getLong(col);
if (val > Integer.MAX_VALUE || val < Integer.MIN_VALUE)
return new Long(val);
else
return new Integer((int) val);
case SQLITE_FLOAT:
return new Double(getDouble(col));
case SQLITE_BLOB:
return getBytes(col);
case SQLITE_NULL:
return null;
case SQLITE_TEXT:
default:
return getString(col);
}
}
public Object getObject(String col) throws SQLException {
return getObject(findColumn(col));
}
public Statement getStatement() {
return stmt;
}
public String getCursorName() throws SQLException {
return null;
}
public SQLWarning getWarnings() throws SQLException {
return null;
}
public void clearWarnings() throws SQLException {}
// ResultSetMetaData Functions //////////////////////////////////
// we do not need to check the RS is open, only that colsMeta
// is not null, done with checkCol(int).
public ResultSetMetaData getMetaData() throws SQLException {
return this;
}
public String getCatalogName(int col) throws SQLException {
return db.column_table_name(stmt.pointer, checkCol(col));
}
public String getColumnClassName(int col) throws SQLException {
checkCol(col);
return "java.lang.Object";
}
public int getColumnCount() throws SQLException {
checkCol(1);
return colsMeta.length;
}
public int getColumnDisplaySize(int col) throws SQLException {
return Integer.MAX_VALUE;
}
public String getColumnLabel(int col) throws SQLException {
return getColumnName(col);
}
public String getColumnName(int col) throws SQLException {
return db.column_name(stmt.pointer, checkCol(col));
}
public int getColumnType(int col) throws SQLException {
switch (db.column_type(stmt.pointer, checkCol(col))) {
case SQLITE_INTEGER:
return Types.INTEGER;
case SQLITE_FLOAT:
return Types.FLOAT;
case SQLITE_BLOB:
return Types.BLOB;
case SQLITE_NULL:
return Types.NULL;
case SQLITE_TEXT:
default:
return Types.VARCHAR;
}
}
public String getColumnTypeName(int col) throws SQLException {
switch (db.column_type(stmt.pointer, checkCol(col))) {
case SQLITE_INTEGER:
return "integer";
case SQLITE_FLOAT:
return "float";
case SQLITE_BLOB:
return "blob";
case SQLITE_NULL:
return "null";
case SQLITE_TEXT:
default:
return "text";
}
}
public int getPrecision(int col) throws SQLException {
return 0;
} // FIXME
public int getScale(int col) throws SQLException {
return 0;
}
public String getSchemaName(int col) throws SQLException {
return "";
}
public String getTableName(int col) throws SQLException {
return db.column_table_name(stmt.pointer, checkCol(col));
}
public int isNullable(int col) throws SQLException {
checkMeta();
return meta[checkCol(col)][1] ? columnNoNulls : columnNullable;
}
public boolean isAutoIncrement(int col) throws SQLException {
checkMeta();
return meta[checkCol(col)][2];
}
public boolean isCaseSensitive(int col) throws SQLException {
return true;
}
public boolean isCurrency(int col) throws SQLException {
return false;
}
public boolean isDefinitelyWritable(int col) throws SQLException {
return true;
} // FIXME: check db file constraints?
public boolean isReadOnly(int col) throws SQLException {
return false;
}
public boolean isSearchable(int col) throws SQLException {
return true;
}
public boolean isSigned(int col) throws SQLException {
return false;
}
public boolean isWritable(int col) throws SQLException {
return true;
}
public int getConcurrency() throws SQLException {
return CONCUR_READ_ONLY;
}
public boolean rowDeleted() throws SQLException {
return false;
}
public boolean rowInserted() throws SQLException {
return false;
}
public boolean rowUpdated() throws SQLException {
return false;
}
}