mirror of
https://github.com/amalthea-mc/ShopChest.git
synced 2024-11-26 12:22:24 +00:00
338 lines
9.6 KiB
Java
338 lines
9.6 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.sql.BatchUpdateException;
|
||
|
import java.sql.Connection;
|
||
|
import java.sql.ResultSet;
|
||
|
import java.sql.SQLException;
|
||
|
import java.sql.SQLWarning;
|
||
|
import java.sql.Statement;
|
||
|
|
||
|
import org.sqlite.DB.ProgressObserver;
|
||
|
import org.sqlite.ExtendedCommand.SQLExtension;
|
||
|
|
||
|
class Stmt extends Unused implements Statement, Codes
|
||
|
{
|
||
|
final Conn conn;
|
||
|
final DB db;
|
||
|
final RS rs;
|
||
|
|
||
|
long pointer;
|
||
|
String sql = null;
|
||
|
|
||
|
int batchPos;
|
||
|
Object[] batch = null;
|
||
|
boolean resultsWaiting = false;
|
||
|
|
||
|
Stmt(Conn c) {
|
||
|
conn = c;
|
||
|
db = conn.db();
|
||
|
rs = new RS(this);
|
||
|
}
|
||
|
|
||
|
protected final void checkOpen() throws SQLException {
|
||
|
if (pointer == 0)
|
||
|
throw new SQLException("statement is not executing");
|
||
|
}
|
||
|
|
||
|
boolean isOpen() throws SQLException {
|
||
|
return (pointer != 0);
|
||
|
}
|
||
|
|
||
|
/** Calls sqlite3_step() and sets up results. Expects a clean stmt. */
|
||
|
protected boolean exec() throws SQLException {
|
||
|
if (sql == null)
|
||
|
throw new SQLException("SQLiteJDBC internal error: sql==null");
|
||
|
if (rs.isOpen())
|
||
|
throw new SQLException("SQLite JDBC internal error: rs.isOpen() on exec.");
|
||
|
|
||
|
boolean rc = false;
|
||
|
try {
|
||
|
rc = db.execute(this, null);
|
||
|
}
|
||
|
finally {
|
||
|
resultsWaiting = rc;
|
||
|
}
|
||
|
|
||
|
return db.column_count(pointer) != 0;
|
||
|
}
|
||
|
|
||
|
protected boolean exec(String sql) throws SQLException {
|
||
|
if (sql == null)
|
||
|
throw new SQLException("SQLiteJDBC internal error: sql==null");
|
||
|
if (rs.isOpen())
|
||
|
throw new SQLException("SQLite JDBC internal error: rs.isOpen() on exec.");
|
||
|
|
||
|
boolean rc = false;
|
||
|
try {
|
||
|
rc = db.execute(sql);
|
||
|
}
|
||
|
finally {
|
||
|
resultsWaiting = rc;
|
||
|
}
|
||
|
|
||
|
return db.column_count(pointer) != 0;
|
||
|
}
|
||
|
|
||
|
// PUBLIC INTERFACE /////////////////////////////////////////////
|
||
|
|
||
|
public void close() throws SQLException {
|
||
|
if (pointer == 0)
|
||
|
return;
|
||
|
rs.close();
|
||
|
batch = null;
|
||
|
batchPos = 0;
|
||
|
int resp = db.finalize(this);
|
||
|
if (resp != SQLITE_OK && resp != SQLITE_MISUSE)
|
||
|
db.throwex();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void finalize() throws SQLException {
|
||
|
close();
|
||
|
}
|
||
|
|
||
|
public boolean execute(String sql) throws SQLException {
|
||
|
close();
|
||
|
this.sql = sql;
|
||
|
|
||
|
db.prepare(this);
|
||
|
return exec();
|
||
|
}
|
||
|
|
||
|
public ResultSet executeQuery(String sql) throws SQLException {
|
||
|
close();
|
||
|
this.sql = sql;
|
||
|
|
||
|
db.prepare(this);
|
||
|
if (!exec()) {
|
||
|
close();
|
||
|
throw new SQLException("query does not return ResultSet");
|
||
|
}
|
||
|
return getResultSet();
|
||
|
}
|
||
|
|
||
|
static class BackupObserver implements ProgressObserver
|
||
|
{
|
||
|
public void progress(int remaining, int pageCount) {
|
||
|
System.out.println(String.format("remaining:%d, page count:%d", remaining, pageCount));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int executeUpdate(String sql) throws SQLException {
|
||
|
close();
|
||
|
this.sql = sql;
|
||
|
|
||
|
int changes = 0;
|
||
|
SQLExtension ext = ExtendedCommand.parse(sql);
|
||
|
if (ext != null) {
|
||
|
// execute extended command
|
||
|
ext.execute(db);
|
||
|
}
|
||
|
else {
|
||
|
try {
|
||
|
//db.prepare(this);
|
||
|
//changes = db.executeUpdate(this, null);
|
||
|
|
||
|
// directly invokes the exec API to support multiple SQL statements
|
||
|
int statusCode = db._exec(sql);
|
||
|
if (statusCode != SQLITE_OK)
|
||
|
throw DB.newSQLException(statusCode, "");
|
||
|
|
||
|
changes = db.changes();
|
||
|
}
|
||
|
finally {
|
||
|
close();
|
||
|
}
|
||
|
}
|
||
|
return changes;
|
||
|
}
|
||
|
|
||
|
public ResultSet getResultSet() throws SQLException {
|
||
|
checkOpen();
|
||
|
if (rs.isOpen())
|
||
|
throw new SQLException("ResultSet already requested");
|
||
|
if (db.column_count(pointer) == 0)
|
||
|
throw new SQLException("no ResultSet available");
|
||
|
if (rs.colsMeta == null)
|
||
|
rs.colsMeta = db.column_names(pointer);
|
||
|
rs.cols = rs.colsMeta;
|
||
|
|
||
|
rs.open = resultsWaiting;
|
||
|
resultsWaiting = false;
|
||
|
return rs;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* This function has a complex behaviour best understood by carefully
|
||
|
* reading the JavaDoc for getMoreResults() and considering the test
|
||
|
* StatementTest.execute().
|
||
|
*/
|
||
|
public int getUpdateCount() throws SQLException {
|
||
|
if (pointer != 0 && !rs.isOpen() && !resultsWaiting && db.column_count(pointer) == 0)
|
||
|
return db.changes();
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
public void addBatch(String sql) throws SQLException {
|
||
|
close();
|
||
|
if (batch == null || batchPos + 1 >= batch.length) {
|
||
|
Object[] nb = new Object[Math.max(10, batchPos * 2)];
|
||
|
if (batch != null)
|
||
|
System.arraycopy(batch, 0, nb, 0, batch.length);
|
||
|
batch = nb;
|
||
|
}
|
||
|
batch[batchPos++] = sql;
|
||
|
}
|
||
|
|
||
|
public void clearBatch() throws SQLException {
|
||
|
batchPos = 0;
|
||
|
if (batch != null)
|
||
|
for (int i = 0; i < batch.length; i++)
|
||
|
batch[i] = null;
|
||
|
}
|
||
|
|
||
|
public int[] executeBatch() throws SQLException {
|
||
|
// TODO: optimize
|
||
|
close();
|
||
|
if (batch == null || batchPos == 0)
|
||
|
return new int[] {};
|
||
|
|
||
|
int[] changes = new int[batchPos];
|
||
|
|
||
|
synchronized (db) {
|
||
|
try {
|
||
|
for (int i = 0; i < changes.length; i++) {
|
||
|
try {
|
||
|
this.sql = (String) batch[i];
|
||
|
db.prepare(this);
|
||
|
changes[i] = db.executeUpdate(this, null);
|
||
|
}
|
||
|
catch (SQLException e) {
|
||
|
throw new BatchUpdateException("batch entry " + i + ": " + e.getMessage(), changes);
|
||
|
}
|
||
|
finally {
|
||
|
db.finalize(this);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally {
|
||
|
clearBatch();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return changes;
|
||
|
}
|
||
|
|
||
|
public void setCursorName(String name) {}
|
||
|
|
||
|
public SQLWarning getWarnings() throws SQLException {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public void clearWarnings() throws SQLException {}
|
||
|
|
||
|
public Connection getConnection() throws SQLException {
|
||
|
return conn;
|
||
|
}
|
||
|
|
||
|
public void cancel() throws SQLException {
|
||
|
rs.checkOpen();
|
||
|
db.interrupt();
|
||
|
}
|
||
|
|
||
|
public int getQueryTimeout() throws SQLException {
|
||
|
return conn.getTimeout();
|
||
|
}
|
||
|
|
||
|
public void setQueryTimeout(int seconds) throws SQLException {
|
||
|
if (seconds < 0)
|
||
|
throw new SQLException("query timeout must be >= 0");
|
||
|
conn.setTimeout(1000 * seconds);
|
||
|
}
|
||
|
|
||
|
// TODO: write test
|
||
|
public int getMaxRows() throws SQLException {
|
||
|
//checkOpen();
|
||
|
return rs.maxRows;
|
||
|
}
|
||
|
|
||
|
public void setMaxRows(int max) throws SQLException {
|
||
|
//checkOpen();
|
||
|
if (max < 0)
|
||
|
throw new SQLException("max row count must be >= 0");
|
||
|
rs.maxRows = max;
|
||
|
}
|
||
|
|
||
|
public int getMaxFieldSize() throws SQLException {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
public void setMaxFieldSize(int max) throws SQLException {
|
||
|
if (max < 0)
|
||
|
throw new SQLException("max field size " + max + " cannot be negative");
|
||
|
}
|
||
|
|
||
|
public int getFetchSize() throws SQLException {
|
||
|
return rs.getFetchSize();
|
||
|
}
|
||
|
|
||
|
public void setFetchSize(int r) throws SQLException {
|
||
|
rs.setFetchSize(r);
|
||
|
}
|
||
|
|
||
|
public int getFetchDirection() throws SQLException {
|
||
|
return rs.getFetchDirection();
|
||
|
}
|
||
|
|
||
|
public void setFetchDirection(int d) throws SQLException {
|
||
|
rs.setFetchDirection(d);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* As SQLite's last_insert_rowid() function is DB-specific not statement
|
||
|
* specific, this function introduces a race condition if the same
|
||
|
* connection is used by two threads and both insert.
|
||
|
*/
|
||
|
public ResultSet getGeneratedKeys() throws SQLException {
|
||
|
return ((MetaData) conn.getMetaData()).getGeneratedKeys();
|
||
|
}
|
||
|
|
||
|
/** SQLite does not support multiple results from execute(). */
|
||
|
public boolean getMoreResults() throws SQLException {
|
||
|
return getMoreResults(0);
|
||
|
}
|
||
|
|
||
|
public boolean getMoreResults(int c) throws SQLException {
|
||
|
checkOpen();
|
||
|
close(); // as we never have another result, clean up pointer
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public int getResultSetConcurrency() throws SQLException {
|
||
|
return ResultSet.CONCUR_READ_ONLY;
|
||
|
}
|
||
|
|
||
|
public int getResultSetHoldability() throws SQLException {
|
||
|
return ResultSet.CLOSE_CURSORS_AT_COMMIT;
|
||
|
}
|
||
|
|
||
|
public int getResultSetType() throws SQLException {
|
||
|
return ResultSet.TYPE_FORWARD_ONLY;
|
||
|
}
|
||
|
}
|