Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
node-sqlite3
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
俞永鹏
node-sqlite3
Commits
db72749d
Commit
db72749d
authored
Feb 14, 2011
by
Konstantin Käfer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
unify indentation and rework database opening, closing and garbage collection
parent
493050a9
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
617 additions
and
434 deletions
+617
-434
sqlite3.js
lib/sqlite3.js
+6
-1
database.cc
src/database.cc
+406
-356
database.h
src/database.h
+39
-29
macros.h
src/macros.h
+109
-33
sqlite3_bindings.cc
src/sqlite3_bindings.cc
+45
-2
statement.cc
src/statement.cc
+10
-10
blob.test.js
test/blob.test.js
+2
-3
No files found.
lib/sqlite3.js
View file @
db72749d
...
@@ -16,6 +16,9 @@
...
@@ -16,6 +16,9 @@
var
sqlite3
=
module
.
exports
=
exports
=
require
(
'./sqlite3_bindings'
);
var
sqlite3
=
module
.
exports
=
exports
=
require
(
'./sqlite3_bindings'
);
var
sys
=
require
(
"sys"
);
var
sys
=
require
(
"sys"
);
/*
sqlite3.Database.prototype.query = function(sql, bindings, rowCallback) {
sqlite3.Database.prototype.query = function(sql, bindings, rowCallback) {
var self = this;
var self = this;
...
@@ -68,7 +71,7 @@ function _doStep(db, statement, rowCallback) {
...
@@ -68,7 +71,7 @@ function _doStep(db, statement, rowCallback) {
// Execute a single SQL query with the given optional parameters. Calls
// Execute a single SQL query with the given optional parameters. Calls
// `callback` with all rows or an error on query completion.
// `callback` with all rows or an error on query completion.
sqlite3
.
Database
.
prototype
.
execute
=
function
(
sql
/* , bindings, callback
*/
)
{
sqlite3.Database.prototype.execute = function (sql /* , bindings, callback ) {
var self = this;
var self = this;
var bindings, callback;
var bindings, callback;
var n = arguments.length;
var n = arguments.length;
...
@@ -248,3 +251,4 @@ sqlite3.sanitizeError = function(err, data) {
...
@@ -248,3 +251,4 @@ sqlite3.sanitizeError = function(err, data) {
'" with values ' + JSON.stringify(data, false, 4);
'" with values ' + JSON.stringify(data, false, 4);
return err;
return err;
};
};
*/
\ No newline at end of file
src/database.cc
View file @
db72749d
// Copyright (c) 2010, Orlando Vazquez <ovazquez@gmail.com>
// Copyright (c) 2010, Orlando Vazquez <ovazquez@gmail.com>
//
//
// Permission to use, copy, modify, and/or distribute this software for any
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
// copyright notice and this permission notice appear in all copies.
//
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
...
@@ -28,182 +28,202 @@ using namespace node;
...
@@ -28,182 +28,202 @@ using namespace node;
Persistent
<
FunctionTemplate
>
Database
::
constructor_template
;
Persistent
<
FunctionTemplate
>
Database
::
constructor_template
;
void
Database
::
Init
(
v8
::
Handle
<
Object
>
target
)
{
void
Database
::
Init
(
v8
::
Handle
<
Object
>
target
)
{
HandleScope
scope
;
HandleScope
scope
;
Local
<
FunctionTemplate
>
t
=
FunctionTemplate
::
New
(
New
);
Local
<
FunctionTemplate
>
t
=
FunctionTemplate
::
New
(
New
);
constructor_template
=
Persistent
<
FunctionTemplate
>::
New
(
t
);
constructor_template
=
Persistent
<
FunctionTemplate
>::
New
(
t
);
constructor_template
->
Inherit
(
EventEmitter
::
constructor_template
);
constructor_template
->
Inherit
(
EventEmitter
::
constructor_template
);
constructor_template
->
InstanceTemplate
()
->
SetInternalFieldCount
(
1
);
constructor_template
->
InstanceTemplate
()
->
SetInternalFieldCount
(
1
);
constructor_template
->
SetClassName
(
String
::
NewSymbol
(
"Database"
));
constructor_template
->
SetClassName
(
String
::
NewSymbol
(
"Database"
));
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"open"
,
Open
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"open"
,
Open
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"close"
,
Close
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"openSync"
,
OpenSync
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"prepare"
,
Prepar
e
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"close"
,
Clos
e
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"prepareAndStep"
,
PrepareAndStep
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"closeSync"
,
CloseSync
);
target
->
Set
(
v8
::
String
::
NewSymbol
(
"Database"
),
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"prepare"
,
Prepare
);
constructor_template
->
GetFunction
());
// insert/update execution result mask
target
->
Set
(
v8
::
String
::
NewSymbol
(
"Database"
),
NODE_DEFINE_CONSTANT
(
target
,
EXEC_EMPTY
);
constructor_template
->
GetFunction
());
NODE_DEFINE_CONSTANT
(
target
,
EXEC_LAST_INSERT_ID
);
NODE_DEFINE_CONSTANT
(
target
,
EXEC_AFFECTED_ROWS
);
}
Handle
<
Value
>
Database
::
New
(
const
Arguments
&
args
)
{
// insert/update execution result mask
HandleScope
scope
;
NODE_DEFINE_CONSTANT
(
target
,
EXEC_EMPTY
);
Database
*
db
=
new
Database
();
NODE_DEFINE_CONSTANT
(
target
,
EXEC_LAST_INSERT_ID
);
db
->
Wrap
(
args
.
This
());
NODE_DEFINE_CONSTANT
(
target
,
EXEC_AFFECTED_ROWS
);
return
args
.
This
();
}
}
int
Database
::
EIO_AfterOpen
(
eio_req
*
req
)
{
Handle
<
Value
>
Database
::
New
(
const
Arguments
&
args
)
{
ev_unref
(
EV_DEFAULT_UC
);
HandleScope
scope
;
HandleScope
scope
;
Database
*
db
=
new
Database
();
struct
open_request
*
open_req
=
(
struct
open_request
*
)(
req
->
data
);
db
->
Wrap
(
args
.
This
());
return
args
.
This
();
Local
<
Value
>
argv
[
1
];
bool
err
=
false
;
if
(
req
->
result
)
{
err
=
true
;
argv
[
0
]
=
Exception
::
Error
(
String
::
New
(
"Error opening database"
));
}
TryCatch
try_catch
;
open_req
->
db
->
Unref
();
open_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
err
?
1
:
0
,
argv
);
if
(
try_catch
.
HasCaught
())
{
FatalException
(
try_catch
);
}
open_req
->
db
->
Emit
(
String
::
New
(
"ready"
),
0
,
NULL
);
open_req
->
cb
.
Dispose
();
free
(
open_req
);
return
0
;
}
}
int
Database
::
EIO_Open
(
eio_req
*
req
)
{
struct
open_request
*
open_req
=
(
struct
open_request
*
)(
req
->
data
);
sqlite3
**
dbptr
=
open_req
->
db
->
GetDBPtr
();
int
rc
=
sqlite3_open_v2
(
open_req
->
filename
,
dbptr
,
SQLITE_OPEN_READWRITE
|
SQLITE_OPEN_CREATE
|
SQLITE_OPEN_FULLMUTEX
,
NULL
);
req
->
result
=
rc
;
// Set the a 10s timeout valuei for retries on BUSY errors.
Handle
<
Value
>
Database
::
OpenSync
(
const
Arguments
&
args
)
{
sqlite3_busy_timeout
(
*
dbptr
,
10000
);
HandleScope
scope
;
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
if
(
db
->
readyState
==
CLOSED
)
{
if
(
!
Open
(
db
))
{
EXCEPTION
(
db
->
error_message
.
c_str
(),
db
->
error_status
,
exception
);
return
ThrowException
(
exception
);
}
else
{
args
.
This
()
->
Set
(
String
::
NewSymbol
(
"opened"
),
True
(),
ReadOnly
);
db
->
Emit
(
String
::
NewSymbol
(
"opened"
),
0
,
NULL
);
// sqlite3 *db = *dbptr;
if
(
db
->
pending
==
0
)
{
// sqlite3_commit_hook(db, CommitHook, open_req->db);
db
->
Emit
(
String
::
NewSymbol
(
"idle"
),
0
,
NULL
);
// sqlite3_rollback_hook(db, RollbackHook, open_req->db);
}
// sqlite3_update_hook(db, UpdateHook, open_req->db);
}
}
return
0
;
return
args
.
This
()
;
}
}
Handle
<
Value
>
Database
::
Open
(
const
Arguments
&
args
)
{
Handle
<
Value
>
Database
::
Open
(
const
Arguments
&
args
)
{
HandleScope
scope
;
HandleScope
scope
;
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
REQ_STR_ARG
(
0
,
filename
);
REQ_FUN_ARG
(
1
,
cb
);
if
(
db
->
readyState
==
CLOSED
)
{
db
->
readyState
=
OPENING
;
db
->
Ref
();
eio_custom
(
EIO_Open
,
EIO_PRI_DEFAULT
,
EIO_AfterOpen
,
db
);
ev_ref
(
EV_DEFAULT_UC
);
}
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
return
args
.
This
();
}
struct
open_request
*
open_req
=
(
struct
open_request
*
)
bool
Database
::
Open
(
Database
*
db
)
{
calloc
(
1
,
sizeof
(
struct
open_request
)
+
filename
.
length
());
db
->
error_status
=
sqlite3_open_v2
(
db
->
filename
.
c_str
(),
&
db
->
handle
,
SQLITE_OPEN_FULLMUTEX
|
db
->
open_mode
,
NULL
);
if
(
db
->
error_status
!=
SQLITE_OK
)
{
db
->
error_message
=
std
::
string
(
sqlite3_errmsg
(
db
->
handle
));
db
->
readyState
=
CLOSED
;
return
false
;
}
else
{
db
->
readyState
=
OPEN
;
return
true
;
}
}
if
(
!
open_
req
)
{
int
Database
::
EIO_Open
(
eio_req
*
req
)
{
V8
::
LowMemoryNotification
(
);
Database
*
db
=
static_cast
<
Database
*>
(
req
->
data
);
return
ThrowException
(
Exception
::
Error
(
Open
(
db
);
String
::
New
(
"Could not allocate enough memory"
)))
;
return
0
;
}
}
strcpy
(
open_req
->
filename
,
*
filename
);
int
Database
::
EIO_AfterOpen
(
eio_req
*
req
)
{
open_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
HandleScope
scope
;
open_req
->
db
=
db
;
Database
*
db
=
static_cast
<
Database
*>
(
req
->
data
);
ev_unref
(
EV_DEFAULT_UC
);
db
->
Unref
();
Local
<
Value
>
argv
[
1
];
if
(
db
->
error_status
!=
SQLITE_OK
)
{
EXCEPTION
(
db
->
error_message
.
c_str
(),
db
->
error_status
,
exception
);
argv
[
0
]
=
exception
;
}
else
{
argv
[
0
]
=
Local
<
Value
>::
New
(
Null
());
db
->
handle_
->
Set
(
String
::
NewSymbol
(
"opened"
),
True
(),
ReadOnly
);
}
eio_custom
(
EIO_Open
,
EIO_PRI_DEFAULT
,
EIO_AfterOpen
,
open_req
);
db
->
Emit
(
String
::
NewSymbol
(
"opened"
),
1
,
argv
);
ev_ref
(
EV_DEFAULT_UC
);
if
(
db
->
pending
==
0
)
{
db
->
Ref
();
db
->
Emit
(
String
::
NewSymbol
(
"idle"
),
0
,
NULL
);
}
return
Undefined
()
;
return
0
;
}
}
int
Database
::
EIO_AfterClose
(
eio_req
*
req
)
{
ev_unref
(
EV_DEFAULT_UC
);
HandleScope
scope
;
struct
close_request
*
close_req
=
(
struct
close_request
*
)(
req
->
data
);
Handle
<
Value
>
Database
::
CloseSync
(
const
Arguments
&
args
)
{
HandleScope
scope
;
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
Local
<
Value
>
argv
[
1
];
if
(
db
->
readyState
==
OPEN
)
{
bool
err
=
false
;
if
(
!
Close
(
db
))
{
if
(
req
->
result
)
{
EXCEPTION
(
db
->
error_message
.
c_str
(),
db
->
error_status
,
exception
);
err
=
true
;
return
ThrowException
(
exception
);
argv
[
0
]
=
Exception
::
Error
(
String
::
New
(
"Error closing database"
));
}
}
else
{
args
.
This
()
->
Set
(
String
::
NewSymbol
(
"opened"
),
False
(),
ReadOnly
);
db
->
Emit
(
String
::
NewSymbol
(
"closed"
),
0
,
NULL
);
}
}
TryCatch
try_catch
;
return
True
();
}
close_req
->
db
->
Unref
();
Handle
<
Value
>
Database
::
Close
(
const
Arguments
&
args
)
{
close_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
err
?
1
:
0
,
argv
);
HandleScope
scope
;
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
if
(
db
->
readyState
==
OPEN
)
{
db
->
readyState
=
CLOSING
;
db
->
Ref
();
eio_custom
(
EIO_Close
,
EIO_PRI_DEFAULT
,
EIO_AfterClose
,
db
);
ev_ref
(
EV_DEFAULT_UC
);
}
if
(
try_catch
.
HasCaught
())
{
return
args
.
This
();
FatalException
(
try_catch
);
}
}
close_req
->
cb
.
Dispose
();
bool
Database
::
Close
(
Database
*
db
)
{
assert
(
db
->
handle
);
free
(
close_req
);
db
->
error_status
=
sqlite3_close
(
db
->
handle
);
return
0
;
if
(
db
->
error_status
!=
SQLITE_OK
)
{
db
->
error_message
=
std
::
string
(
sqlite3_errmsg
(
db
->
handle
));
db
->
readyState
=
OPEN
;
return
false
;
}
else
{
db
->
readyState
=
CLOSED
;
db
->
handle
=
NULL
;
return
true
;
}
}
}
int
Database
::
EIO_Close
(
eio_req
*
req
)
{
int
Database
::
EIO_Close
(
eio_req
*
req
)
{
struct
close_request
*
close_req
=
(
struct
close_request
*
)(
req
->
data
);
Database
*
db
=
static_cast
<
Database
*>
(
req
->
data
);
Database
*
db
=
close_req
->
db
;
Close
(
db
);
req
->
result
=
sqlite3_close
(
db
->
db_
);
return
0
;
db
->
db_
=
NULL
;
return
0
;
}
}
Handle
<
Value
>
Database
::
Close
(
const
Arguments
&
args
)
{
int
Database
::
EIO_AfterClose
(
eio_req
*
req
)
{
HandleScope
scope
;
HandleScope
scope
;
Database
*
db
=
static_cast
<
Database
*>
(
req
->
data
);
REQ_FUN_ARG
(
0
,
cb
);
ev_unref
(
EV_DEFAULT_UC
);
db
->
Unref
();
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
Local
<
Value
>
argv
[
1
];
struct
close_request
*
close_req
=
(
struct
close_request
*
)
if
(
db
->
error_status
!=
SQLITE_OK
)
{
calloc
(
1
,
sizeof
(
struct
close_request
));
EXCEPTION
(
db
->
error_message
.
c_str
(),
db
->
error_status
,
exception
);
argv
[
0
]
=
exception
;
if
(
!
close_req
)
{
}
V8
::
LowMemoryNotification
();
else
{
return
ThrowException
(
Exception
::
Error
(
argv
[
0
]
=
Local
<
Value
>::
New
(
Null
());
String
::
New
(
"Could not allocate enough memory"
)));
db
->
handle_
->
Set
(
String
::
NewSymbol
(
"opened"
),
False
(),
ReadOnly
);
}
}
close_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
close_req
->
db
=
db
;
eio_custom
(
EIO_Close
,
EIO_PRI_DEFAULT
,
EIO_AfterClose
,
close_req
);
ev_ref
(
EV_DEFAULT_UC
);
db
->
Emit
(
String
::
NewSymbol
(
"closed"
),
1
,
argv
);
db
->
Ref
();
return
Undefined
()
;
return
0
;
}
}
// // TODO: libeio'fy
// // TODO: libeio'fy
...
@@ -233,279 +253,309 @@ Handle<Value> Database::Close(const Arguments& args) {
...
@@ -233,279 +253,309 @@ Handle<Value> Database::Close(const Arguments& args) {
// }
// }
int
Database
::
EIO_AfterPrepareAndStep
(
eio_req
*
req
)
{
int
Database
::
EIO_AfterPrepareAndStep
(
eio_req
*
req
)
{
ev_unref
(
EV_DEFAULT_UC
);
ev_unref
(
EV_DEFAULT_UC
);
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)(
req
->
data
);
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)(
req
->
data
);
HandleScope
scope
;
HandleScope
scope
;
Local
<
Value
>
argv
[
2
];
Local
<
Value
>
argv
[
2
];
int
argc
=
0
;
int
argc
=
0
;
// if the prepare failed
// if the prepare failed
if
(
req
->
result
!=
SQLITE_OK
)
{
if
(
req
->
result
!=
SQLITE_OK
)
{
argv
[
0
]
=
Exception
::
Error
(
argv
[
0
]
=
Exception
::
Error
(
String
::
New
(
sqlite3_errmsg
(
prep_req
->
db
->
db_
)));
String
::
New
(
sqlite3_errmsg
(
prep_req
->
db
->
handle
)));
argc
=
1
;
argc
=
1
;
}
}
else
{
else
{
if
(
req
->
int1
==
SQLITE_DONE
)
{
if
(
req
->
int1
==
SQLITE_DONE
)
{
if
(
prep_req
->
mode
!=
EXEC_EMPTY
)
{
if
(
prep_req
->
mode
!=
EXEC_EMPTY
)
{
argv
[
0
]
=
Local
<
Value
>::
New
(
Undefined
());
// no error
argv
[
0
]
=
Local
<
Value
>::
New
(
Undefined
());
// no error
Local
<
Object
>
info
=
Object
::
New
();
Local
<
Object
>
info
=
Object
::
New
();
if
(
prep_req
->
mode
&
EXEC_LAST_INSERT_ID
)
{
if
(
prep_req
->
mode
&
EXEC_LAST_INSERT_ID
)
{
info
->
Set
(
String
::
NewSymbol
(
"last_inserted_id"
),
info
->
Set
(
String
::
NewSymbol
(
"last_inserted_id"
),
Integer
::
NewFromUnsigned
(
prep_req
->
lastInsertId
));
Integer
::
NewFromUnsigned
(
prep_req
->
lastInsertId
));
}
}
if
(
prep_req
->
mode
&
EXEC_AFFECTED_ROWS
)
{
if
(
prep_req
->
mode
&
EXEC_AFFECTED_ROWS
)
{
info
->
Set
(
String
::
NewSymbol
(
"affected_rows"
),
info
->
Set
(
String
::
NewSymbol
(
"affected_rows"
),
Integer
::
New
(
prep_req
->
affectedRows
));
Integer
::
New
(
prep_req
->
affectedRows
));
}
}
argv
[
1
]
=
info
;
argv
[
1
]
=
info
;
argc
=
2
;
argc
=
2
;
}
else
{
}
else
{
argc
=
0
;
argc
=
0
;
}
}
}
else
{
argv
[
0
]
=
External
::
New
(
prep_req
->
stmt
);
argv
[
1
]
=
Integer
::
New
(
req
->
int1
);
Persistent
<
Object
>
statement
(
Statement
::
constructor_template
->
GetFunction
()
->
NewInstance
(
2
,
argv
));
if
(
prep_req
->
tail
)
{
statement
->
Set
(
String
::
New
(
"tail"
),
String
::
New
(
prep_req
->
tail
));
}
argv
[
0
]
=
Local
<
Value
>::
New
(
Undefined
());
argv
[
1
]
=
Local
<
Value
>::
New
(
statement
);
argc
=
2
;
}
}
}
else
{
argv
[
0
]
=
External
::
New
(
prep_req
->
stmt
);
argv
[
1
]
=
Integer
::
New
(
req
->
int1
);
Persistent
<
Object
>
statement
(
Statement
::
constructor_template
->
GetFunction
()
->
NewInstance
(
2
,
argv
));
if
(
prep_req
->
tail
)
{
statement
->
Set
(
String
::
New
(
"tail"
),
String
::
New
(
prep_req
->
tail
));
}
argv
[
0
]
=
Local
<
Value
>::
New
(
Undefined
());
argv
[
1
]
=
Local
<
Value
>::
New
(
statement
);
argc
=
2
;
}
}
TryCatch
try_catch
;
TryCatch
try_catch
;
prep_req
->
db
->
Unref
();
prep_req
->
db
->
Unref
();
prep_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
argc
,
argv
);
prep_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
argc
,
argv
);
if
(
try_catch
.
HasCaught
())
{
if
(
try_catch
.
HasCaught
())
{
FatalException
(
try_catch
);
FatalException
(
try_catch
);
}
}
prep_req
->
cb
.
Dispose
();
prep_req
->
cb
.
Dispose
();
free
(
prep_req
);
free
(
prep_req
);
return
0
;
return
0
;
}
}
int
Database
::
EIO_PrepareAndStep
(
eio_req
*
req
)
{
int
Database
::
EIO_PrepareAndStep
(
eio_req
*
req
)
{
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)(
req
->
data
);
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)(
req
->
data
);
prep_req
->
stmt
=
NULL
;
prep_req
->
stmt
=
NULL
;
prep_req
->
tail
=
NULL
;
prep_req
->
tail
=
NULL
;
sqlite3
*
db
=
prep_req
->
db
->
db_
;
sqlite3
*
db
=
prep_req
->
db
->
handle
;
int
rc
=
sqlite3_prepare_v2
(
db
,
prep_req
->
sql
,
-
1
,
int
rc
=
sqlite3_prepare_v2
(
db
,
prep_req
->
sql
,
-
1
,
&
(
prep_req
->
stmt
),
&
(
prep_req
->
tail
));
&
(
prep_req
->
stmt
),
&
(
prep_req
->
tail
));
req
->
result
=
rc
;
req
->
result
=
rc
;
req
->
int1
=
-
1
;
req
->
int1
=
-
1
;
// This might be a INSERT statement. Let's try to get the first row.
// This might be a INSERT statement. Let's try to get the first row.
// This is to optimize out further calls to the thread pool. This is only
// This is to optimize out further calls to the thread pool. This is only
// possible in the case where there are no variable placeholders/bindings
// possible in the case where there are no variable placeholders/bindings
// in the SQL.
// in the SQL.
if
(
rc
==
SQLITE_OK
&&
!
sqlite3_bind_parameter_count
(
prep_req
->
stmt
))
{
if
(
rc
==
SQLITE_OK
&&
!
sqlite3_bind_parameter_count
(
prep_req
->
stmt
))
{
rc
=
sqlite3_step
(
prep_req
->
stmt
);
rc
=
sqlite3_step
(
prep_req
->
stmt
);
req
->
int1
=
rc
;
req
->
int1
=
rc
;
// no more rows to return, clean up statement
// no more rows to return, clean up statement
if
(
rc
==
SQLITE_DONE
)
{
if
(
rc
==
SQLITE_DONE
)
{
rc
=
sqlite3_finalize
(
prep_req
->
stmt
);
rc
=
sqlite3_finalize
(
prep_req
->
stmt
);
prep_req
->
stmt
=
NULL
;
prep_req
->
stmt
=
NULL
;
assert
(
rc
==
SQLITE_OK
);
assert
(
rc
==
SQLITE_OK
);
}
}
}
}
prep_req
->
lastInsertId
=
0
;
prep_req
->
lastInsertId
=
0
;
prep_req
->
affectedRows
=
0
;
prep_req
->
affectedRows
=
0
;
// load custom properties
// load custom properties
if
(
prep_req
->
mode
&
EXEC_LAST_INSERT_ID
)
if
(
prep_req
->
mode
&
EXEC_LAST_INSERT_ID
)
prep_req
->
lastInsertId
=
sqlite3_last_insert_rowid
(
db
);
prep_req
->
lastInsertId
=
sqlite3_last_insert_rowid
(
db
);
if
(
prep_req
->
mode
&
EXEC_AFFECTED_ROWS
)
if
(
prep_req
->
mode
&
EXEC_AFFECTED_ROWS
)
prep_req
->
affectedRows
=
sqlite3_changes
(
db
);
prep_req
->
affectedRows
=
sqlite3_changes
(
db
);
return
0
;
return
0
;
}
}
Handle
<
Value
>
Database
::
PrepareAndStep
(
const
Arguments
&
args
)
{
Handle
<
Value
>
Database
::
PrepareAndStep
(
const
Arguments
&
args
)
{
HandleScope
scope
;
HandleScope
scope
;
REQ_STR_AR
G
(
0
,
sql
);
REQUIRE_ARGUMENT_STRIN
G
(
0
,
sql
);
REQ_FUN_ARG
(
1
,
cb
);
REQUIRE_ARGUMENT_FUNCTION
(
1
,
cb
);
OPT_INT_ARG
(
2
,
mode
,
EXEC_EMPTY
);
OPTIONAL_ARGUMENT_INTEGER
(
2
,
mode
,
EXEC_EMPTY
);
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)
calloc
(
1
,
sizeof
(
struct
prepare_request
)
+
sql
.
length
());
calloc
(
1
,
sizeof
(
struct
prepare_request
)
+
sql
.
length
());
if
(
!
prep_req
)
{
if
(
!
prep_req
)
{
V8
::
LowMemoryNotification
();
V8
::
LowMemoryNotification
();
return
ThrowException
(
Exception
::
Error
(
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Could not allocate enough memory"
)));
String
::
New
(
"Could not allocate enough memory"
)));
}
}
strcpy
(
prep_req
->
sql
,
*
sql
);
strcpy
(
prep_req
->
sql
,
*
sql
);
prep_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
prep_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
prep_req
->
db
=
db
;
prep_req
->
db
=
db
;
prep_req
->
mode
=
mode
;
prep_req
->
mode
=
mode
;
eio_custom
(
EIO_PrepareAndStep
,
EIO_PRI_DEFAULT
,
EIO_AfterPrepareAndStep
,
prep_req
);
eio_custom
(
EIO_PrepareAndStep
,
EIO_PRI_DEFAULT
,
EIO_AfterPrepareAndStep
,
prep_req
);
ev_ref
(
EV_DEFAULT_UC
);
ev_ref
(
EV_DEFAULT_UC
);
db
->
Ref
();
db
->
Ref
();
return
Undefined
();
return
Undefined
();
}
}
int
Database
::
EIO_AfterPrepare
(
eio_req
*
req
)
{
int
Database
::
EIO_AfterPrepare
(
eio_req
*
req
)
{
ev_unref
(
EV_DEFAULT_UC
);
ev_unref
(
EV_DEFAULT_UC
);
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)(
req
->
data
);
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)(
req
->
data
);
HandleScope
scope
;
HandleScope
scope
;
Local
<
Value
>
argv
[
3
];
Local
<
Value
>
argv
[
3
];
int
argc
=
0
;
int
argc
=
0
;
// if the prepare failed
// if the prepare failed
if
(
req
->
result
!=
SQLITE_OK
)
{
if
(
req
->
result
!=
SQLITE_OK
)
{
argv
[
0
]
=
Exception
::
Error
(
argv
[
0
]
=
Exception
::
Error
(
String
::
New
(
sqlite3_errmsg
(
prep_req
->
db
->
db_
)));
String
::
New
(
sqlite3_errmsg
(
prep_req
->
db
->
handle
)));
argc
=
1
;
argc
=
1
;
}
else
{
argv
[
0
]
=
External
::
New
(
prep_req
->
stmt
);
argv
[
1
]
=
Integer
::
New
(
-
1
);
argv
[
2
]
=
Integer
::
New
(
prep_req
->
mode
);
Persistent
<
Object
>
statement
(
Statement
::
constructor_template
->
GetFunction
()
->
NewInstance
(
3
,
argv
));
if
(
prep_req
->
tail
)
{
statement
->
Set
(
String
::
New
(
"tail"
),
String
::
New
(
prep_req
->
tail
));
}
}
else
{
argv
[
0
]
=
External
::
New
(
prep_req
->
stmt
);
argv
[
1
]
=
Integer
::
New
(
-
1
);
argv
[
2
]
=
Integer
::
New
(
prep_req
->
mode
);
Persistent
<
Object
>
statement
(
Statement
::
constructor_template
->
GetFunction
()
->
NewInstance
(
3
,
argv
));
if
(
prep_req
->
tail
)
{
statement
->
Set
(
String
::
New
(
"tail"
),
String
::
New
(
prep_req
->
tail
));
}
argc
=
2
;
argc
=
2
;
argv
[
0
]
=
Local
<
Value
>::
New
(
Undefined
());
argv
[
0
]
=
Local
<
Value
>::
New
(
Undefined
());
argv
[
1
]
=
Local
<
Value
>::
New
(
statement
);
argv
[
1
]
=
Local
<
Value
>::
New
(
statement
);
}
}
TryCatch
try_catch
;
TryCatch
try_catch
;
prep_req
->
db
->
Unref
();
prep_req
->
db
->
Unref
();
prep_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
argc
,
argv
);
prep_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
argc
,
argv
);
if
(
try_catch
.
HasCaught
())
{
if
(
try_catch
.
HasCaught
())
{
FatalException
(
try_catch
);
FatalException
(
try_catch
);
}
}
prep_req
->
cb
.
Dispose
();
prep_req
->
cb
.
Dispose
();
free
(
prep_req
);
free
(
prep_req
);
return
0
;
return
0
;
}
}
int
Database
::
EIO_Prepare
(
eio_req
*
req
)
{
int
Database
::
EIO_Prepare
(
eio_req
*
req
)
{
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)(
req
->
data
);
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)(
req
->
data
);
prep_req
->
stmt
=
NULL
;
prep_req
->
stmt
=
NULL
;
prep_req
->
tail
=
NULL
;
prep_req
->
tail
=
NULL
;
sqlite3
*
db
=
prep_req
->
db
->
db_
;
sqlite3
*
db
=
prep_req
->
db
->
handle
;
int
rc
=
sqlite3_prepare_v2
(
db
,
prep_req
->
sql
,
-
1
,
int
rc
=
sqlite3_prepare_v2
(
db
,
prep_req
->
sql
,
-
1
,
&
(
prep_req
->
stmt
),
&
(
prep_req
->
tail
));
&
(
prep_req
->
stmt
),
&
(
prep_req
->
tail
));
req
->
result
=
rc
;
req
->
result
=
rc
;
prep_req
->
lastInsertId
=
0
;
prep_req
->
lastInsertId
=
0
;
prep_req
->
affectedRows
=
0
;
prep_req
->
affectedRows
=
0
;
// load custom properties
// load custom properties
if
(
prep_req
->
mode
&
EXEC_LAST_INSERT_ID
)
if
(
prep_req
->
mode
&
EXEC_LAST_INSERT_ID
)
prep_req
->
lastInsertId
=
sqlite3_last_insert_rowid
(
db
);
prep_req
->
lastInsertId
=
sqlite3_last_insert_rowid
(
db
);
if
(
prep_req
->
mode
&
EXEC_AFFECTED_ROWS
)
if
(
prep_req
->
mode
&
EXEC_AFFECTED_ROWS
)
prep_req
->
affectedRows
=
sqlite3_changes
(
db
);
prep_req
->
affectedRows
=
sqlite3_changes
(
db
);
return
0
;
return
0
;
}
}
// Statement#prepare(sql, [ options ,] callback);
// Statement#prepare(sql, [ options ,] callback);
Handle
<
Value
>
Database
::
Prepare
(
const
Arguments
&
args
)
{
Handle
<
Value
>
Database
::
Prepare
(
const
Arguments
&
args
)
{
HandleScope
scope
;
HandleScope
scope
;
Local
<
Object
>
options
;
Local
<
Object
>
options
;
Local
<
Function
>
cb
;
Local
<
Function
>
cb
;
int
mode
;
int
mode
;
REQ_STR_ARG
(
0
,
sql
);
REQUIRE_ARGUMENT_STRING
(
0
,
sql
);
// middle argument could be options or
// middle argument could be options or
switch
(
args
.
Length
())
{
switch
(
args
.
Length
())
{
case
2
:
case
2
:
if
(
!
args
[
1
]
->
IsFunction
())
{
if
(
!
args
[
1
]
->
IsFunction
())
{
return
ThrowException
(
Exception
::
TypeError
(
return
ThrowException
(
Exception
::
TypeError
(
String
::
New
(
"Argument 1 must be a function"
)));
String
::
New
(
"Argument 1 must be a function"
)));
}
}
cb
=
Local
<
Function
>::
Cast
(
args
[
1
]);
cb
=
Local
<
Function
>::
Cast
(
args
[
1
]);
options
=
Object
::
New
();
options
=
Object
::
New
();
break
;
break
;
case
3
:
case
3
:
if
(
!
args
[
1
]
->
IsObject
())
{
if
(
!
args
[
1
]
->
IsObject
())
{
return
ThrowException
(
Exception
::
TypeError
(
return
ThrowException
(
Exception
::
TypeError
(
String
::
New
(
"Argument 1 must be an object"
)));
String
::
New
(
"Argument 1 must be an object"
)));
}
}
options
=
Local
<
Function
>::
Cast
(
args
[
1
]);
options
=
Local
<
Function
>::
Cast
(
args
[
1
]);
if
(
!
args
[
2
]
->
IsFunction
())
{
if
(
!
args
[
2
]
->
IsFunction
())
{
return
ThrowException
(
Exception
::
TypeError
(
return
ThrowException
(
Exception
::
TypeError
(
String
::
New
(
"Argument 2 must be a function"
)));
String
::
New
(
"Argument 2 must be a function"
)));
}
}
cb
=
Local
<
Function
>::
Cast
(
args
[
2
]);
cb
=
Local
<
Function
>::
Cast
(
args
[
2
]);
break
;
break
;
}
}
mode
=
EXEC_EMPTY
;
mode
=
EXEC_EMPTY
;
if
(
options
->
Get
(
String
::
New
(
"lastInsertRowID"
))
->
IsTrue
())
{
if
(
options
->
Get
(
String
::
New
(
"lastInsertRowID"
))
->
IsTrue
())
{
mode
|=
EXEC_LAST_INSERT_ID
;
mode
|=
EXEC_LAST_INSERT_ID
;
}
}
if
(
options
->
Get
(
String
::
New
(
"affectedRows"
))
->
IsTrue
())
{
if
(
options
->
Get
(
String
::
New
(
"affectedRows"
))
->
IsTrue
())
{
mode
|=
EXEC_AFFECTED_ROWS
;
mode
|=
EXEC_AFFECTED_ROWS
;
}
}
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
Database
*
db
=
ObjectWrap
::
Unwrap
<
Database
>
(
args
.
This
());
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)
calloc
(
1
,
sizeof
(
struct
prepare_request
)
+
sql
.
length
());
calloc
(
1
,
sizeof
(
struct
prepare_request
)
+
sql
.
length
());
if
(
!
prep_req
)
{
if
(
!
prep_req
)
{
V8
::
LowMemoryNotification
();
V8
::
LowMemoryNotification
();
return
ThrowException
(
Exception
::
Error
(
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Could not allocate enough memory"
)));
String
::
New
(
"Could not allocate enough memory"
)));
}
}
strcpy
(
prep_req
->
sql
,
*
sql
);
strcpy
(
prep_req
->
sql
,
*
sql
);
prep_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
prep_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
prep_req
->
db
=
db
;
prep_req
->
db
=
db
;
prep_req
->
mode
=
mode
;
prep_req
->
mode
=
mode
;
eio_custom
(
EIO_Prepare
,
EIO_PRI_DEFAULT
,
EIO_AfterPrepare
,
prep_req
);
eio_custom
(
EIO_Prepare
,
EIO_PRI_DEFAULT
,
EIO_AfterPrepare
,
prep_req
);
ev_ref
(
EV_DEFAULT_UC
);
ev_ref
(
EV_DEFAULT_UC
);
db
->
Ref
();
db
->
Ref
();
return
Undefined
();
return
Undefined
();
}
/**
* Override this so that we can properly close the database when this object
* gets garbage collected.
*/
void
Database
::
Wrap
(
Handle
<
Object
>
handle
)
{
assert
(
handle_
.
IsEmpty
());
assert
(
handle
->
InternalFieldCount
()
>
0
);
handle_
=
Persistent
<
Object
>::
New
(
handle
);
handle_
->
SetPointerInInternalField
(
0
,
this
);
handle_
.
MakeWeak
(
this
,
Destruct
);
}
void
Database
::
Destruct
(
Persistent
<
Value
>
value
,
void
*
data
)
{
Database
*
db
=
static_cast
<
Database
*>
(
data
);
if
(
db
->
handle
)
{
eio_custom
(
EIO_Close
,
EIO_PRI_DEFAULT
,
EIO_AfterDestruct
,
db
);
ev_ref
(
EV_DEFAULT_UC
);
}
else
{
delete
db
;
}
}
int
Database
::
EIO_AfterDestruct
(
eio_req
*
req
)
{
Database
*
db
=
static_cast
<
Database
*>
(
req
->
data
);
ev_unref
(
EV_DEFAULT_UC
);
delete
db
;
return
0
;
}
}
src/database.h
View file @
db72749d
// Copyright (c) 2010, Orlando Vazquez <ovazquez@gmail.com>
// Copyright (c) 2010, Orlando Vazquez <ovazquez@gmail.com>
//
//
// Permission to use, copy, modify, and/or distribute this software for any
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
// copyright notice and this permission notice appear in all copies.
//
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
...
@@ -19,35 +19,51 @@
...
@@ -19,35 +19,51 @@
#include <node.h>
#include <node.h>
#include <node_events.h>
#include <node_events.h>
#include <string>
#include <sqlite3.h>
#include <sqlite3.h>
using
namespace
v8
;
using
namespace
v8
;
using
namespace
node
;
using
namespace
node
;
enum
ReadyState
{
CLOSED
,
OPENING
,
OPEN
,
CLOSING
};
class
Database
:
public
EventEmitter
{
class
Database
:
public
EventEmitter
{
public
:
public
:
static
Persistent
<
FunctionTemplate
>
constructor_template
;
static
Persistent
<
FunctionTemplate
>
constructor_template
;
static
void
Init
(
v8
::
Handle
<
Object
>
target
);
static
void
Init
(
v8
::
Handle
<
Object
>
target
);
protected
:
protected
:
Database
()
:
EventEmitter
(),
db_
(
NULL
)
{
}
Database
()
:
EventEmitter
(),
handle
(
NULL
),
pending
(
0
),
readyState
(
CLOSED
)
{
}
~
Database
()
{
~
Database
()
{
assert
(
db_
==
NULL
);
fprintf
(
stderr
,
"Calling destructor
\n
"
);
printf
(
"Destroying database
\n
"
);
}
}
static
Handle
<
Value
>
New
(
const
Arguments
&
args
);
static
Handle
<
Value
>
New
(
const
Arguments
&
args
);
static
int
EIO_AfterOpen
(
eio_req
*
req
);
static
Handle
<
Value
>
OpenSync
(
const
Arguments
&
args
);
static
int
EIO_Open
(
eio_req
*
req
);
static
Handle
<
Value
>
Open
(
const
Arguments
&
args
);
static
Handle
<
Value
>
Open
(
const
Arguments
&
args
);
static
bool
Open
(
Database
*
db
);
static
int
EIO_Open
(
eio_req
*
req
);
static
int
EIO_AfterOpen
(
eio_req
*
req
);
static
int
EIO_AfterClose
(
eio_req
*
req
);
static
Handle
<
Value
>
CloseSync
(
const
Arguments
&
args
);
static
int
EIO_Close
(
eio_req
*
req
);
static
Handle
<
Value
>
Close
(
const
Arguments
&
args
);
static
Handle
<
Value
>
Close
(
const
Arguments
&
args
);
static
bool
Close
(
Database
*
db
);
static
int
EIO_Close
(
eio_req
*
req
);
static
int
EIO_AfterClose
(
eio_req
*
req
);
// static Handle<Value> LastInsertRowid(const Arguments& args);
static
int
EIO_AfterPrepareAndStep
(
eio_req
*
req
);
static
int
EIO_AfterPrepareAndStep
(
eio_req
*
req
);
static
int
EIO_PrepareAndStep
(
eio_req
*
req
);
static
int
EIO_PrepareAndStep
(
eio_req
*
req
);
static
Handle
<
Value
>
PrepareAndStep
(
const
Arguments
&
args
);
static
Handle
<
Value
>
PrepareAndStep
(
const
Arguments
&
args
);
...
@@ -56,35 +72,29 @@ class Database : public EventEmitter {
...
@@ -56,35 +72,29 @@ class Database : public EventEmitter {
static
int
EIO_Prepare
(
eio_req
*
req
);
static
int
EIO_Prepare
(
eio_req
*
req
);
static
Handle
<
Value
>
Prepare
(
const
Arguments
&
args
);
static
Handle
<
Value
>
Prepare
(
const
Arguments
&
args
);
// Return a pointer to the Sqlite handle pointer so that EIO_Open can
void
Wrap
(
Handle
<
Object
>
handle
);
// pass it to sqlite3_open which wants a pointer to an sqlite3 pointer. This
static
void
Destruct
(
Persistent
<
Value
>
value
,
void
*
data
);
// is because it wants to initialize our original (sqlite3*) pointer to
static
int
EIO_Destruct
(
eio_req
*
req
);
// point to an valid object.
static
int
EIO_AfterDestruct
(
eio_req
*
req
);
sqlite3
**
GetDBPtr
(
void
)
{
return
&
db_
;
}
protected
:
protected
:
sqlite3
*
handle
;
std
::
string
filename
;
int
open_mode
;
std
::
string
error_message
;
int
error_status
;
sqlite3
*
db_
;
int
pending
;
ReadyState
readyState
;
};
};
enum
ExecMode
enum
ExecMode
{
{
EXEC_EMPTY
=
0
,
EXEC_EMPTY
=
0
,
EXEC_LAST_INSERT_ID
=
1
,
EXEC_LAST_INSERT_ID
=
1
,
EXEC_AFFECTED_ROWS
=
2
EXEC_AFFECTED_ROWS
=
2
};
};
struct
open_request
{
Persistent
<
Function
>
cb
;
Database
*
db
;
char
filename
[
1
];
};
struct
close_request
{
Persistent
<
Function
>
cb
;
Database
*
db
;
};
struct
prepare_request
{
struct
prepare_request
{
Persistent
<
Function
>
cb
;
Persistent
<
Function
>
cb
;
Database
*
db
;
Database
*
db
;
...
...
src/macros.h
View file @
db72749d
...
@@ -15,6 +15,9 @@
...
@@ -15,6 +15,9 @@
#ifndef NODE_SQLITE3_SRC_MACROS_H
#ifndef NODE_SQLITE3_SRC_MACROS_H
#define NODE_SQLITE3_SRC_MACROS_H
#define NODE_SQLITE3_SRC_MACROS_H
const
char
*
sqlite_code_string
(
int
code
);
#define CHECK(rc) { if ((rc) != SQLITE_OK) \
#define CHECK(rc) { if ((rc) != SQLITE_OK) \
return ThrowException(Exception::Error(String::New( \
return ThrowException(Exception::Error(String::New( \
sqlite3_errmsg(*db)))); }
sqlite3_errmsg(*db)))); }
...
@@ -23,37 +26,110 @@
...
@@ -23,37 +26,110 @@
return ThrowException(Exception::Error(String::New( \
return ThrowException(Exception::Error(String::New( \
sqlite3_errmsg(sqlite3_db_handle(sto->stmt_))))); }
sqlite3_errmsg(sqlite3_db_handle(sto->stmt_))))); }
#define REQ_ARGS(N) \
if (args.Length() < (N)) \
#define REQUIRE_ARGUMENTS(n) \
return ThrowException(Exception::TypeError( \
if (args.Length() < (n)) { \
String::New("Expected " #N "arguments")));
return ThrowException( \
Exception::TypeError(String::New("Expected " #n "arguments")) \
#define REQ_STR_ARG(I, VAR) \
); \
if (args.Length() <= (I) || !args[I]->IsString()) \
}
return ThrowException(Exception::TypeError( \
String::New("Argument " #I " must be a string"))); \
String::Utf8Value VAR(args[I]->ToString());
#define REQUIRE_ARGUMENT_EXTERNAL(i, var) \
if (args.Length() <= (i) || !args[i]->IsExternal()) { \
#define REQ_FUN_ARG(I, VAR) \
return ThrowException( \
if (args.Length() <= (I) || !args[I]->IsFunction()) \
Exception::TypeError(String::New("Argument " #i " invalid")) \
return ThrowException(Exception::TypeError( \
); \
String::New("Argument " #I " must be a function"))); \
} \
Local<Function> VAR = Local<Function>::Cast(args[I]);
Local<External> var = Local<External>::Cast(args[i]);
#define REQ_EXT_ARG(I, VAR) \
if (args.Length() <= (I) || !args[I]->IsExternal()) \
#define REQUIRE_ARGUMENT_FUNCTION(i, var) \
return ThrowException(Exception::TypeError( \
if (args.Length() <= (i) || !args[i]->IsFunction()) { \
String::New("Argument " #I " invalid"))); \
return ThrowException(Exception::TypeError( \
Local<External> VAR = Local<External>::Cast(args[I]);
String::New("Argument " #i " must be a function")) \
); \
#define OPT_INT_ARG(I, VAR, DEFAULT) \
} \
int VAR; \
Local<Function> var = Local<Function>::Cast(args[i]);
if (args.Length() <= (I)) { \
VAR = (DEFAULT); \
} else if (args[I]->IsInt32()) { \
#define REQUIRE_ARGUMENT_STRING(i, var) \
VAR = args[I]->Int32Value(); \
if (args.Length() <= (i) || !args[i]->IsString()) { \
} else { \
return ThrowException(Exception::TypeError( \
return ThrowException(Exception::TypeError( \
String::New("Argument " #i " must be a string")) \
String::New("Argument " #I " must be an integer"))); \
); \
}
} \
String::Utf8Value var(args[i]->ToString());
#define OPTIONAL_ARGUMENT_FUNCTION(i, var) \
Local<Function> var; \
bool var ## _exists = false; \
if (args.Length() >= i) { \
if (!args[i]->IsFunction()) { \
return ThrowException(Exception::TypeError( \
String::New("Argument " #i " must be a function")) \
); \
} \
var = Local<Function>::Cast(args[i]); \
var ## _exists = true; \
}
#define OPTIONAL_ARGUMENT_INTEGER(i, var, default) \
int var; \
if (args.Length() <= (i)) { \
var = (default); \
} \
else if (args[i]->IsInt32()) { \
var = args[i]->Int32Value(); \
} \
else { \
return ThrowException(Exception::TypeError( \
String::New("Argument " #i " must be an integer")) \
); \
}
#define DEFINE_CONSTANT_INTEGER(target, constant, name) \
(target)->Set( \
String::NewSymbol(#name), \
Integer::New(constant), \
static_cast<PropertyAttribute>(ReadOnly | DontDelete) \
);
#define DEFINE_CONSTANT_STRING(target, constant, name) \
(target)->Set( \
String::NewSymbol(#name), \
String::NewSymbol(constant), \
static_cast<PropertyAttribute>(ReadOnly | DontDelete) \
);
#define NODE_SET_GETTER(target, name, function) \
(target)->InstanceTemplate() \
->SetAccessor(String::NewSymbol(name), (function));
#define GET_STRING(source, name, property) \
String::Utf8Value name((source)->Get(String::NewSymbol(property)));
#define GET_INTEGER(source, name, property) \
int name = (source)->Get(String::NewSymbol(property))->Int32Value();
#define EXCEPTION(msg, errno, name) \
Local<Value> name = Exception::Error( \
String::Concat( \
String::Concat( \
String::NewSymbol(sqlite_code_string(errno)), \
String::NewSymbol(": ") \
), \
String::New(msg) \
) \
); \
Local<Object> name ## _obj = name->ToObject(); \
name ## _obj->Set(NODE_PSYMBOL("errno"), Integer::New(errno)); \
name ## _obj->Set(NODE_PSYMBOL("code"), \
String::NewSymbol(sqlite_code_string(errno)));
#endif
#endif
src/sqlite3_bindings.cc
View file @
db72749d
...
@@ -16,11 +16,54 @@
...
@@ -16,11 +16,54 @@
#include <node.h>
#include <node.h>
#include <node_events.h>
#include <node_events.h>
#include <sqlite3.h>
#include "macros.h"
#include "database.h"
#include "database.h"
#include "statement.h"
#include "statement.h"
extern
"C"
void
init
(
v8
::
Handle
<
Object
>
target
)
{
extern
"C"
void
init
(
v8
::
Handle
<
Object
>
target
)
{
Database
::
Init
(
target
);
Database
::
Init
(
target
);
Statement
::
Init
(
target
);
Statement
::
Init
(
target
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_OPEN_READONLY
,
OPEN_READONLY
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_OPEN_READWRITE
,
OPEN_READWRITE
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_OPEN_CREATE
,
OPEN_CREATE
);
DEFINE_CONSTANT_STRING
(
target
,
SQLITE_VERSION
,
VERSION
);
DEFINE_CONSTANT_INTEGER
(
target
,
SQLITE_VERSION_NUMBER
,
VERSION_NUMBER
);
}
}
const
char
*
sqlite_code_string
(
int
code
)
{
switch
(
code
)
{
case
SQLITE_OK
:
return
"SQLITE_OK"
;
case
SQLITE_ERROR
:
return
"SQLITE_ERROR"
;
case
SQLITE_INTERNAL
:
return
"SQLITE_INTERNAL"
;
case
SQLITE_PERM
:
return
"SQLITE_PERM"
;
case
SQLITE_ABORT
:
return
"SQLITE_ABORT"
;
case
SQLITE_BUSY
:
return
"SQLITE_BUSY"
;
case
SQLITE_LOCKED
:
return
"SQLITE_LOCKED"
;
case
SQLITE_NOMEM
:
return
"SQLITE_NOMEM"
;
case
SQLITE_READONLY
:
return
"SQLITE_READONLY"
;
case
SQLITE_INTERRUPT
:
return
"SQLITE_INTERRUPT"
;
case
SQLITE_IOERR
:
return
"SQLITE_IOERR"
;
case
SQLITE_CORRUPT
:
return
"SQLITE_CORRUPT"
;
case
SQLITE_NOTFOUND
:
return
"SQLITE_NOTFOUND"
;
case
SQLITE_FULL
:
return
"SQLITE_FULL"
;
case
SQLITE_CANTOPEN
:
return
"SQLITE_CANTOPEN"
;
case
SQLITE_PROTOCOL
:
return
"SQLITE_PROTOCOL"
;
case
SQLITE_EMPTY
:
return
"SQLITE_EMPTY"
;
case
SQLITE_SCHEMA
:
return
"SQLITE_SCHEMA"
;
case
SQLITE_TOOBIG
:
return
"SQLITE_TOOBIG"
;
case
SQLITE_CONSTRAINT
:
return
"SQLITE_CONSTRAINT"
;
case
SQLITE_MISMATCH
:
return
"SQLITE_MISMATCH"
;
case
SQLITE_MISUSE
:
return
"SQLITE_MISUSE"
;
case
SQLITE_NOLFS
:
return
"SQLITE_NOLFS"
;
case
SQLITE_AUTH
:
return
"SQLITE_AUTH"
;
case
SQLITE_FORMAT
:
return
"SQLITE_FORMAT"
;
case
SQLITE_RANGE
:
return
"SQLITE_RANGE"
;
case
SQLITE_NOTADB
:
return
"SQLITE_NOTADB"
;
case
SQLITE_ROW
:
return
"SQLITE_ROW"
;
case
SQLITE_DONE
:
return
"SQLITE_DONE"
;
default
:
return
"UNKNOWN"
;
}
}
src/statement.cc
View file @
db72749d
...
@@ -50,7 +50,7 @@ void Statement::Init(v8::Handle<Object> target) {
...
@@ -50,7 +50,7 @@ void Statement::Init(v8::Handle<Object> target) {
Handle
<
Value
>
Statement
::
New
(
const
Arguments
&
args
)
{
Handle
<
Value
>
Statement
::
New
(
const
Arguments
&
args
)
{
HandleScope
scope
;
HandleScope
scope
;
REQ
_EXT_ARG
(
0
,
stmt
);
REQ
UIRE_ARGUMENT_EXTERNAL
(
0
,
stmt
);
int
first_rc
=
args
[
1
]
->
IntegerValue
();
int
first_rc
=
args
[
1
]
->
IntegerValue
();
int
mode
=
args
[
2
]
->
IntegerValue
();
int
mode
=
args
[
2
]
->
IntegerValue
();
...
@@ -169,8 +169,8 @@ Handle<Value> Statement::BindObject(const Arguments& args) {
...
@@ -169,8 +169,8 @@ Handle<Value> Statement::BindObject(const Arguments& args) {
HandleScope
scope
;
HandleScope
scope
;
Statement
*
sto
=
ObjectWrap
::
Unwrap
<
Statement
>
(
args
.
This
());
Statement
*
sto
=
ObjectWrap
::
Unwrap
<
Statement
>
(
args
.
This
());
REQ
_ARG
S
(
2
);
REQ
UIRE_ARGUMENT
S
(
2
);
REQ
_FUN_ARG
(
1
,
cb
);
REQ
UIRE_ARGUMENT_FUNCTION
(
1
,
cb
);
if
(
!
args
[
0
]
->
IsObject
())
if
(
!
args
[
0
]
->
IsObject
())
return
ThrowException
(
Exception
::
TypeError
(
return
ThrowException
(
Exception
::
TypeError
(
...
@@ -253,8 +253,8 @@ Handle<Value> Statement::BindArray(const Arguments& args) {
...
@@ -253,8 +253,8 @@ Handle<Value> Statement::BindArray(const Arguments& args) {
HandleScope
scope
;
HandleScope
scope
;
Statement
*
sto
=
ObjectWrap
::
Unwrap
<
Statement
>
(
args
.
This
());
Statement
*
sto
=
ObjectWrap
::
Unwrap
<
Statement
>
(
args
.
This
());
REQ
_ARG
S
(
2
);
REQ
UIRE_ARGUMENT
S
(
2
);
REQ
_FUN_ARG
(
1
,
cb
);
REQ
UIRE_ARGUMENT_FUNCTION
(
1
,
cb
);
if
(
!
args
[
0
]
->
IsArray
())
if
(
!
args
[
0
]
->
IsArray
())
return
ThrowException
(
Exception
::
TypeError
(
return
ThrowException
(
Exception
::
TypeError
(
String
::
New
(
"First argument must be an Array."
)));
String
::
New
(
"First argument must be an Array."
)));
...
@@ -349,8 +349,8 @@ Handle<Value> Statement::Bind(const Arguments& args) {
...
@@ -349,8 +349,8 @@ Handle<Value> Statement::Bind(const Arguments& args) {
HandleScope
scope
;
HandleScope
scope
;
Statement
*
sto
=
ObjectWrap
::
Unwrap
<
Statement
>
(
args
.
This
());
Statement
*
sto
=
ObjectWrap
::
Unwrap
<
Statement
>
(
args
.
This
());
REQ
_ARG
S
(
2
);
REQ
UIRE_ARGUMENT
S
(
2
);
REQ
_FUN_ARG
(
2
,
cb
);
REQ
UIRE_ARGUMENT_FUNCTION
(
2
,
cb
);
if
(
!
(
args
[
0
]
->
IsString
()
if
(
!
(
args
[
0
]
->
IsString
()
||
args
[
0
]
->
IsInt32
()
||
args
[
0
]
->
IsInt32
()
...
@@ -475,7 +475,7 @@ Handle<Value> Statement::Finalize(const Arguments& args) {
...
@@ -475,7 +475,7 @@ Handle<Value> Statement::Finalize(const Arguments& args) {
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Already stepping"
)));
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Already stepping"
)));
}
}
REQ
_FUN_ARG
(
0
,
cb
);
REQ
UIRE_ARGUMENT_FUNCTION
(
0
,
cb
);
sto
->
SetCallback
(
cb
);
sto
->
SetCallback
(
cb
);
...
@@ -740,7 +740,7 @@ Handle<Value> Statement::Step(const Arguments& args) {
...
@@ -740,7 +740,7 @@ Handle<Value> Statement::Step(const Arguments& args) {
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Already stepping"
)));
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Already stepping"
)));
}
}
REQ
_FUN_ARG
(
0
,
cb
);
REQ
UIRE_ARGUMENT_FUNCTION
(
0
,
cb
);
sto
->
SetCallback
(
cb
);
sto
->
SetCallback
(
cb
);
...
@@ -1011,7 +1011,7 @@ int Statement::EIO_FetchAll(eio_req *req) {
...
@@ -1011,7 +1011,7 @@ int Statement::EIO_FetchAll(eio_req *req) {
Handle
<
Value
>
Statement
::
FetchAll
(
const
Arguments
&
args
)
{
Handle
<
Value
>
Statement
::
FetchAll
(
const
Arguments
&
args
)
{
HandleScope
scope
;
HandleScope
scope
;
REQ
_FUN_ARG
(
0
,
cb
);
REQ
UIRE_ARGUMENT_FUNCTION
(
0
,
cb
);
struct
fetchall_request
*
fetchall_req
=
(
struct
fetchall_request
*
)
struct
fetchall_request
*
fetchall_req
=
(
struct
fetchall_request
*
)
calloc
(
1
,
sizeof
(
struct
fetchall_request
));
calloc
(
1
,
sizeof
(
struct
fetchall_request
));
...
...
test/blob.test.js
View file @
db72749d
...
@@ -14,11 +14,10 @@ exports['Blob overflow test'] = function(beforeExit) {
...
@@ -14,11 +14,10 @@ exports['Blob overflow test'] = function(beforeExit) {
var
inserted
=
0
;
var
inserted
=
0
;
var
retrieved
=
0
;
var
retrieved
=
0
;
db
.
openSync
(
''
);
Step
(
Step
(
function
()
{
function
()
{
db
.
open
(
''
,
this
);
},
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
.
isUndefined
(
err
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment