Skip to content

Commit 6afed0a

Browse files
committed
Use extended result codes
1 parent 4484854 commit 6afed0a

File tree

9 files changed

+283
-53
lines changed

9 files changed

+283
-53
lines changed

src/main/java/org/sqlite/SQLiteConfig.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public class SQLiteConfig
5353
public DatePrecision datePrecision;
5454
public long dateMultiplier;
5555
public String dateStringFormat;
56+
private boolean extendedResultCodesUsed;
5657

5758
/**
5859
* Default constructor.
@@ -88,6 +89,7 @@ public SQLiteConfig(Properties prop) {
8889
datePrecision = DatePrecision.getPrecision(pragmaTable.getProperty(Pragma.DATE_PRECISION.pragmaName, DatePrecision.MILLISECONDS.name()));
8990
dateMultiplier = (datePrecision == DatePrecision.MILLISECONDS) ? 1L : 1000L;
9091
dateStringFormat = pragmaTable.getProperty(Pragma.DATE_STRING_FORMAT.pragmaName, DEFAULT_DATE_STRING_FORMAT);
92+
extendedResultCodesUsed = Boolean.valueOf(pragmaTable.getProperty(Pragma.EXTENDED_RESULT_CODES.pragmaName, "FALSE"));
9193

9294
busyTimeout = Integer.parseInt(pragmaTable.getProperty(Pragma.BUSY_TIMEOUT.pragmaName, "3000"));
9395
}
@@ -119,6 +121,7 @@ public void apply(Connection conn) throws SQLException {
119121
pragmaParams.remove(Pragma.DATE_PRECISION.pragmaName);
120122
pragmaParams.remove(Pragma.DATE_CLASS.pragmaName);
121123
pragmaParams.remove(Pragma.DATE_STRING_FORMAT.pragmaName);
124+
pragmaParams.remove(Pragma.EXTENDED_RESULT_CODES.pragmaName);
122125

123126
Statement stat = conn.createStatement();
124127
try {
@@ -213,6 +216,7 @@ public Properties toProperties() {
213216
pragmaTable.setProperty(Pragma.DATE_CLASS.pragmaName, dateClass.getValue());
214217
pragmaTable.setProperty(Pragma.DATE_PRECISION.pragmaName, datePrecision.getValue());
215218
pragmaTable.setProperty(Pragma.DATE_STRING_FORMAT.pragmaName, dateStringFormat);
219+
pragmaTable.setProperty(Pragma.EXTENDED_RESULT_CODES.pragmaName, Boolean.toString(extendedResultCodesUsed));
216220

217221
return pragmaTable;
218222
}
@@ -237,6 +241,10 @@ static DriverPropertyInfo[] getDriverPropertyInfo() {
237241

238242
private static final String[] OnOff = new String[] { "true", "false" };
239243

244+
public boolean isExtendedResultCodesUsed() {
245+
return extendedResultCodesUsed;
246+
}
247+
240248
public static enum Pragma {
241249

242250
// Parameters requiring SQLite3 API invocation
@@ -275,7 +283,8 @@ public static enum Pragma {
275283
DATE_PRECISION("date_precision", "\"seconds\": Read and store integer dates as seconds from the Unix Epoch (SQLite standard).\n\"milliseconds\": (DEFAULT) Read and store integer dates as milliseconds from the Unix Epoch (Java standard).", toStringArray(DatePrecision.values())),
276284
DATE_CLASS("date_class", "\"integer\": (Default) store dates as number of seconds or milliseconds from the Unix Epoch\n\"text\": store dates as a string of text\n\"real\": store dates as Julian Dates", toStringArray(DateClass.values())),
277285
DATE_STRING_FORMAT("date_string_format", "Format to store and retrieve dates stored as text. Defaults to \"yyyy-MM-dd HH:mm:ss.SSS\"", null),
278-
BUSY_TIMEOUT("busy_timeout", null);
286+
BUSY_TIMEOUT("busy_timeout", null),
287+
EXTENDED_RESULT_CODES("extended result codes", OnOff);
279288

280289
public final String pragmaName;
281290
public final String[] choices;

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

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
//--------------------------------------
2525
package org.sqlite;
2626

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

68116
public final int code;
69117
public final String message;
@@ -85,14 +133,29 @@ private SQLiteErrorCode(int code, String message)
85133
*/
86134
public static SQLiteErrorCode getErrorCode(int errorCode)
87135
{
136+
return fromVendorCode(errorCode);
137+
}
138+
139+
public static SQLiteErrorCode fromVendorCode(int vendorCode) {
88140
for (SQLiteErrorCode each : SQLiteErrorCode.values())
89141
{
90-
if (errorCode == each.code)
142+
if (vendorCode == each.code)
91143
return each;
92144
}
93145
return UNKNOWN_ERROR;
94146
}
95147

148+
public static SQLiteErrorCode fromException(SQLException e) {
149+
return fromVendorCode(e.getErrorCode());
150+
}
151+
152+
public int toVendorCode(boolean useExtendedResultCodes) {
153+
if (useExtendedResultCodes) {
154+
return code;
155+
}
156+
return code & 0xff;
157+
}
158+
96159
/**
97160
* @see java.lang.Enum#toString()
98161
*/

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public abstract class CoreConnection {
2929
private static final String RESOURCE_NAME_PREFIX = ":resource:";
3030

3131
private final String url;
32+
private final boolean useExtendedResultCodes;
3233
private String fileName;
3334
protected DB db = null;
3435
protected CoreDatabaseMetaData meta = null;
@@ -72,6 +73,7 @@ protected CoreConnection(String url, String fileName, Properties prop) throws SQ
7273
this.datePrecision = config.datePrecision;
7374
this.transactionMode = config.getTransactionMode();
7475
this.openModeFlags = config.getOpenModeFlags();
76+
this.useExtendedResultCodes = config.isExtendedResultCodesUsed();
7577

7678
open(openModeFlags, config.busyTimeout);
7779

@@ -394,4 +396,8 @@ public void close() throws SQLException {
394396
db.close();
395397
db = null;
396398
}
399+
400+
public boolean isExtendedResultCodesUsed() {
401+
return useExtendedResultCodes;
402+
}
397403
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ protected boolean exec(String sql) throws SQLException {
112112

113113
protected void internalClose() throws SQLException {
114114
if (db.conn.isClosed())
115-
throw DB.newSQLException(SQLITE_ERROR, "Connection is closed");
115+
throw db.newSQLException(SQLITE_ERROR, "Connection is closed");
116116

117117
if (pointer == 0)
118118
return;
@@ -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: 17 additions & 11 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 {
@@ -749,8 +750,9 @@ final synchronized int[] executeBatch(long stmt, int count, Object[] vals) throw
749750
for (int i = 0; i < count; i++) {
750751
reset(stmt);
751752
for (int j = 0; j < params; j++) {
752-
if (sqlbind(stmt, j, vals[(i * params) + j]) != SQLITE_OK) {
753-
throwex();
753+
rc = sqlbind(stmt, j, vals[(i * params) + j]);
754+
if (rc != SQLITE_OK) {
755+
throwex(rc);
754756
}
755757
}
756758

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

766768
changes[i] = changes();
@@ -790,8 +792,9 @@ public final synchronized boolean execute(CoreStatement stmt, Object[] vals) thr
790792
}
791793

792794
for (int i = 0; i < params; i++) {
793-
if (sqlbind(stmt.pointer, i, vals[i]) != SQLITE_OK) {
794-
throwex();
795+
int rc = sqlbind(stmt.pointer, i, vals[i]);
796+
if (rc != SQLITE_OK) {
797+
throwex(rc);
795798
}
796799
}
797800
}
@@ -891,9 +894,11 @@ final void throwex(int errorCode, String errorMessage) throws SQLException {
891894
* @return Formated SQLException with error code and message.
892895
* @throws SQLException
893896
*/
894-
public static SQLException newSQLException(int errorCode, String errorMessage) throws SQLException {
897+
public SQLException newSQLException(int errorCode, String errorMessage) throws SQLException {
895898
SQLiteErrorCode code = SQLiteErrorCode.getErrorCode(errorCode);
896-
SQLException e = new SQLException(String.format("%s (%s)", code, errorMessage), null, code.code);
899+
SQLException e = new SQLException(
900+
String.format("%s (%s)", code, errorMessage), null, code.toVendorCode(conn.isExtendedResultCodesUsed())
901+
);
897902
return e;
898903
}
899904

@@ -956,9 +961,10 @@ final void ensureAutoCommit() throws SQLException {
956961
{
957962
return; // assume we are in a transaction
958963
}
959-
if (step(commit) != SQLITE_DONE) {
964+
int rc = step(commit);
965+
if (rc != SQLITE_DONE) {
960966
reset(commit);
961-
throwex();
967+
throwex(rc);
962968
}
963969
//throw new SQLException("unable to auto-commit");
964970
}

0 commit comments

Comments
 (0)