Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrap sqlite3 OPEN_URI option #785

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ Various options are accepted:

- `options.fileMustExist`: if the database does not exist, an `Error` will be thrown instead of creating a new file. This option is ignored for in-memory, temporary, or readonly database connections (default: `false`).

- `options.uriPath`: The filename can be interpreted as an URI if this flag is set (passes `SQLITE_OPEN_URI` to the underlying `sqlite3_open_v2()`). See also: [`sqlite3_open_v2()` documentation](https://sqlite.org/c3ref/open.html)

- `options.timeout`: the number of milliseconds to wait when executing queries on a locked database, before throwing a `SQLITE_BUSY` error (default: `5000`).

- `options.verbose`: provide a function that gets called with every SQL string executed by the database connection (default: `null`).
Expand Down
5 changes: 3 additions & 2 deletions lib/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function Database(filenameGiven, options) {
const anonymous = filename === '' || filename === ':memory:';
const readonly = util.getBooleanOption(options, 'readonly');
const fileMustExist = util.getBooleanOption(options, 'fileMustExist');
const uriPath = util.getBooleanOption(options, 'uriPath');
const timeout = 'timeout' in options ? options.timeout : 5000;
const verbose = 'verbose' in options ? options.verbose : null;
const nativeBindingPath = 'nativeBinding' in options ? options.nativeBinding : null;
Expand All @@ -55,12 +56,12 @@ function Database(filenameGiven, options) {
}

// Make sure the specified directory exists
if (!anonymous && !fs.existsSync(path.dirname(filename))) {
if (!anonymous && !uriPath && !fs.existsSync(path.dirname(filename))) {
throw new TypeError('Cannot open database because the directory does not exist');
}

Object.defineProperties(this, {
[util.cppdb]: { value: new addon.Database(filename, filenameGiven, anonymous, readonly, fileMustExist, timeout, verbose || null, buffer || null) },
[util.cppdb]: { value: new addon.Database(filename, filenameGiven, anonymous, readonly, fileMustExist, uriPath, timeout, verbose || null, buffer || null) },
...wrappers.getters,
});
}
Expand Down
74 changes: 39 additions & 35 deletions src/better_sqlite3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,9 +414,10 @@ void Database::JS_new (v8::FunctionCallbackInfo <v8 :: Value> const & info)
if ( info . Length ( ) <= ( 2 ) || ! info [ 2 ] -> IsBoolean ( ) ) return ThrowTypeError ( "Expected " "third" " argument to be " "a boolean" ) ; bool in_memory = ( info [ 2 ] . As < v8 :: Boolean > ( ) ) -> Value ( ) ;
if ( info . Length ( ) <= ( 3 ) || ! info [ 3 ] -> IsBoolean ( ) ) return ThrowTypeError ( "Expected " "fourth" " argument to be " "a boolean" ) ; bool readonly = ( info [ 3 ] . As < v8 :: Boolean > ( ) ) -> Value ( ) ;
if ( info . Length ( ) <= ( 4 ) || ! info [ 4 ] -> IsBoolean ( ) ) return ThrowTypeError ( "Expected " "fifth" " argument to be " "a boolean" ) ; bool must_exist = ( info [ 4 ] . As < v8 :: Boolean > ( ) ) -> Value ( ) ;
if ( info . Length ( ) <= ( 5 ) || ! info [ 5 ] -> IsInt32 ( ) ) return ThrowTypeError ( "Expected " "sixth" " argument to be " "a 32-bit signed integer" ) ; int timeout = ( info [ 5 ] . As < v8 :: Int32 > ( ) ) -> Value ( ) ;
if ( info . Length ( ) <= ( 6 ) ) return ThrowTypeError ( "Expected a " "seventh" " argument" ) ; v8 :: Local < v8 :: Value > logger = info [ 6 ] ;
if ( info . Length ( ) <= ( 7 ) ) return ThrowTypeError ( "Expected a " "eighth" " argument" ) ; v8 :: Local < v8 :: Value > buffer = info [ 7 ] ;
if ( info . Length ( ) <= ( 5 ) || ! info [ 5 ] -> IsBoolean ( ) ) return ThrowTypeError ( "Expected " "sixth" " argument to be " "a boolean" ) ; bool uri_path = ( info [ 5 ] . As < v8 :: Boolean > ( ) ) -> Value ( ) ;
if ( info . Length ( ) <= ( 6 ) || ! info [ 6 ] -> IsInt32 ( ) ) return ThrowTypeError ( "Expected " "seventh" " argument to be " "a 32-bit signed integer" ) ; int timeout = ( info [ 6 ] . As < v8 :: Int32 > ( ) ) -> Value ( ) ;
if ( info . Length ( ) <= ( 7 ) ) return ThrowTypeError ( "Expected a " "eighth" " argument" ) ; v8 :: Local < v8 :: Value > logger = info [ 7 ] ;
if ( info . Length ( ) <= ( 8 ) ) return ThrowTypeError ( "Expected a " "ninth" " argument" ) ; v8 :: Local < v8 :: Value > buffer = info [ 8 ] ;

Addon * addon = static_cast < Addon * > ( info . Data ( ) . As < v8 :: External > ( ) -> Value ( ) ) ;
v8 :: Isolate * isolate = info . GetIsolate ( ) ;
Expand All @@ -425,6 +426,9 @@ void Database::JS_new (v8::FunctionCallbackInfo <v8 :: Value> const & info)
int mask = readonly ? SQLITE_OPEN_READONLY
: must_exist ? SQLITE_OPEN_READWRITE
: (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
if (uri_path) {
mask |= SQLITE_OPEN_URI;
}

if (sqlite3_open_v2(*utf8, &db_handle, mask, NULL) != SQLITE_OK) {
ThrowSqliteError(addon, db_handle);
Expand Down Expand Up @@ -458,9 +462,9 @@ void Database::JS_new (v8::FunctionCallbackInfo <v8 :: Value> const & info)

info.GetReturnValue().Set(info.This());
}
#line 201 "./src/objects/database.lzz"
#line 205 "./src/objects/database.lzz"
void Database::JS_prepare (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 201 "./src/objects/database.lzz"
#line 205 "./src/objects/database.lzz"
{
if ( info . Length ( ) <= ( 0 ) || ! info [ 0 ] -> IsString ( ) ) return ThrowTypeError ( "Expected " "first" " argument to be " "a string" ) ; v8 :: Local < v8 :: String > source = ( info [ 0 ] . As < v8 :: String > ( ) ) ;
if ( info . Length ( ) <= ( 1 ) || ! info [ 1 ] -> IsObject ( ) ) return ThrowTypeError ( "Expected " "second" " argument to be " "an object" ) ; v8 :: Local < v8 :: Object > database = ( info [ 1 ] . As < v8 :: Object > ( ) ) ;
Expand All @@ -476,9 +480,9 @@ void Database::JS_prepare (v8::FunctionCallbackInfo <v8 :: Value> const & info)
addon->privileged_info = NULL;
if (!maybeStatement.IsEmpty()) info.GetReturnValue().Set(maybeStatement.ToLocalChecked());
}
#line 217 "./src/objects/database.lzz"
#line 221 "./src/objects/database.lzz"
void Database::JS_exec (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 217 "./src/objects/database.lzz"
#line 221 "./src/objects/database.lzz"
{
Database* db = node :: ObjectWrap :: Unwrap <Database>(info.This());
if ( info . Length ( ) <= ( 0 ) || ! info [ 0 ] -> IsString ( ) ) return ThrowTypeError ( "Expected " "first" " argument to be " "a string" ) ; v8 :: Local < v8 :: String > source = ( info [ 0 ] . As < v8 :: String > ( ) ) ;
Expand Down Expand Up @@ -518,9 +522,9 @@ void Database::JS_exec (v8::FunctionCallbackInfo <v8 :: Value> const & info)
db->ThrowDatabaseError();
}
}
#line 257 "./src/objects/database.lzz"
#line 261 "./src/objects/database.lzz"
void Database::JS_backup (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 257 "./src/objects/database.lzz"
#line 261 "./src/objects/database.lzz"
{
if ( info . Length ( ) <= ( 0 ) || ! info [ 0 ] -> IsObject ( ) ) return ThrowTypeError ( "Expected " "first" " argument to be " "an object" ) ; v8 :: Local < v8 :: Object > database = ( info [ 0 ] . As < v8 :: Object > ( ) ) ;
if ( info . Length ( ) <= ( 1 ) || ! info [ 1 ] -> IsString ( ) ) return ThrowTypeError ( "Expected " "second" " argument to be " "a string" ) ; v8 :: Local < v8 :: String > attachedName = ( info [ 1 ] . As < v8 :: String > ( ) ) ;
Expand All @@ -538,9 +542,9 @@ void Database::JS_backup (v8::FunctionCallbackInfo <v8 :: Value> const & info)
addon->privileged_info = NULL;
if (!maybeBackup.IsEmpty()) info.GetReturnValue().Set(maybeBackup.ToLocalChecked());
}
#line 275 "./src/objects/database.lzz"
#line 279 "./src/objects/database.lzz"
void Database::JS_serialize (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 275 "./src/objects/database.lzz"
#line 279 "./src/objects/database.lzz"
{
Database* db = node :: ObjectWrap :: Unwrap <Database>(info.This());
if ( info . Length ( ) <= ( 0 ) || ! info [ 0 ] -> IsString ( ) ) return ThrowTypeError ( "Expected " "first" " argument to be " "a string" ) ; v8 :: Local < v8 :: String > attachedName = ( info [ 0 ] . As < v8 :: String > ( ) ) ;
Expand All @@ -562,9 +566,9 @@ void Database::JS_serialize (v8::FunctionCallbackInfo <v8 :: Value> const & info
node::Buffer::New(isolate, reinterpret_cast<char*>(data), length, FreeSerialization, NULL).ToLocalChecked()
);
}
#line 297 "./src/objects/database.lzz"
#line 301 "./src/objects/database.lzz"
void Database::JS_function (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 297 "./src/objects/database.lzz"
#line 301 "./src/objects/database.lzz"
{
Database* db = node :: ObjectWrap :: Unwrap <Database>(info.This());
if ( info . Length ( ) <= ( 0 ) || ! info [ 0 ] -> IsFunction ( ) ) return ThrowTypeError ( "Expected " "first" " argument to be " "a function" ) ; v8 :: Local < v8 :: Function > fn = ( info [ 0 ] . As < v8 :: Function > ( ) ) ;
Expand All @@ -588,9 +592,9 @@ void Database::JS_function (v8::FunctionCallbackInfo <v8 :: Value> const & info)
db->ThrowDatabaseError();
}
}
#line 321 "./src/objects/database.lzz"
#line 325 "./src/objects/database.lzz"
void Database::JS_aggregate (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 321 "./src/objects/database.lzz"
#line 325 "./src/objects/database.lzz"
{
Database* db = node :: ObjectWrap :: Unwrap <Database>(info.This());
if ( info . Length ( ) <= ( 0 ) ) return ThrowTypeError ( "Expected a " "first" " argument" ) ; v8 :: Local < v8 :: Value > start = info [ 0 ] ;
Expand Down Expand Up @@ -619,9 +623,9 @@ void Database::JS_aggregate (v8::FunctionCallbackInfo <v8 :: Value> const & info
db->ThrowDatabaseError();
}
}
#line 350 "./src/objects/database.lzz"
#line 354 "./src/objects/database.lzz"
void Database::JS_table (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 350 "./src/objects/database.lzz"
#line 354 "./src/objects/database.lzz"
{
Database* db = node :: ObjectWrap :: Unwrap <Database>(info.This());
if ( info . Length ( ) <= ( 0 ) || ! info [ 0 ] -> IsFunction ( ) ) return ThrowTypeError ( "Expected " "first" " argument to be " "a function" ) ; v8 :: Local < v8 :: Function > factory = ( info [ 0 ] . As < v8 :: Function > ( ) ) ;
Expand All @@ -641,9 +645,9 @@ void Database::JS_table (v8::FunctionCallbackInfo <v8 :: Value> const & info)
}
db->busy = false;
}
#line 370 "./src/objects/database.lzz"
#line 374 "./src/objects/database.lzz"
void Database::JS_loadExtension (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 370 "./src/objects/database.lzz"
#line 374 "./src/objects/database.lzz"
{
Database* db = node :: ObjectWrap :: Unwrap <Database>(info.This());
v8::Local<v8::String> entryPoint;
Expand All @@ -665,9 +669,9 @@ void Database::JS_loadExtension (v8::FunctionCallbackInfo <v8 :: Value> const &
}
sqlite3_free(error);
}
#line 392 "./src/objects/database.lzz"
#line 396 "./src/objects/database.lzz"
void Database::JS_close (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 392 "./src/objects/database.lzz"
#line 396 "./src/objects/database.lzz"
{
Database* db = node :: ObjectWrap :: Unwrap <Database>(info.This());
if (db->open) {
Expand All @@ -677,39 +681,39 @@ void Database::JS_close (v8::FunctionCallbackInfo <v8 :: Value> const & info)
db->CloseHandles();
}
}
#line 402 "./src/objects/database.lzz"
#line 406 "./src/objects/database.lzz"
void Database::JS_defaultSafeIntegers (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 402 "./src/objects/database.lzz"
#line 406 "./src/objects/database.lzz"
{
Database* db = node :: ObjectWrap :: Unwrap <Database>(info.This());
if (info.Length() == 0) db->safe_ints = true;
else { if ( info . Length ( ) <= ( 0 ) || ! info [ 0 ] -> IsBoolean ( ) ) return ThrowTypeError ( "Expected " "first" " argument to be " "a boolean" ) ; db -> safe_ints = ( info [ 0 ] . As < v8 :: Boolean > ( ) ) -> Value ( ) ; }
}
#line 408 "./src/objects/database.lzz"
#line 412 "./src/objects/database.lzz"
void Database::JS_unsafeMode (v8::FunctionCallbackInfo <v8 :: Value> const & info)
#line 408 "./src/objects/database.lzz"
#line 412 "./src/objects/database.lzz"
{
Database* db = node :: ObjectWrap :: Unwrap <Database>(info.This());
if (info.Length() == 0) db->unsafe_mode = true;
else { if ( info . Length ( ) <= ( 0 ) || ! info [ 0 ] -> IsBoolean ( ) ) return ThrowTypeError ( "Expected " "first" " argument to be " "a boolean" ) ; db -> unsafe_mode = ( info [ 0 ] . As < v8 :: Boolean > ( ) ) -> Value ( ) ; }
sqlite3_db_config(db->db_handle, SQLITE_DBCONFIG_DEFENSIVE, static_cast<int>(!db->unsafe_mode), NULL);
}
#line 415 "./src/objects/database.lzz"
#line 419 "./src/objects/database.lzz"
void Database::JS_open (v8::Local <v8 :: String> _, v8::PropertyCallbackInfo <v8 :: Value> const & info)
#line 415 "./src/objects/database.lzz"
#line 419 "./src/objects/database.lzz"
{
info.GetReturnValue().Set( node :: ObjectWrap :: Unwrap <Database>(info.This())->open);
}
#line 419 "./src/objects/database.lzz"
#line 423 "./src/objects/database.lzz"
void Database::JS_inTransaction (v8::Local <v8 :: String> _, v8::PropertyCallbackInfo <v8 :: Value> const & info)
#line 419 "./src/objects/database.lzz"
#line 423 "./src/objects/database.lzz"
{
Database* db = node :: ObjectWrap :: Unwrap <Database>(info.This());
info.GetReturnValue().Set(db->open && !static_cast<bool>(sqlite3_get_autocommit(db->db_handle)));
}
#line 424 "./src/objects/database.lzz"
#line 428 "./src/objects/database.lzz"
bool Database::Deserialize (v8::Local <v8::Object> buffer, Addon * addon, sqlite3 * db_handle, bool readonly)
#line 424 "./src/objects/database.lzz"
#line 428 "./src/objects/database.lzz"
{
size_t length = node::Buffer::Length(buffer);
unsigned char* data = (unsigned char*)sqlite3_malloc64(length);
Expand All @@ -734,15 +738,15 @@ bool Database::Deserialize (v8::Local <v8::Object> buffer, Addon * addon, sqlite

return true;
}
#line 449 "./src/objects/database.lzz"
#line 453 "./src/objects/database.lzz"
void Database::FreeSerialization (char * data, void * _)
#line 449 "./src/objects/database.lzz"
#line 453 "./src/objects/database.lzz"
{
sqlite3_free(data);
}
#line 453 "./src/objects/database.lzz"
#line 457 "./src/objects/database.lzz"
int const Database::MAX_BUFFER_SIZE;
#line 454 "./src/objects/database.lzz"
#line 458 "./src/objects/database.lzz"
int const Database::MAX_STRING_SIZE;
#line 4 "./src/objects/statement.lzz"
v8::Local <v8 :: Function> Statement::Init (v8::Isolate * isolate, v8::Local <v8 :: External> data)
Expand Down
Loading