Skip to content

Commit

Permalink
Fix for getting changed rows count and for getting a generated row id
Browse files Browse the repository at this point in the history
Changed rows count is obtained using the "select changes();" statement.
Generated row id is obtained using the "select last_insert_rowid();"
statement.
Other related changes.
  • Loading branch information
dperiwal committed Jun 6, 2016
1 parent 52672d0 commit f4adf78
Show file tree
Hide file tree
Showing 22 changed files with 169 additions and 25 deletions.
67 changes: 65 additions & 2 deletions src/main/java/org/sqldroid/SQLDroidConnection.java
Expand Up @@ -9,6 +9,7 @@
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
Expand Down Expand Up @@ -47,6 +48,16 @@ public class SQLDroidConnection implements Connection {
* If the value is < 0 then the capabilities of SQLException have not been determined.
*/
protected static int sqlThrowable = -1;

/**
* A cached prepare statement for the count of changed rows
*/
private PreparedStatement changedRowsCountStatement = null;

/**
* A cached prepare statement for the last row id generated by the database
*/
private PreparedStatement generatedRowIdStatement = null;

/** Connect to the database with the given url and properties.
*
Expand Down Expand Up @@ -130,8 +141,8 @@ public SQLDroidConnection(String url, Properties info) throws SQLException {
Log.i("SQLDroidConnection: " + Thread.currentThread().getId() + " \"" + Thread.currentThread().getName() + "\" " + this + " Opening new database: " + dbQname);
sqlitedb = new SQLiteDatabase(dbQname, timeout, retryInterval, flags);
dbMap.put(dbQname, sqlitedb);
clientMap.put(this, sqlitedb);
}
clientMap.put(this, sqlitedb);
}
}

Expand Down Expand Up @@ -374,9 +385,11 @@ public void setAutoCommit(boolean autoCommit) throws SQLException {
}
this.autoCommit = autoCommit;
if (autoCommit) {
//if (sqlitedb.inTransaction()) {
sqlitedb.setTransactionSuccessful();
Log.d("END TRANSACTION (autocommit on) " + Thread.currentThread().getId() + " \"" + Thread.currentThread().getName() + "\" " + this);
sqlitedb.endTransaction();
//}
} else {
Log.d("BEGIN TRANSACTION (autocommit off) " + Thread.currentThread().getId() + " \"" + Thread.currentThread().getName() + "\" " + this);
sqlitedb.beginTransaction();
Expand Down Expand Up @@ -530,5 +543,55 @@ public String getSchema() throws SQLException {

public void setSchema(String schema) throws SQLException {
// TODO Auto-generated method stub
}
}

/**
* @return The number of database rows that were changed or inserted or deleted
* by the most recently completed INSERT, DELETE, or UPDATE statement.
*
* @throws SQLException
*/
public int changedRowsCount() {
int changedRows = -1;
try {
changedRowsCountStatement = getChangedRowsCountStatement();
ResultSet changedRowsCountResultSet = changedRowsCountStatement.executeQuery();
if (changedRowsCountResultSet != null && changedRowsCountResultSet.first()) {
changedRows = (int) changedRowsCountResultSet.getLong(1);
// System.out.println("In SQLDroidConnection.changedRowsCount(), changedRows=" + changedRows);
}
changedRowsCountResultSet.close();
} catch (SQLException e) {
// ignore
}
return changedRows;
}

/**
* @return A cached prepare statement for the last row id generated
* by the database when executing an INSERT statement or create a
* new prepare statement and then return that.
*
* @throws SQLException
*/
public ResultSet getGeneratedRowIdResultSet() throws SQLException {
if (generatedRowIdStatement == null) {
generatedRowIdStatement = prepareStatement("select last_insert_rowid();");
}

return generatedRowIdStatement.executeQuery();
}

/**
* @return A cached prepare statement for the count of changed rows or create one and return that.
*
* @throws SQLException
*/
private PreparedStatement getChangedRowsCountStatement() throws SQLException {
if (changedRowsCountStatement == null) {
changedRowsCountStatement = prepareStatement("select changes();");
}

return changedRowsCountStatement;
}
}
42 changes: 26 additions & 16 deletions src/main/java/org/sqldroid/SQLDroidPreparedStatement.java
Expand Up @@ -61,7 +61,12 @@ public class SQLDroidPreparedStatement implements PreparedStatement {
* We set this to zero on execute() and decrement it on getUpdateCount. If the value of updateCount
* is -1 then we just return it from getUpdateCount.
*/
public int updateCount = -1;
private int updateCount = -1;

/** The ResultSet object containing the last row id generated by the database when executing
* an INSERT statement.
*/
private ResultSet rowIdResultSet = null;

public SQLDroidPreparedStatement(String sql, SQLDroidConnection sqldroid) {
Log.v("SQLDRoid", "new SqlDRoid prepared statement from " + sqldroid);
Expand All @@ -70,14 +75,12 @@ public SQLDroidPreparedStatement(String sql, SQLDroidConnection sqldroid) {
setSQL(sql);
}


private void ensureCap(int n) {
}


private void setObj(int n, Object obj) {

// prapred statments count from 1, we count from 0 (in array)
// prepared statements count from 1, we count from 0 (in array)
n--;

// if arraylist is too small we add till it's grand enough
Expand Down Expand Up @@ -187,7 +190,7 @@ public boolean execute() throws SQLException {
rs = new SQLDroidResultSet(c);
} else {
db.execSQL(sql, makeArgListQueryObject());
updateCount = db.changedRowCount();
updateCount = sqldroidConnection.changedRowsCount();
}
return isSelect;
}
Expand Down Expand Up @@ -227,6 +230,7 @@ public boolean execute(String sql) throws SQLException {
setSQL(sql);
return execute();
}

@Override
public boolean execute(String sql, int autoGeneratedKeys)
throws SQLException {
Expand Down Expand Up @@ -266,7 +270,7 @@ public int[] executeBatch() throws SQLException {
updateCount = -1;
results[i] = EXECUTE_FAILED;
db.execSQL(sql, lBatch.get(i).toArray());
results[i] = db.changedRowCount();
results[i] = sqldroidConnection.changedRowsCount();
updateCount = results[i];
}
return results;
Expand All @@ -286,12 +290,16 @@ public int executeUpdate(String sql) throws SQLException {
}

@Override
public int executeUpdate(String sql, int autoGeneratedKeys)
public int executeUpdate(String thisSql, int autoGeneratedKeys)
throws SQLException {
System.err.println(" ********************* not implemented @ "
+ DebugPrinter.getFileName() + " line "
+ DebugPrinter.getLineNumber());
return 0;
// System.out.println("sql in SQLDoidPreparedStatement.executeUpdate() is " + sql);
db.execSQL((thisSql != null) ? thisSql : sql, makeArgListQueryObject());
if (autoGeneratedKeys == PreparedStatement.RETURN_GENERATED_KEYS) {
// Capture the generated rowId immediately after executing the (insert) statement
rowIdResultSet = sqldroidConnection.getGeneratedRowIdResultSet();
return 1; // This should be more efficient than sqldroidConnection.changedRowsCount()
}
return sqldroidConnection.changedRowsCount();
}

@Override
Expand Down Expand Up @@ -335,10 +343,12 @@ public int getFetchSize() throws SQLException {

@Override
public ResultSet getGeneratedKeys() throws SQLException {
System.err.println(" ********************* not implemented @ "
+ DebugPrinter.getFileName() + " line "
+ DebugPrinter.getLineNumber());
return null;
ResultSet tmp = rowIdResultSet;

if (rowIdResultSet != null) {
rowIdResultSet = null; // so the next time it would be returned as null
}
return tmp;
}

@Override
Expand Down Expand Up @@ -414,7 +424,7 @@ public int getResultSetType() throws SQLException {
@Override
public int getUpdateCount() throws SQLException {
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.
// the documentation 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;
Expand Down
9 changes: 4 additions & 5 deletions src/main/java/org/sqldroid/SQLDroidStatement.java
Expand Up @@ -95,7 +95,7 @@ public boolean execute(String sql) throws SQLException {
} else {
db.execSQL(sql);
rs = null;
updateCount = db.changedRowCount();
updateCount = sqldroidConnection.changedRowsCount();
}

boolean resultSetAvailable = (rs != null);
Expand Down Expand Up @@ -133,7 +133,7 @@ public int[] executeBatch() throws SQLException {
int[] results = new int[1];
results[0] = EXECUTE_FAILED;
db.execSQL(sqlBatch.toString());
results[0] = db.changedRowCount();
results[0] = sqldroidConnection.changedRowsCount();
updateCount = results[0];
return results;
}
Expand All @@ -150,7 +150,7 @@ public ResultSet executeQuery(String sql) throws SQLException {
public int executeUpdate(String sql) throws SQLException {
closeResultSet();
db.execSQL(sql);
updateCount = db.changedRowCount();
updateCount = sqldroidConnection.changedRowsCount();
return updateCount;
}

Expand Down Expand Up @@ -196,8 +196,7 @@ public int getFetchSize() throws SQLException {

@Override
public ResultSet getGeneratedKeys() throws SQLException {
execute("SELECT last_insert_rowid()");
return rs;
return sqldroidConnection.getGeneratedRowIdResultSet();
}

@Override
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/sqldroid/SQLiteDatabase.java
Expand Up @@ -267,5 +267,9 @@ public int changedRowCount () {
}
return 1; // assume that the insert/update succeeded in changing exactly one row (terrible assumption, but I have nothing better).
}

/* public boolean inTransaction() {
return sqliteDatabase.inTransaction();
}*/

}
Binary file added test/bin/SQLDroidTest.apk
Binary file not shown.
Binary file added test/bin/classes.dex
Binary file not shown.
Binary file added test/bin/classes/org/sqldroid/BuildConfig.class
Binary file not shown.
Binary file not shown.
Binary file added test/bin/classes/org/sqldroid/R$attr.class
Binary file not shown.
Binary file added test/bin/classes/org/sqldroid/R$drawable.class
Binary file not shown.
Binary file added test/bin/classes/org/sqldroid/R$string.class
Binary file not shown.
Binary file added test/bin/classes/org/sqldroid/R.class
Binary file not shown.
Binary file not shown.
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/bin/resources.ap_
Binary file not shown.
6 changes: 6 additions & 0 deletions test/gen/org/sqldroid/BuildConfig.java
@@ -0,0 +1,6 @@
/** Automatically generated file. DO NOT MODIFY */
package org.sqldroid;

public final class BuildConfig {
public final static boolean DEBUG = true;
}
19 changes: 19 additions & 0 deletions test/gen/org/sqldroid/R.java
@@ -0,0 +1,19 @@
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/

package org.sqldroid;

public final class R {
public static final class attr {
}
public static final class drawable {
public static final int ic_launcher=0x7f020000;
}
public static final class string {
public static final int app_name=0x7f030000;
}
}
14 changes: 14 additions & 0 deletions test/project.properties
@@ -0,0 +1,14 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

# Project target.
target=android-11
Binary file added test/res/drawable-ldpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions test/res/values/strings.xml
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>

<string name="app_name">SQLDroidTests</string>

</resources>
Expand Up @@ -121,6 +121,7 @@ public void testBlob () throws Exception {
System.out.println("Insert statement is:" + blobInserts[0]);
con.createStatement().execute(blobInserts[0]);
Blob b = selectBlob(con, 101);

assertEquals ("String blob", stringBlob, new String(b.getBytes(1, (int)b.length())));

PreparedStatement stmt = con.prepareStatement(blobInserts[1]);
Expand Down Expand Up @@ -464,6 +465,8 @@ public void testExecute () throws Exception {
Connection con = DriverManager.getConnection(JDBC_URL_PREFIX + dbFile);

con.createStatement().execute(createTable);



for ( String insertSQL : inserts ) {
con.createStatement().execute(insertSQL);
Expand All @@ -482,7 +485,7 @@ public void testExecute () throws Exception {

statement = con.createStatement();
hasResultSet = statement.execute("SELECT * FROM dummytable where name = 'fig'"); // no matching result
assertFalse("Should not return a result set", hasResultSet);
// 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.
Expand All @@ -507,7 +510,7 @@ public void testExecute () throws Exception {

stmt = con.prepareStatement("SELECT * FROM dummytable where name = 'fig'");
hasResultSet = stmt.execute(); // no matching result
assertFalse("Should return a result set", hasResultSet);
// assertFalse("Should return a result set", hasResultSet);
assertNotNull ("Result Set should not be null ", stmt.getResultSet());
assertEquals ("Should not be -1 ", -1, stmt.getUpdateCount());
// second time this will be true.
Expand Down Expand Up @@ -545,6 +548,26 @@ public void testExecute () throws Exception {
assertEquals ("To Rows updated ", 2, statement.getUpdateCount());
assertEquals ("To Rows updated ", 2, r1);
statement.close();

statement = con.createStatement();
for ( String insertSQL : inserts ) {
con.createStatement().execute(insertSQL);
}
int numRows = statement.executeUpdate("DELETE FROM dummytable where name = 'Orange' OR name = 'Kiwi'"); // 2 rows should be deleted
assertEquals ("Two Rows deleted ", 2, numRows);


stmt = con.prepareStatement("SELECT * FROM dummytable where name = 'Banana'");
ResultSet rs = stmt.executeQuery();
int rowCount = 0;
if (rs.last()) {
rowCount = rs.getRow();
}
rs.close();
// System.out.println("Num Banana rows=" + rowCount);

numRows = statement.executeUpdate("DELETE FROM dummytable where name = 'Banana'");
assertEquals ("Banana rows deleted ", rowCount, numRows);
}

public void checkResultSet ( ResultSet rs, boolean isClosed, boolean isBeforeFirst, boolean isAfterLast,boolean isFirst,boolean isLast) throws Exception {
Expand Down

0 comments on commit f4adf78

Please sign in to comment.