Commit eaf72f23 by Konstantin Käfer

saving work

parent c09549d0
...@@ -16,273 +16,22 @@ ...@@ -16,273 +16,22 @@
var sqlite3 = module.exports = exports = require('./sqlite3_bindings'); var sqlite3 = module.exports = exports = require('./sqlite3_bindings');
var sys = require("sys"); var sys = require("sys");
function noop(err) { // function noop(err) {
if (err) throw err; // if (err) throw err;
};
var Database = sqlite3.Database;
// var realClose = Database.prototype.close;
// sqlite3.Database.prototype.close = function(callback) {
// if (this.status === sqlite3.STATUS_IDLE) {
// return realClose.call(this, callback);
// } else {
// this.once('idle', function() {
// realClose.call(this, callback);
// });
// }
// }; // };
// var realClose = sqlite3.Database.prototype.close; var Database = sqlite3.Database;
// sqlite3.Database.prototype.close = function() { var Statement = sqlite3.Statement;
// var db = this;
// process.nextTick(function() {
// if (!db.idle) {
// db.on('idle', function fn() {
// realClose.call(db);
// db.removeListener('idle', fn);
// });
// } else {
// realClose.call(db);
// }
// });
// return this;
// };
/*
sqlite3.Database.prototype.query = function(sql, bindings, rowCallback) {
var self = this;
if (typeof(bindings) == "function") {
rowCallback = bindings;
bindings = undefined;
}
this.prepare(sql, function(error, statement) {
function next() {
_doStep(self, statement, rowCallback);
}
if (error) {
return rowCallback (error);
}
if (statement) {
if (Array.isArray(bindings)) {
statement.bindArray(bindings, next);
}
else if (typeof(bindings) === 'object') {
statement.bindObject(bindings, next);
}
else {
next();
}
}
else {
rowCallback();
}
});
}
function _doStep(db, statement, rowCallback) {
statement.step(function (error, row) {
if (error) {
return rowCallback(error);
}
if (!row) {
rowCallback();
statement.finalize(function(){});
return;
}
rowCallback(undefined, row);
_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 ) {
var self = this;
var bindings, callback;
var n = arguments.length;
switch (n) {
case 3:
callback = arguments[2];
bindings = arguments[1];
break;
case 2:
callback = arguments[1];
break;
default: throw new Error("Invalid number of arguments ("+n+")");
}
self.prepare(sql, function (error, statement) { // Database#prepare(sql, [bind1, bind2, ...], [callback])
function next (error) { Database.prototype.prepare = function(sql) {
if (error) return callback(new Error("Error binding: " + error.toString())); var callback, params = Array.prototype.slice.call(arguments, 1);
fetchAll(statement);
}
if (error) { if (params.length && typeof params[params.length - 1] === 'function') {
return callback(error); callback = params.pop();
} }
if (bindings) {
if (Array.isArray(bindings)) {
statement.bindArray(bindings, next);
}
else if (typeof(bindings) === 'object') {
statement.bindObject(bindings, next);
}
}
else {
next();
}
function fetchAll(statement) {
statement.fetchAll(function (error, rows) {
if (error) {
return callback(error);
}
statement.finalize(function () {
callback(undefined, rows);
});
});
}
});
}
// Execute SQL statements separated by semi-colons.
// SQL must contain no placeholders. Results are discarded.
sqlite3.Database.prototype.executeScript = function (script, callback) {
var self = this;
(function stepOverSQL(sql) {
self.prepare(sql, function(error, statement) {
if (error) {
return callback(error);
}
statement.step(function (error, row) {
var tail;
if (error) {
callback(error);
return;
}
if (!row) {
statement.finalize(function(){});
tail = statement.tail;
if (typeof tail == "string") {
tail = tail.trim();
}
if (tail) {
stepOverSQL(tail);
}
else {
callback();
}
}
});
});
})(script);
}
sqlite3.Database.prototype.insertMany = function (table, columns, rows, callback) { return new Statement(this, sql, params, callback);
var columnsFragment = columns.join(",");
var placeholdersFragment = [];
var i = columns.length;
if (!rows.length) {
callback();
return;
}
while (i--) {
placeholdersFragment.push('?');
}
placeholdersFragment = placeholdersFragment.join(", ");
var sql = [ 'INSERT INTO'
, table
, '('
, columnsFragment
, ')'
, 'VALUES'
, '('
, placeholdersFragment
, ')'
]
.join(" ");
var i = rows.length;
var statement;
function doStep(i) {
statement.bindArray(rows[i], function () {
statement.step(function (error, row) {
if (error) return callback(error);
statement.reset();
if (i) {
doStep(--i);
}
else {
statement.finalize(function () {
callback();
});
}
});
});
}
this.prepare(sql, function (error, stmt) {
if (error) return callback(error);
statement = stmt;
doStep(--i);
});
}
sqlite3.fromErrorCode = function(code) {
switch (code) {
case 0: return "SQLITE_OK";
case 1: return "SQLITE_ERROR";
case 2: return "SQLITE_INTERNAL";
case 3: return "SQLITE_PERM";
case 4: return "SQLITE_ABORT";
case 5: return "SQLITE_BUSY";
case 6: return "SQLITE_LOCKED";
case 7: return "SQLITE_NOMEM";
case 8: return "SQLITE_READONLY";
case 9: return "SQLITE_INTERRUPT";
case 10: return "SQLITE_IOERR";
case 11: return "SQLITE_CORRUPT";
case 12: return "SQLITE_NOTFOUND";
case 13: return "SQLITE_FULL";
case 14: return "SQLITE_CANTOPEN";
case 15: return "SQLITE_PROTOCOL";
case 16: return "SQLITE_EMPTY";
case 17: return "SQLITE_SCHEMA";
case 18: return "SQLITE_TOOBIG";
case 19: return "SQLITE_CONSTRAINT";
case 20: return "SQLITE_MISMATCH";
case 21: return "SQLITE_MISUSE";
case 22: return "SQLITE_NOLFS";
case 23: return "SQLITE_AUTH";
case 24: return "SQLITE_FORMAT";
case 25: return "SQLITE_RANGE";
case 26: return "SQLITE_NOTADB";
}
}; };
sqlite3.sanitizeError = function(err, data) {
err.message = exports.fromErrorCode(err.errno) + ', ' + err.message +
' in query "' + err.query +
'" with values ' + JSON.stringify(data, false, 4);
return err;
};
*/
\ No newline at end of file
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
#include <node.h> #include <node.h>
#include <node_events.h> #include <node_events.h>
#include "deferred_call.h"
#include <string> #include <string>
#include <queue> #include <queue>
...@@ -29,34 +27,52 @@ ...@@ -29,34 +27,52 @@
using namespace v8; using namespace v8;
using namespace node; using namespace node;
class Database;
static struct Baton {
Database* db;
Persistent<Function> callback;
int status;
std::string message;
~Baton() {
callback.Dispose();
}
};
static struct OpenBaton : Baton {
std::string filename;
int mode;
};
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);
static enum Status { static inline bool HasInstance(Handle<Value> val) {
IsClosed = 1 << 0, if (!val->IsObject()) return false;
IsOpening = 1 << 1, Local<Object> obj = val->ToObject();
IsOpen = 1 << 2, return constructor_template->HasInstance(obj);
IsClosing = 1 << 3, }
DoesntMatter = IsClosed | IsOpening | IsOpen | IsClosing
};
typedef Deferred::Call<Status> Call; typedef void (*EIO_Callback)(Baton* baton);
struct Baton { struct Call {
Baton(Database* db_, Persistent<Function> callback_) : Call(EIO_Callback callback_, Baton* baton_, bool exclusive_ = false) :
db(db_), callback(callback_) {}; callback(callback_), exclusive(exclusive_), baton(baton_) {};
Database* db; EIO_Callback callback;
Persistent<Function> callback; bool exclusive;
Baton* baton;
}; };
friend class Statement;
protected: protected:
Database() : EventEmitter(), Database() : EventEmitter(),
handle(NULL), handle(NULL),
pending(0), open(false),
status(IsClosed) { locked(false),
pending(0) {
} }
...@@ -65,64 +81,32 @@ class Database : public EventEmitter { ...@@ -65,64 +81,32 @@ class Database : public EventEmitter {
} }
static Handle<Value> New(const Arguments& args); static Handle<Value> New(const Arguments& args);
static void EIO_BeginOpen(Baton* baton);
static void ProcessQueue(Database* db);
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_Open(eio_req *req);
static int EIO_AfterOpen(eio_req *req); static int EIO_AfterOpen(eio_req *req);
static Handle<Value> CloseSync(const Arguments& args); static void Schedule(Database* db, EIO_Callback callback, Baton* baton,
bool exclusive);
static void Process(Database* db);
static Handle<Value> Close(const Arguments& args); static Handle<Value> Close(const Arguments& args);
static bool Close(Database* db); static void EIO_BeginClose(Baton* baton);
static int EIO_Close(eio_req *req); static int EIO_Close(eio_req *req);
static int EIO_AfterClose(eio_req *req); static int EIO_AfterClose(eio_req *req);
static int EIO_AfterPrepareAndStep(eio_req *req);
static int EIO_PrepareAndStep(eio_req *req);
static Handle<Value> PrepareAndStep(const Arguments& args);
static int EIO_AfterPrepare(eio_req *req);
static int EIO_Prepare(eio_req *req);
static Handle<Value> Prepare(const Arguments& args);
void Wrap (Handle<Object> handle); void Wrap (Handle<Object> handle);
static void Destruct (Persistent<Value> value, void *data); static void Destruct (Persistent<Value> value, void *data);
static int EIO_Destruct(eio_req *req); static int EIO_Destruct(eio_req *req);
static int EIO_AfterDestruct(eio_req *req); static int EIO_AfterDestruct(eio_req *req);
protected: protected:
sqlite3* handle; sqlite3* handle;
std::string filename;
int open_mode;
std::string error_message; bool open;
int error_status; bool locked;
unsigned int pending;
int pending;
Status status;
std::queue<Call*> queue; std::queue<Call*> queue;
private:
};
enum ExecMode {
EXEC_EMPTY = 0,
EXEC_LAST_INSERT_ID = 1,
EXEC_AFFECTED_ROWS = 2
};
struct prepare_request {
Persistent<Function> cb;
Database *db;
sqlite3_stmt* stmt;
int mode;
sqlite3_int64 lastInsertId;
int affectedRows;
const char* tail;
char sql[1];
}; };
#endif #endif
...@@ -121,7 +121,7 @@ const char* sqlite_code_string(int code); ...@@ -121,7 +121,7 @@ const char* sqlite_code_string(int code);
String::NewSymbol(sqlite_code_string(errno)), \ String::NewSymbol(sqlite_code_string(errno)), \
String::NewSymbol(": ") \ String::NewSymbol(": ") \
), \ ), \
String::New(msg) \ (msg) \
) \ ) \
); \ ); \
Local<Object> name ##_obj = name->ToObject(); \ Local<Object> name ##_obj = name->ToObject(); \
...@@ -129,30 +129,19 @@ const char* sqlite_code_string(int code); ...@@ -129,30 +129,19 @@ const char* sqlite_code_string(int code);
name ##_obj->Set(NODE_PSYMBOL("code"), \ name ##_obj->Set(NODE_PSYMBOL("code"), \
String::NewSymbol(sqlite_code_string(errno))); String::NewSymbol(sqlite_code_string(errno)));
#define EVENT_ONCE(event, callback) \
Local<Value> argv[2] = { \ #define EMIT_EVENT(obj, argc, argv) \
String::NewSymbol(event), \ TRY_CATCH_CALL((obj), \
args.This()->Get(String::NewSymbol(callback)) \ Local<Function>::Cast((obj)->Get(String::NewSymbol("emit"))), \
}; \ argc, argv \
v8::Local<v8::Value> fn_val = args.This()->Get(String::NewSymbol("once")); \ );
Local<Function> fn = Local<Function>::Cast(fn_val); \
fn->Call(args.This(), 2, argv);
#define SET_STRING(sym, str) \
Set(String::NewSymbol(#sym), String::New(str), ReadOnly)
#define SET_INTEGER(sym, i) \
Set(String::NewSymbol(#sym), Integer::New(i), ReadOnly)
#define TRY_CATCH_CALL(context, callback, argc, argv) \ #define TRY_CATCH_CALL(context, callback, argc, argv) \
{ \ { TryCatch try_catch; \
TryCatch try_catch; \
(callback)->Call((context), (argc), (argv)); \ (callback)->Call((context), (argc), (argv)); \
if (try_catch.HasCaught()) { \ if (try_catch.HasCaught()) { \
FatalException(try_catch); \ FatalException(try_catch); \
} \ } }
}
#endif #endif
// 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
...@@ -18,139 +18,50 @@ ...@@ -18,139 +18,50 @@
#include <v8.h> #include <v8.h>
#include <node.h> #include <node.h>
#include <node_events.h> #include <node_events.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <node_buffer.h>
extern "C" { #include "database.h"
#include <mpool.h>
}; #include <string>
#include <queue>
#include <sqlite3.h>
using namespace v8; using namespace v8;
using namespace node; using namespace node;
struct cell_node { class Statement;
void *value;
int type;
struct cell_node *next;
int size;
};
struct row_node { static struct PrepareBaton : Baton {
struct cell_node *cells; Statement* stmt;
struct row_node *next; std::string sql;
}; };
// represent strings with this struct
struct string_t {
size_t bytes;
char data[];
};
class Statement : public EventEmitter { class Statement : public EventEmitter {
public: public:
static Persistent<FunctionTemplate> constructor_template; static Persistent<FunctionTemplate> constructor_template;
static void Init(v8::Handle<Object> target); static void Init(Handle<Object> target);
static Handle<Value> New(const Arguments& args); static Handle<Value> New(const Arguments& args);
protected: Statement(Database* db_) : EventEmitter() {
db = db_;
Statement(sqlite3_stmt* stmt, int first_rc = -1, int mode = 0) db->Ref();
: EventEmitter(), first_rc_(first_rc), mode_(mode), stmt_(stmt) {
column_count_ = -1;
column_names_ = NULL;
} }
~Statement() { ~Statement() {
if (stmt_) sqlite3_finalize(stmt_); db->Unref();
if (column_names_) FreeColumnData();
} }
static Handle<Value> Bind(const Arguments &args); protected:
static Handle<Value> BindObject(const Arguments &args); static void EIO_BeginPrepare(Baton* baton);
static Handle<Value> BindArray(const Arguments &args); static int EIO_Prepare(eio_req *req);
static int EIO_BindArray(eio_req *req); static int EIO_AfterPrepare(eio_req *req);
static int EIO_AfterBindArray(eio_req *req);
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 Handle<Value> ClearBindings(const Arguments &args);
static int EIO_AfterStep(eio_req *req);
static int EIO_Step(eio_req *req);
static Handle<Value> Step(const Arguments &args);
static int EIO_AfterFetchAll(eio_req *req);
static int EIO_FetchAll(eio_req *req);
static Handle<Value> FetchAll(const Arguments &args);
void InitializeColumns(void);
void FreeColumnData(void);
bool HasCallback();
void SetCallback(Local<Function> cb);
Local<Function> GetCallback(); private:
Database* db;
private:
int column_count_;
char **column_names_;
int error_;
Local<String> error_msg_;
int first_rc_;
int mode_;
sqlite3_stmt* stmt_;
// for statment.step
cell_node *cells;
};
// indicates the key type (integer index or name string)
enum BindKeyType {
KEY_INT,
KEY_STRING
};
// indicate the parameter type
enum BindValueType {
VALUE_INT,
VALUE_DOUBLE,
VALUE_BLOB,
VALUE_STRING,
VALUE_NULL
};
struct bind_request {
Persistent<Function> cb;
Statement *sto;
struct bind_pair *pairs;
size_t len;
};
struct bind_pair {
enum BindKeyType key_type;
enum BindValueType value_type;
void *key; // char * | int *
void *value; // char * | int * | double * | 0
size_t value_size;
};
struct fetchall_request { sqlite3_stmt* handle;
Persistent<Function> cb;
Statement *sto;
mpool_t *pool;
char *error;
struct row_node *rows;
}; };
#endif #endif
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