class Mysql2::Statement
Public Instance Methods
execute
click to toggle source
Executes the current prepared statement, returns result.
static VALUE execute(int argc, VALUE *argv, VALUE self) {
MYSQL_BIND *bind_buffers = NULL;
unsigned long *length_buffers = NULL;
unsigned long bind_count;
long i;
MYSQL_STMT *stmt;
MYSQL_RES *metadata;
VALUE current;
VALUE resultObj;
VALUE *params_enc;
int is_streaming;
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *conn_enc;
#endif
GET_STATEMENT(self);
GET_CLIENT(stmt_wrapper->client);
#ifdef HAVE_RUBY_ENCODING_H
conn_enc = rb_to_encoding(wrapper->encoding);
#endif
/* Scratch space for string encoding exports, allocate on the stack. */
params_enc = alloca(sizeof(VALUE) * argc);
stmt = stmt_wrapper->stmt;
bind_count = mysql_stmt_param_count(stmt);
if (argc != (long)bind_count) {
rb_raise(cMysql2Error, "Bind parameter count (%ld) doesn't match number of arguments (%d)", bind_count, argc);
}
// setup any bind variables in the query
if (bind_count > 0) {
bind_buffers = xcalloc(bind_count, sizeof(MYSQL_BIND));
length_buffers = xcalloc(bind_count, sizeof(unsigned long));
for (i = 0; i < argc; i++) {
bind_buffers[i].buffer = NULL;
params_enc[i] = Qnil;
switch (TYPE(argv[i])) {
case T_NIL:
bind_buffers[i].buffer_type = MYSQL_TYPE_NULL;
break;
case T_FIXNUM:
#if SIZEOF_INT < SIZEOF_LONG
bind_buffers[i].buffer_type = MYSQL_TYPE_LONGLONG;
bind_buffers[i].buffer = xmalloc(sizeof(long long int));
*(long*)(bind_buffers[i].buffer) = FIX2LONG(argv[i]);
#else
bind_buffers[i].buffer_type = MYSQL_TYPE_LONG;
bind_buffers[i].buffer = xmalloc(sizeof(int));
*(long*)(bind_buffers[i].buffer) = FIX2INT(argv[i]);
#endif
break;
case T_BIGNUM:
bind_buffers[i].buffer_type = MYSQL_TYPE_LONGLONG;
bind_buffers[i].buffer = xmalloc(sizeof(long long int));
*(LONG_LONG*)(bind_buffers[i].buffer) = rb_big2ll(argv[i]);
break;
case T_FLOAT:
bind_buffers[i].buffer_type = MYSQL_TYPE_DOUBLE;
bind_buffers[i].buffer = xmalloc(sizeof(double));
*(double*)(bind_buffers[i].buffer) = NUM2DBL(argv[i]);
break;
case T_STRING:
{
params_enc[i] = argv[i];
#ifdef HAVE_RUBY_ENCODING_H
params_enc[i] = rb_str_export_to_enc(params_enc[i], conn_enc);
#endif
bind_buffers[i].buffer_type = MYSQL_TYPE_STRING;
bind_buffers[i].buffer = RSTRING_PTR(params_enc[i]);
bind_buffers[i].buffer_length = RSTRING_LEN(params_enc[i]);
length_buffers[i] = bind_buffers[i].buffer_length;
bind_buffers[i].length = &length_buffers[i];
}
break;
default:
// TODO: what Ruby type should support MYSQL_TYPE_TIME
if (CLASS_OF(argv[i]) == rb_cTime || CLASS_OF(argv[i]) == cDateTime) {
MYSQL_TIME t;
VALUE rb_time = argv[i];
bind_buffers[i].buffer_type = MYSQL_TYPE_DATETIME;
bind_buffers[i].buffer = xmalloc(sizeof(MYSQL_TIME));
memset(&t, 0, sizeof(MYSQL_TIME));
t.neg = 0;
t.second_part = FIX2INT(rb_funcall(rb_time, intern_usec, 0));
t.second = FIX2INT(rb_funcall(rb_time, intern_sec, 0));
t.minute = FIX2INT(rb_funcall(rb_time, intern_min, 0));
t.hour = FIX2INT(rb_funcall(rb_time, intern_hour, 0));
t.day = FIX2INT(rb_funcall(rb_time, intern_day, 0));
t.month = FIX2INT(rb_funcall(rb_time, intern_month, 0));
t.year = FIX2INT(rb_funcall(rb_time, intern_year, 0));
*(MYSQL_TIME*)(bind_buffers[i].buffer) = t;
} else if (CLASS_OF(argv[i]) == cDate) {
MYSQL_TIME t;
VALUE rb_time = argv[i];
bind_buffers[i].buffer_type = MYSQL_TYPE_DATE;
bind_buffers[i].buffer = xmalloc(sizeof(MYSQL_TIME));
memset(&t, 0, sizeof(MYSQL_TIME));
t.second_part = 0;
t.neg = 0;
t.day = FIX2INT(rb_funcall(rb_time, intern_day, 0));
t.month = FIX2INT(rb_funcall(rb_time, intern_month, 0));
t.year = FIX2INT(rb_funcall(rb_time, intern_year, 0));
*(MYSQL_TIME*)(bind_buffers[i].buffer) = t;
} else if (CLASS_OF(argv[i]) == cBigDecimal) {
bind_buffers[i].buffer_type = MYSQL_TYPE_NEWDECIMAL;
}
break;
}
}
// copies bind_buffers into internal storage
if (mysql_stmt_bind_param(stmt, bind_buffers)) {
FREE_BINDS;
rb_raise_mysql2_stmt_error(self);
}
}
if ((VALUE)rb_thread_call_without_gvl(nogvl_execute, stmt, RUBY_UBF_IO, 0) == Qfalse) {
FREE_BINDS;
rb_raise_mysql2_stmt_error(self);
}
FREE_BINDS;
metadata = mysql_stmt_result_metadata(stmt);
if (metadata == NULL) {
if (mysql_stmt_errno(stmt) != 0) {
// either CR_OUT_OF_MEMORY or CR_UNKNOWN_ERROR. both fatal.
MARK_CONN_INACTIVE(stmt_wrapper->client);
rb_raise_mysql2_stmt_error(self);
}
// no data and no error, so query was not a SELECT
return Qnil;
}
current = rb_hash_dup(rb_iv_get(stmt_wrapper->client, "@query_options"));
(void)RB_GC_GUARD(current);
Check_Type(current, T_HASH);
is_streaming = (Qtrue == rb_hash_aref(current, sym_stream));
if (!is_streaming) {
// recieve the whole result set from the server
if (rb_thread_call_without_gvl(nogvl_stmt_store_result, stmt, RUBY_UBF_IO, 0) == Qfalse) {
mysql_free_result(metadata);
rb_raise_mysql2_stmt_error(self);
}
MARK_CONN_INACTIVE(stmt_wrapper->client);
}
resultObj = rb_mysql_result_to_obj(stmt_wrapper->client, wrapper->encoding, current, metadata, self);
if (!is_streaming) {
// cache all result
rb_funcall(resultObj, intern_each, 0);
}
return resultObj;
}
field_count # → Numeric
click to toggle source
Returns the number of fields the prepared statement returns.
static VALUE field_count(VALUE self) {
GET_STATEMENT(self);
return UINT2NUM(mysql_stmt_field_count(stmt_wrapper->stmt));
}
fields # → array
click to toggle source
Returns a list of fields that will be returned by this statement.
static VALUE fields(VALUE self) {
MYSQL_FIELD *fields;
MYSQL_RES *metadata;
unsigned int field_count;
unsigned int i;
VALUE field_list;
MYSQL_STMT* stmt;
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *default_internal_enc, *conn_enc;
#endif
GET_STATEMENT(self);
stmt = stmt_wrapper->stmt;
#ifdef HAVE_RUBY_ENCODING_H
default_internal_enc = rb_default_internal_encoding();
{
GET_CLIENT(stmt_wrapper->client);
conn_enc = rb_to_encoding(wrapper->encoding);
}
#endif
metadata = mysql_stmt_result_metadata(stmt);
fields = mysql_fetch_fields(metadata);
field_count = mysql_stmt_field_count(stmt);
field_list = rb_ary_new2((long)field_count);
for(i = 0; i < field_count; i++) {
VALUE rb_field;
rb_field = rb_str_new(fields[i].name, fields[i].name_length);
#ifdef HAVE_RUBY_ENCODING_H
rb_enc_associate(rb_field, conn_enc);
if (default_internal_enc) {
rb_field = rb_str_export_to_enc(rb_field, default_internal_enc);
}
#endif
rb_ary_store(field_list, (long)i, rb_field);
}
mysql_free_result(metadata);
return field_list;
}
param_count # → Numeric
click to toggle source
Returns the number of parameters the prepared statement expects.
static VALUE param_count(VALUE self) {
GET_STATEMENT(self);
return ULL2NUM(mysql_stmt_param_count(stmt_wrapper->stmt));
}