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
f89fa7e3
Commit
f89fa7e3
authored
Jul 04, 2010
by
Orlando Vazquez
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rename the Sqlite3Db class to Database, and move it to its own file
parent
f7cb2ad2
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
52 additions
and
485 deletions
+52
-485
README.md
README.md
+2
-4
sqlite3_bindings.cc
src/sqlite3_bindings.cc
+2
-424
sqlite3_bindings.h
src/sqlite3_bindings.h
+0
-8
statement.h
src/statement.h
+47
-48
wscript
wscript
+1
-1
No files found.
README.md
View file @
f89fa7e3
...
...
@@ -131,8 +131,8 @@ Ryan Dahl [ry@tinyclouds.org]
THANKS
------
Many thanks to Eric Fredricksen for his synchronous driver on which this
was
based.
Many thanks to Eric Fredricksen for his synchronous driver on which this
driver was originally
based.
*
http://github.com/grumdrig/node-sqlite/
*
http://grumdrig.com/node-sqlite/
...
...
@@ -142,6 +142,4 @@ LICENSE
node-sqlite is BSD licensed.
(c) 2010 Eric Fredricksen
(c) 2010 Orlando Vazquez
src/sqlite3_bindings.cc
View file @
f89fa7e3
...
...
@@ -14,436 +14,14 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <v8.h>
#include <node.h>
#include <node_events.h>
#include <sqlite3.h>
#include "sqlite3_bindings.h"
#include "statement.h"
using
namespace
v8
;
using
namespace
node
;
// static Persistent<String> callback_sym;
class
Sqlite3Db
:
public
EventEmitter
{
public
:
static
Persistent
<
FunctionTemplate
>
constructor_template
;
static
void
Init
(
v8
::
Handle
<
Object
>
target
)
{
HandleScope
scope
;
Local
<
FunctionTemplate
>
t
=
FunctionTemplate
::
New
(
New
);
constructor_template
=
Persistent
<
FunctionTemplate
>::
New
(
t
);
constructor_template
->
Inherit
(
EventEmitter
::
constructor_template
);
constructor_template
->
InstanceTemplate
()
->
SetInternalFieldCount
(
1
);
constructor_template
->
SetClassName
(
String
::
NewSymbol
(
"Database"
));
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"open"
,
Open
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"close"
,
Close
);
NODE_SET_PROTOTYPE_METHOD
(
constructor_template
,
"prepare"
,
Prepare
);
// NODE_SET_PROTOTYPE_METHOD(constructor_template, "changes", Changes);
// NODE_SET_PROTOTYPE_METHOD(constructor_template, "lastInsertRowid", LastInsertRowid);
target
->
Set
(
v8
::
String
::
NewSymbol
(
"Database"
),
constructor_template
->
GetFunction
());
// insert/update execution result mask
NODE_DEFINE_CONSTANT
(
target
,
EXEC_EMPTY
);
NODE_DEFINE_CONSTANT
(
target
,
EXEC_LAST_INSERT_ID
);
NODE_DEFINE_CONSTANT
(
target
,
EXEC_AFFECTED_ROWS
);
Statement
::
Init
(
target
);
}
protected
:
Sqlite3Db
()
:
EventEmitter
(),
db_
(
NULL
)
{
}
~
Sqlite3Db
()
{
assert
(
db_
==
NULL
);
}
sqlite3
*
db_
;
// Return a pointer to the Sqlite handle pointer so that EIO_Open can
// pass it to sqlite3_open which wants a pointer to an sqlite3 pointer. This
// is because it wants to initialize our original (sqlite3*) pointer to
// point to an valid object.
sqlite3
**
GetDBPtr
(
void
)
{
return
&
db_
;
}
protected
:
static
Handle
<
Value
>
New
(
const
Arguments
&
args
)
{
HandleScope
scope
;
Sqlite3Db
*
dbo
=
new
Sqlite3Db
();
dbo
->
Wrap
(
args
.
This
());
return
args
.
This
();
}
// To pass arguments to the functions that will run in the thread-pool we
// have to pack them into a struct and pass eio_custom a pointer to it.
struct
open_request
{
Persistent
<
Function
>
cb
;
Sqlite3Db
*
dbo
;
char
filename
[
1
];
};
static
int
EIO_AfterOpen
(
eio_req
*
req
)
{
ev_unref
(
EV_DEFAULT_UC
);
HandleScope
scope
;
struct
open_request
*
open_req
=
(
struct
open_request
*
)(
req
->
data
);
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
->
dbo
->
Unref
();
open_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
err
?
1
:
0
,
argv
);
if
(
try_catch
.
HasCaught
())
{
FatalException
(
try_catch
);
}
open_req
->
dbo
->
Emit
(
String
::
New
(
"ready"
),
0
,
NULL
);
open_req
->
cb
.
Dispose
();
free
(
open_req
);
return
0
;
}
static
int
EIO_Open
(
eio_req
*
req
)
{
struct
open_request
*
open_req
=
(
struct
open_request
*
)(
req
->
data
);
sqlite3
**
dbptr
=
open_req
->
dbo
->
GetDBPtr
();
int
rc
=
sqlite3_open_v2
(
open_req
->
filename
,
dbptr
,
SQLITE_OPEN_READWRITE
|
SQLITE_OPEN_CREATE
|
SQLITE_OPEN_FULLMUTEX
,
NULL
);
req
->
result
=
rc
;
// sqlite3 *db = *dbptr;
// sqlite3_commit_hook(db, CommitHook, open_req->dbo);
// sqlite3_rollback_hook(db, RollbackHook, open_req->dbo);
// sqlite3_update_hook(db, UpdateHook, open_req->dbo);
return
0
;
}
static
Handle
<
Value
>
Open
(
const
Arguments
&
args
)
{
HandleScope
scope
;
REQ_STR_ARG
(
0
,
filename
);
REQ_FUN_ARG
(
1
,
cb
);
Sqlite3Db
*
dbo
=
ObjectWrap
::
Unwrap
<
Sqlite3Db
>
(
args
.
This
());
struct
open_request
*
open_req
=
(
struct
open_request
*
)
calloc
(
1
,
sizeof
(
struct
open_request
)
+
filename
.
length
());
if
(
!
open_req
)
{
V8
::
LowMemoryNotification
();
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Could not allocate enough memory"
)));
}
strcpy
(
open_req
->
filename
,
*
filename
);
open_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
open_req
->
dbo
=
dbo
;
eio_custom
(
EIO_Open
,
EIO_PRI_DEFAULT
,
EIO_AfterOpen
,
open_req
);
ev_ref
(
EV_DEFAULT_UC
);
dbo
->
Ref
();
return
Undefined
();
}
//
// JS DatabaseSync bindings
//
// TODO: libeio'fy
static
Handle
<
Value
>
Changes
(
const
Arguments
&
args
)
{
HandleScope
scope
;
Sqlite3Db
*
dbo
=
ObjectWrap
::
Unwrap
<
Sqlite3Db
>
(
args
.
This
());
Local
<
Number
>
result
=
Integer
::
New
(
sqlite3_changes
(
dbo
->
db_
));
return
scope
.
Close
(
result
);
}
struct
close_request
{
Persistent
<
Function
>
cb
;
Sqlite3Db
*
dbo
;
};
static
int
EIO_AfterClose
(
eio_req
*
req
)
{
ev_unref
(
EV_DEFAULT_UC
);
HandleScope
scope
;
struct
close_request
*
close_req
=
(
struct
close_request
*
)(
req
->
data
);
Local
<
Value
>
argv
[
1
];
bool
err
=
false
;
if
(
req
->
result
)
{
err
=
true
;
argv
[
0
]
=
Exception
::
Error
(
String
::
New
(
"Error closing database"
));
}
TryCatch
try_catch
;
close_req
->
dbo
->
Unref
();
close_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
err
?
1
:
0
,
argv
);
if
(
try_catch
.
HasCaught
())
{
FatalException
(
try_catch
);
}
close_req
->
cb
.
Dispose
();
free
(
close_req
);
return
0
;
}
static
int
EIO_Close
(
eio_req
*
req
)
{
struct
close_request
*
close_req
=
(
struct
close_request
*
)(
req
->
data
);
Sqlite3Db
*
dbo
=
close_req
->
dbo
;
req
->
result
=
sqlite3_close
(
dbo
->
db_
);
dbo
->
db_
=
NULL
;
return
0
;
}
static
Handle
<
Value
>
Close
(
const
Arguments
&
args
)
{
HandleScope
scope
;
REQ_FUN_ARG
(
0
,
cb
);
Sqlite3Db
*
dbo
=
ObjectWrap
::
Unwrap
<
Sqlite3Db
>
(
args
.
This
());
struct
close_request
*
close_req
=
(
struct
close_request
*
)
calloc
(
1
,
sizeof
(
struct
close_request
));
if
(
!
close_req
)
{
V8
::
LowMemoryNotification
();
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Could not allocate enough memory"
)));
}
close_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
close_req
->
dbo
=
dbo
;
eio_custom
(
EIO_Close
,
EIO_PRI_DEFAULT
,
EIO_AfterClose
,
close_req
);
ev_ref
(
EV_DEFAULT_UC
);
dbo
->
Ref
();
return
Undefined
();
}
// TODO: libeio'fy
static
Handle
<
Value
>
LastInsertRowid
(
const
Arguments
&
args
)
{
HandleScope
scope
;
Sqlite3Db
*
dbo
=
ObjectWrap
::
Unwrap
<
Sqlite3Db
>
(
args
.
This
());
Local
<
Number
>
result
=
Integer
::
New
(
sqlite3_last_insert_rowid
(
dbo
->
db_
));
return
scope
.
Close
(
result
);
};
// Hooks
// static int CommitHook(void* v_this) {
// HandleScope scope;
// Sqlite3Db* db = static_cast<Sqlite3Db*>(v_this);
// db->Emit(String::New("commit"), 0, NULL);
// // TODO: allow change in return value to convert to rollback...somehow
// return 0;
// }
//
// static void RollbackHook(void* v_this) {
// HandleScope scope;
// Sqlite3Db* db = static_cast<Sqlite3Db*>(v_this);
// db->Emit(String::New("rollback"), 0, NULL);
// }
//
// static void UpdateHook(void* v_this, int operation, const char* database,
// const char* table, sqlite_int64 rowid) {
// HandleScope scope;
// Sqlite3Db* db = static_cast<Sqlite3Db*>(v_this);
// Local<Value> args[] = { Int32::New(operation), String::New(database),
// String::New(table), Number::New(rowid) };
// db->Emit(String::New("update"), 4, args);
// }
struct
prepare_request
{
Persistent
<
Function
>
cb
;
Sqlite3Db
*
dbo
;
sqlite3_stmt
*
stmt
;
int
mode
;
sqlite3_int64
lastInsertId
;
int
affectedRows
;
const
char
*
tail
;
char
sql
[
1
];
};
static
int
EIO_AfterPrepare
(
eio_req
*
req
)
{
ev_unref
(
EV_DEFAULT_UC
);
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)(
req
->
data
);
HandleScope
scope
;
Local
<
Value
>
argv
[
2
];
int
argc
=
0
;
// if the prepare failed
if
(
req
->
result
!=
SQLITE_OK
)
{
argv
[
0
]
=
Exception
::
Error
(
String
::
New
(
sqlite3_errmsg
(
prep_req
->
dbo
->
db_
)));
argc
=
1
;
}
else
{
if
(
req
->
int1
==
SQLITE_DONE
)
{
if
(
prep_req
->
mode
!=
EXEC_EMPTY
)
{
argv
[
0
]
=
Local
<
Value
>::
New
(
Undefined
());
// no error
Local
<
Object
>
info
=
Object
::
New
();
if
(
prep_req
->
mode
&
EXEC_LAST_INSERT_ID
)
{
info
->
Set
(
String
::
NewSymbol
(
"last_inserted_id"
),
Integer
::
NewFromUnsigned
(
prep_req
->
lastInsertId
));
}
if
(
prep_req
->
mode
&
EXEC_AFFECTED_ROWS
)
{
info
->
Set
(
String
::
NewSymbol
(
"affected_rows"
),
Integer
::
New
(
prep_req
->
affectedRows
));
}
argv
[
1
]
=
info
;
argc
=
2
;
}
else
{
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
;
}
}
TryCatch
try_catch
;
prep_req
->
dbo
->
Unref
();
prep_req
->
cb
->
Call
(
Context
::
GetCurrent
()
->
Global
(),
argc
,
argv
);
if
(
try_catch
.
HasCaught
())
{
FatalException
(
try_catch
);
}
prep_req
->
cb
.
Dispose
();
free
(
prep_req
);
return
0
;
}
static
int
EIO_Prepare
(
eio_req
*
req
)
{
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)(
req
->
data
);
prep_req
->
stmt
=
NULL
;
prep_req
->
tail
=
NULL
;
sqlite3
*
db
=
prep_req
->
dbo
->
db_
;
int
rc
=
sqlite3_prepare_v2
(
db
,
prep_req
->
sql
,
-
1
,
&
(
prep_req
->
stmt
),
&
(
prep_req
->
tail
));
req
->
result
=
rc
;
req
->
int1
=
-
1
;
// 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
// possible in the case where there are no variable placeholders/bindings
// in the SQL.
if
(
rc
==
SQLITE_OK
&&
!
sqlite3_bind_parameter_count
(
prep_req
->
stmt
))
{
rc
=
sqlite3_step
(
prep_req
->
stmt
);
req
->
int1
=
rc
;
// no more rows to return, clean up statement
if
(
rc
==
SQLITE_DONE
)
{
rc
=
sqlite3_finalize
(
prep_req
->
stmt
);
prep_req
->
stmt
=
NULL
;
assert
(
rc
==
SQLITE_OK
);
}
}
prep_req
->
lastInsertId
=
0
;
prep_req
->
affectedRows
=
0
;
// load custom properties
if
(
prep_req
->
mode
&
EXEC_LAST_INSERT_ID
)
prep_req
->
lastInsertId
=
sqlite3_last_insert_rowid
(
db
);
if
(
prep_req
->
mode
&
EXEC_AFFECTED_ROWS
)
prep_req
->
affectedRows
=
sqlite3_changes
(
db
);
return
0
;
}
static
Handle
<
Value
>
Prepare
(
const
Arguments
&
args
)
{
HandleScope
scope
;
REQ_STR_ARG
(
0
,
sql
);
REQ_FUN_ARG
(
1
,
cb
);
OPT_INT_ARG
(
2
,
mode
,
EXEC_EMPTY
);
Sqlite3Db
*
dbo
=
ObjectWrap
::
Unwrap
<
Sqlite3Db
>
(
args
.
This
());
struct
prepare_request
*
prep_req
=
(
struct
prepare_request
*
)
calloc
(
1
,
sizeof
(
struct
prepare_request
)
+
sql
.
length
());
if
(
!
prep_req
)
{
V8
::
LowMemoryNotification
();
return
ThrowException
(
Exception
::
Error
(
String
::
New
(
"Could not allocate enough memory"
)));
}
strcpy
(
prep_req
->
sql
,
*
sql
);
prep_req
->
cb
=
Persistent
<
Function
>::
New
(
cb
);
prep_req
->
dbo
=
dbo
;
prep_req
->
mode
=
mode
;
eio_custom
(
EIO_Prepare
,
EIO_PRI_DEFAULT
,
EIO_AfterPrepare
,
prep_req
);
ev_ref
(
EV_DEFAULT_UC
);
dbo
->
Ref
();
return
Undefined
();
}
};
Persistent
<
FunctionTemplate
>
Sqlite3Db
::
constructor_template
;
#include "database.h"
extern
"C"
void
init
(
v8
::
Handle
<
Object
>
target
)
{
Sqlite3Db
::
Init
(
target
);
Database
::
Init
(
target
);
}
src/sqlite3_bindings.h
View file @
f89fa7e3
...
...
@@ -58,12 +58,4 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
return ThrowException(Exception::TypeError( \
String::New("Argument " #I " must be an integer"))); \
}
enum
ExecMode
{
EXEC_EMPTY
=
0
,
EXEC_LAST_INSERT_ID
=
1
,
EXEC_AFFECTED_ROWS
=
2
};
#endif
src/statement.h
View file @
f89fa7e3
...
...
@@ -25,62 +25,61 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
using
namespace
v8
;
using
namespace
node
;
class
Statement
:
public
EventEmitter
{
public
:
static
Persistent
<
FunctionTemplate
>
constructor_template
;
static
void
Init
(
v8
::
Handle
<
Object
>
target
);
static
Handle
<
Value
>
New
(
const
Arguments
&
args
);
static
Persistent
<
FunctionTemplate
>
constructor_template
;
static
void
Init
(
v8
::
Handle
<
Object
>
target
);
static
Handle
<
Value
>
New
(
const
Arguments
&
args
);
protected
:
Statement
(
sqlite3_stmt
*
stmt
,
int
first_rc
=
-
1
)
:
EventEmitter
(),
first_rc_
(
first_rc
),
stmt_
(
stmt
)
{
column_count_
=
-
1
;
column_types_
=
NULL
;
column_names_
=
NULL
;
column_data_
=
NULL
;
}
~
Statement
()
{
if
(
stmt_
)
sqlite3_finalize
(
stmt_
);
if
(
column_types_
)
free
(
column_types_
);
if
(
column_names_
)
free
(
column_names_
);
if
(
column_data_
)
FreeColumnData
();
}
static
int
EIO_AfterBind
(
eio_req
*
req
);
static
int
EIO_Bind
(
eio_req
*
req
);
static
Handle
<
Value
>
Bind
(
const
Arguments
&
args
);
static
int
EIO_AfterFinalize
(
eio_req
*
req
);
static
int
EIO_Finalize
(
eio_req
*
req
);
static
Handle
<
Value
>
Finalize
(
const
Arguments
&
args
);
static
Handle
<
Value
>
Reset
(
const
Arguments
&
args
);
static
int
EIO_AfterStep
(
eio_req
*
req
);
static
int
EIO_Step
(
eio_req
*
req
);
static
Handle
<
Value
>
Step
(
const
Arguments
&
args
);
void
FreeColumnData
(
void
);
bool
HasCallback
();
void
SetCallback
(
Local
<
Function
>
cb
);
Local
<
Function
>
GetCallback
();
Statement
(
sqlite3_stmt
*
stmt
,
int
first_rc
=
-
1
)
:
EventEmitter
(),
first_rc_
(
first_rc
),
stmt_
(
stmt
)
{
column_count_
=
-
1
;
column_types_
=
NULL
;
column_names_
=
NULL
;
column_data_
=
NULL
;
}
~
Statement
()
{
if
(
stmt_
)
sqlite3_finalize
(
stmt_
);
if
(
column_types_
)
free
(
column_types_
);
if
(
column_names_
)
free
(
column_names_
);
if
(
column_data_
)
FreeColumnData
();
}
static
int
EIO_AfterBind
(
eio_req
*
req
);
static
int
EIO_Bind
(
eio_req
*
req
);
static
Handle
<
Value
>
Bind
(
const
Arguments
&
args
);
static
int
EIO_AfterFinalize
(
eio_req
*
req
);
static
int
EIO_Finalize
(
eio_req
*
req
);
static
Handle
<
Value
>
Finalize
(
const
Arguments
&
args
);
static
Handle
<
Value
>
Reset
(
const
Arguments
&
args
);
static
int
EIO_AfterStep
(
eio_req
*
req
);
static
int
EIO_Step
(
eio_req
*
req
);
static
Handle
<
Value
>
Step
(
const
Arguments
&
args
);
void
FreeColumnData
(
void
);
bool
HasCallback
();
void
SetCallback
(
Local
<
Function
>
cb
);
Local
<
Function
>
GetCallback
();
private
:
int
column_count_
;
int
*
column_types_
;
char
**
column_names_
;
void
**
column_data_
;
bool
error_
;
int
first_rc_
;
sqlite3_stmt
*
stmt_
;
int
column_count_
;
int
*
column_types_
;
char
**
column_names_
;
void
**
column_data_
;
bool
error_
;
int
first_rc_
;
sqlite3_stmt
*
stmt_
;
};
// indicates the key type (integer index or name string)
...
...
wscript
View file @
f89fa7e3
...
...
@@ -24,7 +24,7 @@ def build(bld):
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"]
obj.target = "sqlite3_bindings"
obj.source = "src/sqlite3_bindings.cc src/statement.cc"
obj.source = "src/sqlite3_bindings.cc src/
database.cc src/
statement.cc"
obj.uselib = "SQLITE3 PROFILER"
t = 'sqlite3_bindings.node'
...
...
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