Skip to content

Commit 8aad3be

Browse files
committed
Use extended error codes
1 parent 1182886 commit 8aad3be

File tree

6 files changed

+145
-16
lines changed

6 files changed

+145
-16
lines changed

src/main/java/org/sqlite/SQLiteErrorCode.java

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,56 @@ public enum SQLiteErrorCode {
6363
SQLITE_RANGE(25, " 2nd parameter to sqlite3_bind out of range"),
6464
SQLITE_NOTADB(26, " File opened that is not a database file"),
6565
SQLITE_ROW(100, " sqlite3_step() has another row ready"),
66-
SQLITE_DONE(101, " sqlite3_step() has finished executing");
66+
SQLITE_DONE(101, " sqlite3_step() has finished executing"),
67+
/* Beginning of extended error codes */
68+
SQLITE_BUSY_RECOVERY(261, " Another process is busy recovering a WAL mode database file following a crash"),
69+
SQLITE_LOCKED_SHAREDCACHE(262, " Contention with a different database connection that shares the cache"),
70+
SQLITE_READONLY_RECOVERY(264, " The database file needs to be recovered"),
71+
SQLITE_IOERR_READ(266, " I/O error in the VFS layer while trying to read from a file on disk"),
72+
SQLITE_CORRUPT_VTAB(267, " Content in the virtual table is corrupt"),
73+
SQLITE_CONSTRAINT_CHECK(275, " A CHECK constraint failed"),
74+
SQLITE_ABORT_ROLLBACK(516, " The transaction that was active when the SQL statement first started was rolled back"),
75+
SQLITE_BUSY_SNAPSHOT(517, " Another database connection has already written to the database"),
76+
SQLITE_READONLY_CANTLOCK(520, " The shared-memory file associated with that database is read-only"),
77+
SQLITE_IOERR_SHORT_READ(522, " The VFS layer was unable to obtain as many bytes as was requested"),
78+
SQLITE_CANTOPEN_ISDIR(526, " The file is really a directory"),
79+
SQLITE_CONSTRAINT_COMMITHOOK(531, " A commit hook callback returned non-zero"),
80+
SQLITE_READONLY_ROLLBACK(776, " Hot journal needs to be rolled back"),
81+
SQLITE_IOERR_WRITE(778, " I/O error in the VFS layer while trying to write to a file on disk"),
82+
SQLITE_CANTOPEN_FULLPATH(782, " The operating system was unable to convert the filename into a full pathname"),
83+
SQLITE_CONSTRAINT_FOREIGNKEY(787, " A foreign key constraint failed"),
84+
SQLITE_READONLY_DBMOVED(1032, " The database file has been moved since it was opened"),
85+
SQLITE_IOERR_FSYNC(1034, " I/O error in the VFS layer while trying to flush previously written content"),
86+
SQLITE_CANTOPEN_CONVPATH(1038, " cygwin_conv_path() system call failed while trying to open a file"),
87+
SQLITE_CONSTRAINT_FUNCTION(1043, " Error reported by extension function"),
88+
SQLITE_IOERR_DIR_FSYNC(1290, " I/O error in the VFS layer while trying to invoke fsync() on a directory"),
89+
SQLITE_CONSTRAINT_NOTNULL(1299, " A NOT NULL constraint failed"),
90+
SQLITE_IOERR_TRUNCATE(1546, " I/O error in the VFS layer while trying to truncate a file to a smaller size"),
91+
SQLITE_CONSTRAINT_PRIMARYKEY(1555, " A PRIMARY KEY constraint failed"),
92+
SQLITE_IOERR_FSTAT(1802, " I/O error in the VFS layer while trying to invoke fstat()"),
93+
SQLITE_CONSTRAINT_TRIGGER(1811, " A RAISE function within a trigger fired, causing the SQL statement to abort"),
94+
SQLITE_IOERR_UNLOCK(2058, " I/O error within xUnlock"),
95+
SQLITE_CONSTRAINT_UNIQUE(2067, " A UNIQUE constraint failed"),
96+
SQLITE_IOERR_RDLOCK(2314, " I/O error within xLock"),
97+
SQLITE_CONSTRAINT_VTAB(2323, " Error reported by application-defined virtual table"),
98+
SQLITE_IOERR_DELETE(2570, " I/O error within xDelete"),
99+
SQLITE_CONSTRAINT_ROWID(2579, " rowid is not unique"),
100+
SQLITE_IOERR_NOMEM(3082, " Unable to allocate sufficient memory"),
101+
SQLITE_IOERR_ACCESS(3338, " I/O error within the xAccess"),
102+
SQLITE_IOERR_CHECKRESERVEDLOCK(3594, " I/O error within xCheckReservedLock"),
103+
SQLITE_IOERR_LOCK(3850, " I/O error in the advisory file locking logic"),
104+
SQLITE_IOERR_CLOSE(4106, " I/O error within xClose"),
105+
SQLITE_IOERR_SHMOPEN(4618, " I/O error within xShmMap while trying to open a new shared memory segment"),
106+
SQLITE_IOERR_SHMSIZE(4874, " I/O error within xShmMap while trying to resize an existing shared memory segment"),
107+
SQLITE_IOERR_SHMMAP(5386, " I/O error within xShmMap while trying to map a shared memory segment"),
108+
SQLITE_IOERR_SEEK(5642, " I/O error while trying to seek a file descriptor"),
109+
SQLITE_IOERR_DELETE_NOENT(5898, " The file being deleted does not exist"),
110+
SQLITE_IOERR_MMAP(6154, " I/O error while trying to map or unmap part of the database file"),
111+
SQLITE_IOERR_GETTEMPPATH(6410, " Unable to determine a suitable directory in which to place temporary files"),
112+
SQLITE_IOERR_CONVPATH(6666, " cygwin_conv_path() system call failed");
67113

68114
public final int code;
115+
public final int extended;
69116
public final String message;
70117

71118
/**
@@ -75,7 +122,8 @@ public enum SQLiteErrorCode {
75122
*/
76123
private SQLiteErrorCode(int code, String message)
77124
{
78-
this.code = code;
125+
this.code = code & 0xff;
126+
this.extended = code;
79127
this.message = message;
80128
}
81129

@@ -87,7 +135,12 @@ public static SQLiteErrorCode getErrorCode(int errorCode)
87135
{
88136
for (SQLiteErrorCode each : SQLiteErrorCode.values())
89137
{
90-
if (errorCode == each.code)
138+
if (errorCode == each.extended)
139+
return each;
140+
}
141+
for (SQLiteErrorCode each : SQLiteErrorCode.values())
142+
{
143+
if ((errorCode & 0xff) == each.code)
91144
return each;
92145
}
93146
return UNKNOWN_ERROR;

src/main/java/org/sqlite/core/CoreStatement.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ protected void internalClose() throws SQLException {
123123
int resp = db.finalize(this);
124124

125125
if (resp != SQLITE_OK && resp != SQLITE_MISUSE)
126-
db.throwex();
126+
db.throwex(resp);
127127
}
128128

129129
public abstract ResultSet executeQuery(String sql, boolean closeStmt) throws SQLException;

src/main/java/org/sqlite/core/DB.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,15 @@ public final synchronized void exec(String sql) throws SQLException {
132132
long pointer = 0;
133133
try {
134134
pointer = prepare(sql);
135-
switch (step(pointer)) {
135+
int rc = step(pointer);
136+
switch (rc) {
136137
case SQLITE_DONE:
137138
ensureAutoCommit();
138139
return;
139140
case SQLITE_ROW:
140141
return;
141142
default:
142-
throwex();
143+
throwex(rc);
143144
}
144145
}
145146
finally {
@@ -746,8 +747,9 @@ final synchronized int[] executeBatch(long stmt, int count, Object[] vals) throw
746747
for (int i = 0; i < count; i++) {
747748
reset(stmt);
748749
for (int j = 0; j < params; j++) {
749-
if (sqlbind(stmt, j, vals[(i * params) + j]) != SQLITE_OK) {
750-
throwex();
750+
rc = sqlbind(stmt, j, vals[(i * params) + j]);
751+
if (rc != SQLITE_OK) {
752+
throwex(rc);
751753
}
752754
}
753755

@@ -757,7 +759,7 @@ final synchronized int[] executeBatch(long stmt, int count, Object[] vals) throw
757759
if (rc == SQLITE_ROW) {
758760
throw new BatchUpdateException("batch entry " + i + ": query returns results", changes);
759761
}
760-
throwex();
762+
throwex(rc);
761763
}
762764

763765
changes[i] = changes();
@@ -787,8 +789,9 @@ public final synchronized boolean execute(CoreStatement stmt, Object[] vals) thr
787789
}
788790

789791
for (int i = 0; i < params; i++) {
790-
if (sqlbind(stmt.pointer, i, vals[i]) != SQLITE_OK) {
791-
throwex();
792+
int rc = sqlbind(stmt.pointer, i, vals[i]);
793+
if (rc != SQLITE_OK) {
794+
throwex(rc);
792795
}
793796
}
794797
}
@@ -953,9 +956,10 @@ final void ensureAutoCommit() throws SQLException {
953956
{
954957
return; // assume we are in a transaction
955958
}
956-
if (step(commit) != SQLITE_DONE) {
959+
int rc = step(commit);
960+
if (rc != SQLITE_DONE) {
957961
reset(commit);
958-
throwex();
962+
throwex(rc);
959963
}
960964
//throw new SQLException("unable to auto-commit");
961965
}

src/main/java/org/sqlite/core/NativeDB.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,16 @@ static void throwex_msg(JNIEnv *env, const char *str)
7070
(*env)->NewStringUTF(env, str));
7171
}
7272

73-
static void throwex_errorcode_and_msg(JNIEnv *env, int errorCode, const char *str)
73+
static void throwex_errorcode_and_msg(JNIEnv *env, jobject this, int errorCode, const char *str)
7474
{
7575
static jmethodID mth_throwexmsg = 0;
7676

77-
if (!mth_throwexmsg) mth_throwexmsg = (*env)->GetStaticMethodID(
77+
if (!mth_throwexmsg) mth_throwexmsg = (*env)->GetMethodID(
7878
env, dbclass, "throwex", "(ILjava/lang/String;)V");
7979

80-
(*env)->CallStaticVoidMethod(env, dbclass, mth_throwexmsg, (jint) errorCode,
80+
assert(mth_throwexmsg);
81+
82+
(*env)->CallVoidMethod(env, this, mth_throwexmsg, (jint) errorCode,
8183
(*env)->NewStringUTF(env, str));
8284
}
8385

@@ -354,6 +356,9 @@ JNIEXPORT void JNICALL Java_org_sqlite_core_NativeDB__1open(
354356
return;
355357
}
356358

359+
// Ignore failures, as we can tolerate regular result codes.
360+
(void) sqlite3_extended_result_codes(db, 1);
361+
357362
sethandle(env, this, db);
358363
}
359364

src/test/java/org/sqlite/AllTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
BackupTest.class,
1010
ConnectionTest.class,
1111
DBMetaDataTest.class,
12+
ErrorMessageTest.class,
1213
ExtendedCommandTest.class,
1314
ExtensionTest.class,
1415
FetchSizeTest.class,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.sqlite;
2+
3+
import static org.junit.Assume.assumeTrue;
4+
5+
import java.io.File;
6+
import java.io.IOException;
7+
import java.sql.Connection;
8+
import java.sql.DriverManager;
9+
import java.sql.SQLException;
10+
import java.sql.Statement;
11+
12+
import org.junit.Rule;
13+
import org.junit.Test;
14+
import org.junit.matchers.JUnitMatchers;
15+
import org.junit.rules.ExpectedException;
16+
17+
public class ErrorMessageTest
18+
{
19+
@Rule
20+
public ExpectedException thrown = ExpectedException.none();
21+
22+
@Test
23+
public void moved() throws SQLException, IOException {
24+
File from = File.createTempFile("error-message-test-moved-from", ".sqlite");
25+
from.deleteOnExit();
26+
27+
Connection conn = DriverManager.getConnection("jdbc:sqlite:" + from.getAbsolutePath());
28+
Statement stmt = conn.createStatement();
29+
stmt.executeUpdate("create table sample(id, name)");
30+
stmt.executeUpdate("insert into sample values(1, \"foo\")");
31+
32+
File to = File.createTempFile("error-message-test-moved-from", ".sqlite");
33+
assumeTrue(to.delete());
34+
assumeTrue(from.renameTo(to));
35+
36+
thrown.expectMessage(JUnitMatchers.containsString("[SQLITE_READONLY_DBMOVED]"));
37+
stmt.executeUpdate("insert into sample values(2, \"bar\")");
38+
39+
stmt.close();
40+
conn.close();
41+
}
42+
43+
@Test
44+
public void writeProtected() throws SQLException, IOException {
45+
File file = File.createTempFile("error-message-test-moved-from", ".sqlite");
46+
file.deleteOnExit();
47+
48+
Connection conn = DriverManager.getConnection("jdbc:sqlite:" + file.getAbsolutePath());
49+
Statement stmt = conn.createStatement();
50+
stmt.executeUpdate("create table sample(id, name)");
51+
stmt.executeUpdate("insert into sample values(1, \"foo\")");
52+
stmt.close();
53+
conn.close();
54+
55+
assumeTrue(file.setReadOnly());
56+
57+
conn = DriverManager.getConnection("jdbc:sqlite:" + file.getAbsolutePath());
58+
stmt = conn.createStatement();
59+
thrown.expectMessage(JUnitMatchers.containsString("[SQLITE_READONLY]"));
60+
stmt.executeUpdate("insert into sample values(2, \"bar\")");
61+
stmt.close();
62+
conn.close();
63+
}
64+
65+
66+
}

0 commit comments

Comments
 (0)