Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
node-sqlite3
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
俞永鹏
node-sqlite3
Commits
db72749d
Commit
db72749d
authored
Feb 14, 2011
by
Konstantin Käfer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
unify indentation and rework database opening, closing and garbage collection
parent
493050a9
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
360 additions
and
177 deletions
+360
-177
sqlite3.js
lib/sqlite3.js
+6
-1
database.cc
src/database.cc
+161
-111
database.h
src/database.h
+37
-27
macros.h
src/macros.h
+101
-25
sqlite3_bindings.cc
src/sqlite3_bindings.cc
+43
-0
statement.cc
src/statement.cc
+10
-10
blob.test.js
test/blob.test.js
+2
-3
No files found.
lib/sqlite3.js
View file @
db72749d
...
...
@@ -16,6 +16,9 @@
var
sqlite3
=
module
.
exports
=
exports
=
require
(
'./sqlite3_bindings'
);
var
sys
=
require
(
"sys"
);
/*
sqlite3.Database.prototype.query = function(sql, bindings, rowCallback) {
var self = this;
...
...
@@ -68,7 +71,7 @@ function _doStep(db, statement, rowCallback) {
// Execute a single SQL query with the given optional parameters. Calls
// `callback` with all rows or an error on query completion.
sqlite3
.
Database
.
prototype
.
execute
=
function
(
sql
/* , bindings, callback
*/
)
{
sqlite3.Database.prototype.execute = function (sql /* , bindings, callback ) {
var self = this;
var bindings, callback;
var n = arguments.length;
...
...
@@ -248,3 +251,4 @@ sqlite3.sanitizeError = function(err, data) {
'" with values ' + JSON.stringify(data, false, 4);
return err;
};
*/
\ No newline at end of file
src/database.cc
View file @
db72749d
...
...
@@ -38,17 +38,19 @@ void Database::Init(v8::Handle<Object> target) {
constructor_template
->
SetClassName
(
String
::
NewSymbol
(
"Database"
));
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"open"
,
Open
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"openSync"
,
OpenSync
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"close"
,
Close
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"closeSync"
,
CloseSync
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"prepare"
,
Prepare
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"prepareAndStep"
,
PrepareAndStep
);
target
->
Set
(
v8
::
String
::
NewSymbol
(
"Database"
),
constructor_template
->
GetFunction
());
// insert/update execution result mask
NODE_DEFINE_CONSTANT
(
target
,
EXEC_EMPTY
);
NODE_DEFINE_CONSTANT
(
target
,
EXEC_LAST_INSERT_ID
);
NODE_DEFINE_CONSTANT
(
target
,
EXEC_AFFECTED_ROWS
);
NODE_DEFINE_CONSTANT
(
target
,
EXEC_EMPTY
);
NODE_DEFINE_CONSTANT
(
target
,
EXEC_LAST_INSERT_ID
);
NODE_DEFINE_CONSTANT
(
target
,
EXEC_AFFECTED_ROWS
);
}
Handle
<
Value
>
Database
::
New
(
const
Arguments
&
args
)
{
...
...
@@ -58,152 +60,170 @@ Handle<Value> Database::New(const Arguments& args) {
return
args
.
This
();
}
int
Database
::
EIO_AfterOpen
(
eio_req
*
req
)
{
ev_unref
(
EV_DEFAULT_UC
);
Handle
<
Value
>
Database
::
OpenSync
(
const
Arguments
&
args
)
{
HandleScope
scope
;
struct
open_request
*
open_req
=
(
struct
open_request
*
)(
req
->
data
);
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
()
);
Local
<
Value
>
argv
[
1
];
bool
err
=
false
;
if
(
req
->
result
)
{
err
=
true
;
argv
[
0
]
=
Exception
::
Error
(
String
::
New
(
"Error opening database"
));
if
(
db
->
readyState
==
CLOSED
)
{
if
(
!
Open
(
db
))
{
EXCEPTION
(
db
->
error_message
.
c_str
(),
db
->
error_status
,
exception
);
return
ThrowException
(
exception
);
}
else
{
args
.
This
()
->
Set
(
String
::
NewSymbol
(
"opened"
),
True
(),
ReadOnly
);
db
->
Emit
(
String
::
NewSymbol
(
"opened"
),
0
,
NULL
);
TryCatch
try_catch
;
if
(
db
->
pending
==
0
)
{
db
->
Emit
(
String
::
NewSymbol
(
"idle"
),
0
,
NULL
);
}
}
}
open_req
->
db
->
Unref
();
open_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
err
?
1
:
0
,
argv
);
return
args
.
This
();
}
if
(
try_catch
.
HasCaught
()
)
{
FatalException
(
try_catch
)
;
}
Handle
<
Value
>
Database
::
Open
(
const
Arguments
&
args
)
{
HandleScope
scope
;
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
open_req
->
db
->
Emit
(
String
::
New
(
"ready"
),
0
,
NULL
);
open_req
->
cb
.
Dispose
();
if
(
db
->
readyState
==
CLOSED
)
{
db
->
readyState
=
OPENING
;
db
->
Ref
();
eio_custom
(
EIO_Open
,
EIO_PRI_DEFAULT
,
EIO_AfterOpen
,
db
);
ev_ref
(
EV_DEFAULT_UC
);
}
free
(
open_req
);
return
args
.
This
();
}
return
0
;
bool
Database
::
Open
(
Database
*
db
)
{
db
->
error_status
=
sqlite3_open_v2
(
db
->
filename
.
c_str
(),
&
db
->
handle
,
SQLITE_OPEN_FULLMUTEX
|
db
->
open_mode
,
NULL
);
if
(
db
->
error_status
!=
SQLITE_OK
)
{
db
->
error_message
=
std
::
string
(
sqlite3_errmsg
(
db
->
handle
));
db
->
readyState
=
CLOSED
;
return
false
;
}
else
{
db
->
readyState
=
OPEN
;
return
true
;
}
}
int
Database
::
EIO_Open
(
eio_req
*
req
)
{
struct
open_request
*
open_req
=
(
struct
open_request
*
)(
req
->
data
);
sqlite3
**
dbptr
=
open_req
->
db
->
GetDBPtr
();
int
rc
=
sqlite3_open_v2
(
open_req
->
filename
,
dbptr
,
SQLITE_OPEN_READWRITE
|
SQLITE_OPEN_CREATE
|
SQLITE_OPEN_FULLMUTEX
,
NULL
);
Database
*
db
=
static_cast
<
Database
*>
(
req
->
data
);
Open
(
db
);
return
0
;
}
req
->
result
=
rc
;
int
Database
::
EIO_AfterOpen
(
eio_req
*
req
)
{
HandleScope
scope
;
Database
*
db
=
static_cast
<
Database
*>
(
req
->
data
);
ev_unref
(
EV_DEFAULT_UC
);
db
->
Unref
();
// Set the a 10s timeout valuei for retries on BUSY errors.
sqlite3_busy_timeout
(
*
dbptr
,
10000
);
Local
<
Value
>
argv
[
1
];
if
(
db
->
error_status
!=
SQLITE_OK
)
{
EXCEPTION
(
db
->
error_message
.
c_str
(),
db
->
error_status
,
exception
);
argv
[
0
]
=
exception
;
}
else
{
argv
[
0
]
=
Local
<
Value
>::
New
(
Null
());
db
->
handle_
->
Set
(
String
::
NewSymbol
(
"opened"
),
True
(),
ReadOnly
);
}
db
->
Emit
(
String
::
NewSymbol
(
"opened"
),
1
,
argv
);
// sqlite3 *db = *dbptr;
// sqlite3_commit_hook(db, CommitHook, open_req->db);
// sqlite3_rollback_hook(db, RollbackHook, open_req->db);
// sqlite3_update_hook(db, UpdateHook, open_req->db);
if
(
db
->
pending
==
0
)
{
db
->
Emit
(
String
::
NewSymbol
(
"idle"
),
0
,
NULL
);
}
return
0
;
}
Handle
<
Value
>
Database
::
Open
(
const
Arguments
&
args
)
{
HandleScope
scope
;
REQ_STR_ARG
(
0
,
filename
);
REQ_FUN_ARG
(
1
,
cb
);
Handle
<
Value
>
Database
::
CloseSync
(
const
Arguments
&
args
)
{
HandleScope
scope
;
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
struct
open_request
*
open_req
=
(
struct
open_request
*
)
calloc
(
1
,
sizeof
(
struct
open_request
)
+
filename
.
length
());
if
(
!
open_req
)
{
V8
::
LowMemoryNotification
();
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Could not allocate enough memory"
)));
if
(
db
->
readyState
==
OPEN
)
{
if
(
!
Close
(
db
))
{
EXCEPTION
(
db
->
error_message
.
c_str
(),
db
->
error_status
,
exception
);
return
ThrowException
(
exception
);
}
else
{
args
.
This
()
->
Set
(
String
::
NewSymbol
(
"opened"
),
False
(),
ReadOnly
);
db
->
Emit
(
String
::
NewSymbol
(
"closed"
),
0
,
NULL
);
}
}
strcpy
(
open_req
->
filename
,
*
filename
);
open_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
open_req
->
db
=
db
;
return
True
();
}
eio_custom
(
EIO_Open
,
EIO_PRI_DEFAULT
,
EIO_AfterOpen
,
open_req
);
Handle
<
Value
>
Database
::
Close
(
const
Arguments
&
args
)
{
HandleScope
scope
;
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
ev_ref
(
EV_DEFAULT_UC
);
if
(
db
->
readyState
==
OPEN
)
{
db
->
readyState
=
CLOSING
;
db
->
Ref
();
eio_custom
(
EIO_Close
,
EIO_PRI_DEFAULT
,
EIO_AfterClose
,
db
);
ev_ref
(
EV_DEFAULT_UC
);
}
return
Undefined
();
return
args
.
This
();
}
int
Database
::
EIO_AfterClose
(
eio_req
*
req
)
{
ev_unref
(
EV_DEFAULT_UC
);
HandleScope
scope
;
bool
Database
::
Close
(
Database
*
db
)
{
assert
(
db
->
handle
);
struct
close_request
*
close_req
=
(
struct
close_request
*
)(
req
->
data
);
db
->
error_status
=
sqlite3_close
(
db
->
handle
);
Local
<
Value
>
argv
[
1
];
bool
err
=
false
;
if
(
req
->
result
)
{
err
=
true
;
argv
[
0
]
=
Exception
::
Error
(
String
::
New
(
"Error closing database"
));
if
(
db
->
error_status
!=
SQLITE_OK
)
{
db
->
error_message
=
std
::
string
(
sqlite3_errmsg
(
db
->
handle
));
db
->
readyState
=
OPEN
;
return
false
;
}
TryCatch
try_catch
;
close_req
->
db
->
Unref
();
close_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
err
?
1
:
0
,
argv
);
if
(
try_catch
.
HasCaught
())
{
FatalException
(
try_catch
);
else
{
db
->
readyState
=
CLOSED
;
db
->
handle
=
NULL
;
return
true
;
}
close_req
->
cb
.
Dispose
();
free
(
close_req
);
return
0
;
}
int
Database
::
EIO_Close
(
eio_req
*
req
)
{
struct
close_request
*
close_req
=
(
struct
close_request
*
)(
req
->
data
);
Database
*
db
=
close_req
->
db
;
req
->
result
=
sqlite3_close
(
db
->
db_
);
db
->
db_
=
NULL
;
Database
*
db
=
static_cast
<
Database
*>
(
req
->
data
);
Close
(
db
);
return
0
;
}
Handle
<
Value
>
Database
::
Close
(
const
Arguments
&
args
)
{
int
Database
::
EIO_AfterClose
(
eio_req
*
req
)
{
HandleScope
scope
;
Database
*
db
=
static_cast
<
Database
*>
(
req
->
data
);
ev_unref
(
EV_DEFAULT_UC
);
db
->
Unref
();
REQ_FUN_ARG
(
0
,
cb
);
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
struct
close_request
*
close_req
=
(
struct
close_request
*
)
calloc
(
1
,
sizeof
(
struct
close_request
));
if
(
!
close_req
)
{
V8
::
LowMemoryNotification
();
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Could not allocate enough memory"
)));
Local
<
Value
>
argv
[
1
];
if
(
db
->
error_status
!=
SQLITE_OK
)
{
EXCEPTION
(
db
->
error_message
.
c_str
(),
db
->
error_status
,
exception
);
argv
[
0
]
=
exception
;
}
else
{
argv
[
0
]
=
Local
<
Value
>::
New
(
Null
());
db
->
handle_
->
Set
(
String
::
NewSymbol
(
"opened"
),
False
(),
ReadOnly
);
}
close_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
close_req
->
db
=
db
;
eio_custom
(
EIO_Close
,
EIO_PRI_DEFAULT
,
EIO_AfterClose
,
close_req
);
ev_ref
(
EV_DEFAULT_UC
);
db
->
Ref
();
db
->
Emit
(
String
::
NewSymbol
(
"closed"
),
1
,
argv
);
return
Undefined
()
;
return
0
;
}
// // TODO: libeio'fy
...
...
@@ -243,7 +263,7 @@ int Database::EIO_AfterPrepareAndStep(eio_req *req) {
// if the prepare failed
if
(
req
->
result
!=
SQLITE_OK
)
{
argv
[
0
]
=
Exception
::
Error
(
String
::
New
(
sqlite3_errmsg
(
prep_req
->
db
->
db_
)));
String
::
New
(
sqlite3_errmsg
(
prep_req
->
db
->
handle
)));
argc
=
1
;
}
...
...
@@ -307,7 +327,7 @@ int Database::EIO_PrepareAndStep(eio_req *req) {
prep_req
->
stmt
=
NULL
;
prep_req
->
tail
=
NULL
;
sqlite3
*
db
=
prep_req
->
db
->
db_
;
sqlite3
*
db
=
prep_req
->
db
->
handle
;
int
rc
=
sqlite3_prepare_v2
(
db
,
prep_req
->
sql
,
-
1
,
&
(
prep_req
->
stmt
),
&
(
prep_req
->
tail
));
...
...
@@ -346,9 +366,9 @@ int Database::EIO_PrepareAndStep(eio_req *req) {
Handle
<
Value
>
Database
::
PrepareAndStep
(
const
Arguments
&
args
)
{
HandleScope
scope
;
REQ_STR_AR
G
(
0
,
sql
);
REQ_FUN_ARG
(
1
,
cb
);
OPT_INT_ARG
(
2
,
mode
,
EXEC_EMPTY
);
REQUIRE_ARGUMENT_STRIN
G
(
0
,
sql
);
REQUIRE_ARGUMENT_FUNCTION
(
1
,
cb
);
OPTIONAL_ARGUMENT_INTEGER
(
2
,
mode
,
EXEC_EMPTY
);
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
...
...
@@ -385,7 +405,7 @@ int Database::EIO_AfterPrepare(eio_req *req) {
// if the prepare failed
if
(
req
->
result
!=
SQLITE_OK
)
{
argv
[
0
]
=
Exception
::
Error
(
String
::
New
(
sqlite3_errmsg
(
prep_req
->
db
->
db_
)));
String
::
New
(
sqlite3_errmsg
(
prep_req
->
db
->
handle
)));
argc
=
1
;
}
else
{
...
...
@@ -423,7 +443,7 @@ int Database::EIO_Prepare(eio_req *req) {
prep_req
->
stmt
=
NULL
;
prep_req
->
tail
=
NULL
;
sqlite3
*
db
=
prep_req
->
db
->
db_
;
sqlite3
*
db
=
prep_req
->
db
->
handle
;
int
rc
=
sqlite3_prepare_v2
(
db
,
prep_req
->
sql
,
-
1
,
&
(
prep_req
->
stmt
),
&
(
prep_req
->
tail
));
...
...
@@ -449,7 +469,7 @@ Handle<Value> Database::Prepare(const Arguments& args) {
Local
<
Function
>
cb
;
int
mode
;
REQ_STR_AR
G
(
0
,
sql
);
REQUIRE_ARGUMENT_STRIN
G
(
0
,
sql
);
// middle argument could be options or
switch
(
args
.
Length
())
{
...
...
@@ -509,3 +529,33 @@ Handle<Value> Database::Prepare(const Arguments& args) {
return
Undefined
();
}
/**
* Override this so that we can properly close the database when this object
* gets garbage collected.
*/
void
Database
::
Wrap
(
Handle
<
Object
>
handle
)
{
assert
(
handle_
.
IsEmpty
());
assert
(
handle
->
InternalFieldCount
()
>
0
);
handle_
=
Persistent
<
Object
>::
New
(
handle
);
handle_
->
SetPointerInInternalField
(
0
,
this
);
handle_
.
MakeWeak
(
this
,
Destruct
);
}
void
Database
::
Destruct
(
Persistent
<
Value
>
value
,
void
*
data
)
{
Database
*
db
=
static_cast
<
Database
*>
(
data
);
if
(
db
->
handle
)
{
eio_custom
(
EIO_Close
,
EIO_PRI_DEFAULT
,
EIO_AfterDestruct
,
db
);
ev_ref
(
EV_DEFAULT_UC
);
}
else
{
delete
db
;
}
}
int
Database
::
EIO_AfterDestruct
(
eio_req
*
req
)
{
Database
*
db
=
static_cast
<
Database
*>
(
req
->
data
);
ev_unref
(
EV_DEFAULT_UC
);
delete
db
;
return
0
;
}
src/database.h
View file @
db72749d
...
...
@@ -19,35 +19,51 @@
#include <node.h>
#include <node_events.h>
#include <string>
#include <sqlite3.h>
using
namespace
v8
;
using
namespace
node
;
enum
ReadyState
{
CLOSED
,
OPENING
,
OPEN
,
CLOSING
};
class
Database
:
public
EventEmitter
{
public
:
static
Persistent
<
FunctionTemplate
>
constructor_template
;
static
void
Init
(
v8
::
Handle
<
Object
>
target
);
protected
:
Database
()
:
EventEmitter
(),
db_
(
NULL
)
{
}
Database
()
:
EventEmitter
(),
handle
(
NULL
),
pending
(
0
),
readyState
(
CLOSED
)
{
}
~
Database
()
{
assert
(
db_
==
NULL
);
printf
(
"Destroying database
\n
"
);
fprintf
(
stderr
,
"Calling destructor
\n
"
);
}
static
Handle
<
Value
>
New
(
const
Arguments
&
args
);
static
int
EIO_AfterOpen
(
eio_req
*
req
);
static
int
EIO_Open
(
eio_req
*
req
);
static
Handle
<
Value
>
OpenSync
(
const
Arguments
&
args
);
static
Handle
<
Value
>
Open
(
const
Arguments
&
args
);
static
bool
Open
(
Database
*
db
);
static
int
EIO_Open
(
eio_req
*
req
);
static
int
EIO_AfterOpen
(
eio_req
*
req
);
static
int
EIO_AfterClose
(
eio_req
*
req
);
static
int
EIO_Close
(
eio_req
*
req
);
static
Handle
<
Value
>
CloseSync
(
const
Arguments
&
args
);
static
Handle
<
Value
>
Close
(
const
Arguments
&
args
);
static
bool
Close
(
Database
*
db
);
static
int
EIO_Close
(
eio_req
*
req
);
static
int
EIO_AfterClose
(
eio_req
*
req
);
// static Handle<Value> LastInsertRowid(const Arguments& args);
static
int
EIO_AfterPrepareAndStep
(
eio_req
*
req
);
static
int
EIO_PrepareAndStep
(
eio_req
*
req
);
static
Handle
<
Value
>
PrepareAndStep
(
const
Arguments
&
args
);
...
...
@@ -56,35 +72,29 @@ class Database : public EventEmitter {
static
int
EIO_Prepare
(
eio_req
*
req
);
static
Handle
<
Value
>
Prepare
(
const
Arguments
&
args
);
// Return a pointer to the Sqlite handle pointer so that EIO_Open can
// pass it to sqlite3_open which wants a pointer to an sqlite3 pointer. This
// is because it wants to initialize our original (sqlite3*) pointer to
// point to an valid object.
sqlite3
**
GetDBPtr
(
void
)
{
return
&
db_
;
}
void
Wrap
(
Handle
<
Object
>
handle
);
static
void
Destruct
(
Persistent
<
Value
>
value
,
void
*
data
);
static
int
EIO_Destruct
(
eio_req
*
req
);
static
int
EIO_AfterDestruct
(
eio_req
*
req
);
protected
:
sqlite3
*
handle
;
std
::
string
filename
;
int
open_mode
;
std
::
string
error_message
;
int
error_status
;
sqlite3
*
db_
;
int
pending
;
ReadyState
readyState
;
};
enum
ExecMode
{
enum
ExecMode
{
EXEC_EMPTY
=
0
,
EXEC_LAST_INSERT_ID
=
1
,
EXEC_AFFECTED_ROWS
=
2
};
struct
open_request
{
Persistent
<
Function
>
cb
;
Database
*
db
;
char
filename
[
1
];
};
struct
close_request
{
Persistent
<
Function
>
cb
;
Database
*
db
;
};
struct
prepare_request
{
Persistent
<
Function
>
cb
;
Database
*
db
;
...
...
src/macros.h
View file @
db72749d
...
...
@@ -15,6 +15,9 @@
#ifndef NODE_SQLITE3_SRC_MACROS_H
#define NODE_SQLITE3_SRC_MACROS_H
const
char
*
sqlite_code_string
(
int
code
);
#define CHECK(rc) { if ((rc) != SQLITE_OK) \
return ThrowException(Exception::Error(String::New( \
sqlite3_errmsg(*db)))); }
...
...
@@ -23,37 +26,110 @@
return ThrowException(Exception::Error(String::New( \
sqlite3_errmsg(sqlite3_db_handle(sto->stmt_))))); }
#define REQ_ARGS(N) \
if (args.Length() < (N)) \
return ThrowException(Exception::TypeError( \
String::New("Expected " #N "arguments")));
#define REQ_STR_ARG(I, VAR) \
if (args.Length() <= (I) || !args[I]->IsString()) \
#define REQUIRE_ARGUMENTS(n) \
if (args.Length() < (n)) { \
return ThrowException( \
Exception::TypeError(String::New("Expected " #n "arguments")) \
); \
}
#define REQUIRE_ARGUMENT_EXTERNAL(i, var) \
if (args.Length() <= (i) || !args[i]->IsExternal()) { \
return ThrowException( \
Exception::TypeError(String::New("Argument " #i " invalid")) \
); \
} \
Local<External> var = Local<External>::Cast(args[i]);
#define REQUIRE_ARGUMENT_FUNCTION(i, var) \
if (args.Length() <= (i) || !args[i]->IsFunction()) { \
return ThrowException(Exception::TypeError( \
String::New("Argument " #I " must be a string"))); \
String::Utf8Value VAR(args[I]->ToString());
String::New("Argument " #i " must be a function")) \
); \
} \
Local<Function> var = Local<Function>::Cast(args[i]);
#define REQ
_FUN_ARG(I, VAR)
\
if (args.Length() <= (I) || !args[I]->IsFunction())
\
#define REQ
UIRE_ARGUMENT_STRING(i, var)
\
if (args.Length() <= (i) || !args[i]->IsString()) {
\
return ThrowException(Exception::TypeError( \
String::New("Argument " #I " must be a function"))); \
Local<Function> VAR = Local<Function>::Cast(args[I]);
String::New("Argument " #i " must be a string")) \
); \
} \
String::Utf8Value var(args[i]->ToString());
#define REQ_EXT_ARG(I, VAR) \
if (args.Length() <= (I) || !args[I]->IsExternal()) \
#define OPTIONAL_ARGUMENT_FUNCTION(i, var) \
Local<Function> var; \
bool var ## _exists = false; \
if (args.Length() >= i) { \
if (!args[i]->IsFunction()) { \
return ThrowException(Exception::TypeError( \
String::New("Argument " #I " invalid"))); \
Local<External> VAR = Local<External>::Cast(args[I]);
#define OPT_INT_ARG(I, VAR, DEFAULT) \
int VAR; \
if (args.Length() <= (I)) { \
VAR = (DEFAULT); \
} else if (args[I]->IsInt32()) { \
VAR = args[I]->Int32Value(); \
} else { \
String::New("Argument " #i " must be a function")) \
); \
} \
var = Local<Function>::Cast(args[i]); \
var ## _exists = true; \
}
#define OPTIONAL_ARGUMENT_INTEGER(i, var, default) \
int var; \
if (args.Length() <= (i)) { \
var = (default); \
} \
else if (args[i]->IsInt32()) { \
var = args[i]->Int32Value(); \
} \
else { \
return ThrowException(Exception::TypeError( \
String::New("Argument " #I " must be an integer"))); \
String::New("Argument " #i " must be an integer")) \
); \
}
#define DEFINE_CONSTANT_INTEGER(target, constant, name) \
(target)->Set( \
String::NewSymbol(#name), \
Integer::New(constant), \
static_cast<PropertyAttribute>(ReadOnly | DontDelete) \
);
#define DEFINE_CONSTANT_STRING(target, constant, name) \
(target)->Set( \
String::NewSymbol(#name), \
String::NewSymbol(constant), \
static_cast<PropertyAttribute>(ReadOnly | DontDelete) \
);
#define NODE_SET_GETTER(target, name, function) \
(target)->InstanceTemplate() \
->SetAccessor(String::NewSymbol(name), (function));
#define GET_STRING(source, name, property) \
String::Utf8Value name((source)->Get(String::NewSymbol(property)));
#define GET_INTEGER(source, name, property) \
int name = (source)->Get(String::NewSymbol(property))->Int32Value();
#define EXCEPTION(msg, errno, name) \
Local<Value> name = Exception::Error( \
String::Concat( \
String::Concat( \
String::NewSymbol(sqlite_code_string(errno)), \
String::NewSymbol(": ") \
), \
String::New(msg) \
) \
); \
Local<Object> name ## _obj = name->ToObject(); \
name ## _obj->Set(NODE_PSYMBOL("errno"), Integer::New(errno)); \
name ## _obj->Set(NODE_PSYMBOL("code"), \
String::NewSymbol(sqlite_code_string(errno)));
#endif
src/sqlite3_bindings.cc
View file @
db72749d
...
...
@@ -16,11 +16,54 @@
#include <node.h>
#include <node_events.h>
#include <sqlite3.h>
#include "macros.h"
#include "database.h"
#include "statement.h"
extern
"C"
void
init
(
v8
::
Handle
<
Object
>
target
)
{
Database
::
Init
(
target
);
Statement
::
Init
(
target
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_OPEN_READONLY
,
OPEN_READONLY
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_OPEN_READWRITE
,
OPEN_READWRITE
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_OPEN_CREATE
,
OPEN_CREATE
);
DEFINE_CONSTANT_STRING
(
target
,
SQLITE_VERSION
,
VERSION
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_VERSION_NUMBER
,
VERSION_NUMBER
);
}
const
char
*
sqlite_code_string
(
int
code
)
{
switch
(
code
)
{
case
SQLITE_OK
:
return
"SQLITE_OK"
;
case
SQLITE_ERROR
:
return
"SQLITE_ERROR"
;
case
SQLITE_INTERNAL
:
return
"SQLITE_INTERNAL"
;
case
SQLITE_PERM
:
return
"SQLITE_PERM"
;
case
SQLITE_ABORT
:
return
"SQLITE_ABORT"
;
case
SQLITE_BUSY
:
return
"SQLITE_BUSY"
;
case
SQLITE_LOCKED
:
return
"SQLITE_LOCKED"
;
case
SQLITE_NOMEM
:
return
"SQLITE_NOMEM"
;
case
SQLITE_READONLY
:
return
"SQLITE_READONLY"
;
case
SQLITE_INTERRUPT
:
return
"SQLITE_INTERRUPT"
;
case
SQLITE_IOERR
:
return
"SQLITE_IOERR"
;
case
SQLITE_CORRUPT
:
return
"SQLITE_CORRUPT"
;
case
SQLITE_NOTFOUND
:
return
"SQLITE_NOTFOUND"
;
case
SQLITE_FULL
:
return
"SQLITE_FULL"
;
case
SQLITE_CANTOPEN
:
return
"SQLITE_CANTOPEN"
;
case
SQLITE_PROTOCOL
:
return
"SQLITE_PROTOCOL"
;
case
SQLITE_EMPTY
:
return
"SQLITE_EMPTY"
;
case
SQLITE_SCHEMA
:
return
"SQLITE_SCHEMA"
;
case
SQLITE_TOOBIG
:
return
"SQLITE_TOOBIG"
;
case
SQLITE_CONSTRAINT
:
return
"SQLITE_CONSTRAINT"
;
case
SQLITE_MISMATCH
:
return
"SQLITE_MISMATCH"
;
case
SQLITE_MISUSE
:
return
"SQLITE_MISUSE"
;
case
SQLITE_NOLFS
:
return
"SQLITE_NOLFS"
;
case
SQLITE_AUTH
:
return
"SQLITE_AUTH"
;
case
SQLITE_FORMAT
:
return
"SQLITE_FORMAT"
;
case
SQLITE_RANGE
:
return
"SQLITE_RANGE"
;
case
SQLITE_NOTADB
:
return
"SQLITE_NOTADB"
;
case
SQLITE_ROW
:
return
"SQLITE_ROW"
;
case
SQLITE_DONE
:
return
"SQLITE_DONE"
;
default
:
return
"UNKNOWN"
;
}
}
src/statement.cc
View file @
db72749d
...
...
@@ -50,7 +50,7 @@ void Statement::Init(v8::Handle<Object> target) {
Handle
<
Value
>
Statement
::
New
(
const
Arguments
&
args
)
{
HandleScope
scope
;
REQ
_EXT_ARG
(
0
,
stmt
);
REQ
UIRE_ARGUMENT_EXTERNAL
(
0
,
stmt
);
int
first_rc
=
args
[
1
]
->
IntegerValue
();
int
mode
=
args
[
2
]
->
IntegerValue
();
...
...
@@ -169,8 +169,8 @@ Handle<Value> Statement::BindObject(const Arguments& args) {
HandleScope
scope
;
Statement
*
sto
=
ObjectWrap
::
Unwrap
<
Statement
>
(
args
.
This
());
REQ
_ARG
S
(
2
);
REQ
_FUN_ARG
(
1
,
cb
);
REQ
UIRE_ARGUMENT
S
(
2
);
REQ
UIRE_ARGUMENT_FUNCTION
(
1
,
cb
);
if
(
!
args
[
0
]
->
IsObject
())
return
ThrowException
(
Exception
::
TypeError
(
...
...
@@ -253,8 +253,8 @@ Handle<Value> Statement::BindArray(const Arguments& args) {
HandleScope
scope
;
Statement
*
sto
=
ObjectWrap
::
Unwrap
<
Statement
>
(
args
.
This
());
REQ
_ARG
S
(
2
);
REQ
_FUN_ARG
(
1
,
cb
);
REQ
UIRE_ARGUMENT
S
(
2
);
REQ
UIRE_ARGUMENT_FUNCTION
(
1
,
cb
);
if
(
!
args
[
0
]
->
IsArray
())
return
ThrowException
(
Exception
::
TypeError
(
String
::
New
(
"First argument must be an Array."
)));
...
...
@@ -349,8 +349,8 @@ Handle<Value> Statement::Bind(const Arguments& args) {
HandleScope
scope
;
Statement
*
sto
=
ObjectWrap
::
Unwrap
<
Statement
>
(
args
.
This
());
REQ
_ARG
S
(
2
);
REQ
_FUN_ARG
(
2
,
cb
);
REQ
UIRE_ARGUMENT
S
(
2
);
REQ
UIRE_ARGUMENT_FUNCTION
(
2
,
cb
);
if
(
!
(
args
[
0
]
->
IsString
()
||
args
[
0
]
->
IsInt32
()
...
...
@@ -475,7 +475,7 @@ Handle<Value> Statement::Finalize(const Arguments& args) {
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Already stepping"
)));
}
REQ
_FUN_ARG
(
0
,
cb
);
REQ
UIRE_ARGUMENT_FUNCTION
(
0
,
cb
);
sto
->
SetCallback
(
cb
);
...
...
@@ -740,7 +740,7 @@ Handle<Value> Statement::Step(const Arguments& args) {
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Already stepping"
)));
}
REQ
_FUN_ARG
(
0
,
cb
);
REQ
UIRE_ARGUMENT_FUNCTION
(
0
,
cb
);
sto
->
SetCallback
(
cb
);
...
...
@@ -1011,7 +1011,7 @@ int Statement::EIO_FetchAll(eio_req *req) {
Handle
<
Value
>
Statement
::
FetchAll
(
const
Arguments
&
args
)
{
HandleScope
scope
;
REQ
_FUN_ARG
(
0
,
cb
);
REQ
UIRE_ARGUMENT_FUNCTION
(
0
,
cb
);
struct
fetchall_request
*
fetchall_req
=
(
struct
fetchall_request
*
)
calloc
(
1
,
sizeof
(
struct
fetchall_request
));
...
...
test/blob.test.js
View file @
db72749d
...
...
@@ -14,11 +14,10 @@ exports['Blob overflow test'] = function(beforeExit) {
var
inserted
=
0
;
var
retrieved
=
0
;
db
.
openSync
(
''
);
Step
(
function
()
{
db
.
open
(
''
,
this
);
},
function
()
{
var
next
=
this
;
db
.
prepare
(
'CREATE TABLE elmos (image BLOB);'
,
function
(
err
,
statement
)
{
assert
.
isUndefined
(
err
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment