0

I have the following code: result is the cursor.

    if (result.getCount() == 1 && result.getColumnCount() > 0) {
        result.moveToFirst();
        int columnIndex = result.getColumnIndex(TrackerContract.WorkLog.COLUMN_BLOCK_IN);
        long time = currentTimeMilliMinutes();
        sumTotal = time - result.getLong(columnIndex);
    }

So, even though I'm checking for rows and columns, it throws the error in the title. I don't know what else I should be doing to prevent this error. The cursor should only have 1 row, 1 column, value long, I have checked the sql statement via adb and it seems to be correct.

EDIT:

Here is the query:

Cursor result = db.rawQuery("SELECT MAX("+TrackerContract.WorkLog.COLUMN_BLOCK_IN+
            ") FROM "+TrackerContract.WorkLog.TABLE_NAME+" WHERE "+TrackerContract.WorkLog.COLUMN_FDP_BEGIN+
            "=(SELECT MAX("+TrackerContract.WorkLog.COLUMN_FDP_BEGIN+") FROM "+TrackerContract.WorkLog.TABLE_NAME+");", 
            null);

When I enter the same sql via adb, I get the correct long value as the only return value (1 row, 1 col). Here is the actual SQL statement, incase my encoding didn't go correctly. I plan on refactoring this to use the parameterized query method rather than raw sql, but for now I am just making sure it works, and using the raw statements is easier for me.

select max(blockTimeEnd) from WorkLog where dutyDayStart=(select max(dutyDayStart) from WorkLog);

The Stack Trace:

12-25 16:55:00.477: E/AndroidRuntime(32708): Caused by: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
12-25 16:55:00.477: E/AndroidRuntime(32708):    at android.database.CursorWindow.nativeGetLong(Native Method)
12-25 16:55:00.477: E/AndroidRuntime(32708):    at android.database.CursorWindow.getLong(CursorWindow.java:507)
12-25 16:55:00.477: E/AndroidRuntime(32708):    at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75)
12-25 16:55:00.477: E/AndroidRuntime(32708):    at com.berrmal.timetracker.MainActivity.currentRest(MainActivity.java:503)
12-25 16:55:00.477: E/AndroidRuntime(32708):    at com.berrmal.timetracker.MainActivity.updateTimeTotals(MainActivity.java:567)
12-25 16:55:00.477: E/AndroidRuntime(32708):    at com.berrmal.timetracker.MainActivity.populateViews(MainActivity.java:187)
12-25 16:55:00.477: E/AndroidRuntime(32708):    at com.berrmal.timetracker.MainActivity.onResume(MainActivity.java:183)

Edit 2: did some logging/debugging, the column name in the cursor returned is max(blockTimeEnd) where it should be blockTimeEnd. This is clearly the error.

nexus_2006
  • 744
  • 2
  • 14
  • 29

2 Answers2

0

Looking at the error message, result.getColumnIndex(TrackerContract.WorkLog.COLUMN_BLOCK_IN) returns -1 as it cannot find the column. From the Android documentation on getColumnIndex:

Returns the zero-based index for the given column name, or -1 if the column doesn't exist.

Make sure that TrackerContract.WorkLog.COLUMN_BLOCK_IN is a proper column name.

UPDATE:

As you're using SELECT MAX(blockTimeEnd), the returned column name is not blockTimeEnd. Change the select part of your query to use the alias SELECT MAX(blockTimeEnd) AS blockTimeEnd or in case of using constants:

Cursor result = db.rawQuery("SELECT MAX("+TrackerContract.WorkLog.COLUMN_BLOCK_IN+
        ") AS " + TrackerContract.WorkLog.COLUMN_BLOCK_IN + " FROM "+TrackerContract.WorkLog.TABLE_NAME+" WHERE "+TrackerContract.WorkLog.COLUMN_FDP_BEGIN+
        "=(SELECT MAX("+TrackerContract.WorkLog.COLUMN_FDP_BEGIN+") FROM "+TrackerContract.WorkLog.TABLE_NAME+");", 
        null);

Alternatively, read the column by number in your code as you know you have only 1 returned:

if (result.getCount() == 1 && result.getColumnCount() > 0) {
    result.moveToFirst();
    long time = currentTimeMilliMinutes();
    sumTotal = time - result.getLong(0);
}
Szymon
  • 42,577
  • 16
  • 96
  • 114
  • Thanks. I don't understand why the code tries to access columnIndex -1, the if statement checks if the cursor has exactly 1 row and a column count > 0, so if the column count is -1 that line should not be executed, right? – nexus_2006 Dec 26 '13 at 18:46
  • See my update. The problem is that if you use an aggregate function, the returned column name is different. See my update for solutions. – Szymon Dec 26 '13 at 20:05
0

I found the error: when using the sql statement SELECT max(column) FROM table WHERE..." it appears the returned column name is max(column), not column.

Maybe this is common knowledge, I'm an SQL beginner, but this was not clear to me after reading the documentation of the max() function.

I changed the line

if (result.getCount() == 1 && 
            (columnIndex = result.getColumnIndex(TrackerContract.WorkLog.COLUMN_BLOCK_IN)) >= 0) {

to

if (result.getCount() == 1 && 
            (columnIndex = result.getColumnIndex("max("+TrackerContract.WorkLog.COLUMN_BLOCK_IN + ")")) >= 0) {

and the function now works as designed.

Since I know, by design, my query should only return 1 row 1 column, I could also just select column index 0 without checking the name.

nexus_2006
  • 744
  • 2
  • 14
  • 29