137
137
* @param res Pointer to the drizzled::String object that will contain the result
138
138
* @return a drizzled::String containing the value returned by executed JavaScript code (value of last executed statement)
140
String *JsEvalFunction::val_str(String *str)
140
String *JsEvalFunction::val_str( String *str )
142
assert( fixed == 1 );
143
143
// If we return from any of the error conditions during method, then
144
144
// return value of the drizzle function is null.
145
145
null_value= true;
147
147
String *source_str=NULL;
148
source_str = args[0]->val_str(str);
148
source_str = args[0]->val_str( str );
150
150
// TODO Some of this (ObjectTemplate bindings) should probably be
151
151
// moved to initialize, but then it must be allocated on the heap.
164
164
v8::Handle<v8::ObjectTemplate> db = v8::ObjectTemplate::New();
165
165
v8::Handle<v8::ObjectTemplate> js = v8::ObjectTemplate::New();
166
166
// Bind the 'version' function
167
global->Set(v8::String::New("db"), db);
168
db->Set(v8::String::New("js"), js);
169
js->Set(v8::String::New("version"), v8::FunctionTemplate::New(V8Version));
170
js->Set(v8::String::New("engine"), v8::FunctionTemplate::New(JsEngine));
167
global->Set( v8::String::New("db"), db );
168
db->Set( v8::String::New("js"), js );
169
js->Set( v8::String::New("version"), v8::FunctionTemplate::New(V8Version) );
170
js->Set( v8::String::New("engine"), v8::FunctionTemplate::New(JsEngine) );
172
172
// Now bind the arguments into argv[]
173
173
// v8::Array can only be created when context is already entered (otherwise v8 segfaults!)
174
v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
175
if (context.IsEmpty()) {
174
v8::Persistent<v8::Context> context = v8::Context::New( NULL, global );
175
if ( context.IsEmpty() ) {
176
176
// TODO: how do I set warning/error in the drizzle result?
177
printf("Error in js_eval() while creating JavaScript context in v8.\n");
177
printf( "Error in js_eval() while creating JavaScript context in v8.\n" );
180
180
context->Enter();
182
182
v8::Handle<v8::Array> a = v8::Array::New(arg_count-1);
183
183
for( uint64_t n = 1; n < arg_count; n++ )
185
a->Set(n-1, v8::String::New(args[n]->val_str(str)->c_str()));
185
// Need to do this differently for ints, doubles and strings
186
// TODO: There is also ROW_RESULT. Is that relevant here? What does it look like? I could pass rows as an array or object.
187
if( args[n]->result_type() == INT_RESULT ){
188
if( args[n]->is_unsigned() ) {
189
a->Set( n-1, v8::Integer::NewFromUnsigned( (uint32_t) args[n]->val_uint() ) );
191
a->Set( n-1, v8::Integer::New((int32_t)args[n]->val_int() ) );
193
} else if ( args[n]->result_type() == REAL_RESULT || args[n]->result_type() == DECIMAL_RESULT ) {
194
a->Set( n-1, v8::Number::New(args[n]->val_real() ) );
195
// TODO: Here's a question: Should DECIMAL_RESULT be sent as double or string?
196
// Kind of unusable either way, we'd need to bind some biginteger arithmetic library into the js environment to make them usable
197
} else if ( true || args[n]->result_type() == STRING_RESULT ) {
198
// Default to creating string values in JavaScript
199
a->Set( n-1, v8::String::New(args[n]->val_str(str)->c_str() ) );
201
// If user has given a name to the arguments, pass these as global variables
202
if( ! args[n]->is_autogenerated_name ) {
203
if( args[n]->result_type() == INT_RESULT ){
204
if( args[n]->is_unsigned() ) {
205
context->Global()->Set( v8::String::New(args[n]->name ), v8::Integer::NewFromUnsigned( (uint32_t) args[n]->val_uint() ) );
207
context->Global()->Set( v8::String::New(args[n]->name ), v8::Integer::New((int32_t)args[n]->val_int() ) );
209
} else if ( args[n]->result_type() == REAL_RESULT || args[n]->result_type() == DECIMAL_RESULT ) {
210
context->Global()->Set( v8::String::New(args[n]->name ), v8::Number::New(args[n]->val_real() ) );
211
} else if ( true || args[n]->result_type() == STRING_RESULT ) {
212
context->Global()->Set( v8::String::New(args[n]->name ), v8::String::New(args[n]->val_str(str)->c_str() ) );
187
216
//Need to fetch the global element back from context, global doesn't work anymore
188
context->Global()->Set(v8::String::New("argv"), a);
217
context->Global()->Set( v8::String::New("arguments"), a );
196
225
// Convert from drizzled::String to char* string to v8::String.
197
226
v8::Handle<v8::String> source = v8::String::New(source_str->c_str());
198
227
v8::Handle<v8::Script> script = v8::Script::Compile(source);
199
if (script.IsEmpty()) {
228
if ( script.IsEmpty() ) {
200
229
// TODO: how do I set warning/error in the drizzle result?
201
230
// Print errors that happened during compilation.
202
231
ReportException(&try_catch);
205
234
result = script->Run();
206
if (result.IsEmpty()) {
207
assert(try_catch.HasCaught());
235
if ( result.IsEmpty() ) {
236
assert( try_catch.HasCaught() );
208
237
// TODO: how do I set warning/error in the drizzle result?
209
238
// Print errors that happened during execution.
210
ReportException(&try_catch);
239
ReportException( &try_catch );
211
240
// Dispose of Persistent objects before returning. (Is it needed?)
213
242
context.Dispose();
216
assert(!try_catch.HasCaught());
217
if (result->IsUndefined()) {
218
printf("js_eval() got Undefined result back from v8.\n");
245
assert( !try_catch.HasCaught() );
246
if ( result->IsUndefined() ) {
247
// Nothing wrong here, but we return Undefined as NULL.
219
248
// Dispose of Persistent objects before returning. (Is it needed?)
221
250
context.Dispose();
231
260
// Convert the result to a drizzled::String and print it.
232
261
// Allocate space to the drizzled::String
233
262
str->free(); //TODO: Check the source for alloc(), but apparently I don't need this line?
234
str->alloc(rstring->Utf8Length());
263
str->alloc( rstring->Utf8Length() );
235
264
// Now copy string from v8 heap to drizzled heap
236
rstring->WriteUtf8(str->ptr());
265
rstring->WriteUtf8( str->ptr() );
237
266
// drizzled::String doesn't actually set string length properly in alloc(), so set it now
238
str->length(rstring->Utf8Length());
267
str->length( rstring->Utf8Length() );
241
270
context.Dispose();
251
280
plugin::Create_function<JsEvalFunction> *js_eval_function = NULL;
253
static int initialize(module::Context &context)
282
static int initialize( module::Context &context )
255
js_eval_function = new plugin::Create_function<JsEvalFunction>("js_eval");
256
context.add(js_eval_function);
284
js_eval_function = new plugin::Create_function<JsEvalFunction>( "js_eval" );
285
context.add( js_eval_function );
258
287
v8::V8::Initialize();
263
292
/* v8 related functions ********************************/
265
v8::Handle<v8::Value> V8Version(const v8::Arguments&) {
266
return v8::String::New(v8::V8::GetVersion());
294
v8::Handle<v8::Value> V8Version( const v8::Arguments& ) {
295
return v8::String::New( v8::V8::GetVersion() );
269
v8::Handle<v8::Value> JsEngine(const v8::Arguments&) {
270
return v8::String::New(JS_ENGINE);
298
v8::Handle<v8::Value> JsEngine( const v8::Arguments& ) {
299
return v8::String::New( JS_ENGINE );