Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Changes to SQL execution so that the behavior matches the documentation

for Statement.  Including a valid return for an update and insert.
  • Loading branch information...
commit 19af69483d2f850b5bb876ba1c2dccdfe4c4f29f 1 parent e922cfa
@ergouser ergouser authored
View
2  compat/android/database/AbstractCursor.java
@@ -188,5 +188,5 @@ public int getType(int ci) {
int columnType = SQLite.sqlite3_column_type(pStmt,ci);
return columnType;
}
-
+
}
View
7 compat/android/database/sqlite/SQLiteDatabase.java
@@ -157,5 +157,12 @@ public int getVersion() {
/** For compatibility. Does nothing. */
public void setLocale(Locale default1) {
}
+
+ /** Returns the number of rows changed associated with the last update or insert. */
+ public int changedRowCount () {
+ return SQLite.sqlite3_changes(pDb);
+ }
+
+
}
View
4 compat/android/util/Log.java
@@ -14,6 +14,10 @@ public static void i(String string, String sql) {
Logger.getLogger(Log.class).info(string + ":" + sql);
}
+ public static void v(String string, String sql) {
+ Logger.getLogger(Log.class).debug(string + ":" + sql);
+ }
+
public static void e(String string, String sql) {
Logger.getLogger(Log.class).error(string + ":" + sql);
}
View
6 src/org/sqldroid/SQLDroidConnection.java
@@ -46,7 +46,7 @@
*/
public SQLDroidConnection(String url, Properties info) throws SQLException {
String note = "new sqlite jdbc from url '" + url + "', " + "'" + info + "'";
- Log.i("Sqldroid", note);
+ Log.v("Sqldroid", note);
// Make a filename from url
String dbQname;
@@ -74,7 +74,7 @@ public SQLDroidConnection(String url, Properties info) throws SQLException {
Log.e("SQlDRoid", "Error Parsing URL \"" + url + "\" Timeout String \"" + timeoutString + "\" is not a valid long", nfe);
}
}
- Log.i("SQlDRoid", "opening database " + dbQname);
+ Log.v("SQlDRoid", "opening database " + dbQname);
int flags = android.database.sqlite.SQLiteDatabase.CREATE_IF_NECESSARY | android.database.sqlite.SQLiteDatabase.OPEN_READWRITE;
if ( info != null ) {
if ( info.getProperty(SQLDroidDriver.DATABASE_FLAGS) != null ) {
@@ -375,7 +375,7 @@ public void setTypeMap(Map<String, Class<?>> arg0) throws SQLException {
@Override
protected void finalize() throws Throwable {
- Log.i("Sqldroid", " --- Finalize Sqldroid, closing db.");
+ Log.v("Sqldroid", " --- Finalize Sqldroid, closing db.");
if (sqlitedb != null) {
sqlitedb.close();
}
View
3  src/org/sqldroid/SQLDroidDatabaseMetaData.java
@@ -222,6 +222,9 @@ else if ( type.equals("BLOB") ) {
column[4] = java.sql.Types.NULL;
}
int nullable = c.getInt(3);
+ //public static final int columnNoNulls 0
+ //public static final int columnNullable 1
+ //public static final int columnNullableUnknown 2
if ( nullable == 0 ) {
column[10] = new Integer[1];
}
View
75 src/org/sqldroid/SQLDroidPreparedStatement.java
@@ -64,7 +64,7 @@
public int updateCount = -1;
public SQLDroidPreparedStatement(String sql, SQLDroidConnection sqldroid) {
- Log.i("SQLDRoid", "new SqlDRoid prepared statement from " + sqldroid);
+ Log.v("SQLDRoid", "new SqlDRoid prepared statement from " + sqldroid);
this.sqldroidConnection = sqldroid;
this.db = sqldroid.getDb();
setSQL(sql);
@@ -185,31 +185,42 @@ public void close() throws SQLException {
@Override
public boolean execute() throws SQLException {
- updateCount = 0;
- if ( rs!= null && !rs.isClosed() ) {
- rs.close();
- }
- rs = null;
+ updateCount = -1;
+ boolean resultsAvailable = false;
+ closeResultSet();
if (isSelect) {
Cursor c = db.rawQuery(sql, makeArgListQueryString());
- //rs = new SQLDroidResultSet(c);
- if ( c.getColumnCount() != 0 ) {
- rs = new SQLDroidResultSet(c);
- }
- else {
- if ( c != null ) {
- c.close();
- }
+ rs = new SQLDroidResultSet(c);
+ if ( c.getCount() != 0 ) {
+ resultsAvailable = true;
}
+// else { // can't close if we're going to return a result set.
+// if ( c != null ) {
+// c.close();
+// }
+// }
}
else {
db.execSQL(sql, makeArgListQueryObject());
+ updateCount = db.changedRowCount();
+ }
+ return resultsAvailable;
+ }
+
+ /** Close the result set (if open) and null the rs variable. */
+ public void closeResultSet() throws SQLException {
+ if (rs != null && !rs.isClosed()) {
+ if (!rs.isClosed()) {
+ rs.close();
+ }
+ rs = null;
}
- return potentialResultSet && rs != null && rs.getMetaData().getColumnCount() != 0;
}
@Override
public ResultSet executeQuery() throws SQLException {
+ updateCount = -1;
+ closeResultSet();
//Log.d("sqldroid", "executeQuery " + sql);
// when querying, all ? values must be converted to Strings for some reason
Cursor c = db.rawQuery(sql, makeArgListQueryString());
@@ -222,7 +233,9 @@ public ResultSet executeQuery() throws SQLException {
@Override
public int executeUpdate() throws SQLException {
// TODO we can't count the actual number of updates .... :S
- return execute() ? 1 : 0;
+ execute();
+ return updateCount;
+
}
@Override
@@ -279,9 +292,8 @@ public ResultSet executeQuery(String sql) throws SQLException {
@Override
public int executeUpdate(String sql) throws SQLException {
- db.execSQL(sql);
-
- return 0;
+ setSQL(sql);
+ return executeUpdate();
}
@Override
@@ -362,20 +374,18 @@ public int getMaxRows() throws SQLException {
// stmt is a Statement object
((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))*/
public boolean getMoreResults() throws SQLException {
- System.err.println(" ********************* not implemented @ "
- + DebugPrinter.getFileName() + " line "
- + DebugPrinter.getLineNumber());
- return false;
+ return getMoreResults(CLOSE_CURRENT_RESULT);
}
@Override
public boolean getMoreResults(int current) throws SQLException {
- System.err.println(" ********************* not implemented @ "
- + DebugPrinter.getFileName() + " line "
- + DebugPrinter.getLineNumber());
+ if ( current == CLOSE_CURRENT_RESULT ) {
+ closeResultSet();
+ }
return false;
}
+
@Override
public int getQueryTimeout() throws SQLException {
System.err.println(" ********************* not implemented @ "
@@ -413,17 +423,22 @@ public int getResultSetType() throws SQLException {
return 0;
}
- @Override
/**Retrieves the current result as an update count; if the result is a ResultSet object or there are no more results, -1 is returned. This method should be called only once per result.
Returns:
the current result as an update count; -1 if the current result is a ResultSet object or there are no more results*/
+ @Override
public int getUpdateCount() throws SQLException {
- if ( updateCount == -1 ) {
- return -1;
+ if ( updateCount != -1 ) { // for any successful update/insert, update count will have been set
+ // the documenation states that you're only supposed to call this once per result.
+ // on subsequent calls, we'll return -1 (which would appear to be the correct return
+ int tmp = updateCount;
+ updateCount = -1;
+ return tmp;
}
- return updateCount--;
+ return updateCount; // if the result was a result set, or this is the second call, then this will be -1
}
+
@Override
public SQLWarning getWarnings() throws SQLException {
System.err.println(" ********************* not implemented @ "
View
39 src/org/sqldroid/SQLDroidStatement.java
@@ -13,6 +13,7 @@
private SQLiteDatabase db;
private SQLDroidConnection sqldroidConnection;
private SQLDroidResultSet rs = null;
+
private Integer maxRows = null;
/** The update count. We don't know this, but need to respond in such a way that:
@@ -65,15 +66,22 @@ public void close() throws SQLException {
db = null;
}
+ /** Close the result set (if open) and null the rs variable. */
public void closeResultSet() throws SQLException {
- if (rs != null) {
- rs.close();
+ if (rs != null && !rs.isClosed()) {
+ if (!rs.isClosed()) {
+ rs.close();
+ }
rs = null;
}
}
@Override
+ /** Execute the SQL statement.
+ * @return false if there are no result (if the request was not a select or similar) or the result set was empty. True if a
+ * non-empty result set is available. This meets the requirement of java.sql.Statement.
+ */
public boolean execute(String sql) throws SQLException {
- updateCount = 0;
+ updateCount = -1; // default outcome. If the sql is a query or any other sql fails.
boolean ok = false;
closeResultSet();
boolean isSelect = sql.toUpperCase().matches("(?m)(?s)\\s*SELECT.*");
@@ -88,15 +96,16 @@ public boolean execute(String sql) throws SQLException {
if (isSelect) {
String limitedSql = sql + (maxRows != null ? " LIMIT " + maxRows : "");
Cursor c = db.rawQuery(limitedSql, new String[0]);
- if ( c.getColumnCount() != 0 ) {
- rs = new SQLDroidResultSet(c);
+ rs = new SQLDroidResultSet(c);
+ if ( c.getCount() != 0 ) {
+ ok = true;
}
} else {
db.execSQL(sql);
+ updateCount = db.changedRowCount();
}
- ok = true;
- boolean resultSetAvailable = ok && !sql.toUpperCase().startsWith("CREATE") && rs != null && rs.getMetaData().getColumnCount() != 0;
+ boolean resultSetAvailable = ok && !sql.toUpperCase().startsWith("CREATE") && rs != null;
// if (resultSetAvailable) {
// boolean headerDrawn = false;
@@ -165,7 +174,7 @@ public ResultSet executeQuery(String sql) throws SQLException {
public int executeUpdate(String sql) throws SQLException {
closeResultSet();
db.execSQL(sql);
- return 0;
+ return updateCount;
}
@Override
@@ -236,7 +245,9 @@ public boolean getMoreResults() throws SQLException {
@Override
public boolean getMoreResults(int current) throws SQLException {
- closeResultSet();
+ if ( current == CLOSE_CURRENT_RESULT ) {
+ closeResultSet();
+ }
return false;
}
@@ -275,10 +286,14 @@ public int getResultSetType() throws SQLException {
@Override
public int getUpdateCount() throws SQLException {
- if ( updateCount == -1 ) {
- return -1;
+ if ( updateCount != -1 ) { // for any successful update/insert, update count will have been set
+ // the documenation states that you're only supposed to call this once per result.
+ // on subsequent calls, we'll return -1 (which would appear to be the correct return
+ int tmp = updateCount;
+ updateCount = -1;
+ return tmp;
}
- return updateCount--;
+ return updateCount; // if the result was a result set, or this is the second call, then this will be -1
}
@Override
View
34 src/org/sqldroid/SQLiteDatabase.java
@@ -1,11 +1,10 @@
package org.sqldroid;
+import java.lang.reflect.Method;
import java.sql.SQLException;
-import java.util.Locale;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
-import android.util.Log;
/** A proxy class for the database that allows actions to be retried without forcing every method
@@ -50,6 +49,9 @@
/** The name of the database. */
protected String dbQname;
+
+ /** The method to invoke to get the changed row count. */
+ protected Method getChangedRowCount;
/** Returns true if the exception is an instance of "SQLiteDatabaseLockedException". Since this exception does not exist
* in APIs below 11 this code uses reflection to check the exception type.
@@ -232,4 +234,32 @@ public void close() throws SQLException {
execNoArgVoidMethod(Transaction.close);
}
+
+ /** The count of changed rows. On JNA platforms, this is a call to sqlite3_changes
+ * On Android, it's a convoluted call to a package-private method (or, if that fails, the
+ * response is '1'.
+ */
+ public int changedRowCount () {
+ if ( getChangedRowCount == null ) {
+ try { // JNA/J2SE compatibility method.
+ getChangedRowCount = sqliteDatabase.getClass().getMethod("changedRowCount", (Class<?>[])null);
+ } catch ( Exception any ) {
+ try {
+ // Android
+ getChangedRowCount = sqliteDatabase.getClass().getDeclaredMethod("lastChangeCount", (Class<?>[])null);
+ getChangedRowCount.setAccessible(true);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+ if ( getChangedRowCount != null ) {
+ try {
+ return ((Integer)getChangedRowCount.invoke(sqliteDatabase, (Object[])null)).intValue();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ return 1; // assume that the insert/update succeeded in changing exactly one row (terrible assumption, but I have nothing better).
+ }
}
View
56 test/org/sqldroid/DriverUnitTest.java
@@ -202,52 +202,81 @@ public void testExecute () throws Exception {
Statement statement = con.createStatement();
boolean hasResultSet = statement.execute("SELECT * FROM dummytable order by value");
assertTrue("Should return a result set", hasResultSet);
- assertNotSame ("Should not be -1 ", -1, statement.getUpdateCount());
+ assertEquals ("Should be -1 ", -1, statement.getUpdateCount());
+ assertNotNull ("Result Set should be non-null ", statement.getResultSet());
// second time this will be true.
boolean noMoreResults = ((statement.getMoreResults() == false) && (statement.getUpdateCount() == -1));
assertTrue("Should be no more results ", noMoreResults);
- assertNotNull ("Result Set should be non-null ", statement.getResultSet());
+ assertNull ("Result Set should be non-null ", statement.getResultSet());
statement.close();
statement = con.createStatement();
hasResultSet = statement.execute("SELECT * FROM dummytable where name = 'fig'"); // no matching result
- assertFalse("Should return a result set", hasResultSet);
- assertNull ("Result Set should be null ", statement.getResultSet());
- assertNotSame ("Should not be -1 ", -1, statement.getUpdateCount());
+ assertFalse("Should not return a result set", hasResultSet);
+ assertNotNull ("Result Set should not be null ", statement.getResultSet());
+ assertEquals ("Should not be -1 ", -1, statement.getUpdateCount());
// second time this will be true.
noMoreResults = ((statement.getMoreResults() == false) && (statement.getUpdateCount() == -1));
assertTrue("Should be no more results ", noMoreResults);
- assertNotNull ("Result Set should be non-null ", statement.getResultSet());
+ assertNull ("Result Set should be null - no results ", statement.getResultSet());
statement.close();
-
PreparedStatement stmt = con.prepareStatement("SELECT ?,? FROM dummytable order by ?");
stmt.setString(1, "name");
stmt.setString(2, "value");
stmt.setString(3, "value");
hasResultSet = stmt.execute();
assertTrue("Should return a result set", hasResultSet);
- assertNotSame ("Should not be -1 ", -1, stmt.getUpdateCount());
+ assertEquals ("Should not be -1 ", -1, stmt.getUpdateCount());
// second time this will be true.
noMoreResults = ((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1));
assertTrue("Should be no more results ", noMoreResults);
- assertNotNull ("Result Set should be non-null ", stmt.getResultSet());
+ assertNull ("Result Set should be null ", stmt.getResultSet()); // no more results
stmt.close();
stmt = con.prepareStatement("SELECT * FROM dummytable where name = 'fig'");
hasResultSet = stmt.execute(); // no matching result
assertFalse("Should return a result set", hasResultSet);
- assertNull ("Result Set should be null ", stmt.getResultSet());
- assertNotSame ("Should not be -1 ", -1, stmt.getUpdateCount());
+ assertNotNull ("Result Set should not be null ", stmt.getResultSet());
+ assertEquals ("Should not be -1 ", -1, stmt.getUpdateCount());
// second time this will be true.
noMoreResults = ((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1));
assertTrue("Should be no more results ", noMoreResults);
- assertNotNull ("Result Set should be non-null ", stmt.getResultSet());
+ assertNull ("Result Set should be null - no results ", stmt.getResultSet());
+ stmt.close();
+
+ stmt = con.prepareStatement("update dummytable set name='Kumquat' where name = 'Orange' OR name = 'Kiwi'");
+ stmt.execute();
+ assertEquals ("To Rows updated ", 2, stmt.getUpdateCount());
+ for ( String insertSQL : inserts ) {
+ Statement s = con.createStatement();
+ s.execute(insertSQL);
+ assertEquals ("To Rows updated ", 1, s.getUpdateCount());
+ }
+ int rows = stmt.executeUpdate();
+ assertEquals ("To Rows updated ", 2, rows);
+ assertEquals ("To Rows updated ", 2, stmt.getUpdateCount());
stmt.close();
+
+ for ( String insertSQL : inserts ) {
+ stmt = con.prepareStatement(insertSQL);
+ stmt.execute();
+ assertEquals ("To Rows updated ", 1, stmt.getUpdateCount());
+ }
- }
+ statement = con.createStatement();
+ hasResultSet = statement.execute("update dummytable set name='Kumquat' where name = 'Orange' OR name = 'Kiwi'"); // no matching result
+ assertFalse("Should not return a result set", hasResultSet);
+ for ( String insertSQL : inserts ) {
+ con.createStatement().execute(insertSQL);
+ }
+ int r1 = statement.executeUpdate("update dummytable set name='Kumquat' where name = 'Orange' OR name = 'Kiwi'"); // no matching result
+ assertEquals ("To Rows updated ", 2, statement.getUpdateCount());
+ assertEquals ("To Rows updated ", 2, r1);
+ statement.close();
+ }
public void checkResultSet ( ResultSet rs, boolean isClosed, boolean isBeforeFirst, boolean isAfterLast,boolean isFirst,boolean isLast) throws Exception {
assertEquals ("Is Closed", isClosed, rs.isClosed());
@@ -433,6 +462,7 @@ public static Test suite () {
suite.addTest(new DriverUnitTest("testBlob"));
suite.addTest(new DriverUnitTest("testMetaData"));
suite.addTest(new DriverUnitTest("testCursors"));
+ suite.addTest(new DriverUnitTest("testExecute"));
return suite;
}
Please sign in to comment.
Something went wrong with that request. Please try again.