コード例 #1
0
ファイル: mysql2_ext.c プロジェクト: foobargem/mysql2
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;
  }
}
コード例 #2
0
ファイル: client.c プロジェクト: jaylane/mysql2
/* call-seq:
 *    client.query(sql, options = {})
 *
 * Query the database with +sql+, with optional +options+.  For the possible
 * options, see default_query_options on the Mysql2::Client class.
 */
static VALUE rb_query(VALUE self, VALUE sql, VALUE current) {
#ifndef _WIN32
  struct async_query_args async_args;
#endif
  struct nogvl_send_query_args args;
  GET_CLIENT(self);

  REQUIRE_CONNECTED(wrapper);
  args.mysql = wrapper->client;

  (void)RB_GC_GUARD(current);
  Check_Type(current, T_HASH);
  rb_iv_set(self, "@current_query_options", current);

  Check_Type(sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
  /* ensure the string is in the encoding the connection is expecting */
  args.sql = rb_str_export_to_enc(sql, rb_to_encoding(wrapper->encoding));
#else
  args.sql = sql;
#endif
  args.sql_ptr = RSTRING_PTR(args.sql);
  args.sql_len = RSTRING_LEN(args.sql);
  args.wrapper = wrapper;

  rb_mysql_client_set_active_thread(self);

#ifndef _WIN32
  rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);

  if (rb_hash_aref(current, sym_async) == Qtrue) {
    return Qnil;
  } else {
    async_args.fd = wrapper->client->net.fd;
    async_args.self = self;

    rb_rescue2(do_query, (VALUE)&async_args, disconnect_and_raise, self, rb_eException, (VALUE)0);

    return rb_mysql_client_async_result(self);
  }
#else
  do_send_query(&args);

  /* this will just block until the result is ready */
  return rb_ensure(rb_mysql_client_async_result, self, finish_and_mark_inactive, self);
#endif
}
コード例 #3
0
ファイル: client.c プロジェクト: 0xCCD/mysql2
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
#ifndef _WIN32
  struct async_query_args async_args;
#endif
  struct nogvl_send_query_args args;
  int async = 0;
  VALUE opts, defaults;
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *conn_enc;
#endif
  GET_CLIENT(self);

  REQUIRE_OPEN_DB(wrapper);
  args.mysql = wrapper->client;


  defaults = rb_iv_get(self, "@query_options");
  if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
    opts = rb_funcall(defaults, intern_merge, 1, opts);
    rb_iv_set(self, "@query_options", opts);

    if (rb_hash_aref(opts, sym_async) == Qtrue) {
      async = 1;
    }
  } else {
    opts = defaults;
  }

  Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
  conn_enc = rb_to_encoding(wrapper->encoding);
  // ensure the string is in the encoding the connection is expecting
  args.sql = rb_str_export_to_enc(args.sql, conn_enc);
#endif

  // see if this connection is still waiting on a result from a previous query
  if (wrapper->active == 0) {
    // mark this connection active
    wrapper->active = 1;
  } else {
    rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
  }

  args.wrapper = wrapper;
  rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);

#ifndef _WIN32
  if (!async) {
    async_args.fd = wrapper->client->net.fd;
    async_args.self = self;

    rb_rescue2(do_query, (VALUE)&async_args, disconnect_and_raise, self, rb_eException, (VALUE)0);

    return rb_mysql_client_async_result(self);
  } else {
    return Qnil;
  }
#else
  // this will just block until the result is ready
  return rb_ensure(rb_mysql_client_async_result, self, finish_and_mark_inactive, self);
#endif
}
コード例 #4
0
ファイル: client.c プロジェクト: notonthehighstreet/mysql2
/* call-seq:
 *    client.query(sql, options = {})
 *
 * Query the database with +sql+, with optional +options+.  For the possible
 * options, see @@default_query_options on the Mysql2::Client class.
 */
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
#ifndef _WIN32
  struct async_query_args async_args;
#endif
  struct nogvl_send_query_args args;
  int async = 0;
  VALUE opts, current;
  VALUE thread_current = rb_thread_current();
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *conn_enc;
#endif
  GET_CLIENT(self);

  REQUIRE_CONNECTED(wrapper);
  args.mysql = wrapper->client;

  current = rb_hash_dup(rb_iv_get(self, "@query_options"));
  RB_GC_GUARD(current);
  Check_Type(current, T_HASH);
  rb_iv_set(self, "@current_query_options", current);

  if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
    rb_funcall(current, intern_merge_bang, 1, opts);

    if (rb_hash_aref(current, sym_async) == Qtrue) {
      async = 1;
    }
  }

  Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
  conn_enc = rb_to_encoding(wrapper->encoding);
  /* ensure the string is in the encoding the connection is expecting */
  args.sql = rb_str_export_to_enc(args.sql, conn_enc);
#endif
  args.sql_ptr = RSTRING_PTR(args.sql);
  args.sql_len = RSTRING_LEN(args.sql);

  /* see if this connection is still waiting on a result from a previous query */
  if (NIL_P(wrapper->active_thread)) {
    /* mark this connection active */
    wrapper->active_thread = thread_current;
  } else if (wrapper->active_thread == thread_current) {
    rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
  } else {
    VALUE inspect = rb_inspect(wrapper->active_thread);
    const char *thr = StringValueCStr(inspect);

    rb_raise(cMysql2Error, "This connection is in use by: %s", thr);
    RB_GC_GUARD(inspect);
  }

  args.wrapper = wrapper;

#ifndef _WIN32
  rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);

  if (!async) {
    async_args.fd = wrapper->client->net.fd;
    async_args.self = self;

    rb_rescue2(do_query, (VALUE)&async_args, disconnect_and_raise, self, rb_eException, (VALUE)0);

    return rb_mysql_client_async_result(self);
  } else {
    return Qnil;
  }
#else
  do_send_query(&args);

  /* this will just block until the result is ready */
  return rb_ensure(rb_mysql_client_async_result, self, finish_and_mark_inactive, self);
#endif
}
コード例 #5
0
ファイル: client.c プロジェクト: leadtune/mysql2
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, defaults, read_timeout;
#ifdef HAVE_RUBY_ENCODING_H
    rb_encoding *conn_enc;
#endif
    struct timeval tv;
    struct timeval* tvp;
    long int sec;
    VALUE result;
    GET_CLIENT(self);

    REQUIRE_OPEN_DB(wrapper);
    args.mysql = wrapper->client;

    // see if this connection is still waiting on a result from a previous query
    if (wrapper->active == 0) {
        // mark this connection active
        wrapper->active = 1;
    } else {
        rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
    }

    defaults = rb_iv_get(self, "@query_options");
    if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
        opts = rb_funcall(defaults, intern_merge, 1, opts);
        rb_iv_set(self, "@query_options", opts);

        if (rb_hash_aref(opts, sym_async) == Qtrue) {
            async = 1;
        }
    } else {
        opts = defaults;
    }

    Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
    conn_enc = rb_to_encoding(wrapper->encoding);
    // ensure the string is in the encoding the connection is expecting
    args.sql = rb_str_export_to_enc(args.sql, conn_enc);
#endif

    if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
        // an error occurred, we're not active anymore
        MARK_CONN_INACTIVE(self);
        return rb_raise_mysql2_error(wrapper);
    }

    read_timeout = rb_iv_get(self, "@read_timeout");

    tvp = NULL;
    if (!NIL_P(read_timeout)) {
        Check_Type(read_timeout, T_FIXNUM);
        tvp = &tv;
        sec = FIX2INT(read_timeout);
        // TODO: support partial seconds?
        // also, this check is here for sanity, we also check up in Ruby
        if (sec >= 0) {
            tvp->tv_sec = sec;
        } else {
            rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
        }
        tvp->tv_usec = 0;
    }

    if (!async) {
        // the below code is largely from do_mysql
        // http://github.com/datamapper/do
        fd = wrapper->client->net.fd;
        for(;;) {
            int fd_set_fd = fd;

#if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION)
            WSAPROTOCOL_INFO wsa_pi;
            // dupicate the SOCKET from libmysql
            int r = WSADuplicateSocket(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);
#endif

            FD_ZERO(&fdset);
            FD_SET(fd_set_fd, &fdset);

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

#if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION)
            // cleanup the CRT fd
            _close(fd_set_fd);
            // cleanup the duplicated SOCKET
            closesocket(s);
#endif

            if (retval == 0) {
                rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
            }

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

            if (retval > 0) {
                break;
            }
        }

        result = rb_mysql_client_async_result(self);

        return result;
    } else {
        return Qnil;
    }
}
コード例 #6
0
ファイル: client.c プロジェクト: heathd/mysql2
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, defaults, read_timeout;
    GET_CLIENT(self);

    REQUIRE_OPEN_DB(wrapper);
    args.mysql = wrapper->client;

    // see if this connection is still waiting on a result from a previous query
    if (wrapper->active == 0) {
        // mark this connection active
        wrapper->active = 1;
    } else {
        rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
    }

    defaults = rb_iv_get(self, "@query_options");
    if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
        opts = rb_funcall(defaults, intern_merge, 1, opts);
        rb_iv_set(self, "@query_options", opts);

        if (rb_hash_aref(opts, sym_async) == Qtrue) {
            async = 1;
        }
    } else {
        opts = defaults;
    }

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

    if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
        // an error occurred, we're not active anymore
        MARK_CONN_INACTIVE(self);
        return rb_raise_mysql2_error(wrapper->client);
    }

    read_timeout = rb_iv_get(self, "@read_timeout");
    struct timeval tv;
    struct timeval* tvp = NULL;
    if (!NIL_P(read_timeout)) {
        Check_Type(read_timeout, T_FIXNUM);
        tvp = &tv;
        long int sec = FIX2INT(read_timeout);
        // TODO: support partial seconds?
        // also, this check is here for sanity, we also check up in Ruby
        if (sec >= 0) {
            tvp->tv_sec = sec;
        } else {
            rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %d", sec);
        }
        tvp->tv_usec = 0;
    }

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

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

            if (retval == 0) {
                rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
            }

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

            if (retval > 0) {
                break;
            }
        }

        VALUE result = rb_mysql_client_async_result(self);

        return result;
    } else {
        return Qnil;
    }
}