Commit db72749d by Konstantin Käfer

unify indentation and rework database opening, closing and garbage collection

parent 493050a9
......@@ -16,6 +16,9 @@
var sqlite3 = module.exports = exports = require('./sqlite3_bindings');
var sys = require("sys");
/*
sqlite3.Database.prototype.query = function(sql, bindings, rowCallback) {
var self = this;
......@@ -68,7 +71,7 @@ function _doStep(db, statement, rowCallback) {
// Execute a single SQL query with the given optional parameters. Calls
// `callback` with all rows or an error on query completion.
sqlite3.Database.prototype.execute = function (sql /* , bindings, callback */) {
sqlite3.Database.prototype.execute = function (sql /* , bindings, callback ) {
var self = this;
var bindings, callback;
var n = arguments.length;
......@@ -248,3 +251,4 @@ sqlite3.sanitizeError = function(err, data) {
'" with values ' + JSON.stringify(data, false, 4);
return err;
};
*/
\ No newline at end of file
// Copyright (c) 2010, Orlando Vazquez <ovazquez@gmail.com>
//
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
......@@ -19,35 +19,51 @@
#include <node.h>
#include <node_events.h>
#include <string>
#include <sqlite3.h>
using namespace v8;
using namespace node;
enum ReadyState {
CLOSED,
OPENING,
OPEN,
CLOSING
};
class Database : public EventEmitter {
public:
static Persistent<FunctionTemplate> constructor_template;
static void Init(v8::Handle<Object> target);
protected:
Database() : EventEmitter(), db_(NULL) { }
Database() : EventEmitter(),
handle(NULL),
pending(0),
readyState(CLOSED) {
}
~Database() {
assert(db_ == NULL);
printf("Destroying database\n");
fprintf(stderr, "Calling destructor\n");
}
static Handle<Value> New(const Arguments& args);
static int EIO_AfterOpen(eio_req *req);
static int EIO_Open(eio_req *req);
static Handle<Value> OpenSync(const Arguments& args);
static Handle<Value> Open(const Arguments& args);
static bool Open(Database* db);
static int EIO_Open(eio_req *req);
static int EIO_AfterOpen(eio_req *req);
static int EIO_AfterClose(eio_req *req);
static int EIO_Close(eio_req *req);
static Handle<Value> CloseSync(const Arguments& args);
static Handle<Value> Close(const Arguments& args);
static bool Close(Database* db);
static int EIO_Close(eio_req *req);
static int EIO_AfterClose(eio_req *req);
// static Handle<Value> LastInsertRowid(const Arguments& args);
static int EIO_AfterPrepareAndStep(eio_req *req);
static int EIO_PrepareAndStep(eio_req *req);
static Handle<Value> PrepareAndStep(const Arguments& args);
......@@ -56,35 +72,29 @@ class Database : public EventEmitter {
static int EIO_Prepare(eio_req *req);
static Handle<Value> Prepare(const Arguments& args);
// Return a pointer to the Sqlite handle pointer so that EIO_Open can
// pass it to sqlite3_open which wants a pointer to an sqlite3 pointer. This
// is because it wants to initialize our original (sqlite3*) pointer to
// point to an valid object.
sqlite3** GetDBPtr(void) { return &db_; }
void Wrap (Handle<Object> handle);
static void Destruct (Persistent<Value> value, void *data);
static int EIO_Destruct(eio_req *req);
static int EIO_AfterDestruct(eio_req *req);
protected:
sqlite3* handle;
std::string filename;
int open_mode;
std::string error_message;
int error_status;
sqlite3* db_;
int pending;
ReadyState readyState;
};
enum ExecMode
{
enum ExecMode {
EXEC_EMPTY = 0,
EXEC_LAST_INSERT_ID = 1,
EXEC_AFFECTED_ROWS = 2
};
struct open_request {
Persistent<Function> cb;
Database *db;
char filename[1];
};
struct close_request {
Persistent<Function> cb;
Database *db;
};
struct prepare_request {
Persistent<Function> cb;
Database *db;
......
......@@ -15,6 +15,9 @@
#ifndef NODE_SQLITE3_SRC_MACROS_H
#define NODE_SQLITE3_SRC_MACROS_H
const char* sqlite_code_string(int code);
#define CHECK(rc) { if ((rc) != SQLITE_OK) \
return ThrowException(Exception::Error(String::New( \
sqlite3_errmsg(*db)))); }
......@@ -23,37 +26,110 @@
return ThrowException(Exception::Error(String::New( \
sqlite3_errmsg(sqlite3_db_handle(sto->stmt_))))); }
#define REQ_ARGS(N) \
if (args.Length() < (N)) \
return ThrowException(Exception::TypeError( \
String::New("Expected " #N "arguments")));
#define REQ_STR_ARG(I, VAR) \
if (args.Length() <= (I) || !args[I]->IsString()) \
return ThrowException(Exception::TypeError( \
String::New("Argument " #I " must be a string"))); \
String::Utf8Value VAR(args[I]->ToString());
#define REQ_FUN_ARG(I, VAR) \
if (args.Length() <= (I) || !args[I]->IsFunction()) \
return ThrowException(Exception::TypeError( \
String::New("Argument " #I " must be a function"))); \
Local<Function> VAR = Local<Function>::Cast(args[I]);
#define REQ_EXT_ARG(I, VAR) \
if (args.Length() <= (I) || !args[I]->IsExternal()) \
return ThrowException(Exception::TypeError( \
String::New("Argument " #I " invalid"))); \
Local<External> VAR = Local<External>::Cast(args[I]);
#define OPT_INT_ARG(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 REQUIRE_ARGUMENTS(n) \
if (args.Length() < (n)) { \
return ThrowException( \
Exception::TypeError(String::New("Expected " #n "arguments")) \
); \
}
#define REQUIRE_ARGUMENT_EXTERNAL(i, var) \
if (args.Length() <= (i) || !args[i]->IsExternal()) { \
return ThrowException( \
Exception::TypeError(String::New("Argument " #i " invalid")) \
); \
} \
Local<External> var = Local<External>::Cast(args[i]);
#define REQUIRE_ARGUMENT_FUNCTION(i, var) \
if (args.Length() <= (i) || !args[i]->IsFunction()) { \
return ThrowException(Exception::TypeError( \
String::New("Argument " #i " must be a function")) \
); \
} \
Local<Function> var = Local<Function>::Cast(args[i]);
#define REQUIRE_ARGUMENT_STRING(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 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
......@@ -16,11 +16,54 @@
#include <node.h>
#include <node_events.h>
#include <sqlite3.h>
#include "macros.h"
#include "database.h"
#include "statement.h"
extern "C" void init (v8::Handle<Object> target) {
Database::Init(target);
Statement::Init(target);
Database::Init(target);
Statement::Init(target);
DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_READONLY, OPEN_READONLY);
DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_READWRITE, OPEN_READWRITE);
DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_CREATE, OPEN_CREATE);
DEFINE_CONSTANT_STRING(target, SQLITE_VERSION, VERSION);
DEFINE_CONSTANT_INTEGER(target, SQLITE_VERSION_NUMBER, VERSION_NUMBER);
}
const char* sqlite_code_string(int code) {
switch (code) {
case SQLITE_OK: return "SQLITE_OK";
case SQLITE_ERROR: return "SQLITE_ERROR";
case SQLITE_INTERNAL: return "SQLITE_INTERNAL";
case SQLITE_PERM: return "SQLITE_PERM";
case SQLITE_ABORT: return "SQLITE_ABORT";
case SQLITE_BUSY: return "SQLITE_BUSY";
case SQLITE_LOCKED: return "SQLITE_LOCKED";
case SQLITE_NOMEM: return "SQLITE_NOMEM";
case SQLITE_READONLY: return "SQLITE_READONLY";
case SQLITE_INTERRUPT: return "SQLITE_INTERRUPT";
case SQLITE_IOERR: return "SQLITE_IOERR";
case SQLITE_CORRUPT: return "SQLITE_CORRUPT";
case SQLITE_NOTFOUND: return "SQLITE_NOTFOUND";
case SQLITE_FULL: return "SQLITE_FULL";
case SQLITE_CANTOPEN: return "SQLITE_CANTOPEN";
case SQLITE_PROTOCOL: return "SQLITE_PROTOCOL";
case SQLITE_EMPTY: return "SQLITE_EMPTY";
case SQLITE_SCHEMA: return "SQLITE_SCHEMA";
case SQLITE_TOOBIG: return "SQLITE_TOOBIG";
case SQLITE_CONSTRAINT: return "SQLITE_CONSTRAINT";
case SQLITE_MISMATCH: return "SQLITE_MISMATCH";
case SQLITE_MISUSE: return "SQLITE_MISUSE";
case SQLITE_NOLFS: return "SQLITE_NOLFS";
case SQLITE_AUTH: return "SQLITE_AUTH";
case SQLITE_FORMAT: return "SQLITE_FORMAT";
case SQLITE_RANGE: return "SQLITE_RANGE";
case SQLITE_NOTADB: return "SQLITE_NOTADB";
case SQLITE_ROW: return "SQLITE_ROW";
case SQLITE_DONE: return "SQLITE_DONE";
default: return "UNKNOWN";
}
}
......@@ -50,7 +50,7 @@ void Statement::Init(v8::Handle<Object> target) {
Handle<Value> Statement::New(const Arguments& args) {
HandleScope scope;
REQ_EXT_ARG(0, stmt);
REQUIRE_ARGUMENT_EXTERNAL(0, stmt);
int first_rc = args[1]->IntegerValue();
int mode = args[2]->IntegerValue();
......@@ -169,8 +169,8 @@ Handle<Value> Statement::BindObject(const Arguments& args) {
HandleScope scope;
Statement* sto = ObjectWrap::Unwrap<Statement>(args.This());
REQ_ARGS(2);
REQ_FUN_ARG(1, cb);
REQUIRE_ARGUMENTS(2);
REQUIRE_ARGUMENT_FUNCTION(1, cb);
if (! args[0]->IsObject())
return ThrowException(Exception::TypeError(
......@@ -253,8 +253,8 @@ Handle<Value> Statement::BindArray(const Arguments& args) {
HandleScope scope;
Statement* sto = ObjectWrap::Unwrap<Statement>(args.This());
REQ_ARGS(2);
REQ_FUN_ARG(1, cb);
REQUIRE_ARGUMENTS(2);
REQUIRE_ARGUMENT_FUNCTION(1, cb);
if (! args[0]->IsArray())
return ThrowException(Exception::TypeError(
String::New("First argument must be an Array.")));
......@@ -349,8 +349,8 @@ Handle<Value> Statement::Bind(const Arguments& args) {
HandleScope scope;
Statement* sto = ObjectWrap::Unwrap<Statement>(args.This());
REQ_ARGS(2);
REQ_FUN_ARG(2, cb);
REQUIRE_ARGUMENTS(2);
REQUIRE_ARGUMENT_FUNCTION(2, cb);
if (!( args[0]->IsString()
|| args[0]->IsInt32()
......@@ -475,7 +475,7 @@ Handle<Value> Statement::Finalize(const Arguments& args) {
return ThrowException(Exception::Error(String::New("Already stepping")));
}
REQ_FUN_ARG(0, cb);
REQUIRE_ARGUMENT_FUNCTION(0, cb);
sto->SetCallback(cb);
......@@ -740,7 +740,7 @@ Handle<Value> Statement::Step(const Arguments& args) {
return ThrowException(Exception::Error(String::New("Already stepping")));
}
REQ_FUN_ARG(0, cb);
REQUIRE_ARGUMENT_FUNCTION(0, cb);
sto->SetCallback(cb);
......@@ -1011,7 +1011,7 @@ int Statement::EIO_FetchAll(eio_req *req) {
Handle<Value> Statement::FetchAll(const Arguments& args) {
HandleScope scope;
REQ_FUN_ARG(0, cb);
REQUIRE_ARGUMENT_FUNCTION(0, cb);
struct fetchall_request *fetchall_req = (struct fetchall_request *)
calloc(1, sizeof(struct fetchall_request));
......
......@@ -14,11 +14,10 @@ exports['Blob overflow test'] = function(beforeExit) {
var inserted = 0;
var retrieved = 0;
db.openSync('');
Step(
function() {
db.open('', this);
},
function() {
var next = this;
db.prepare('CREATE TABLE elmos (image BLOB);', function(err, statement) {
assert.isUndefined(err);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment