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
0668424b
Commit
0668424b
authored
Feb 18, 2011
by
Konstantin Käfer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
destroy statement objects as soon as we can
parent
1888eea2
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
212 additions
and
127 deletions
+212
-127
database.cc
src/database.cc
+22
-23
database.h
src/database.h
+2
-3
statement.cc
src/statement.cc
+129
-77
statement.h
src/statement.h
+58
-23
blob.test.js
test/blob.test.js
+1
-1
No files found.
src/database.cc
View file @
0668424b
...
@@ -44,20 +44,22 @@ void Database::Init(v8::Handle<Object> target) {
...
@@ -44,20 +44,22 @@ void Database::Init(v8::Handle<Object> target) {
constructor_template
->
GetFunction
());
constructor_template
->
GetFunction
());
}
}
void
Database
::
Process
(
Database
*
db
)
{
void
Database
::
Process
()
{
if
(
!
db
->
open
&&
db
->
locked
&&
!
db
->
queue
.
empty
())
{
if
(
!
open
&&
locked
&&
!
queue
.
empty
())
{
EXCEPTION
(
String
::
New
(
"Database handle is closed"
),
SQLITE_MISUSE
,
exception
);
EXCEPTION
(
String
::
New
(
"Database handle is closed"
),
SQLITE_MISUSE
,
exception
);
Local
<
Value
>
argv
[]
=
{
exception
};
Local
<
Value
>
argv
[]
=
{
exception
};
bool
called
=
false
;
bool
called
=
false
;
// Call all callbacks with the error object.
// Call all callbacks with the error object.
while
(
!
db
->
queue
.
empty
())
{
while
(
!
queue
.
empty
())
{
Call
*
call
=
db
->
queue
.
front
();
Call
*
call
=
queue
.
front
();
if
(
!
call
->
baton
->
callback
.
IsEmpty
())
{
if
(
!
call
->
baton
->
callback
.
IsEmpty
())
{
TRY_CATCH_CALL
(
db
->
handle_
,
call
->
baton
->
callback
,
1
,
argv
);
TRY_CATCH_CALL
(
handle_
,
call
->
baton
->
callback
,
1
,
argv
);
called
=
true
;
called
=
true
;
}
}
db
->
queue
.
pop
();
queue
.
pop
();
// We don't call the actual callback, so we have to make sure that
// the baton gets destroyed.
delete
call
->
baton
;
delete
call
->
baton
;
delete
call
;
delete
call
;
}
}
...
@@ -66,41 +68,40 @@ void Database::Process(Database* db) {
...
@@ -66,41 +68,40 @@ void Database::Process(Database* db) {
// Database object.
// Database object.
if
(
!
called
)
{
if
(
!
called
)
{
Local
<
Value
>
args
[]
=
{
String
::
NewSymbol
(
"error"
),
exception
};
Local
<
Value
>
args
[]
=
{
String
::
NewSymbol
(
"error"
),
exception
};
EMIT_EVENT
(
db
->
handle_
,
2
,
args
);
EMIT_EVENT
(
handle_
,
2
,
args
);
}
}
return
;
return
;
}
}
while
(
db
->
open
&&
!
db
->
locked
&&
!
db
->
queue
.
empty
())
{
while
(
open
&&
!
locked
&&
!
queue
.
empty
())
{
Call
*
call
=
db
->
queue
.
front
();
Call
*
call
=
queue
.
front
();
if
(
call
->
exclusive
&&
db
->
pending
>
0
)
{
if
(
call
->
exclusive
&&
pending
>
0
)
{
break
;
break
;
}
}
call
->
callback
(
call
->
baton
);
call
->
callback
(
call
->
baton
);
db
->
queue
.
pop
();
queue
.
pop
();
delete
call
;
delete
call
;
}
}
}
}
inline
void
Database
::
Schedule
(
Database
*
db
,
EIO_Callback
callback
,
Baton
*
baton
,
void
Database
::
Schedule
(
EIO_Callback
callback
,
Baton
*
baton
,
bool
exclusive
=
false
)
{
bool
exclusive
=
false
)
{
if
(
!
open
&&
locked
)
{
if
(
!
db
->
open
&&
db
->
locked
)
{
EXCEPTION
(
String
::
New
(
"Database is closed"
),
SQLITE_MISUSE
,
exception
);
EXCEPTION
(
String
::
New
(
"Database is closed"
),
SQLITE_MISUSE
,
exception
);
if
(
!
baton
->
callback
.
IsEmpty
())
{
if
(
!
baton
->
callback
.
IsEmpty
())
{
Local
<
Value
>
argv
[]
=
{
exception
};
Local
<
Value
>
argv
[]
=
{
exception
};
TRY_CATCH_CALL
(
db
->
handle_
,
baton
->
callback
,
1
,
argv
);
TRY_CATCH_CALL
(
handle_
,
baton
->
callback
,
1
,
argv
);
}
}
else
{
else
{
Local
<
Value
>
argv
[]
=
{
String
::
NewSymbol
(
"error"
),
exception
};
Local
<
Value
>
argv
[]
=
{
String
::
NewSymbol
(
"error"
),
exception
};
EMIT_EVENT
(
db
->
handle_
,
2
,
argv
);
EMIT_EVENT
(
handle_
,
2
,
argv
);
}
}
return
;
return
;
}
}
if
(
!
db
->
open
||
db
->
locked
||
(
exclusive
&&
db
->
pending
>
0
))
{
if
(
!
open
||
locked
||
(
exclusive
&&
pending
>
0
))
{
db
->
queue
.
push
(
new
Call
(
callback
,
baton
,
exclusive
));
queue
.
push
(
new
Call
(
callback
,
baton
,
exclusive
));
}
}
else
{
else
{
callback
(
baton
);
callback
(
baton
);
...
@@ -193,11 +194,10 @@ int Database::EIO_AfterOpen(eio_req *req) {
...
@@ -193,11 +194,10 @@ int Database::EIO_AfterOpen(eio_req *req) {
if
(
db
->
open
)
{
if
(
db
->
open
)
{
Local
<
Value
>
args
[]
=
{
String
::
NewSymbol
(
"open"
)
};
Local
<
Value
>
args
[]
=
{
String
::
NewSymbol
(
"open"
)
};
EMIT_EVENT
(
db
->
handle_
,
1
,
args
);
EMIT_EVENT
(
db
->
handle_
,
1
,
args
);
Process
(
db
);
db
->
Process
(
);
}
}
delete
baton
;
delete
baton
;
return
0
;
return
0
;
}
}
...
@@ -207,7 +207,7 @@ Handle<Value> Database::Close(const Arguments& args) {
...
@@ -207,7 +207,7 @@ Handle<Value> Database::Close(const Arguments& args) {
OPTIONAL_ARGUMENT_FUNCTION
(
0
,
callback
);
OPTIONAL_ARGUMENT_FUNCTION
(
0
,
callback
);
Baton
*
baton
=
new
Baton
(
db
,
callback
);
Baton
*
baton
=
new
Baton
(
db
,
callback
);
Schedule
(
db
,
EIO_BeginClose
,
baton
,
true
);
db
->
Schedule
(
EIO_BeginClose
,
baton
,
true
);
return
args
.
This
();
return
args
.
This
();
}
}
...
@@ -264,11 +264,10 @@ int Database::EIO_AfterClose(eio_req *req) {
...
@@ -264,11 +264,10 @@ int Database::EIO_AfterClose(eio_req *req) {
if
(
!
db
->
open
)
{
if
(
!
db
->
open
)
{
Local
<
Value
>
args
[]
=
{
String
::
NewSymbol
(
"close"
),
argv
[
0
]
};
Local
<
Value
>
args
[]
=
{
String
::
NewSymbol
(
"close"
),
argv
[
0
]
};
EMIT_EVENT
(
db
->
handle_
,
1
,
args
);
EMIT_EVENT
(
db
->
handle_
,
1
,
args
);
Process
(
db
);
db
->
Process
(
);
}
}
delete
baton
;
delete
baton
;
return
0
;
return
0
;
}
}
...
...
src/database.h
View file @
0668424b
...
@@ -97,9 +97,8 @@ protected:
...
@@ -97,9 +97,8 @@ protected:
static
int
EIO_Open
(
eio_req
*
req
);
static
int
EIO_Open
(
eio_req
*
req
);
static
int
EIO_AfterOpen
(
eio_req
*
req
);
static
int
EIO_AfterOpen
(
eio_req
*
req
);
static
void
Schedule
(
Database
*
db
,
EIO_Callback
callback
,
Baton
*
baton
,
void
Schedule
(
EIO_Callback
callback
,
Baton
*
baton
,
bool
exclusive
);
bool
exclusive
);
void
Process
();
static
void
Process
(
Database
*
db
);
static
Handle
<
Value
>
Close
(
const
Arguments
&
args
);
static
Handle
<
Value
>
Close
(
const
Arguments
&
args
);
static
void
EIO_BeginClose
(
Baton
*
baton
);
static
void
EIO_BeginClose
(
Baton
*
baton
);
...
...
src/statement.cc
View file @
0668424b
...
@@ -34,10 +34,39 @@ void Statement::Init(v8::Handle<Object> target) {
...
@@ -34,10 +34,39 @@ void Statement::Init(v8::Handle<Object> target) {
constructor_template
->
InstanceTemplate
()
->
SetInternalFieldCount
(
1
);
constructor_template
->
InstanceTemplate
()
->
SetInternalFieldCount
(
1
);
constructor_template
->
SetClassName
(
String
::
NewSymbol
(
"Statement"
));
constructor_template
->
SetClassName
(
String
::
NewSymbol
(
"Statement"
));
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"finalize"
,
Finalize
);
target
->
Set
(
v8
::
String
::
NewSymbol
(
"Statement"
),
target
->
Set
(
v8
::
String
::
NewSymbol
(
"Statement"
),
constructor_template
->
GetFunction
());
constructor_template
->
GetFunction
());
}
}
void
Statement
::
Process
()
{
if
(
finalized
&&
!
queue
.
empty
())
{
return
CleanQueue
();
}
while
(
prepared
&&
!
locked
&&
!
queue
.
empty
())
{
Call
*
call
=
queue
.
front
();
queue
.
pop
();
call
->
callback
(
call
->
baton
);
delete
call
;
}
}
void
Statement
::
Schedule
(
EIO_Callback
callback
,
Baton
*
baton
)
{
if
(
finalized
)
{
queue
.
push
(
new
Call
(
callback
,
baton
));
CleanQueue
();
}
else
if
(
!
prepared
||
locked
)
{
queue
.
push
(
new
Call
(
callback
,
baton
));
}
else
{
callback
(
baton
);
}
}
// { Database db, String sql, Array params, Function callback }
// { Database db, String sql, Array params, Function callback }
Handle
<
Value
>
Statement
::
New
(
const
Arguments
&
args
)
{
Handle
<
Value
>
Statement
::
New
(
const
Arguments
&
args
)
{
HandleScope
scope
;
HandleScope
scope
;
...
@@ -85,10 +114,9 @@ Handle<Value> Statement::New(const Arguments& args) {
...
@@ -85,10 +114,9 @@ Handle<Value> Statement::New(const Arguments& args) {
Statement
*
stmt
=
new
Statement
(
db
);
Statement
*
stmt
=
new
Statement
(
db
);
stmt
->
Wrap
(
args
.
This
());
stmt
->
Wrap
(
args
.
This
());
PrepareBaton
*
baton
=
new
PrepareBaton
(
db
,
Local
<
Function
>::
Cast
(
args
[
3
]));
PrepareBaton
*
baton
=
new
PrepareBaton
(
db
,
Local
<
Function
>::
Cast
(
args
[
3
]),
stmt
);
baton
->
stmt
=
stmt
;
baton
->
sql
=
std
::
string
(
*
String
::
Utf8Value
(
sql
));
baton
->
sql
=
std
::
string
(
*
String
::
Utf8Value
(
sql
));
Database
::
Schedule
(
db
,
EIO_BeginPrepare
,
baton
,
false
);
db
->
Schedule
(
EIO_BeginPrepare
,
baton
,
false
);
return
args
.
This
();
return
args
.
This
();
}
}
...
@@ -97,8 +125,6 @@ Handle<Value> Statement::New(const Arguments& args) {
...
@@ -97,8 +125,6 @@ Handle<Value> Statement::New(const Arguments& args) {
void
Statement
::
EIO_BeginPrepare
(
Database
::
Baton
*
baton
)
{
void
Statement
::
EIO_BeginPrepare
(
Database
::
Baton
*
baton
)
{
assert
(
baton
->
db
->
open
);
assert
(
baton
->
db
->
open
);
assert
(
!
baton
->
db
->
locked
);
assert
(
!
baton
->
db
->
locked
);
static_cast
<
PrepareBaton
*>
(
baton
)
->
stmt
->
Ref
();
ev_ref
(
EV_DEFAULT_UC
);
fprintf
(
stderr
,
"Prepare started
\n
"
);
fprintf
(
stderr
,
"Prepare started
\n
"
);
eio_custom
(
EIO_Prepare
,
EIO_PRI_DEFAULT
,
EIO_AfterPrepare
,
baton
);
eio_custom
(
EIO_Prepare
,
EIO_PRI_DEFAULT
,
EIO_AfterPrepare
,
baton
);
}
}
...
@@ -108,6 +134,8 @@ int Statement::EIO_Prepare(eio_req *req) {
...
@@ -108,6 +134,8 @@ int Statement::EIO_Prepare(eio_req *req) {
Database
*
db
=
baton
->
db
;
Database
*
db
=
baton
->
db
;
Statement
*
stmt
=
baton
->
stmt
;
Statement
*
stmt
=
baton
->
stmt
;
// In case preparing fails, we use a mutex to make sure we get the associated
// error message.
sqlite3_mutex
*
mtx
=
sqlite3_db_mutex
(
db
->
handle
);
sqlite3_mutex
*
mtx
=
sqlite3_db_mutex
(
db
->
handle
);
sqlite3_mutex_enter
(
mtx
);
sqlite3_mutex_enter
(
mtx
);
...
@@ -135,94 +163,118 @@ int Statement::EIO_AfterPrepare(eio_req *req) {
...
@@ -135,94 +163,118 @@ int Statement::EIO_AfterPrepare(eio_req *req) {
Database
*
db
=
baton
->
db
;
Database
*
db
=
baton
->
db
;
Statement
*
stmt
=
baton
->
stmt
;
Statement
*
stmt
=
baton
->
stmt
;
stmt
->
Unref
();
Local
<
Value
>
argv
[
1
];
ev_unref
(
EV_DEFAULT_UC
);
if
(
baton
->
status
!=
SQLITE_OK
)
{
EXCEPTION
(
String
::
New
(
baton
->
message
.
c_str
()),
baton
->
status
,
exception
);
argv
[
0
]
=
exception
;
}
else
{
stmt
->
prepared
=
true
;
argv
[
0
]
=
Local
<
Value
>::
New
(
Null
());
}
// Local<Value> argv[1];
// Fire callbacks.
// if (baton->status != SQLITE_OK) {
if
(
!
baton
->
callback
.
IsEmpty
())
{
// EXCEPTION(String::New(baton->message), baton->status, exception);
TRY_CATCH_CALL
(
stmt
->
handle_
,
baton
->
callback
,
1
,
argv
);
// argv[0] = exception;
}
// }
else
{
// else {
Local
<
Value
>
args
[]
=
{
String
::
NewSymbol
(
"error"
),
argv
[
0
]
};
// db->open = false;
EMIT_EVENT
(
stmt
->
handle_
,
2
,
args
);
// // Leave db->locked to indicate that this db object has reached
}
// // the end of its life.
// argv[0] = Local<Value>::New(Null());
// }
//
// // Fire callbacks.
// if (!baton->callback.IsEmpty()) {
// TRY_CATCH_CALL(db->handle_, baton->callback, 1, argv);
// }
// else if (db->open) {
// Local<Value> args[] = { String::NewSymbol("error"), argv[0] };
// EMIT_EVENT(db->handle_, 2, args);
// }
//
// if (!db->open) {
// Local<Value> args[] = { String::NewSymbol("close"), argv[0] };
// EMIT_EVENT(db->handle_, 1, args);
// Process(db);
// }
fprintf
(
stderr
,
"Prepare completed
\n
"
);
db
->
Process
(
);
// V8::AdjustAmountOfExternalAllocatedMemory(10000000);
if
(
stmt
->
prepared
)
{
stmt
->
Process
();
}
else
{
stmt
->
Finalize
();
}
Database
::
Process
(
db
);
delete
baton
;
delete
baton
;
return
0
;
return
0
;
}
}
/**
* Override this so that we can properly finalize the statement when it
* gets garbage collected.
*/
void
Statement
::
Wrap
(
Handle
<
Object
>
handle
)
{
assert
(
handle_
.
IsEmpty
());
assert
(
handle
->
InternalFieldCount
()
>
0
);
handle_
=
Persistent
<
Object
>::
New
(
handle
);
handle_
->
SetPointerInInternalField
(
0
,
this
);
handle_
.
MakeWeak
(
this
,
Destruct
);
}
inline
void
Statement
::
MakeWeak
(
void
)
{
handle_
.
MakeWeak
(
this
,
Destruct
);
}
void
Statement
::
Unref
()
{
Handle
<
Value
>
Statement
::
Finalize
(
const
Arguments
&
args
)
{
assert
(
!
handle_
.
IsEmpty
());
HandleScope
scope
;
assert
(
!
handle_
.
IsWeak
());
Statement
*
stmt
=
ObjectWrap
::
Unwrap
<
Statement
>
(
args
.
This
());
assert
(
refs_
>
0
);
OPTIONAL_ARGUMENT_FUNCTION
(
0
,
callback
);
if
(
--
refs_
==
0
)
{
MakeWeak
();
}
}
void
Statement
::
Destruct
(
Persistent
<
Value
>
value
,
void
*
data
)
{
Baton
*
baton
=
new
Baton
(
stmt
,
callback
);
Statement
*
stmt
=
static_cast
<
Statement
*>
(
data
);
stmt
->
Schedule
(
Finalize
,
baton
);
if
(
stmt
->
handle
)
{
eio_custom
(
EIO_Destruct
,
EIO_PRI_DEFAULT
,
EIO_AfterDestruct
,
stmt
);
return
scope
.
Close
(
stmt
->
db
->
handle_
);
ev_ref
(
EV_DEFAULT_UC
);
}
else
{
delete
stmt
;
}
}
}
int
Statement
::
EIO_Destruct
(
eio_req
*
req
)
{
void
Statement
::
Finalize
(
Baton
*
baton
)
{
Statement
*
stmt
=
static_cast
<
Statement
*>
(
req
->
data
);
baton
->
stmt
->
Finalize
(
);
fprintf
(
stderr
,
"Auto-Finalizing handle
\n
"
);
// Fire callback in case there was one.
sqlite3_finalize
(
stmt
->
handle
);
if
(
!
baton
->
callback
.
IsEmpty
())
{
stmt
->
handle
=
NULL
;
TRY_CATCH_CALL
(
baton
->
stmt
->
handle_
,
baton
->
callback
,
0
,
NULL
);
}
return
0
;
delete
baton
;
}
}
int
Statement
::
EIO_AfterDestruct
(
eio_req
*
req
)
{
void
Statement
::
Finalize
()
{
Statement
*
stmt
=
static_cast
<
Statement
*>
(
req
->
data
);
assert
(
!
finalized
);
ev_unref
(
EV_DEFAULT_UC
);
finalized
=
true
;
delete
stmt
;
fprintf
(
stderr
,
"Statement destruct
\n
"
);
return
0
;
CleanQueue
();
// Finalize returns the status code of the last operation. We already fired
// error events in case those failed.
sqlite3_finalize
(
handle
);
handle
=
NULL
;
db
->
pending
--
;
db
->
Process
();
db
->
Unref
();
}
void
Statement
::
CleanQueue
()
{
if
(
prepared
&&
!
queue
.
empty
())
{
// This statement has already been prepared and is now finalized.
// Fire error for all remaining items in the queue.
EXCEPTION
(
String
::
New
(
"Statement is already finalized"
),
SQLITE_MISUSE
,
exception
);
Local
<
Value
>
argv
[]
=
{
exception
};
bool
called
=
false
;
// Clear out the queue so that this object can get GC'ed.
while
(
!
queue
.
empty
())
{
Call
*
call
=
queue
.
front
();
queue
.
pop
();
if
(
prepared
&&
!
call
->
baton
->
callback
.
IsEmpty
())
{
TRY_CATCH_CALL
(
handle_
,
call
->
baton
->
callback
,
1
,
argv
);
called
=
true
;
}
// We don't call the actual callback, so we have to make sure that
// the baton gets destroyed.
delete
call
->
baton
;
delete
call
;
}
// When we couldn't call a callback function, emit an error on the
// Statement object.
if
(
!
called
)
{
Local
<
Value
>
args
[]
=
{
String
::
NewSymbol
(
"error"
),
exception
};
EMIT_EVENT
(
handle_
,
2
,
args
);
}
}
else
while
(
!
queue
.
empty
())
{
// Just delete all items in the queue; we already fired an event when
// preparing the statement failed.
Call
*
call
=
queue
.
front
();
queue
.
pop
();
// We don't call the actual callback, so we have to make sure that
// the baton gets destroyed.
delete
call
->
baton
;
delete
call
;
}
}
}
src/statement.h
View file @
0668424b
...
@@ -29,16 +29,6 @@
...
@@ -29,16 +29,6 @@
using
namespace
v8
;
using
namespace
v8
;
using
namespace
node
;
using
namespace
node
;
class
Statement
;
static
struct
PrepareBaton
:
Database
::
Baton
{
Statement
*
stmt
;
std
::
string
sql
;
PrepareBaton
(
Database
*
db_
,
Handle
<
Function
>
cb_
)
:
Baton
(
db_
,
cb_
)
{}
};
class
Statement
:
public
EventEmitter
{
class
Statement
:
public
EventEmitter
{
public
:
public
:
static
Persistent
<
FunctionTemplate
>
constructor_template
;
static
Persistent
<
FunctionTemplate
>
constructor_template
;
...
@@ -46,18 +36,56 @@ public:
...
@@ -46,18 +36,56 @@ public:
static
void
Init
(
Handle
<
Object
>
target
);
static
void
Init
(
Handle
<
Object
>
target
);
static
Handle
<
Value
>
New
(
const
Arguments
&
args
);
static
Handle
<
Value
>
New
(
const
Arguments
&
args
);
Statement
(
Database
*
db_
)
:
EventEmitter
()
{
static
struct
Baton
{
db
=
db_
;
Statement
*
stmt
;
Persistent
<
Function
>
callback
;
int
status
;
std
::
string
message
;
Baton
(
Statement
*
stmt_
,
Handle
<
Function
>
cb_
)
:
stmt
(
stmt_
)
{
stmt
->
Ref
();
ev_ref
(
EV_DEFAULT_UC
);
callback
=
Persistent
<
Function
>::
New
(
cb_
);
}
~
Baton
()
{
stmt
->
Unref
();
ev_unref
(
EV_DEFAULT_UC
);
callback
.
Dispose
();
}
};
static
struct
PrepareBaton
:
Database
::
Baton
{
Statement
*
stmt
;
std
::
string
sql
;
PrepareBaton
(
Database
*
db_
,
Handle
<
Function
>
cb_
,
Statement
*
stmt_
)
:
Baton
(
db_
,
cb_
),
stmt
(
stmt_
)
{
stmt
->
Ref
();
}
~
PrepareBaton
()
{
stmt
->
Unref
();
}
};
typedef
void
(
*
EIO_Callback
)(
Baton
*
baton
);
struct
Call
{
Call
(
EIO_Callback
cb_
,
Baton
*
baton_
)
:
callback
(
cb_
),
baton
(
baton_
)
{};
EIO_Callback
callback
;
Baton
*
baton
;
};
Statement
(
Database
*
db_
)
:
EventEmitter
(),
db
(
db_
),
handle
(
NULL
),
prepared
(
false
),
locked
(
false
),
finalized
(
false
)
{
db
->
pending
++
;
db
->
pending
++
;
db
->
Ref
();
db
->
Ref
();
}
}
~
Statement
()
{
~
Statement
()
{
fprintf
(
stderr
,
"Deleted Statement
\n
"
);
if
(
!
finalized
)
Finalize
();
assert
(
handle
==
NULL
);
db
->
pending
--
;
Database
::
Process
(
db
);
db
->
Unref
();
}
}
protected
:
protected
:
...
@@ -65,17 +93,24 @@ protected:
...
@@ -65,17 +93,24 @@ protected:
static
int
EIO_Prepare
(
eio_req
*
req
);
static
int
EIO_Prepare
(
eio_req
*
req
);
static
int
EIO_AfterPrepare
(
eio_req
*
req
);
static
int
EIO_AfterPrepare
(
eio_req
*
req
);
void
Wrap
(
Handle
<
Object
>
handle
);
inline
void
MakeWeak
();
virtual
void
Unref
();
static
void
Destruct
(
Persistent
<
Value
>
value
,
void
*
data
);
static
int
EIO_Destruct
(
eio_req
*
req
);
static
int
EIO_AfterDestruct
(
eio_req
*
req
);
void
Schedule
(
EIO_Callback
callback
,
Baton
*
baton
);
void
Process
();
void
CleanQueue
();
static
Handle
<
Value
>
Finalize
(
const
Arguments
&
args
);
static
void
Finalize
(
Baton
*
baton
);
void
Finalize
();
protected
:
protected
:
Database
*
db
;
Database
*
db
;
sqlite3_stmt
*
handle
;
sqlite3_stmt
*
handle
;
bool
prepared
;
bool
locked
;
bool
finalized
;
std
::
queue
<
Call
*>
queue
;
};
};
#endif
#endif
test/blob.test.js
View file @
0668424b
...
@@ -18,7 +18,7 @@ exports['Blob overflow test'] = function(beforeExit) {
...
@@ -18,7 +18,7 @@ exports['Blob overflow test'] = function(beforeExit) {
function
()
{
function
()
{
var
next
=
this
;
var
next
=
this
;
db
.
prepare
(
'CREATE TABLE elmos (image BLOB);'
,
function
(
err
,
statement
)
{
db
.
prepare
(
'CREATE TABLE elmos (image BLOB);'
,
function
(
err
,
statement
)
{
assert
.
isUndefined
(
err
);
assert
.
ok
(
!
err
);
statement
.
step
(
next
);
statement
.
step
(
next
);
});
});
},
},
...
...
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