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
dd3ef522
Commit
dd3ef522
authored
Jul 08, 2019
by
Jim Schlight
Committed by
Mohamed Akram
Apr 11, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix compilation
parent
fc09ced9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
515 additions
and
442 deletions
+515
-442
backup.cc
src/backup.cc
+80
-76
backup.h
src/backup.h
+15
-15
database.cc
src/database.cc
+109
-97
database.h
src/database.h
+25
-22
macros.h
src/macros.h
+57
-54
node_sqlite3.cc
src/node_sqlite3.cc
+44
-40
statement.cc
src/statement.cc
+168
-122
statement.h
src/statement.h
+15
-14
database_fail.test.js
test/database_fail.test.js
+2
-2
No files found.
src/backup.cc
View file @
dd3ef522
...
...
@@ -16,25 +16,22 @@ Napi::FunctionReference Backup::constructor;
Napi
::
Object
Backup
::
Init
(
Napi
::
Env
env
,
Napi
::
Object
exports
)
{
Napi
::
HandleScope
scope
(
env
);
Napi
::
FunctionReference
t
=
Napi
::
Function
::
New
(
env
,
New
);
t
->
SetClassName
(
Napi
::
String
::
New
(
env
,
"Backup"
));
InstanceMethod
(
"step"
,
&
Step
),
InstanceMethod
(
"finish"
,
&
Finish
),
NODE_SET_GETTER
(
t
,
"idle"
,
IdleGetter
);
NODE_SET_GETTER
(
t
,
"completed"
,
CompletedGetter
);
NODE_SET_GETTER
(
t
,
"failed"
,
FailedGetter
);
NODE_SET_GETTER
(
t
,
"remaining"
,
RemainingGetter
);
NODE_SET_GETTER
(
t
,
"pageCount"
,
PageCountGetter
);
NODE_SET_SETTER
(
t
,
"retryErrors"
,
RetryErrorGetter
,
RetryErrorSetter
);
constructor
.
Reset
(
t
);
(
target
).
Set
(
Napi
::
String
::
New
(
env
,
"Backup"
),
Napi
::
GetFunction
(
t
));
Napi
::
Function
t
=
DefineClass
(
env
,
"Backup"
,
{
InstanceMethod
(
"step"
,
&
Backup
::
Step
),
InstanceMethod
(
"finish"
,
&
Backup
::
Finish
),
InstanceAccessor
(
"idle"
,
&
Backup
::
IdleGetter
,
nullptr
),
InstanceAccessor
(
"completed"
,
&
Backup
::
CompletedGetter
,
nullptr
),
InstanceAccessor
(
"failed"
,
&
Backup
::
FailedGetter
,
nullptr
),
InstanceAccessor
(
"remaining"
,
&
Backup
::
RemainingGetter
,
nullptr
),
InstanceAccessor
(
"pageCount"
,
&
Backup
::
PageCountGetter
,
nullptr
),
InstanceAccessor
(
"retryErrors"
,
&
Backup
::
RetryErrorGetter
,
&
Backup
::
RetryErrorSetter
),
});
constructor
=
Napi
::
Persistent
(
t
);
constructor
.
SuppressDestruct
();
exports
.
Set
(
"Backup"
,
t
);
return
exports
;
}
void
Backup
::
Process
()
{
...
...
@@ -65,32 +62,34 @@ void Backup::Schedule(Work_Callback callback, Baton* baton) {
}
template
<
class
T
>
void
Backup
::
Error
(
T
*
baton
)
{
Napi
::
Env
env
=
baton
->
backup
->
Env
();
Napi
::
HandleScope
scope
(
env
);
Backup
*
backup
=
baton
->
backup
;
// Fail hard on logic errors.
assert
(
backup
->
status
!=
0
);
EXCEPTION
(
backup
->
message
,
backup
->
status
,
exception
);
EXCEPTION
(
Napi
::
String
::
New
(
env
,
backup
->
message
)
,
backup
->
status
,
exception
);
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
IsEmpty
()
&&
cb
->
IsFunction
())
{
if
(
!
cb
.
IsEmpty
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
exception
};
TRY_CATCH_CALL
(
backup
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
backup
->
Valu
e
(),
cb
,
1
,
argv
);
}
else
{
Napi
::
Value
argv
[]
=
{
Napi
::
String
::
New
(
env
,
"error"
),
exception
};
EMIT_EVENT
(
backup
->
handl
e
(),
2
,
argv
);
EMIT_EVENT
(
backup
->
Valu
e
(),
2
,
argv
);
}
}
void
Backup
::
CleanQueue
()
{
Napi
::
Env
env
=
this
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
inited
&&
!
queue
.
empty
())
{
// This backup has already been initialized and is now finished.
// Fire error for all remaining items in the queue.
EXCEPTION
(
"Backup is already finished"
,
SQLITE_MISUSE
,
exception
);
EXCEPTION
(
Napi
::
String
::
New
(
env
,
"Backup is already finished"
)
,
SQLITE_MISUSE
,
exception
);
Napi
::
Value
argv
[]
=
{
exception
};
bool
called
=
false
;
...
...
@@ -99,11 +98,11 @@ void Backup::CleanQueue() {
Call
*
call
=
queue
.
front
();
queue
.
pop
();
Napi
::
Function
cb
=
Napi
::
New
(
env
,
call
->
baton
->
callback
);
Napi
::
Function
cb
=
call
->
baton
->
callback
.
Value
(
);
if
(
inited
&&
!
cb
.
IsEmpty
()
&&
cb
->
IsFunction
())
{
TRY_CATCH_CALL
(
handl
e
(),
cb
,
1
,
argv
);
cb
.
IsFunction
())
{
TRY_CATCH_CALL
(
Valu
e
(),
cb
,
1
,
argv
);
called
=
true
;
}
...
...
@@ -117,7 +116,7 @@ void Backup::CleanQueue() {
// Backup object.
if
(
!
called
)
{
Napi
::
Value
info
[]
=
{
Napi
::
String
::
New
(
env
,
"error"
),
exception
};
EMIT_EVENT
(
handl
e
(),
2
,
info
);
EMIT_EVENT
(
Valu
e
(),
2
,
info
);
}
}
else
while
(
!
queue
.
empty
())
{
...
...
@@ -133,61 +132,59 @@ void Backup::CleanQueue() {
}
}
Napi
::
Value
Backup
::
New
(
const
Napi
::
CallbackInfo
&
info
)
{
Backup
::
Backup
(
const
Napi
::
CallbackInfo
&
info
)
:
Napi
::
ObjectWrap
<
Backup
>
(
info
)
{
Napi
::
Env
env
=
info
.
Env
();
if
(
!
info
.
IsConstructCall
())
{
Napi
::
TypeError
::
New
(
env
,
"Use the new operator to create new Backup objects"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
int
length
=
info
.
Length
();
if
(
length
<=
0
||
!
Database
::
HasInstance
(
info
[
0
]))
{
Napi
::
TypeError
::
New
(
env
,
"Database object expected"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
else
if
(
length
<=
1
||
!
info
[
1
].
IsString
())
{
Napi
::
TypeError
::
New
(
env
,
"Filename expected"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
else
if
(
length
<=
2
||
!
info
[
2
].
IsString
())
{
Napi
::
TypeError
::
New
(
env
,
"Source database name expected"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
else
if
(
length
<=
3
||
!
info
[
3
].
IsString
())
{
Napi
::
TypeError
::
New
(
env
,
"Destination database name expected"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
else
if
(
length
<=
4
||
!
info
[
4
].
IsBoolean
())
{
Napi
::
TypeError
::
New
(
env
,
"Direction flag expected"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
else
if
(
length
>
5
&&
!
info
[
5
].
IsUndefined
()
&&
!
info
[
5
].
IsFunction
())
{
Napi
::
TypeError
::
New
(
env
,
"Callback expected"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
Database
*
db
=
info
[
0
].
As
<
Napi
::
Object
>
().
Unwrap
<
Database
>
(
);
Database
*
db
=
Napi
::
ObjectWrap
<
Database
>::
Unwrap
(
info
[
0
].
As
<
Napi
::
Object
>
()
);
Napi
::
String
filename
=
info
[
1
].
As
<
Napi
::
String
>
();
Napi
::
String
sourceName
=
info
[
2
].
As
<
Napi
::
String
>
();
Napi
::
String
destName
=
info
[
3
].
As
<
Napi
::
String
>
();
Napi
::
Boolean
filenameIsDest
=
info
[
4
].
As
<
Napi
::
Boolean
>
();
info
.
This
().
DefineProperty
(
Napi
::
String
::
New
(
env
,
"filename"
),
filename
,
ReadOnly
);
info
.
This
().
DefineProperty
(
Napi
::
String
::
New
(
env
,
"sourceName"
),
sourceName
,
ReadOnly
);
info
.
This
().
DefineProperty
(
Napi
::
String
::
New
(
env
,
"destName"
),
destName
,
ReadOnly
);
info
.
This
().
DefineProperty
(
Napi
::
String
::
New
(
env
,
"filenameIsDest"
),
filenameIsDest
,
ReadOnly
);
info
.
This
().
As
<
Napi
::
Object
>
().
DefineProperty
(
Napi
::
PropertyDescriptor
::
Value
(
"filename"
,
filename
)
);
info
.
This
().
As
<
Napi
::
Object
>
().
DefineProperty
(
Napi
::
PropertyDescriptor
::
Value
(
"sourceName"
,
sourceName
)
);
info
.
This
().
As
<
Napi
::
Object
>
().
DefineProperty
(
Napi
::
PropertyDescriptor
::
Value
(
"destName"
,
destName
)
);
info
.
This
().
As
<
Napi
::
Object
>
().
DefineProperty
(
Napi
::
PropertyDescriptor
::
Value
(
"filenameIsDest"
,
filenameIsDest
)
);
Backup
*
backup
=
new
Backup
(
db
);
backup
->
Wrap
(
info
.
This
());
init
(
db
);
InitializeBaton
*
baton
=
new
InitializeBaton
(
db
,
info
[
5
].
As
<
Napi
::
Function
>
(),
backup
);
baton
->
filename
=
std
::
string
(
filename
->
As
<
Napi
::
String
>
().
Utf8Value
().
c_str
()
);
baton
->
sourceName
=
s
td
::
string
(
sourceName
->
As
<
Napi
::
String
>
().
Utf8Value
().
c_str
()
);
baton
->
destName
=
std
::
string
(
destName
->
As
<
Napi
::
String
>
().
Utf8Value
().
c_str
()
);
baton
->
filenameIsDest
=
filenameIsDest
.
As
<
Napi
::
Boolean
>
().
Value
();
InitializeBaton
*
baton
=
new
InitializeBaton
(
db
,
info
[
5
].
As
<
Napi
::
Function
>
(),
this
);
baton
->
filename
=
filename
.
Utf8Value
(
);
baton
->
sourceName
=
s
ourceName
.
Utf8Value
(
);
baton
->
destName
=
destName
.
Utf8Value
(
);
baton
->
filenameIsDest
=
filenameIsDest
.
Value
();
db
->
Schedule
(
Work_BeginInitialize
,
baton
);
return
info
.
This
();
}
void
Backup
::
Work_BeginInitialize
(
Database
::
Baton
*
baton
)
{
...
...
@@ -228,20 +225,21 @@ void Backup::Work_Initialize(uv_work_t* req) {
}
void
Backup
::
Work_AfterInitialize
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
BACKUP_INIT
(
InitializeBaton
);
Napi
::
Env
env
=
backup
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
backup
->
status
!=
SQLITE_OK
)
{
Error
(
baton
);
backup
->
FinishAll
();
}
else
{
backup
->
inited
=
true
;
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
IsEmpty
()
&&
cb
->
IsFunction
())
{
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
IsEmpty
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
env
.
Null
()
};
TRY_CATCH_CALL
(
backup
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
backup
->
Valu
e
(),
cb
,
1
,
argv
);
}
}
BACKUP_END
();
...
...
@@ -249,6 +247,7 @@ void Backup::Work_AfterInitialize(uv_work_t* req) {
Napi
::
Value
Backup
::
Step
(
const
Napi
::
CallbackInfo
&
info
)
{
Backup
*
backup
=
this
;
Napi
::
Env
env
=
backup
->
Env
();
REQUIRE_ARGUMENT_INTEGER
(
0
,
pages
);
OPTIONAL_ARGUMENT_FUNCTION
(
1
,
callback
);
...
...
@@ -288,10 +287,11 @@ void Backup::Work_Step(uv_work_t* req) {
}
void
Backup
::
Work_AfterStep
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
BACKUP_INIT
(
StepBaton
);
Napi
::
Env
env
=
backup
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
backup
->
status
==
SQLITE_DONE
)
{
backup
->
completed
=
true
;
}
else
if
(
!
backup
->
_handle
)
{
...
...
@@ -303,10 +303,10 @@ void Backup::Work_AfterStep(uv_work_t* req) {
}
else
{
// Fire callbacks.
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
IsEmpty
()
&&
cb
->
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
env
.
Null
(),
Napi
::
New
(
env
,
backup
->
status
==
SQLITE_DONE
)
};
TRY_CATCH_CALL
(
backup
->
handl
e
(),
cb
,
2
,
argv
);
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
IsEmpty
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
env
.
Null
(),
Napi
::
Boolean
::
New
(
env
,
backup
->
status
==
SQLITE_DONE
)
};
TRY_CATCH_CALL
(
backup
->
Valu
e
(),
cb
,
2
,
argv
);
}
}
...
...
@@ -315,6 +315,7 @@ void Backup::Work_AfterStep(uv_work_t* req) {
Napi
::
Value
Backup
::
Finish
(
const
Napi
::
CallbackInfo
&
info
)
{
Backup
*
backup
=
this
;
Napi
::
Env
env
=
backup
->
Env
();
OPTIONAL_ARGUMENT_FUNCTION
(
0
,
callback
);
...
...
@@ -333,15 +334,17 @@ void Backup::Work_Finish(uv_work_t* req) {
}
void
Backup
::
Work_AfterFinish
(
uv_work_t
*
req
)
{
BACKUP_INIT
(
Baton
);
Napi
::
Env
env
=
backup
->
Env
();
Napi
::
HandleScope
scope
(
env
);
BACKUP_INIT
(
Baton
);
backup
->
FinishAll
();
// Fire callback in case there was one.
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
IsEmpty
()
&&
cb
->
IsFunction
())
{
TRY_CATCH_CALL
(
backup
->
handl
e
(),
cb
,
0
,
NULL
);
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
IsEmpty
()
&&
cb
.
IsFunction
())
{
TRY_CATCH_CALL
(
backup
->
Valu
e
(),
cb
,
0
,
NULL
);
}
BACKUP_END
();
...
...
@@ -373,39 +376,40 @@ void Backup::FinishSqlite() {
Napi
::
Value
Backup
::
IdleGetter
(
const
Napi
::
CallbackInfo
&
info
)
{
Backup
*
backup
=
this
;
bool
idle
=
backup
->
inited
&&
!
backup
->
locked
&&
backup
->
queue
.
empty
();
return
idle
;
return
Napi
::
Boolean
::
New
(
this
->
Env
(),
idle
)
;
}
Napi
::
Value
Backup
::
CompletedGetter
(
const
Napi
::
CallbackInfo
&
info
)
{
Backup
*
backup
=
this
;
return
backup
->
completed
;
return
Napi
::
Boolean
::
New
(
this
->
Env
(),
backup
->
completed
)
;
}
Napi
::
Value
Backup
::
FailedGetter
(
const
Napi
::
CallbackInfo
&
info
)
{
Backup
*
backup
=
this
;
return
backup
->
failed
;
return
Napi
::
Boolean
::
New
(
this
->
Env
(),
backup
->
failed
)
;
}
Napi
::
Value
Backup
::
RemainingGetter
(
const
Napi
::
CallbackInfo
&
info
)
{
Backup
*
backup
=
this
;
return
backup
->
remaining
;
return
Napi
::
Number
::
New
(
this
->
Env
(),
backup
->
remaining
)
;
}
Napi
::
Value
Backup
::
PageCountGetter
(
const
Napi
::
CallbackInfo
&
info
)
{
Backup
*
backup
=
this
;
return
backup
->
pageCount
;
return
Napi
::
Number
::
New
(
this
->
Env
(),
backup
->
pageCount
)
;
}
Napi
::
Value
Backup
::
RetryErrorGetter
(
const
Napi
::
CallbackInfo
&
info
)
{
Backup
*
backup
=
this
;
return
Napi
::
New
(
env
,
backup
->
retryErrors
);
return
backup
->
retryErrors
.
Value
(
);
}
void
Backup
::
RetryErrorSetter
(
const
Napi
::
CallbackInfo
&
info
,
const
Napi
::
Value
&
value
)
{
Backup
*
backup
=
this
;
if
(
!
value
->
IsArray
())
{
Napi
::
Env
env
=
backup
->
Env
();
if
(
!
value
.
IsArray
())
{
Napi
::
Error
::
New
(
env
,
"retryErrors must be an array"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
Napi
::
Array
array
=
value
.
As
<
Napi
::
Array
>
();
backup
->
retryErrors
.
Reset
(
array
);
...
...
@@ -413,8 +417,8 @@ void Backup::RetryErrorSetter(const Napi::CallbackInfo& info, const Napi::Value&
void
Backup
::
GetRetryErrors
(
std
::
set
<
int
>&
retryErrorsSet
)
{
retryErrorsSet
.
clear
();
Napi
::
Array
array
=
Napi
::
New
(
env
,
retryErrors
);
int
length
=
array
->
Length
();
Napi
::
Array
array
=
retryErrors
.
Value
(
);
int
length
=
array
.
Length
();
for
(
int
i
=
0
;
i
<
length
;
i
++
)
{
Napi
::
Value
code
=
(
array
).
Get
(
i
);
if
(
code
.
IsNumber
())
{
...
...
src/backup.h
View file @
dd3ef522
...
...
@@ -12,7 +12,6 @@
#include <uv.h>
using
namespace
Napi
;
using
namespace
Napi
;
namespace
node_sqlite3
{
...
...
@@ -98,7 +97,6 @@ public:
static
Napi
::
FunctionReference
constructor
;
static
Napi
::
Object
Init
(
Napi
::
Env
env
,
Napi
::
Object
exports
);
static
Napi
::
Value
New
(
const
Napi
::
CallbackInfo
&
info
);
struct
Baton
{
uv_work_t
request
;
...
...
@@ -150,21 +148,23 @@ public:
Baton
*
baton
;
};
Backup
(
Database
*
db_
)
:
Napi
::
ObjectWrap
<
Backup
>
(),
db
(
db_
),
_handle
(
NULL
),
_otherDb
(
NULL
),
_destDb
(
NULL
),
inited
(
false
),
locked
(
true
),
completed
(
false
),
failed
(
false
),
remaining
(
-
1
),
pageCount
(
-
1
),
finished
(
false
)
{
void
init
(
Database
*
db_
)
{
db
=
db_
;
_handle
=
NULL
;
_otherDb
=
NULL
;
_destDb
=
NULL
;
inited
=
false
;
locked
=
true
;
completed
=
false
;
failed
=
false
;
remaining
=
-
1
;
pageCount
=
-
1
;
finished
=
false
;
db
->
Ref
();
}
Backup
(
const
Napi
::
CallbackInfo
&
info
);
~
Backup
()
{
if
(
!
finished
)
{
FinishAll
();
...
...
@@ -216,7 +216,7 @@ protected:
bool
finished
;
std
::
queue
<
Call
*>
queue
;
Napi
::
Persistent
<
Array
>
retryErrors
;
Napi
::
Reference
<
Array
>
retryErrors
;
};
}
...
...
src/database.cc
View file @
dd3ef522
...
...
@@ -11,42 +11,40 @@ Napi::FunctionReference Database::constructor;
Napi
::
Object
Database
::
Init
(
Napi
::
Env
env
,
Napi
::
Object
exports
)
{
Napi
::
HandleScope
scope
(
env
);
Napi
::
FunctionReference
t
=
Napi
::
Function
::
New
(
env
,
New
);
Napi
::
Function
t
=
DefineClass
(
env
,
"Database"
,
{
InstanceMethod
(
"close"
,
&
Database
::
Close
),
InstanceMethod
(
"exec"
,
&
Database
::
Exec
),
InstanceMethod
(
"wait"
,
&
Database
::
Wait
),
InstanceMethod
(
"loadExtension"
,
&
Database
::
LoadExtension
),
InstanceMethod
(
"serialize"
,
&
Database
::
Serialize
),
InstanceMethod
(
"parallelize"
,
&
Database
::
Parallelize
),
InstanceMethod
(
"configure"
,
&
Database
::
Configure
),
InstanceMethod
(
"interrupt"
,
&
Database
::
Interrupt
),
InstanceAccessor
(
"open"
,
&
Database
::
OpenGetter
,
nullptr
)
});
constructor
=
Napi
::
Persistent
(
t
);
constructor
.
SuppressDestruct
();
t
->
SetClassName
(
Napi
::
String
::
New
(
env
,
"Database"
));
InstanceMethod
(
"close"
,
&
Close
),
InstanceMethod
(
"exec"
,
&
Exec
),
InstanceMethod
(
"wait"
,
&
Wait
),
InstanceMethod
(
"loadExtension"
,
&
LoadExtension
),
InstanceMethod
(
"serialize"
,
&
Serialize
),
InstanceMethod
(
"parallelize"
,
&
Parallelize
),
InstanceMethod
(
"configure"
,
&
Configure
),
InstanceMethod
(
"interrupt"
,
&
Interrupt
),
NODE_SET_GETTER
(
t
,
"open"
,
OpenGetter
);
constructor
.
Reset
(
t
);
(
target
).
Set
(
Napi
::
String
::
New
(
env
,
"Database"
),
Napi
::
GetFunction
(
t
));
exports
.
Set
(
"Database"
,
t
);
return
exports
;
}
void
Database
::
Process
()
{
Napi
::
Env
env
=
this
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
!
open
&&
locked
&&
!
queue
.
empty
())
{
EXCEPTION
(
"Database handle is closed"
,
SQLITE_MISUSE
,
exception
);
EXCEPTION
(
Napi
::
String
::
New
(
env
,
"Database handle is closed"
)
,
SQLITE_MISUSE
,
exception
);
Napi
::
Value
argv
[]
=
{
exception
};
bool
called
=
false
;
// Call all callbacks with the error object.
while
(
!
queue
.
empty
())
{
Call
*
call
=
queue
.
front
();
Napi
::
Function
cb
=
Napi
::
New
(
env
,
call
->
baton
->
callback
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
TRY_CATCH_CALL
(
this
->
handl
e
(),
cb
,
1
,
argv
);
Napi
::
Function
cb
=
call
->
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
TRY_CATCH_CALL
(
this
->
Valu
e
(),
cb
,
1
,
argv
);
called
=
true
;
}
queue
.
pop
();
...
...
@@ -60,7 +58,7 @@ void Database::Process() {
// Database object.
if
(
!
called
)
{
Napi
::
Value
info
[]
=
{
Napi
::
String
::
New
(
env
,
"error"
),
exception
};
EMIT_EVENT
(
handl
e
(),
2
,
info
);
EMIT_EVENT
(
Valu
e
(),
2
,
info
);
}
return
;
}
...
...
@@ -82,18 +80,19 @@ void Database::Process() {
}
void
Database
::
Schedule
(
Work_Callback
callback
,
Baton
*
baton
,
bool
exclusive
)
{
Napi
::
Env
env
=
this
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
!
open
&&
locked
)
{
EXCEPTION
(
"Database is closed"
,
SQLITE_MISUSE
,
exception
);
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
EXCEPTION
(
Napi
::
String
::
New
(
env
,
"Database is closed"
)
,
SQLITE_MISUSE
,
exception
);
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
exception
};
TRY_CATCH_CALL
(
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
Valu
e
(),
cb
,
1
,
argv
);
}
else
{
Napi
::
Value
argv
[]
=
{
Napi
::
String
::
New
(
env
,
"error"
),
exception
};
EMIT_EVENT
(
handl
e
(),
2
,
argv
);
EMIT_EVENT
(
Valu
e
(),
2
,
argv
);
}
return
;
}
...
...
@@ -107,19 +106,18 @@ void Database::Schedule(Work_Callback callback, Baton* baton, bool exclusive) {
}
}
Napi
::
Value
Database
::
New
(
const
Napi
::
CallbackInfo
&
info
)
{
if
(
!
info
.
IsConstructCall
())
{
Napi
::
TypeError
::
New
(
env
,
"Use the new operator to create new Database objects"
).
ThrowAsJavaScriptException
();
return
env
.
Null
();
}
Database
::
Database
(
const
Napi
::
CallbackInfo
&
info
)
:
Napi
::
ObjectWrap
<
Database
>
(
info
)
{
init
();
Napi
::
Env
env
=
info
.
Env
();
REQUIRE_ARGUMENT_STRING
(
0
,
filename
);
int
pos
=
1
;
unsigned
int
pos
=
1
;
int
mode
;
if
(
info
.
Length
()
>=
pos
&&
info
[
pos
].
IsNumber
())
{
if
(
info
.
Length
()
>=
pos
&&
info
[
pos
].
IsNumber
()
&&
OtherIsInt
(
info
[
pos
].
As
<
Napi
::
Number
>
())
)
{
mode
=
info
[
pos
++
].
As
<
Napi
::
Number
>
().
Int32Value
();
}
else
{
}
else
{
mode
=
SQLITE_OPEN_READWRITE
|
SQLITE_OPEN_CREATE
|
SQLITE_OPEN_FULLMUTEX
;
}
...
...
@@ -128,17 +126,12 @@ Napi::Value Database::New(const Napi::CallbackInfo& info) {
callback
=
info
[
pos
++
].
As
<
Napi
::
Function
>
();
}
Database
*
db
=
new
Database
();
db
->
Wrap
(
info
.
This
());
info
.
This
().
DefineProperty
(
Napi
::
String
::
New
(
env
,
"filename"
),
info
[
0
].
As
<
Napi
::
String
>
(),
ReadOnly
);
info
.
This
().
DefineProperty
(
Napi
::
String
::
New
(
env
,
"mode"
),
Napi
::
New
(
env
,
mode
),
ReadOnly
);
info
.
This
().
As
<
Napi
::
Object
>
().
DefineProperty
(
Napi
::
PropertyDescriptor
::
Value
(
"filename"
,
info
[
0
].
As
<
Napi
::
String
>
(),
napi_default
));
info
.
This
().
As
<
Napi
::
Object
>
().
DefineProperty
(
Napi
::
PropertyDescriptor
::
Value
(
"mode"
,
Napi
::
Number
::
New
(
env
,
mode
),
napi_default
));
// Start opening the database.
OpenBaton
*
baton
=
new
OpenBaton
(
db
,
callback
,
*
filename
,
mode
);
OpenBaton
*
baton
=
new
OpenBaton
(
this
,
callback
,
filename
.
c_str
()
,
mode
);
Work_BeginOpen
(
baton
);
return
info
.
This
();
}
void
Database
::
Work_BeginOpen
(
Baton
*
baton
)
{
...
...
@@ -170,14 +163,15 @@ void Database::Work_Open(uv_work_t* req) {
}
void
Database
::
Work_AfterOpen
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
OpenBaton
*
baton
=
static_cast
<
OpenBaton
*>
(
req
->
data
);
Database
*
db
=
baton
->
db
;
Napi
::
Env
env
=
db
->
Env
();
Napi
::
HandleScope
scope
(
env
);
Napi
::
Value
argv
[
1
];
if
(
baton
->
status
!=
SQLITE_OK
)
{
EXCEPTION
(
baton
->
message
,
baton
->
status
,
exception
);
EXCEPTION
(
Napi
::
String
::
New
(
env
,
baton
->
message
.
c_str
())
,
baton
->
status
,
exception
);
argv
[
0
]
=
exception
;
}
else
{
...
...
@@ -185,19 +179,19 @@ void Database::Work_AfterOpen(uv_work_t* req) {
argv
[
0
]
=
env
.
Null
();
}
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
TRY_CATCH_CALL
(
db
->
handl
e
(),
cb
,
1
,
argv
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
TRY_CATCH_CALL
(
db
->
Valu
e
(),
cb
,
1
,
argv
);
}
else
if
(
!
db
->
open
)
{
Napi
::
Value
info
[]
=
{
Napi
::
String
::
New
(
env
,
"error"
),
argv
[
0
]
};
EMIT_EVENT
(
db
->
handl
e
(),
2
,
info
);
EMIT_EVENT
(
db
->
Valu
e
(),
2
,
info
);
}
if
(
db
->
open
)
{
Napi
::
Value
info
[]
=
{
Napi
::
String
::
New
(
env
,
"open"
)
};
EMIT_EVENT
(
db
->
handl
e
(),
1
,
info
);
EMIT_EVENT
(
db
->
Valu
e
(),
1
,
info
);
db
->
Process
();
}
...
...
@@ -205,11 +199,13 @@ void Database::Work_AfterOpen(uv_work_t* req) {
}
Napi
::
Value
Database
::
OpenGetter
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
this
->
Env
();
Database
*
db
=
this
;
return
db
->
open
;
return
Napi
::
Boolean
::
New
(
env
,
db
->
open
)
;
}
Napi
::
Value
Database
::
Close
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
info
.
Env
();
Database
*
db
=
this
;
OPTIONAL_ARGUMENT_FUNCTION
(
0
,
callback
);
...
...
@@ -248,16 +244,17 @@ void Database::Work_Close(uv_work_t* req) {
}
void
Database
::
Work_AfterClose
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
Baton
*
baton
=
static_cast
<
Baton
*>
(
req
->
data
);
Database
*
db
=
baton
->
db
;
Napi
::
Env
env
=
db
->
Env
();
Napi
::
HandleScope
scope
(
env
);
db
->
closing
=
false
;
Napi
::
Value
argv
[
1
];
if
(
baton
->
status
!=
SQLITE_OK
)
{
EXCEPTION
(
baton
->
message
,
baton
->
status
,
exception
);
EXCEPTION
(
Napi
::
String
::
New
(
env
,
baton
->
message
.
c_str
())
,
baton
->
status
,
exception
);
argv
[
0
]
=
exception
;
}
else
{
...
...
@@ -267,20 +264,20 @@ void Database::Work_AfterClose(uv_work_t* req) {
argv
[
0
]
=
env
.
Null
();
}
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
// Fire callbacks.
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
TRY_CATCH_CALL
(
db
->
handl
e
(),
cb
,
1
,
argv
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
TRY_CATCH_CALL
(
db
->
Valu
e
(),
cb
,
1
,
argv
);
}
else
if
(
db
->
open
)
{
Napi
::
Value
info
[]
=
{
Napi
::
String
::
New
(
env
,
"error"
),
argv
[
0
]
};
EMIT_EVENT
(
db
->
handl
e
(),
2
,
info
);
EMIT_EVENT
(
db
->
Valu
e
(),
2
,
info
);
}
if
(
!
db
->
open
)
{
Napi
::
Value
info
[]
=
{
Napi
::
String
::
New
(
env
,
"close"
),
argv
[
0
]
};
EMIT_EVENT
(
db
->
handl
e
(),
1
,
info
);
EMIT_EVENT
(
db
->
Valu
e
(),
1
,
info
);
db
->
Process
();
}
...
...
@@ -288,13 +285,14 @@ void Database::Work_AfterClose(uv_work_t* req) {
}
Napi
::
Value
Database
::
Serialize
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
this
->
Env
();
Database
*
db
=
this
;
OPTIONAL_ARGUMENT_FUNCTION
(
0
,
callback
);
bool
before
=
db
->
serialize
;
db
->
serialize
=
true
;
if
(
!
callback
.
IsEmpty
()
&&
callback
->
IsFunction
())
{
if
(
!
callback
.
IsEmpty
()
&&
callback
.
IsFunction
())
{
TRY_CATCH_CALL
(
info
.
This
(),
callback
,
0
,
NULL
);
db
->
serialize
=
before
;
}
...
...
@@ -305,13 +303,14 @@ Napi::Value Database::Serialize(const Napi::CallbackInfo& info) {
}
Napi
::
Value
Database
::
Parallelize
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
this
->
Env
();
Database
*
db
=
this
;
OPTIONAL_ARGUMENT_FUNCTION
(
0
,
callback
);
bool
before
=
db
->
serialize
;
db
->
serialize
=
false
;
if
(
!
callback
.
IsEmpty
()
&&
callback
->
IsFunction
())
{
if
(
!
callback
.
IsEmpty
()
&&
callback
.
IsFunction
())
{
TRY_CATCH_CALL
(
info
.
This
(),
callback
,
0
,
NULL
);
db
->
serialize
=
before
;
}
...
...
@@ -322,6 +321,7 @@ Napi::Value Database::Parallelize(const Napi::CallbackInfo& info) {
}
Napi
::
Value
Database
::
Configure
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
this
->
Env
();
Database
*
db
=
this
;
REQUIRE_ARGUMENTS
(
2
);
...
...
@@ -347,13 +347,14 @@ Napi::Value Database::Configure(const Napi::CallbackInfo& info) {
db
->
Schedule
(
SetBusyTimeout
,
baton
);
}
else
{
return
Napi
::
ThrowError
(
Exception
::
Error
(
String
::
Concat
(
Napi
::
TypeError
::
New
(
env
,
(
String
Concat
(
#if V8_MAJOR_VERSION > 6
info
.
GetIsolate
(),
#endif
info
[
0
].
To
<
Napi
::
String
>
(),
info
[
0
].
As
<
Napi
::
String
>
(),
Napi
::
String
::
New
(
env
,
" is not a valid configuration option"
)
)));
)).
Utf8Value
().
c_str
()).
ThrowAsJavaScriptException
();
return
env
.
Null
();
}
db
->
Process
();
...
...
@@ -362,6 +363,7 @@ Napi::Value Database::Configure(const Napi::CallbackInfo& info) {
}
Napi
::
Value
Database
::
Interrupt
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
this
->
Env
();
Database
*
db
=
this
;
if
(
!
db
->
open
)
{
...
...
@@ -416,13 +418,14 @@ void Database::TraceCallback(void* db, const char* sql) {
void
Database
::
TraceCallback
(
Database
*
db
,
std
::
string
*
sql
)
{
// Note: This function is called in the main V8 thread.
Napi
::
Env
env
=
db
->
Env
();
Napi
::
HandleScope
scope
(
env
);
Napi
::
Value
argv
[]
=
{
Napi
::
String
::
New
(
env
,
"trace"
),
Napi
::
New
(
env
,
sql
->
c_str
())
Napi
::
String
::
New
(
env
,
sql
->
c_str
())
};
EMIT_EVENT
(
db
->
handl
e
(),
2
,
argv
);
EMIT_EVENT
(
db
->
Valu
e
(),
2
,
argv
);
delete
sql
;
}
...
...
@@ -456,14 +459,15 @@ void Database::ProfileCallback(void* db, const char* sql, sqlite3_uint64 nsecs)
}
void
Database
::
ProfileCallback
(
Database
*
db
,
ProfileInfo
*
info
)
{
Napi
::
Env
env
=
db
->
Env
();
Napi
::
HandleScope
scope
(
env
);
Napi
::
Value
argv
[]
=
{
Napi
::
String
::
New
(
env
,
"profile"
),
Napi
::
New
(
env
,
info
->
sql
.
c_str
()),
Napi
::
String
::
New
(
env
,
info
->
sql
.
c_str
()),
Napi
::
Number
::
New
(
env
,
(
double
)
info
->
nsecs
/
1000000.0
)
};
EMIT_EVENT
(
db
->
handl
e
(),
3
,
argv
);
EMIT_EVENT
(
db
->
Valu
e
(),
3
,
argv
);
delete
info
;
}
...
...
@@ -500,25 +504,27 @@ void Database::UpdateCallback(void* db, int type, const char* database,
}
void
Database
::
UpdateCallback
(
Database
*
db
,
UpdateInfo
*
info
)
{
Napi
::
Env
env
=
db
->
Env
();
Napi
::
HandleScope
scope
(
env
);
Napi
::
Value
argv
[]
=
{
Napi
::
New
(
env
,
sqlite_authorizer_string
(
info
->
type
)),
Napi
::
New
(
env
,
info
->
database
.
c_str
()),
Napi
::
New
(
env
,
info
->
table
.
c_str
()),
Napi
::
String
::
New
(
env
,
sqlite_authorizer_string
(
info
->
type
)),
Napi
::
String
::
New
(
env
,
info
->
database
.
c_str
()),
Napi
::
String
::
New
(
env
,
info
->
table
.
c_str
()),
Napi
::
Number
::
New
(
env
,
info
->
rowid
),
};
EMIT_EVENT
(
db
->
handl
e
(),
4
,
argv
);
EMIT_EVENT
(
db
->
Valu
e
(),
4
,
argv
);
delete
info
;
}
Napi
::
Value
Database
::
Exec
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
this
->
Env
();
Database
*
db
=
this
;
REQUIRE_ARGUMENT_STRING
(
0
,
sql
);
OPTIONAL_ARGUMENT_FUNCTION
(
1
,
callback
);
Baton
*
baton
=
new
ExecBaton
(
db
,
callback
,
*
sql
);
Baton
*
baton
=
new
ExecBaton
(
db
,
callback
,
sql
.
c_str
()
);
db
->
Schedule
(
Work_BeginExec
,
baton
,
true
);
return
info
.
This
();
...
...
@@ -553,28 +559,29 @@ void Database::Work_Exec(uv_work_t* req) {
}
void
Database
::
Work_AfterExec
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
ExecBaton
*
baton
=
static_cast
<
ExecBaton
*>
(
req
->
data
);
Database
*
db
=
baton
->
db
;
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
Napi
::
Env
env
=
db
->
Env
();
Napi
::
HandleScope
scope
(
env
);
Napi
::
Function
cb
=
baton
->
callback
.
Value
();
if
(
baton
->
status
!=
SQLITE_OK
)
{
EXCEPTION
(
baton
->
message
,
baton
->
status
,
exception
);
EXCEPTION
(
Napi
::
String
::
New
(
env
,
baton
->
message
.
c_str
())
,
baton
->
status
,
exception
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
exception
};
TRY_CATCH_CALL
(
db
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
db
->
Valu
e
(),
cb
,
1
,
argv
);
}
else
{
Napi
::
Value
info
[]
=
{
Napi
::
String
::
New
(
env
,
"error"
),
exception
};
EMIT_EVENT
(
db
->
handl
e
(),
2
,
info
);
EMIT_EVENT
(
db
->
Valu
e
(),
2
,
info
);
}
}
else
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
else
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
env
.
Null
()
};
TRY_CATCH_CALL
(
db
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
db
->
Valu
e
(),
cb
,
1
,
argv
);
}
db
->
Process
();
...
...
@@ -583,6 +590,7 @@ void Database::Work_AfterExec(uv_work_t* req) {
}
Napi
::
Value
Database
::
Wait
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
info
.
Env
();
Database
*
db
=
this
;
OPTIONAL_ARGUMENT_FUNCTION
(
0
,
callback
);
...
...
@@ -594,6 +602,7 @@ Napi::Value Database::Wait(const Napi::CallbackInfo& info) {
}
void
Database
::
Work_Wait
(
Baton
*
baton
)
{
Napi
::
Env
env
=
baton
->
db
->
Env
();
Napi
::
HandleScope
scope
(
env
);
assert
(
baton
->
db
->
locked
);
...
...
@@ -601,10 +610,10 @@ void Database::Work_Wait(Baton* baton) {
assert
(
baton
->
db
->
_handle
);
assert
(
baton
->
db
->
pending
==
0
);
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
env
.
Null
()
};
TRY_CATCH_CALL
(
baton
->
db
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
baton
->
db
->
Valu
e
(),
cb
,
1
,
argv
);
}
baton
->
db
->
Process
();
...
...
@@ -613,12 +622,13 @@ void Database::Work_Wait(Baton* baton) {
}
Napi
::
Value
Database
::
LoadExtension
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
this
->
Env
();
Database
*
db
=
this
;
REQUIRE_ARGUMENT_STRING
(
0
,
filename
);
OPTIONAL_ARGUMENT_FUNCTION
(
1
,
callback
);
Baton
*
baton
=
new
LoadExtensionBaton
(
db
,
callback
,
*
filename
);
Baton
*
baton
=
new
LoadExtensionBaton
(
db
,
callback
,
filename
.
c_str
()
);
db
->
Schedule
(
Work_BeginLoadExtension
,
baton
,
true
);
return
info
.
This
();
...
...
@@ -656,27 +666,29 @@ void Database::Work_LoadExtension(uv_work_t* req) {
}
void
Database
::
Work_AfterLoadExtension
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
LoadExtensionBaton
*
baton
=
static_cast
<
LoadExtensionBaton
*>
(
req
->
data
);
Database
*
db
=
baton
->
db
;
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
Napi
::
Env
env
=
db
->
Env
();
Napi
::
HandleScope
scope
(
env
);
Napi
::
Function
cb
=
baton
->
callback
.
Value
();
if
(
baton
->
status
!=
SQLITE_OK
)
{
EXCEPTION
(
baton
->
message
,
baton
->
status
,
exception
);
EXCEPTION
(
Napi
::
String
::
New
(
env
,
baton
->
message
.
c_str
())
,
baton
->
status
,
exception
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
exception
};
TRY_CATCH_CALL
(
db
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
db
->
Valu
e
(),
cb
,
1
,
argv
);
}
else
{
Napi
::
Value
info
[]
=
{
Napi
::
String
::
New
(
env
,
"error"
),
exception
};
EMIT_EVENT
(
db
->
handl
e
(),
2
,
info
);
EMIT_EVENT
(
db
->
Valu
e
(),
2
,
info
);
}
}
else
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
else
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
env
.
Null
()
};
TRY_CATCH_CALL
(
db
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
db
->
Valu
e
(),
cb
,
1
,
argv
);
}
db
->
Process
();
...
...
src/database.h
View file @
dd3ef522
...
...
@@ -29,7 +29,7 @@ public:
Napi
::
HandleScope
scope
(
env
);
if
(
!
val
.
IsObject
())
return
false
;
Napi
::
Object
obj
=
val
.
As
<
Napi
::
Object
>
();
return
Napi
::
New
(
env
,
constructor
)
->
HasInstance
(
obj
);
return
obj
.
InstanceOf
(
constructor
.
Value
()
);
}
struct
Baton
{
...
...
@@ -43,7 +43,9 @@ public:
db
(
db_
),
status
(
SQLITE_OK
)
{
db
->
Ref
();
request
.
data
=
this
;
callback
.
Reset
(
cb_
);
if
(
!
cb_
.
IsUndefined
()
&&
cb_
.
IsFunction
())
{
callback
.
Reset
(
cb_
,
1
);
}
}
virtual
~
Baton
()
{
db
->
Unref
();
...
...
@@ -102,19 +104,20 @@ public:
friend
class
Statement
;
friend
class
Backup
;
protected
:
Database
()
:
Napi
::
ObjectWrap
<
Database
>
(),
_handle
(
NULL
),
open
(
false
),
closing
(
false
),
locked
(
false
),
pending
(
0
),
serialize
(
false
),
debug_trace
(
NULL
),
debug_profile
(
NULL
),
update_event
(
NULL
)
{
void
init
()
{
_handle
=
NULL
;
open
=
false
;
closing
=
false
;
locked
=
false
;
pending
=
0
;
serialize
=
false
;
debug_trace
=
NULL
;
debug_profile
=
NULL
;
update_event
=
NULL
;
}
Database
(
const
Napi
::
CallbackInfo
&
info
);
~
Database
()
{
RemoveCallbacks
();
sqlite3_close
(
_handle
);
...
...
@@ -122,7 +125,7 @@ protected:
open
=
false
;
}
static
Napi
::
Value
New
(
const
Napi
::
CallbackInfo
&
info
);
protected
:
static
void
Work_BeginOpen
(
Baton
*
baton
);
static
void
Work_Open
(
uv_work_t
*
req
);
static
void
Work_AfterOpen
(
uv_work_t
*
req
);
...
...
@@ -132,30 +135,30 @@ protected:
void
Schedule
(
Work_Callback
callback
,
Baton
*
baton
,
bool
exclusive
=
false
);
void
Process
();
static
Napi
::
Value
Exec
(
const
Napi
::
CallbackInfo
&
info
);
Napi
::
Value
Exec
(
const
Napi
::
CallbackInfo
&
info
);
static
void
Work_BeginExec
(
Baton
*
baton
);
static
void
Work_Exec
(
uv_work_t
*
req
);
static
void
Work_AfterExec
(
uv_work_t
*
req
);
static
Napi
::
Value
Wait
(
const
Napi
::
CallbackInfo
&
info
);
Napi
::
Value
Wait
(
const
Napi
::
CallbackInfo
&
info
);
static
void
Work_Wait
(
Baton
*
baton
);
static
Napi
::
Value
Close
(
const
Napi
::
CallbackInfo
&
info
);
Napi
::
Value
Close
(
const
Napi
::
CallbackInfo
&
info
);
static
void
Work_BeginClose
(
Baton
*
baton
);
static
void
Work_Close
(
uv_work_t
*
req
);
static
void
Work_AfterClose
(
uv_work_t
*
req
);
static
Napi
::
Value
LoadExtension
(
const
Napi
::
CallbackInfo
&
info
);
Napi
::
Value
LoadExtension
(
const
Napi
::
CallbackInfo
&
info
);
static
void
Work_BeginLoadExtension
(
Baton
*
baton
);
static
void
Work_LoadExtension
(
uv_work_t
*
req
);
static
void
Work_AfterLoadExtension
(
uv_work_t
*
req
);
static
Napi
::
Value
Serialize
(
const
Napi
::
CallbackInfo
&
info
);
static
Napi
::
Value
Parallelize
(
const
Napi
::
CallbackInfo
&
info
);
Napi
::
Value
Serialize
(
const
Napi
::
CallbackInfo
&
info
);
Napi
::
Value
Parallelize
(
const
Napi
::
CallbackInfo
&
info
);
static
Napi
::
Value
Configure
(
const
Napi
::
CallbackInfo
&
info
);
Napi
::
Value
Configure
(
const
Napi
::
CallbackInfo
&
info
);
static
Napi
::
Value
Interrupt
(
const
Napi
::
CallbackInfo
&
info
);
Napi
::
Value
Interrupt
(
const
Napi
::
CallbackInfo
&
info
);
static
void
SetBusyTimeout
(
Baton
*
baton
);
...
...
src/macros.h
View file @
dd3ef522
...
...
@@ -3,35 +3,49 @@
const
char
*
sqlite_code_string
(
int
code
);
const
char
*
sqlite_authorizer_string
(
int
type
);
#include <vector>
// TODO: better way to work around StringConcat?
#include <napi.h>
inline
Napi
::
String
StringConcat
(
Napi
::
Value
str1
,
Napi
::
Value
str2
)
{
return
Napi
::
String
::
New
(
str1
.
Env
(),
str1
.
As
<
Napi
::
String
>
().
Utf8Value
()
+
str2
.
As
<
Napi
::
String
>
().
Utf8Value
()
);
}
// A Napi substitute IsInt32()
inline
bool
OtherIsInt
(
Napi
::
Number
source
)
{
double
orig_val
=
source
.
DoubleValue
();
double
int_val
=
(
double
)
source
.
Int32Value
();
if
(
orig_val
==
int_val
)
{
return
true
;
}
else
{
return
false
;
}
}
#define REQUIRE_ARGUMENTS(n) \
if (info.Length() < (n)) { \
Napi::TypeError::New(env, "Expected " #n "arguments").ThrowAsJavaScriptException(); \
return env.Null(); \
}
#define REQUIRE_ARGUMENT_EXTERNAL(i, var) \
if (info.Length() <= (i) || !info[i].IsExternal()) { \
if (info.Length() <= (i) || !info[i].IsExternal()) {
\
Napi::TypeError::New(env, "Argument " #i " invalid").ThrowAsJavaScriptException(); \
return env.Null(); \
} \
Napi::External var = info[i].As<Napi::External>();
#define REQUIRE_ARGUMENT_FUNCTION(i, var) \
if (info.Length() <= (i) || !info[i].IsFunction()) { \
if (info.Length() <= (i) || !info[i].IsFunction()) {
\
Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \
return env.Null(); \
} \
Napi::Function var = info[i].As<Napi::Function>();
#define REQUIRE_ARGUMENT_STRING(i, var) \
if (info.Length() <= (i) || !info[i].IsString()) { \
if (info.Length() <= (i) || !info[i].IsString()) {
\
Napi::TypeError::New(env, "Argument " #i " must be a string").ThrowAsJavaScriptException(); \
return env.Null(); \
} \
std::string var = info[i].As<Napi::String>();
...
...
@@ -43,13 +57,12 @@ const char* sqlite_authorizer_string(int type);
int var(info[i].As<Napi::Number>().Int32Value());
#define OPTIONAL_ARGUMENT_FUNCTION(i, var) \
Napi::Function var; \
if (info.Length() > i && !info[i].IsUndefined()) { \
if (!info[i].IsFunction()) { \
Napi::Function var;
\
if (info.Length() > i && !info[i].IsUndefined()) {
\
if (!info[i].IsFunction()) {
\
Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \
return env.Null(); \
} \
var = info[i].As<Napi::Function>(); \
var = info[i].As<Napi::Function>();
\
}
...
...
@@ -59,67 +72,57 @@ const char* sqlite_authorizer_string(int type);
var = (default); \
} \
else if (info[i].IsNumber()) { \
var = info[i].As<Napi::Number>().Int32Value(); \
if (OtherIsInt(info[i].As<Number>())) { \
var = info[i].As<Napi::Number>().Int32Value(); \
} \
} \
else { \
Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \
return env.Null(); \
}
#define DEFINE_CONSTANT_INTEGER(target, constant, name) \
target->DefineProperty( \
Napi::New(env, #name), \
Napi::Number::New(env, constant), \
static_cast<napi_property_attributes>(napi_enumerable | napi_configurable) \
);
Napi::PropertyDescriptor::Value(#name, Napi::Number::New(env, constant), \
static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)),
#define DEFINE_CONSTANT_STRING(target, constant, name) \
target->DefineProperty( \
Napi::New(env, #name), \
Napi::New(env, constant), \
static_cast<napi_property_attributes>(napi_enumerable | napi_configurable) \
);
#define NODE_SET_GETTER(target, name, function) \
Napi::SetAccessor((target)->InstanceTemplate(), \
Napi::New(env, name), (function));
#define NODE_SET_SETTER(target, name, getter, setter) \
Napi::SetAccessor((target)->InstanceTemplate(), \
Napi::New(env, name), getter, setter);
#define GET_STRING(source, name, property) \
std::string name = (source).Get(\
Napi::New(env, prop.As<Napi::String>()));
#define GET_INTEGER(source, name, prop) \
int name = Napi::To<int>((source).Get(\
Napi::New(env, property)));
Napi::PropertyDescriptor::Value(#name, Napi::String::New(env, constant), \
static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)),
#define EXCEPTION(msg, errno, name) \
Napi::Value name = Exception::Error(Napi::New(env, \
std::string(sqlite_code_string(errno)) + \
std::string(": ") + std::string(msg) \
)); \
Napi::Object name ##_obj = name.As<Napi::Object>(); \
(name ##_obj).Set(Napi::String::New(env, "errno"), Napi::New(env, errno));\
(name ##_obj).Set(Napi::String::New(env, "code"), \
Napi::New(env, sqlite_code_string(errno)));
Napi::Value name = Napi::Error::New(env, \
StringConcat( \
StringConcat( \
Napi::String::New(env, sqlite_code_string(errno)), \
Napi::String::New(env, ": ") \
), \
(msg) \
).Utf8Value() \
).Value(); \
Napi::Object name ##_obj = name.As<Napi::Object>(); \
(name ##_obj).Set( Napi::String::New(env, "errno"), Napi::Number::New(env, errno)); \
(name ##_obj).Set( Napi::String::New(env, "code"), \
Napi::String::New(env, sqlite_code_string(errno)));
#define EMIT_EVENT(obj, argc, argv) \
TRY_CATCH_CALL((obj), \
(obj).Get(\
Napi::String::New(env, "emit")).As<Napi::Function>(),\
(obj).Get("emit").As<Napi::Function>(),\
argc, argv \
);
// The Mac OS compiler complains when argv is NULL unless we
// first assign it to a locally defined variable.
#define TRY_CATCH_CALL(context, callback, argc, argv) \
(callback).MakeCallback((context), (argc), (argv))
Napi::Value* passed_argv = argv;\
std::vector<napi_value> args;\
if ((argc != 0) && (passed_argv != NULL)) {\
args.assign(passed_argv, passed_argv + argc);\
}\
(callback).MakeCallback(Napi::Value(context), args);
#define WORK_DEFINITION(name) \
static Napi::Value name(const Napi::CallbackInfo& info);
\
Napi::Value name(const Napi::CallbackInfo& info);
\
static void Work_Begin##name(Baton* baton); \
static void Work_##name(uv_work_t* req); \
static void Work_After##name(uv_work_t* req);
...
...
src/node_sqlite3.cc
View file @
dd3ef522
...
...
@@ -16,50 +16,54 @@ namespace {
Napi
::
Object
RegisterModule
(
Napi
::
Env
env
,
Napi
::
Object
exports
)
{
Napi
::
HandleScope
scope
(
env
);
Database
::
Init
(
env
,
target
,
module
);
Statement
::
Init
(
env
,
target
,
module
);
Backup
::
Init
(
env
,
target
,
module
);
Database
::
Init
(
env
,
exports
);
Statement
::
Init
(
env
,
exports
);
Backup
::
Init
(
env
,
exports
);
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_INTEGER
(
target
,
SQLITE_OPEN_FULLMUTEX
,
OPEN_FULLMUTEX
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_OPEN_URI
,
OPEN_URI
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_OPEN_SHAREDCACHE
,
OPEN_SHAREDCACHE
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_OPEN_PRIVATECACHE
,
OPEN_PRIVATECACHE
);
DEFINE_CONSTANT_STRING
(
target
,
SQLITE_VERSION
,
VERSION
);
exports
.
DefineProperties
({
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_OPEN_READONLY
,
OPEN_READONLY
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_OPEN_READWRITE
,
OPEN_READWRITE
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_OPEN_CREATE
,
OPEN_CREATE
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_OPEN_FULLMUTEX
,
OPEN_FULLMUTEX
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_OPEN_URI
,
OPEN_URI
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_OPEN_SHAREDCACHE
,
OPEN_SHAREDCACHE
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_OPEN_PRIVATECACHE
,
OPEN_PRIVATECACHE
)
DEFINE_CONSTANT_STRING
(
exports
,
SQLITE_VERSION
,
VERSION
)
#ifdef SQLITE_SOURCE_ID
DEFINE_CONSTANT_STRING
(
target
,
SQLITE_SOURCE_ID
,
SOURCE_ID
);
DEFINE_CONSTANT_STRING
(
exports
,
SQLITE_SOURCE_ID
,
SOURCE_ID
)
#endif
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_VERSION_NUMBER
,
VERSION_NUMBER
);
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_VERSION_NUMBER
,
VERSION_NUMBER
)
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_OK
,
OK
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_ERROR
,
ERROR
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_INTERNAL
,
INTERNAL
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_PERM
,
PERM
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_ABORT
,
ABORT
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_BUSY
,
BUSY
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_LOCKED
,
LOCKED
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_NOMEM
,
NOMEM
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_READONLY
,
READONLY
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_INTERRUPT
,
INTERRUPT
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_IOERR
,
IOERR
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_CORRUPT
,
CORRUPT
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_NOTFOUND
,
NOTFOUND
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_FULL
,
FULL
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_CANTOPEN
,
CANTOPEN
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_PROTOCOL
,
PROTOCOL
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_EMPTY
,
EMPTY
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_SCHEMA
,
SCHEMA
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_TOOBIG
,
TOOBIG
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_CONSTRAINT
,
CONSTRAINT
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_MISMATCH
,
MISMATCH
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_MISUSE
,
MISUSE
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_NOLFS
,
NOLFS
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_AUTH
,
AUTH
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_FORMAT
,
FORMAT
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_RANGE
,
RANGE
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_NOTADB
,
NOTADB
);
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_OK
,
OK
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_ERROR
,
ERROR
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_INTERNAL
,
INTERNAL
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_PERM
,
PERM
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_ABORT
,
ABORT
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_BUSY
,
BUSY
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_LOCKED
,
LOCKED
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_NOMEM
,
NOMEM
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_READONLY
,
READONLY
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_INTERRUPT
,
INTERRUPT
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_IOERR
,
IOERR
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_CORRUPT
,
CORRUPT
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_NOTFOUND
,
NOTFOUND
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_FULL
,
FULL
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_CANTOPEN
,
CANTOPEN
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_PROTOCOL
,
PROTOCOL
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_EMPTY
,
EMPTY
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_SCHEMA
,
SCHEMA
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_TOOBIG
,
TOOBIG
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_CONSTRAINT
,
CONSTRAINT
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_MISMATCH
,
MISMATCH
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_MISUSE
,
MISUSE
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_NOLFS
,
NOLFS
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_AUTH
,
AUTH
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_FORMAT
,
FORMAT
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_RANGE
,
RANGE
)
DEFINE_CONSTANT_INTEGER
(
exports
,
SQLITE_NOTADB
,
NOTADB
)
});
return
exports
;
}
}
...
...
src/statement.cc
View file @
dd3ef522
...
...
@@ -11,26 +11,49 @@
using
namespace
node_sqlite3
;
Napi
::
FunctionReference
Statement
::
constructor
;
static
Napi
::
FunctionReference
date
;
static
Napi
::
FunctionReference
regexp
;
Napi
::
Object
Statement
::
Init
(
Napi
::
Env
env
,
Napi
::
Object
exports
)
{
Napi
::
HandleScope
scope
(
env
);
Napi
::
FunctionReference
t
=
Napi
::
Function
::
New
(
env
,
New
);
Napi
::
Function
t
=
DefineClass
(
env
,
"Statement"
,
{
InstanceMethod
(
"bind"
,
&
Statement
::
Bind
),
InstanceMethod
(
"get"
,
&
Statement
::
Get
),
InstanceMethod
(
"run"
,
&
Statement
::
Run
),
InstanceMethod
(
"all"
,
&
Statement
::
All
),
InstanceMethod
(
"each"
,
&
Statement
::
Each
),
InstanceMethod
(
"reset"
,
&
Statement
::
Reset
),
InstanceMethod
(
"finalize"
,
&
Statement
::
Finalize_
),
});
constructor
=
Napi
::
Persistent
(
t
);
constructor
.
SuppressDestruct
();
t
->
SetClassName
(
Napi
::
String
::
New
(
env
,
"Statement"
));
exports
.
Set
(
"Statement"
,
t
);
return
exports
;
}
// A Napi InstanceOf for Javascript Objects "Date" and "RegExp"
bool
OtherInstanceOf
(
Napi
::
Object
source
,
char
*
object_type
)
{
if
(
date
.
IsEmpty
())
{
Napi
::
Function
date_func
=
source
.
Env
().
Global
().
Get
(
"Date"
).
As
<
Function
>
();
Napi
::
Function
regexp_func
=
source
.
Env
().
Global
().
Get
(
"RegExp"
).
As
<
Function
>
();
InstanceMethod
(
"bind"
,
&
Bind
),
InstanceMethod
(
"get"
,
&
Get
),
InstanceMethod
(
"run"
,
&
Run
),
InstanceMethod
(
"all"
,
&
All
),
InstanceMethod
(
"each"
,
&
Each
),
InstanceMethod
(
"reset"
,
&
Reset
),
InstanceMethod
(
"finalize"
,
&
Finalize
),
date
=
Napi
::
Persistent
(
date_func
);
date
.
SuppressDestruct
();
regexp
=
Napi
::
Persistent
(
regexp_func
);
regexp
.
SuppressDestruct
();
}
constructor
.
Reset
(
t
);
(
target
).
Set
(
Napi
::
String
::
New
(
env
,
"Statement"
),
Napi
::
GetFunction
(
t
));
if
(
object_type
==
"Date"
)
{
return
source
.
InstanceOf
(
date
.
Value
());
}
else
if
(
object_type
==
"RegExp"
)
{
return
source
.
InstanceOf
(
regexp
.
Value
());
}
return
false
;
}
void
Statement
::
Process
()
{
...
...
@@ -61,60 +84,56 @@ void Statement::Schedule(Work_Callback callback, Baton* baton) {
}
template
<
class
T
>
void
Statement
::
Error
(
T
*
baton
)
{
Statement
*
stmt
=
baton
->
stmt
;
Napi
::
Env
env
=
stmt
->
Env
();
Napi
::
HandleScope
scope
(
env
);
Statement
*
stmt
=
baton
->
stmt
;
// Fail hard on logic errors.
assert
(
stmt
->
status
!=
0
);
EXCEPTION
(
stmt
->
message
,
stmt
->
status
,
exception
);
EXCEPTION
(
Napi
::
String
::
New
(
env
,
stmt
->
message
.
c_str
())
,
stmt
->
status
,
exception
);
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
exception
};
TRY_CATCH_CALL
(
stmt
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
stmt
->
Valu
e
(),
cb
,
1
,
argv
);
}
else
{
Napi
::
Value
argv
[]
=
{
Napi
::
String
::
New
(
env
,
"error"
),
exception
};
EMIT_EVENT
(
stmt
->
handl
e
(),
2
,
argv
);
EMIT_EVENT
(
stmt
->
Valu
e
(),
2
,
argv
);
}
}
// { Database db, String sql, Array params, Function callback }
Napi
::
Value
Statement
::
New
(
const
Napi
::
CallbackInfo
&
info
)
{
if
(
!
info
.
IsConstructCall
())
{
Napi
::
TypeError
::
New
(
env
,
"Use the new operator to create new Statement objects"
).
ThrowAsJavaScriptException
();
return
env
.
Null
();
}
Statement
::
Statement
(
const
Napi
::
CallbackInfo
&
info
)
:
Napi
::
ObjectWrap
<
Statement
>
(
info
)
{
Napi
::
Env
env
=
info
.
Env
();
int
length
=
info
.
Length
();
if
(
length
<=
0
||
!
Database
::
HasInstance
(
info
[
0
]))
{
Napi
::
TypeError
::
New
(
env
,
"Database object expected"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
else
if
(
length
<=
1
||
!
info
[
1
].
IsString
())
{
Napi
::
TypeError
::
New
(
env
,
"SQL query expected"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
else
if
(
length
>
2
&&
!
info
[
2
].
IsUndefined
()
&&
!
info
[
2
].
IsFunction
())
{
Napi
::
TypeError
::
New
(
env
,
"Callback expected"
).
ThrowAsJavaScriptException
();
return
env
.
Null
()
;
return
;
}
Database
*
db
=
info
[
0
].
As
<
Napi
::
Object
>
().
Unwrap
<
Database
>
(
);
Database
*
db
=
Napi
::
ObjectWrap
<
Database
>::
Unwrap
(
info
[
0
].
As
<
Napi
::
Object
>
()
);
Napi
::
String
sql
=
info
[
1
].
As
<
Napi
::
String
>
();
info
.
This
().
DefineProperty
(
Napi
::
String
::
New
(
env
,
"sql"
),
sql
,
ReadOnly
);
info
.
This
().
As
<
Napi
::
Object
>
().
DefineProperty
(
Napi
::
PropertyDescriptor
::
Value
(
"sql"
,
sql
,
napi_default
)
);
Statement
*
stmt
=
new
Statemen
t
(
db
);
stmt
->
Wrap
(
info
.
This
())
;
ini
t
(
db
);
Statement
*
stmt
=
this
;
PrepareBaton
*
baton
=
new
PrepareBaton
(
db
,
info
[
2
].
As
<
Napi
::
Function
>
(),
stmt
);
baton
->
sql
=
std
::
string
(
sql
->
As
<
Napi
::
String
>
().
Utf8Value
().
c_str
());
baton
->
sql
=
std
::
string
(
sql
.
As
<
Napi
::
String
>
().
Utf8Value
().
c_str
());
db
->
Schedule
(
Work_BeginPrepare
,
baton
);
return
info
.
This
();
}
void
Statement
::
Work_BeginPrepare
(
Database
::
Baton
*
baton
)
{
...
...
@@ -150,20 +169,21 @@ void Statement::Work_Prepare(uv_work_t* req) {
}
void
Statement
::
Work_AfterPrepare
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
STATEMENT_INIT
(
PrepareBaton
);
Napi
::
Env
env
=
stmt
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
stmt
->
status
!=
SQLITE_OK
)
{
Error
(
baton
);
stmt
->
Finalize
();
stmt
->
Finalize
_
();
}
else
{
stmt
->
prepared
=
true
;
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
IsEmpty
()
&&
cb
->
IsFunction
())
{
if
(
!
baton
->
callback
.
IsEmpty
()
&&
baton
->
callback
.
Value
().
IsFunction
())
{
Napi
::
Function
cb
=
baton
->
callback
.
Value
();
Napi
::
Value
argv
[]
=
{
env
.
Null
()
};
TRY_CATCH_CALL
(
stmt
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
stmt
->
Valu
e
(),
cb
,
1
,
argv
);
}
}
...
...
@@ -172,28 +192,37 @@ void Statement::Work_AfterPrepare(uv_work_t* req) {
template
<
class
T
>
Values
::
Field
*
Statement
::
BindParameter
(
const
Napi
::
Value
source
,
T
pos
)
{
if
(
source
.
IsString
()
||
source
->
IsRegExp
()
)
{
std
::
string
val
=
source
.
As
<
Napi
::
String
>
();
return
new
Values
::
Text
(
pos
,
val
.
Length
(),
*
val
);
if
(
source
.
IsString
())
{
std
::
string
val
=
source
.
As
<
Napi
::
String
>
()
.
Utf8Value
()
;
return
new
Values
::
Text
(
pos
,
val
.
length
(),
val
.
c_str
()
);
}
else
if
(
source
.
IsNumber
())
{
return
new
Values
::
Integer
(
pos
,
source
.
As
<
Napi
::
Number
>
().
Int32Value
());
else
if
(
OtherInstanceOf
(
source
.
As
<
Object
>
(),
"RegExp"
))
{
std
::
string
val
=
source
.
ToString
().
Utf8Value
();
return
new
Values
::
Text
(
pos
,
val
.
length
(),
val
.
c_str
());
}
else
if
(
source
.
IsNumber
())
{
return
new
Values
::
Float
(
pos
,
source
.
As
<
Napi
::
Number
>
().
DoubleValue
());
if
(
OtherIsInt
(
source
.
As
<
Napi
::
Number
>
()))
{
return
new
Values
::
Integer
(
pos
,
source
.
As
<
Napi
::
Number
>
().
Int32Value
());
}
else
{
return
new
Values
::
Float
(
pos
,
source
.
As
<
Napi
::
Number
>
().
DoubleValue
());
}
}
else
if
(
source
->
IsBoolean
())
{
else
if
(
source
.
IsBoolean
())
{
return
new
Values
::
Integer
(
pos
,
source
.
As
<
Napi
::
Boolean
>
().
Value
()
?
1
:
0
);
}
else
if
(
source
->
IsNull
())
{
else
if
(
source
.
IsNull
())
{
return
new
Values
::
Null
(
pos
);
}
else
if
(
source
.
IsBuffer
())
{
Napi
::
Object
buffer
=
source
.
To
<
Napi
::
Object
>
();
return
new
Values
::
Blob
(
pos
,
Buffer
::
Length
(
buffer
),
Buffer
::
Data
(
buffer
));
Napi
::
Buffer
<
char
>
buffer
=
source
.
As
<
Napi
::
Buffer
<
char
>
>
();
return
new
Values
::
Blob
(
pos
,
buffer
.
Length
(),
buffer
.
Data
(
));
}
else
if
(
source
->
IsDate
())
{
return
new
Values
::
Float
(
pos
,
source
.
As
<
Napi
::
Number
>
().
DoubleValue
());
else
if
(
OtherInstanceOf
(
source
.
As
<
Object
>
(),
"Date"
))
{
return
new
Values
::
Float
(
pos
,
source
.
ToNumber
().
DoubleValue
());
}
else
if
(
source
.
IsObject
())
{
std
::
string
val
=
source
.
ToString
().
Utf8Value
();
return
new
Values
::
Text
(
pos
,
val
.
length
(),
val
.
c_str
());
}
else
{
return
NULL
;
...
...
@@ -201,11 +230,12 @@ template <class T> Values::Field*
}
template
<
class
T
>
T
*
Statement
::
Bind
(
const
Napi
::
CallbackInfo
&
info
,
int
start
,
int
last
)
{
Napi
::
Env
env
=
info
.
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
last
<
0
)
last
=
info
.
Length
();
Napi
::
Function
callback
;
if
(
last
>
start
&&
info
[
last
-
1
]
->
IsFunction
())
{
if
(
last
>
start
&&
info
[
last
-
1
]
.
IsFunction
())
{
callback
=
info
[
last
-
1
].
As
<
Napi
::
Function
>
();
last
--
;
}
...
...
@@ -215,13 +245,13 @@ template <class T> T* Statement::Bind(const Napi::CallbackInfo& info, int start,
if
(
start
<
last
)
{
if
(
info
[
start
].
IsArray
())
{
Napi
::
Array
array
=
info
[
start
].
As
<
Napi
::
Array
>
();
int
length
=
array
->
Length
();
int
length
=
array
.
Length
();
// Note: bind parameters start with 1.
for
(
int
i
=
0
,
pos
=
1
;
i
<
length
;
i
++
,
pos
++
)
{
baton
->
parameters
.
push_back
(
BindParameter
((
array
).
Get
(
i
),
pos
));
}
}
else
if
(
!
info
[
start
].
IsObject
()
||
info
[
start
].
IsRegExp
()
||
info
[
start
].
IsDate
(
)
||
info
[
start
].
IsBuffer
())
{
else
if
(
!
info
[
start
].
IsObject
()
||
OtherInstanceOf
(
info
[
start
].
As
<
Object
>
(),
"RegExp"
)
||
OtherInstanceOf
(
info
[
start
].
As
<
Object
>
(),
"Date"
)
||
info
[
start
].
IsBuffer
())
{
// Parameters directly in array.
// Note: bind parameters start with 1.
for
(
int
i
=
start
,
pos
=
1
;
i
<
last
;
i
++
,
pos
++
)
{
...
...
@@ -230,8 +260,8 @@ template <class T> T* Statement::Bind(const Napi::CallbackInfo& info, int start,
}
else
if
(
info
[
start
].
IsObject
())
{
Napi
::
Object
object
=
info
[
start
].
As
<
Napi
::
Object
>
();
Napi
::
Array
array
=
Napi
::
GetPropertyNames
(
object
);
int
length
=
array
->
Length
();
Napi
::
Array
array
=
object
.
GetPropertyNames
(
);
int
length
=
array
.
Length
();
for
(
int
i
=
0
;
i
<
length
;
i
++
)
{
Napi
::
Value
name
=
(
array
).
Get
(
i
);
...
...
@@ -241,7 +271,7 @@ template <class T> T* Statement::Bind(const Napi::CallbackInfo& info, int start,
}
else
{
baton
->
parameters
.
push_back
(
BindParameter
((
object
).
Get
(
name
),
name
->
As
<
Napi
::
String
>
().
Utf8Value
().
c_str
()));
name
.
As
<
Napi
::
String
>
().
Utf8Value
().
c_str
()));
}
}
}
...
...
@@ -268,7 +298,7 @@ bool Statement::Bind(const Parameters & parameters) {
Values
::
Field
*
field
=
*
it
;
if
(
field
!=
NULL
)
{
int
pos
;
unsigned
int
pos
;
if
(
field
->
index
>
0
)
{
pos
=
field
->
index
;
}
...
...
@@ -311,6 +341,7 @@ bool Statement::Bind(const Parameters & parameters) {
}
Napi
::
Value
Statement
::
Bind
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
info
.
Env
();
Statement
*
stmt
=
this
;
Baton
*
baton
=
stmt
->
Bind
<
Baton
>
(
info
);
...
...
@@ -338,19 +369,20 @@ void Statement::Work_Bind(uv_work_t* req) {
}
void
Statement
::
Work_AfterBind
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
STATEMENT_INIT
(
Baton
);
Napi
::
Env
env
=
stmt
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
stmt
->
status
!=
SQLITE_OK
)
{
Error
(
baton
);
}
else
{
// Fire callbacks.
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
env
.
Null
()
};
TRY_CATCH_CALL
(
stmt
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
stmt
->
Valu
e
(),
cb
,
1
,
argv
);
}
}
...
...
@@ -360,6 +392,7 @@ void Statement::Work_AfterBind(uv_work_t* req) {
Napi
::
Value
Statement
::
Get
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
info
.
Env
();
Statement
*
stmt
=
this
;
Baton
*
baton
=
stmt
->
Bind
<
RowBaton
>
(
info
);
...
...
@@ -402,25 +435,26 @@ void Statement::Work_Get(uv_work_t* req) {
}
void
Statement
::
Work_AfterGet
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
STATEMENT_INIT
(
RowBaton
);
Napi
::
Env
env
=
stmt
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
stmt
->
status
!=
SQLITE_ROW
&&
stmt
->
status
!=
SQLITE_DONE
)
{
Error
(
baton
);
}
else
{
// Fire callbacks.
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
if
(
stmt
->
status
==
SQLITE_ROW
)
{
// Create the result array from the data we acquired.
Napi
::
Value
argv
[]
=
{
env
.
Null
(),
RowToJS
(
&
baton
->
row
)
};
TRY_CATCH_CALL
(
stmt
->
handl
e
(),
cb
,
2
,
argv
);
Napi
::
Value
argv
[]
=
{
env
.
Null
(),
RowToJS
(
env
,
&
baton
->
row
)
};
TRY_CATCH_CALL
(
stmt
->
Valu
e
(),
cb
,
2
,
argv
);
}
else
{
Napi
::
Value
argv
[]
=
{
env
.
Null
()
};
TRY_CATCH_CALL
(
stmt
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
stmt
->
Valu
e
(),
cb
,
1
,
argv
);
}
}
}
...
...
@@ -429,6 +463,7 @@ void Statement::Work_AfterGet(uv_work_t* req) {
}
Napi
::
Value
Statement
::
Run
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
info
.
Env
();
Statement
*
stmt
=
this
;
Baton
*
baton
=
stmt
->
Bind
<
RunBaton
>
(
info
);
...
...
@@ -473,22 +508,23 @@ void Statement::Work_Run(uv_work_t* req) {
}
void
Statement
::
Work_AfterRun
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
STATEMENT_INIT
(
RunBaton
);
Napi
::
Env
env
=
stmt
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
stmt
->
status
!=
SQLITE_ROW
&&
stmt
->
status
!=
SQLITE_DONE
)
{
Error
(
baton
);
}
else
{
// Fire callbacks.
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
(
stmt
->
handl
e
()).
Set
(
Napi
::
String
::
New
(
env
,
"lastID"
),
Napi
::
Number
::
New
(
env
,
baton
->
inserted_id
));
(
stmt
->
handle
()).
Set
(
Napi
::
String
::
New
(
env
,
"changes"
),
Napi
::
New
(
env
,
baton
->
changes
));
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
(
stmt
->
Valu
e
()).
Set
(
Napi
::
String
::
New
(
env
,
"lastID"
),
Napi
::
Number
::
New
(
env
,
baton
->
inserted_id
));
(
stmt
->
Value
()).
Set
(
Napi
::
String
::
New
(
env
,
"changes"
),
Napi
::
Number
::
New
(
env
,
baton
->
changes
));
Napi
::
Value
argv
[]
=
{
env
.
Null
()
};
TRY_CATCH_CALL
(
stmt
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
stmt
->
Valu
e
(),
cb
,
1
,
argv
);
}
}
...
...
@@ -496,6 +532,7 @@ void Statement::Work_AfterRun(uv_work_t* req) {
}
Napi
::
Value
Statement
::
All
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
info
.
Env
();
Statement
*
stmt
=
this
;
Baton
*
baton
=
stmt
->
Bind
<
RowsBaton
>
(
info
);
...
...
@@ -540,29 +577,30 @@ void Statement::Work_All(uv_work_t* req) {
}
void
Statement
::
Work_AfterAll
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
STATEMENT_INIT
(
RowsBaton
);
Napi
::
Env
env
=
stmt
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
stmt
->
status
!=
SQLITE_DONE
)
{
Error
(
baton
);
}
else
{
// Fire callbacks.
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
if
(
baton
->
rows
.
size
())
{
// Create the result array from the data we acquired.
Napi
::
Array
result
(
Napi
::
Array
::
New
(
env
,
baton
->
rows
.
size
()));
Rows
::
const_iterator
it
=
baton
->
rows
.
begin
();
Rows
::
const_iterator
end
=
baton
->
rows
.
end
();
for
(
int
i
=
0
;
it
<
end
;
++
it
,
i
++
)
{
(
result
).
Set
(
i
,
RowToJS
(
*
it
));
(
result
).
Set
(
i
,
RowToJS
(
env
,
*
it
));
delete
*
it
;
}
Napi
::
Value
argv
[]
=
{
env
.
Null
(),
result
};
TRY_CATCH_CALL
(
stmt
->
handl
e
(),
cb
,
2
,
argv
);
TRY_CATCH_CALL
(
stmt
->
Valu
e
(),
cb
,
2
,
argv
);
}
else
{
// There were no result rows.
...
...
@@ -570,7 +608,7 @@ void Statement::Work_AfterAll(uv_work_t* req) {
env
.
Null
(),
Napi
::
Array
::
New
(
env
,
0
)
};
TRY_CATCH_CALL
(
stmt
->
handl
e
(),
cb
,
2
,
argv
);
TRY_CATCH_CALL
(
stmt
->
Valu
e
(),
cb
,
2
,
argv
);
}
}
}
...
...
@@ -579,12 +617,13 @@ void Statement::Work_AfterAll(uv_work_t* req) {
}
Napi
::
Value
Statement
::
Each
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
info
.
Env
();
Statement
*
stmt
=
this
;
int
last
=
info
.
Length
();
Napi
::
Function
completed
;
if
(
last
>=
2
&&
info
[
last
-
1
]
->
IsFunction
()
&&
info
[
last
-
2
]
->
IsFunction
())
{
if
(
last
>=
2
&&
info
[
last
-
1
]
.
IsFunction
()
&&
info
[
last
-
2
].
IsFunction
())
{
completed
=
info
[
--
last
].
As
<
Napi
::
Function
>
();
}
...
...
@@ -605,8 +644,8 @@ void Statement::Work_BeginEach(Baton* baton) {
// the event loop. This prevents dangling events.
EachBaton
*
each_baton
=
static_cast
<
EachBaton
*>
(
baton
);
each_baton
->
async
=
new
Async
(
each_baton
->
stmt
,
reinterpret_cast
<
uv_async_cb
>
(
AsyncEach
));
each_baton
->
async
->
item_cb
.
Reset
(
each_baton
->
callback
);
each_baton
->
async
->
completed_cb
.
Reset
(
each_baton
->
completed
);
each_baton
->
async
->
item_cb
.
Reset
(
each_baton
->
callback
.
Value
(),
1
);
each_baton
->
async
->
completed_cb
.
Reset
(
each_baton
->
completed
.
Value
(),
1
);
STATEMENT_BEGIN
(
Each
);
}
...
...
@@ -662,10 +701,11 @@ void Statement::CloseCallback(uv_handle_t* handle) {
}
void
Statement
::
AsyncEach
(
uv_async_t
*
handle
,
int
status
)
{
Napi
::
HandleScope
scope
(
env
);
Async
*
async
=
static_cast
<
Async
*>
(
handle
->
data
);
Napi
::
Env
env
=
async
->
stmt
->
Env
();
Napi
::
HandleScope
scope
(
env
);
while
(
true
)
{
// Get the contents out of the data cache for us to process in the JS callback.
Rows
rows
;
...
...
@@ -677,41 +717,42 @@ void Statement::AsyncEach(uv_async_t* handle, int status) {
break
;
}
Napi
::
Function
cb
=
Napi
::
New
(
env
,
async
->
item_cb
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
Napi
::
Function
cb
=
async
->
item_cb
.
Value
(
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[
2
];
argv
[
0
]
=
env
.
Null
();
Rows
::
const_iterator
it
=
rows
.
begin
();
Rows
::
const_iterator
end
=
rows
.
end
();
for
(
int
i
=
0
;
it
<
end
;
++
it
,
i
++
)
{
argv
[
1
]
=
RowToJS
(
*
it
);
argv
[
1
]
=
RowToJS
(
env
,
*
it
);
async
->
retrieved
++
;
TRY_CATCH_CALL
(
async
->
stmt
->
handl
e
(),
cb
,
2
,
argv
);
TRY_CATCH_CALL
(
async
->
stmt
->
Valu
e
(),
cb
,
2
,
argv
);
delete
*
it
;
}
}
}
Napi
::
Function
cb
=
Napi
::
New
(
env
,
async
->
completed_cb
);
Napi
::
Function
cb
=
async
->
completed_cb
.
Value
(
);
if
(
async
->
completed
)
{
if
(
!
cb
.
IsEmpty
()
&&
cb
->
IsFunction
())
{
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
env
.
Null
(),
Napi
::
New
(
env
,
async
->
retrieved
)
Napi
::
N
umber
::
N
ew
(
env
,
async
->
retrieved
)
};
TRY_CATCH_CALL
(
async
->
stmt
->
handl
e
(),
cb
,
2
,
argv
);
TRY_CATCH_CALL
(
async
->
stmt
->
Valu
e
(),
cb
,
2
,
argv
);
}
uv_close
(
reinterpret_cast
<
uv_handle_t
*>
(
handle
),
CloseCallback
);
}
}
void
Statement
::
Work_AfterEach
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
STATEMENT_INIT
(
EachBaton
);
Napi
::
Env
env
=
stmt
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
stmt
->
status
!=
SQLITE_DONE
)
{
Error
(
baton
);
}
...
...
@@ -720,6 +761,7 @@ void Statement::Work_AfterEach(uv_work_t* req) {
}
Napi
::
Value
Statement
::
Reset
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
info
.
Env
();
Statement
*
stmt
=
this
;
OPTIONAL_ARGUMENT_FUNCTION
(
0
,
callback
);
...
...
@@ -742,21 +784,22 @@ void Statement::Work_Reset(uv_work_t* req) {
}
void
Statement
::
Work_AfterReset
(
uv_work_t
*
req
)
{
Napi
::
HandleScope
scope
(
env
);
STATEMENT_INIT
(
Baton
);
Napi
::
Env
env
=
stmt
->
Env
();
Napi
::
HandleScope
scope
(
env
);
// Fire callbacks.
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
Napi
::
Value
argv
[]
=
{
env
.
Null
()
};
TRY_CATCH_CALL
(
stmt
->
handl
e
(),
cb
,
1
,
argv
);
TRY_CATCH_CALL
(
stmt
->
Valu
e
(),
cb
,
1
,
argv
);
}
STATEMENT_END
();
}
Napi
::
Object
Statement
::
RowToJS
(
Row
*
row
)
{
Napi
::
Value
Statement
::
RowToJS
(
Napi
::
Env
env
,
Row
*
row
)
{
Napi
::
EscapableHandleScope
scope
(
env
);
Napi
::
Object
result
=
Napi
::
Object
::
New
(
env
);
...
...
@@ -779,14 +822,14 @@ Napi::Object Statement::RowToJS(Row* row) {
value
=
Napi
::
String
::
New
(
env
,
((
Values
::
Text
*
)
field
)
->
value
.
c_str
(),
((
Values
::
Text
*
)
field
)
->
value
.
size
());
}
break
;
case
SQLITE_BLOB
:
{
value
=
Napi
::
Buffer
::
Copy
(
env
,
((
Values
::
Blob
*
)
field
)
->
value
,
((
Values
::
Blob
*
)
field
)
->
length
);
value
=
Napi
::
Buffer
<
char
>
::
Copy
(
env
,
((
Values
::
Blob
*
)
field
)
->
value
,
((
Values
::
Blob
*
)
field
)
->
length
);
}
break
;
case
SQLITE_NULL
:
{
value
=
env
.
Null
();
}
break
;
}
(
result
).
Set
(
Napi
::
New
(
env
,
field
->
name
.
c_str
()),
value
);
(
result
).
Set
(
Napi
::
String
::
New
(
env
,
field
->
name
.
c_str
()),
value
);
DELETE_FIELD
(
field
);
}
...
...
@@ -826,31 +869,33 @@ void Statement::GetRow(Row* row, sqlite3_stmt* stmt) {
}
}
Napi
::
Value
Statement
::
Finalize
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Value
Statement
::
Finalize_
(
const
Napi
::
CallbackInfo
&
info
)
{
Napi
::
Env
env
=
info
.
Env
();
Statement
*
stmt
=
this
;
OPTIONAL_ARGUMENT_FUNCTION
(
0
,
callback
);
Baton
*
baton
=
new
Baton
(
stmt
,
callback
);
stmt
->
Schedule
(
Finalize
,
baton
);
stmt
->
Schedule
(
Finalize
_
,
baton
);
return
stmt
->
db
->
handl
e
();
return
stmt
->
db
->
Valu
e
();
}
void
Statement
::
Finalize
(
Baton
*
baton
)
{
void
Statement
::
Finalize_
(
Baton
*
baton
)
{
Napi
::
Env
env
=
baton
->
stmt
->
Env
();
Napi
::
HandleScope
scope
(
env
);
baton
->
stmt
->
Finalize
();
baton
->
stmt
->
Finalize
_
();
// Fire callback in case there was one.
Napi
::
Function
cb
=
Napi
::
New
(
env
,
baton
->
callback
);
if
(
!
cb
.
Is
Empty
()
&&
cb
->
IsFunction
())
{
TRY_CATCH_CALL
(
baton
->
stmt
->
handl
e
(),
cb
,
0
,
NULL
);
Napi
::
Function
cb
=
baton
->
callback
.
Value
(
);
if
(
!
cb
.
Is
Undefined
()
&&
cb
.
IsFunction
())
{
TRY_CATCH_CALL
(
baton
->
stmt
->
Valu
e
(),
cb
,
0
,
NULL
);
}
delete
baton
;
}
void
Statement
::
Finalize
()
{
void
Statement
::
Finalize
_
()
{
assert
(
!
finalized
);
finalized
=
true
;
CleanQueue
();
...
...
@@ -862,12 +907,13 @@ void Statement::Finalize() {
}
void
Statement
::
CleanQueue
()
{
Napi
::
Env
env
=
this
->
Env
();
Napi
::
HandleScope
scope
(
env
);
if
(
prepared
&&
!
queue
.
empty
())
{
// This statement has already been prepared and is now finalized.
// Fire error for all remaining items in the queue.
EXCEPTION
(
"Statement is already finalized"
,
SQLITE_MISUSE
,
exception
);
EXCEPTION
(
Napi
::
String
::
New
(
env
,
"Statement is already finalized"
)
,
SQLITE_MISUSE
,
exception
);
Napi
::
Value
argv
[]
=
{
exception
};
bool
called
=
false
;
...
...
@@ -876,11 +922,11 @@ void Statement::CleanQueue() {
Call
*
call
=
queue
.
front
();
queue
.
pop
();
Napi
::
Function
cb
=
Napi
::
New
(
env
,
call
->
baton
->
callback
);
Napi
::
Function
cb
=
call
->
baton
->
callback
.
Value
(
);
if
(
prepared
&&
!
cb
.
IsEmpty
()
&&
cb
->
IsFunction
())
{
TRY_CATCH_CALL
(
handl
e
(),
cb
,
1
,
argv
);
cb
.
IsFunction
())
{
TRY_CATCH_CALL
(
Valu
e
(),
cb
,
1
,
argv
);
called
=
true
;
}
...
...
@@ -894,7 +940,7 @@ void Statement::CleanQueue() {
// Statement object.
if
(
!
called
)
{
Napi
::
Value
info
[]
=
{
Napi
::
String
::
New
(
env
,
"error"
),
exception
};
EMIT_EVENT
(
handl
e
(),
2
,
info
);
EMIT_EVENT
(
Valu
e
(),
2
,
info
);
}
}
else
while
(
!
queue
.
empty
())
{
...
...
src/statement.h
View file @
dd3ef522
...
...
@@ -16,7 +16,6 @@
#include <uv.h>
using
namespace
Napi
;
using
namespace
Napi
;
namespace
node_sqlite3
{
...
...
@@ -144,7 +143,7 @@ public:
if
(
!
db
->
IsOpen
()
&&
db
->
IsLocked
())
{
// The database handle was closed before the statement could be
// prepared.
stmt
->
Finalize
();
stmt
->
Finalize
_
();
}
}
};
...
...
@@ -186,18 +185,20 @@ public:
}
};
Statement
(
Database
*
db_
)
:
Napi
::
ObjectWrap
<
Statement
>
(),
db
(
db_
),
_handle
(
NULL
),
status
(
SQLITE_OK
),
prepared
(
false
),
locked
(
true
),
finalized
(
false
)
{
void
init
(
Database
*
db_
)
{
db
=
db_
;
_handle
=
NULL
;
status
=
SQLITE_OK
;
prepared
=
false
;
locked
=
true
;
finalized
=
false
;
db
->
Ref
();
}
Statement
(
const
Napi
::
CallbackInfo
&
info
);
~
Statement
()
{
if
(
!
finalized
)
Finalize
();
if
(
!
finalized
)
Finalize
_
();
}
WORK_DEFINITION
(
Bind
);
...
...
@@ -207,7 +208,7 @@ public:
WORK_DEFINITION
(
Each
);
WORK_DEFINITION
(
Reset
);
static
Napi
::
Value
Finalize
(
const
Napi
::
CallbackInfo
&
info
);
Napi
::
Value
Finalize_
(
const
Napi
::
CallbackInfo
&
info
);
protected
:
static
void
Work_BeginPrepare
(
Database
::
Baton
*
baton
);
...
...
@@ -217,15 +218,15 @@ protected:
static
void
AsyncEach
(
uv_async_t
*
handle
,
int
status
);
static
void
CloseCallback
(
uv_handle_t
*
handle
);
static
void
Finalize
(
Baton
*
baton
);
void
Finalize
();
static
void
Finalize
_
(
Baton
*
baton
);
void
Finalize
_
();
template
<
class
T
>
inline
Values
::
Field
*
BindParameter
(
const
Napi
::
Value
source
,
T
pos
);
template
<
class
T
>
T
*
Bind
(
const
Napi
::
CallbackInfo
&
info
,
int
start
=
0
,
int
end
=
-
1
);
bool
Bind
(
const
Parameters
&
parameters
);
static
void
GetRow
(
Row
*
row
,
sqlite3_stmt
*
stmt
);
static
Napi
::
Object
RowToJS
(
Row
*
row
);
static
Napi
::
Value
RowToJS
(
Napi
::
Env
env
,
Row
*
row
);
void
Schedule
(
Work_Callback
callback
,
Baton
*
baton
);
void
Process
();
void
CleanQueue
();
...
...
test/database_fail.test.js
View file @
dd3ef522
...
...
@@ -10,11 +10,11 @@ describe('error handling', function() {
it
(
'throw when calling Database() without new'
,
function
()
{
assert
.
throws
(
function
()
{
sqlite3
.
Database
(
':memory:'
);
},
(
/
Use the new operator to create new Database objects
/
));
},
(
/
Class constructors cannot be invoked without 'new'
/
));
assert
.
throws
(
function
()
{
sqlite3
.
Statement
();
},
(
/
Use the new operator to create new Statement objects
/
));
},
(
/
Class constructors cannot be invoked without 'new'
/
));
});
it
(
'should error when calling Database#get on a missing table'
,
function
(
done
)
{
...
...
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