Example #1
0
static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
  MYSQL * client;
  VALUE newStr;
  unsigned long newLen, oldLen;

  Check_Type(str, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *default_internal_enc = rb_default_internal_encoding();
  rb_encoding *conn_enc = rb_to_encoding(rb_iv_get(self, "@encoding"));
  // ensure the string is in the encoding the connection is expecting
  str = rb_str_export_to_enc(str, conn_enc);
#endif

  oldLen = RSTRING_LEN(str);
  char escaped[(oldLen*2)+1];

  Data_Get_Struct(self, MYSQL, client);

  REQUIRE_OPEN_DB(client);
  newLen = mysql_real_escape_string(client, escaped, StringValuePtr(str), RSTRING_LEN(str));
  if (newLen == oldLen) {
    // no need to return a new ruby string if nothing changed
    return str;
  } else {
    newStr = rb_str_new(escaped, newLen);
#ifdef HAVE_RUBY_ENCODING_H
    rb_enc_associate(newStr, conn_enc);
    if (default_internal_enc) {
      newStr = rb_str_export_to_enc(newStr, default_internal_enc);
    }
#endif
    return newStr;
  }
}
Example #2
0
/* call-seq: define_aggregator(name, aggregator)
 *
 * Define an aggregate function named +name+ using the object +aggregator+.
 * +aggregator+ must respond to +step+ and +finalize+.  +step+ will be called
 * with row information and +finalize+ must return the return value for the
 * aggregator function.
 */
static VALUE define_aggregator(VALUE self, VALUE name, VALUE aggregator)
{
  sqlite3RubyPtr ctx;
  int arity, status;

  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  arity = sqlite3_obj_method_arity(aggregator, rb_intern("step"));

  status = sqlite3_create_function(
    ctx->db,
    StringValuePtr(name),
    arity,
    SQLITE_UTF8,
    (void *)aggregator,
    NULL,
    rb_sqlite3_step,
    rb_sqlite3_final
  );

  rb_iv_set(self, "@agregator", aggregator);

  CHECK(ctx->db, status);

  return self;
}
Example #3
0
static VALUE rb_mysql_client_server_info(VALUE self) {
  VALUE version, server_info;
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *default_internal_enc;
  rb_encoding *conn_enc;
#endif
  GET_CLIENT(self);

  REQUIRE_OPEN_DB(wrapper);
#ifdef HAVE_RUBY_ENCODING_H
  default_internal_enc = rb_default_internal_encoding();
  conn_enc = rb_to_encoding(wrapper->encoding);
#endif

  version = rb_hash_new();
  rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
  server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
#ifdef HAVE_RUBY_ENCODING_H
  rb_enc_associate(server_info, conn_enc);
  if (default_internal_enc) {
    server_info = rb_str_export_to_enc(server_info, default_internal_enc);
  }
#endif
  rb_hash_aset(version, sym_version, server_info);
  return version;
}
Example #4
0
static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
    VALUE newStr;
    unsigned long newLen, oldLen;
    GET_CLIENT(self);

    REQUIRE_OPEN_DB(wrapper);
    Check_Type(str, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
    rb_encoding *default_internal_enc = rb_default_internal_encoding();
    rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
    // ensure the string is in the encoding the connection is expecting
    str = rb_str_export_to_enc(str, conn_enc);
#endif

    oldLen = RSTRING_LEN(str);
    newStr = rb_str_new(0, oldLen*2+1);

    newLen = mysql_real_escape_string(wrapper->client, RSTRING_PTR(newStr), StringValuePtr(str), oldLen);
    if (newLen == oldLen) {
        // no need to return a new ruby string if nothing changed
        return str;
    } else {
        rb_str_resize(newStr, newLen);
#ifdef HAVE_RUBY_ENCODING_H
        rb_enc_associate(newStr, conn_enc);
        if (default_internal_enc) {
            newStr = rb_str_export_to_enc(newStr, default_internal_enc);
        }
#endif
        return newStr;
    }
}
Example #5
0
static VALUE rb_mysql_client_async_result(VALUE self) {
    MYSQL_RES * result;
    GET_CLIENT(self);

    REQUIRE_OPEN_DB(wrapper);
    if (rb_thread_blocking_region(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
        // an error occurred, mark this connection inactive
        MARK_CONN_INACTIVE(self);
        return rb_raise_mysql2_error(wrapper->client);
    }

    result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper->client, RUBY_UBF_IO, 0);

    // we have our result, mark this connection inactive
    MARK_CONN_INACTIVE(self);

    if (result == NULL) {
        if (mysql_field_count(wrapper->client) != 0) {
            rb_raise_mysql2_error(wrapper->client);
        }
        return Qnil;
    }

    VALUE resultObj = rb_mysql_result_to_obj(result);
    // pass-through query options for result construction later
    rb_iv_set(resultObj, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), rb_intern("dup"), 0));

#ifdef HAVE_RUBY_ENCODING_H
    mysql2_result_wrapper * result_wrapper;
    GetMysql2Result(resultObj, result_wrapper);
    result_wrapper->encoding = wrapper->encoding;
#endif
    return resultObj;
}
Example #6
0
/* call-seq: define_function(name) { |args,...| }
 *
 * Define a function named +name+ with +args+.  The arity of the block
 * will be used as the arity for the function defined.
 */
static VALUE define_function(VALUE self, VALUE name)
{
  sqlite3RubyPtr ctx;
  VALUE block;
  int status;

  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  block = rb_block_proc();

  status = sqlite3_create_function(
    ctx->db,
    StringValuePtr(name),
    rb_proc_arity(block),
    SQLITE_UTF8,
    (void *)block,
    rb_sqlite3_func,
    NULL,
    NULL
  );

  CHECK(ctx->db, status);

  return self;
}
Example #7
0
/* call-seq: db.transaction_active?
 *
 * Returns +true+ if there is a transaction active, and +false+ otherwise.
 *
 */
static VALUE transaction_active_p(VALUE self)
{
  sqlite3RubyPtr ctx;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  return sqlite3_get_autocommit(ctx->db) ? Qfalse : Qtrue;
}
Example #8
0
/* call-seq: errcode
 *
 * Return an integer representing the last error to have occurred with this
 * database.
 */
static VALUE errcode(VALUE self)
{
  sqlite3RubyPtr ctx;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  return INT2NUM((long)sqlite3_errcode(ctx->db));
}
Example #9
0
static VALUE rb_mysql_client_thread_id(VALUE self) {
  unsigned long retVal;
  GET_CLIENT(self);

  REQUIRE_OPEN_DB(wrapper);
  retVal = mysql_thread_id(wrapper->client);
  return ULL2NUM(retVal);
}
Example #10
0
/* call-seq: changes
 *
 * Returns the number of changes made to this database instance by the last
 * operation performed. Note that a "delete from table" without a where
 * clause will not affect this value.
 */
static VALUE changes(VALUE self)
{
  sqlite3RubyPtr ctx;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  return INT2NUM(sqlite3_changes(ctx->db));
}
Example #11
0
/* call-seq: last_insert_row_id
 *
 * Obtains the unique row ID of the last row to be inserted by this Database
 * instance.
 */
static VALUE last_insert_row_id(VALUE self)
{
  sqlite3RubyPtr ctx;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  return LL2NUM(sqlite3_last_insert_rowid(ctx->db));
}
Example #12
0
/* call-seq: errmsg
 *
 * Return a string describing the last error to have occurred with this
 * database.
 */
static VALUE errmsg(VALUE self)
{
  sqlite3RubyPtr ctx;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  return rb_str_new2(sqlite3_errmsg(ctx->db));
}
Example #13
0
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
  struct nogvl_send_query_args args;
  fd_set fdset;
  int fd, retval;
  int async = 0;
  VALUE opts;
  VALUE rb_async;

  MYSQL * client;

  if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
    if ((rb_async = rb_hash_aref(opts, sym_async)) != Qnil) {
      async = rb_async == Qtrue ? 1 : 0;
    }
  }

  Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *conn_enc = rb_to_encoding(rb_iv_get(self, "@encoding"));
  // ensure the string is in the encoding the connection is expecting
  args.sql = rb_str_export_to_enc(args.sql, conn_enc);
#endif

  Data_Get_Struct(self, MYSQL, client);

  REQUIRE_OPEN_DB(client);

  args.mysql = client;
  if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
    return rb_raise_mysql2_error(client);
  }

  if (!async) {
    // the below code is largely from do_mysql
    // http://github.com/datamapper/do
    fd = client->net.fd;
    for(;;) {
      FD_ZERO(&fdset);
      FD_SET(fd, &fdset);

      retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, NULL);

      if (retval < 0) {
          rb_sys_fail(0);
      }

      if (retval > 0) {
          break;
      }
    }

    return rb_mysql_client_async_result(self);
  } else {
    return Qnil;
  }
}
Example #14
0
/* call-seq: db.enable_load_extension(onoff)
 *
 * Enable or disable extension loading.
 */
static VALUE enable_load_extension(VALUE self, VALUE onoff)
{
  sqlite3RubyPtr ctx;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  CHECK(ctx->db, sqlite3_enable_load_extension(ctx->db, (int)NUM2INT(onoff)));

  return self;
}
Example #15
0
/* call-seq: db.busy_timeout = ms
 *
 * Indicates that if a request for a resource terminates because that
 * resource is busy, SQLite should sleep and retry for up to the indicated
 * number of milliseconds. By default, SQLite does not retry
 * busy resources. To restore the default behavior, send 0 as the
 * +ms+ parameter.
 *
 * See also the mutually exclusive #busy_handler.
 */
static VALUE set_busy_timeout(VALUE self, VALUE timeout)
{
  sqlite3RubyPtr ctx;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  CHECK(ctx->db, sqlite3_busy_timeout(ctx->db, (int)NUM2INT(timeout)));

  return self;
}
Example #16
0
/* call-seq: interrupt
 *
 * Interrupts the currently executing operation, causing it to abort.
 */
static VALUE interrupt(VALUE self)
{
  sqlite3RubyPtr ctx;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  sqlite3_interrupt(ctx->db);

  return self;
}
Example #17
0
static VALUE rb_mysql_client_socket(VALUE self) {
  GET_CLIENT(self);
#ifndef _WIN32
  REQUIRE_OPEN_DB(wrapper);
  int fd_set_fd = wrapper->client->net.fd;
  return INT2NUM(fd_set_fd);
#else
  rb_raise(cMysql2Error, "Raw access to the mysql file descriptor isn't supported on Windows");
#endif
}
Example #18
0
static VALUE rb_mysql_client_affected_rows(VALUE self) {
  my_ulonglong retVal;
  GET_CLIENT(self);

  REQUIRE_OPEN_DB(wrapper);
  retVal = mysql_affected_rows(wrapper->client);
  if (retVal == (my_ulonglong)-1) {
    rb_raise_mysql2_error(wrapper);
  }
  return ULL2NUM(retVal);
}
Example #19
0
/* call-seq:
 *    client.select_db(name)
 *
 * Causes the database specified by +name+ to become the default (current)
 * database on the connection specified by mysql.
 */
static VALUE rb_mysql_client_select_db(VALUE self, VALUE db)
{
  struct nogvl_select_db_args args;

  GET_CLIENT(self);
  REQUIRE_OPEN_DB(wrapper);

  args.mysql = wrapper->client;
  args.db = StringValuePtr(db);

  if (rb_thread_blocking_region(nogvl_select_db, &args, RUBY_UBF_IO, 0) == Qfalse)
    rb_raise_mysql2_error(wrapper); 

  return db;
}
Example #20
0
static VALUE rb_mysql_client_socket(VALUE self) {
    GET_CLIENT(self);
    REQUIRE_OPEN_DB(wrapper);
    int fd_set_fd = wrapper->client->net.fd;
#ifdef _WIN32
    WSAPROTOCOL_INFO wsa_pi;
    // dupicate the SOCKET from libmysql
    int r = WSADuplicateSocket(wrapper->client->net.fd, GetCurrentProcessId(), &wsa_pi);
    SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
    // create the CRT fd so ruby can get back to the SOCKET
    fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY);
    return INT2NUM(fd_set_fd);
#else
    return INT2NUM(fd_set_fd);
#endif
}
Example #21
0
/* call-seq: db.encoding
 *
 * Fetch the encoding set on this database
 */
static VALUE db_encoding(VALUE self)
{
  sqlite3RubyPtr ctx;
  VALUE enc;

  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  enc = rb_iv_get(self, "@encoding");

  if(NIL_P(enc)) {
    sqlite3_exec(ctx->db, "PRAGMA encoding", enc_cb, (void *)self, NULL);
  }

  return rb_iv_get(self, "@encoding");
}
Example #22
0
/* call-seq:
 *    client.async_result
 *
 * Returns the result for the last async issued query.
 */
static VALUE rb_mysql_client_async_result(VALUE self) {
  MYSQL_RES * result;
  VALUE resultObj;
#ifdef HAVE_RUBY_ENCODING_H
  mysql2_result_wrapper * result_wrapper;
#endif
  GET_CLIENT(self);

  // if we're not waiting on a result, do nothing
  if (!wrapper->active)
    return Qnil;

  REQUIRE_OPEN_DB(wrapper);
  if (rb_thread_blocking_region(nogvl_read_query_result, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
    // an error occurred, mark this connection inactive
    MARK_CONN_INACTIVE(self);
    return rb_raise_mysql2_error(wrapper);
  }

  VALUE is_streaming = rb_hash_aref(rb_iv_get(self, "@query_options"), sym_stream);
  if(is_streaming == Qtrue) {
    result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_use_result, wrapper, RUBY_UBF_IO, 0);
  } else {
    result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);
  }

  if (result == NULL) {
    if (mysql_errno(wrapper->client) != 0) {
      MARK_CONN_INACTIVE(self);
      rb_raise_mysql2_error(wrapper);
    }
    // no data and no error, so query was not a SELECT
    return Qnil;
  }

  resultObj = rb_mysql_result_to_obj(result);
  // pass-through query options for result construction later
  rb_iv_set(resultObj, "@query_options", rb_funcall(rb_iv_get(self, "@query_options"), rb_intern("dup"), 0));

#ifdef HAVE_RUBY_ENCODING_H
  GetMysql2Result(resultObj, result_wrapper);
  result_wrapper->encoding = wrapper->encoding;
#endif
  return resultObj;
}
Example #23
0
/* call-seq: set_authorizer = auth
 *
 * Set the authorizer for this database.  +auth+ must respond to +call+, and
 * +call+ must take 5 arguments.
 *
 * Installs (or removes) a block that will be invoked for every access
 * to the database. If the block returns 0 (or +true+), the statement
 * is allowed to proceed. Returning 1 or false causes an authorization error to
 * occur, and returning 2 or nil causes the access to be silently denied.
 */
static VALUE set_authorizer(VALUE self, VALUE authorizer)
{
  sqlite3RubyPtr ctx;
  int status;

  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  status = sqlite3_set_authorizer(
      ctx->db, NIL_P(authorizer) ? NULL : rb_sqlite3_auth, (void *)self
  );

  CHECK(ctx->db, status);

  rb_iv_set(self, "@authorizer", authorizer);

  return self;
}
Example #24
0
/* call-seq:
 *    trace { |sql| ... }
 *    trace(Class.new { def call sql; end }.new)
 *
 * Installs (or removes) a block that will be invoked for every SQL
 * statement executed. The block receives one parameter: the SQL statement
 * executed. If the block is +nil+, any existing tracer will be uninstalled.
 */
static VALUE trace(int argc, VALUE *argv, VALUE self)
{
  sqlite3RubyPtr ctx;
  VALUE block;

  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  rb_scan_args(argc, argv, "01", &block);

  if(NIL_P(block) && rb_block_given_p()) block = rb_block_proc();

  rb_iv_set(self, "@tracefunc", block);

  sqlite3_trace(ctx->db, NIL_P(block) ? NULL : tracefunc, (void *)self);

  return self;
}
Example #25
0
/* call-seq: db.collation(name, comparator)
 *
 * Add a collation with name +name+, and a +comparator+ object.  The
 * +comparator+ object should implement a method called "compare" that takes
 * two parameters and returns an integer less than, equal to, or greater than
 * 0.
 */
static VALUE collation(VALUE self, VALUE name, VALUE comparator)
{
  sqlite3RubyPtr ctx;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  CHECK(ctx->db, sqlite3_create_collation(
        ctx->db,
        StringValuePtr(name),
        SQLITE_UTF8,
        (void *)comparator,
        NIL_P(comparator) ? NULL : rb_comparator_func));

  /* Make sure our comparator doesn't get garbage collected. */
  rb_hash_aset(rb_iv_get(self, "@collations"), name, comparator);

  return self;
}
Example #26
0
/* call-seq: db.enable_load_extension(onoff)
 *
 * Enable or disable extension loading.
 */
static VALUE enable_load_extension(VALUE self, VALUE onoff)
{
  sqlite3RubyPtr ctx;
  int onoffparam;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  if (Qtrue == onoff) {
    onoffparam = 1;
  } else if (Qfalse == onoff) {
    onoffparam = 0;
  } else {
    onoffparam = (int)NUM2INT(onoff);
  }

  CHECK(ctx->db, sqlite3_enable_load_extension(ctx->db, onoffparam));

  return self;
}
Example #27
0
/* call-seq: db.load_extension(file)
 *
 * Loads an SQLite extension library from the named file. Extension
 * loading must be enabled using db.enable_load_extension(1) prior
 * to calling this API.
 */
static VALUE load_extension(VALUE self, VALUE file)
{
  sqlite3RubyPtr ctx;
  int status;
  char *errMsg;
  VALUE errexp;
  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  status = sqlite3_load_extension(ctx->db, RSTRING_PTR(file), 0, &errMsg);
  if (status != SQLITE_OK)
  {
    errexp = rb_exc_new2(rb_eRuntimeError, errMsg);
    sqlite3_free(errMsg);
    rb_exc_raise(errexp);
  }

  return self;
}
Example #28
0
/* call-seq:
 *    busy_handler { |count| ... }
 *    busy_handler(Class.new { def call count; end }.new)
 *
 * Register a busy handler with this database instance. When a requested
 * resource is busy, this handler will be invoked. If the handler returns
 * +false+, the operation will be aborted; otherwise, the resource will
 * be requested again.
 *
 * The handler will be invoked with the name of the resource that was
 * busy, and the number of times it has been retried.
 *
 * See also the mutually exclusive #busy_timeout.
 */
static VALUE busy_handler(int argc, VALUE *argv, VALUE self)
{
  sqlite3RubyPtr ctx;
  VALUE block;
  int status;

  Data_Get_Struct(self, sqlite3Ruby, ctx);
  REQUIRE_OPEN_DB(ctx);

  rb_scan_args(argc, argv, "01", &block);

  if(NIL_P(block) && rb_block_given_p()) block = rb_block_proc();

  rb_iv_set(self, "@busy_handler", block);

  status = sqlite3_busy_handler(
      ctx->db, NIL_P(block) ? NULL : rb_sqlite3_busy_handler, (void *)self);

  CHECK(ctx->db, status);

  return self;
}
Example #29
0
static VALUE rb_mysql_client_async_result(VALUE self) {
  MYSQL * client;
  MYSQL_RES * result;

  Data_Get_Struct(self, MYSQL, client);

  REQUIRE_OPEN_DB(client);
  if (rb_thread_blocking_region(nogvl_read_query_result, client, RUBY_UBF_IO, 0) == Qfalse) {
    return rb_raise_mysql2_error(client);
  }

  result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, client, RUBY_UBF_IO, 0);
  if (result == NULL) {
    if (mysql_field_count(client) != 0) {
      rb_raise_mysql2_error(client);
    }
    return Qnil;
  }

  VALUE resultObj = rb_mysql_result_to_obj(result);
  rb_iv_set(resultObj, "@encoding", rb_iv_get(self, "@encoding"));
  return resultObj;
}
Example #30
0
static VALUE rb_mysql_client_server_info(VALUE self) {
  MYSQL * client;
  VALUE version, server_info;
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *default_internal_enc = rb_default_internal_encoding();
  rb_encoding *conn_enc = rb_to_encoding(rb_iv_get(self, "@encoding"));
#endif

  Data_Get_Struct(self, MYSQL, client);
  REQUIRE_OPEN_DB(client);

  version = rb_hash_new();
  rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(client)));
  server_info = rb_str_new2(mysql_get_server_info(client));
#ifdef HAVE_RUBY_ENCODING_H
  rb_enc_associate(server_info, conn_enc);
  if (default_internal_enc) {
    server_info = rb_str_export_to_enc(server_info, default_internal_enc);
  }
#endif
  rb_hash_aset(version, sym_version, server_info);
  return version;
}