예제 #1
0
파일: session_ext.c 프로젝트: luma/patron
// Perform the actual HTTP request by calling libcurl.
static VALUE perform_request(VALUE self) {
  struct curl_state *state;
  Data_Get_Struct(self, struct curl_state, state);

  CURL* curl = state->handle;

  // headers
  VALUE header_buffer = rb_str_buf_new(32768);
  curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &session_write_handler);
  curl_easy_setopt(curl, CURLOPT_HEADERDATA, header_buffer);

  // body
  VALUE body_buffer = Qnil;
  if (!state->download_file) {
    body_buffer = rb_str_buf_new(32768);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &session_write_handler);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, body_buffer);
  }

#if defined(HAVE_TBR) && defined(USE_TBR)
  CURLcode ret = rb_thread_blocking_region(curl_easy_perform, curl, RUBY_UBF_IO, 0);
#else
  CURLcode ret = curl_easy_perform(curl);
#endif

  if (CURLE_OK == ret) {
    VALUE response = create_response(curl);
    if (!NIL_P(body_buffer)) {
      rb_iv_set(response, "@body", body_buffer);
    }
    rb_funcall(response, rb_intern("parse_headers"), 1, header_buffer);
    return response;
  } else {
    rb_raise(select_error(ret), "%s", state->error_buf);
  }
}
예제 #2
0
파일: client.c 프로젝트: brightbox/mysql2
static VALUE rb_mysql_client_store_result(VALUE self)
{
  MYSQL_RES * result;
  VALUE resultObj;
#ifdef HAVE_RUBY_ENCODING_H
  mysql2_result_wrapper * result_wrapper;
#endif
  
  
  GET_CLIENT(self);
  // MYSQL_RES* res = mysql_store_result(wrapper->client);
  // if (res == NULL)
  //    mysql_raise(wrapper->client);
  // return mysqlres2obj(res);
  
  result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper, RUBY_UBF_IO, 0);

  if (result == NULL) {
    if (mysql_errno(wrapper->client) != 0) {
      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;
  
}
예제 #3
0
파일: result.c 프로젝트: orghub/mysql2
static VALUE rb_mysql_result_fetch_row(int argc, VALUE * argv, VALUE self) {
  VALUE rowHash, opts, block;
  mysql2_result_wrapper * wrapper;
  MYSQL_ROW row;
  MYSQL_FIELD * fields = NULL;
  unsigned int i = 0, symbolizeKeys = 0;
  unsigned long * fieldLengths;
  void * ptr;
#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

  GetMysql2Result(self, wrapper);

  if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1) {
    Check_Type(opts, T_HASH);
    if (rb_hash_aref(opts, sym_symbolize_keys) == Qtrue) {
        symbolizeKeys = 1;
    }
  }

  ptr = wrapper->result;
  row = (MYSQL_ROW)rb_thread_blocking_region(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
  if (row == NULL) {
    return Qnil;
  }

  rowHash = rb_hash_new();
  fields = mysql_fetch_fields(wrapper->result);
  fieldLengths = mysql_fetch_lengths(wrapper->result);
  if (wrapper->fields == Qnil) {
    wrapper->numberOfFields = mysql_num_fields(wrapper->result);
    wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
  }

  for (i = 0; i < wrapper->numberOfFields; i++) {
    VALUE field = rb_mysql_result_fetch_field(self, i, symbolizeKeys);
    if (row[i]) {
      VALUE val;
      switch(fields[i].type) {
        case MYSQL_TYPE_NULL:       // NULL-type field
          val = Qnil;
          break;
        case MYSQL_TYPE_BIT:        // BIT field (MySQL 5.0.3 and up)
          val = rb_str_new(row[i], fieldLengths[i]);
          break;
        case MYSQL_TYPE_TINY:       // TINYINT field
        case MYSQL_TYPE_SHORT:      // SMALLINT field
        case MYSQL_TYPE_LONG:       // INTEGER field
        case MYSQL_TYPE_INT24:      // MEDIUMINT field
        case MYSQL_TYPE_LONGLONG:   // BIGINT field
        case MYSQL_TYPE_YEAR:       // YEAR field
          val = rb_cstr2inum(row[i], 10);
          break;
        case MYSQL_TYPE_DECIMAL:    // DECIMAL or NUMERIC field
        case MYSQL_TYPE_NEWDECIMAL: // Precision math DECIMAL or NUMERIC field (MySQL 5.0.3 and up)
          val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(row[i], fieldLengths[i]));
          break;
        case MYSQL_TYPE_FLOAT:      // FLOAT field
        case MYSQL_TYPE_DOUBLE:     // DOUBLE or REAL field
          val = rb_float_new(strtod(row[i], NULL));
          break;
        case MYSQL_TYPE_TIME: {     // TIME field
          int hour, min, sec, tokens;
          tokens = sscanf(row[i], "%2d:%2d:%2d", &hour, &min, &sec);
          val = rb_funcall(rb_cTime, intern_utc, 6, INT2NUM(0), INT2NUM(1), INT2NUM(1), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
          break;
        }
        case MYSQL_TYPE_TIMESTAMP:  // TIMESTAMP field
        case MYSQL_TYPE_DATETIME: { // DATETIME field
          int year, month, day, hour, min, sec, tokens;
          tokens = sscanf(row[i], "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
          if (year+month+day+hour+min+sec == 0) {
            val = Qnil;
          } else {
            if (month < 1 || day < 1) {
              rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
              val = Qnil;
            } else {
              val = rb_funcall(rb_cTime, intern_utc, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
            }
          }
          break;
        }
        case MYSQL_TYPE_DATE:       // DATE field
        case MYSQL_TYPE_NEWDATE: {  // Newer const used > 5.0
          int year, month, day, tokens;
          tokens = sscanf(row[i], "%4d-%2d-%2d", &year, &month, &day);
          if (year+month+day == 0) {
            val = Qnil;
          } else {
            if (month < 1 || day < 1) {
              rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
              val = Qnil;
            } else {
              val = rb_funcall(cDate, intern_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
            }
          }
          break;
        }
        case MYSQL_TYPE_TINY_BLOB:
        case MYSQL_TYPE_MEDIUM_BLOB:
        case MYSQL_TYPE_LONG_BLOB:
        case MYSQL_TYPE_BLOB:
        case MYSQL_TYPE_VAR_STRING:
        case MYSQL_TYPE_VARCHAR:
        case MYSQL_TYPE_STRING:     // CHAR or BINARY field
        case MYSQL_TYPE_SET:        // SET field
        case MYSQL_TYPE_ENUM:       // ENUM field
        case MYSQL_TYPE_GEOMETRY:   // Spatial fielda
        default:
          val = rb_str_new(row[i], fieldLengths[i]);
#ifdef HAVE_RUBY_ENCODING_H
          // if binary flag is set, respect it's wishes
          if (fields[i].flags & BINARY_FLAG) {
            rb_enc_associate(val, binaryEncoding);
          } else {
            // lookup the encoding configured on this field
            VALUE new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset_code, 1, INT2NUM(fields[i].charsetnr));
            if (new_encoding != Qnil) {
              // use the field encoding we were able to match
              rb_encoding *enc = rb_to_encoding(new_encoding);
              rb_enc_associate(val, enc);
            } else {
              // otherwise fall-back to the connection's encoding
              rb_enc_associate(val, conn_enc);
            }
            if (default_internal_enc) {
              val = rb_str_export_to_enc(val, default_internal_enc);
            }
          }
#endif
          break;
      }
      rb_hash_aset(rowHash, field, val);
    } else {
      rb_hash_aset(rowHash, field, Qnil);
    }
  }
  return rowHash;
}
예제 #4
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;
    }
}
예제 #5
0
파일: statement.c 프로젝트: johncant/mysql2
/* call-seq: stmt.execute
 *
 * Executes the current prepared statement, returns +stmt+.
 */
static VALUE execute(int argc, VALUE *argv, VALUE self) {
  MYSQL_STMT *stmt;
  MYSQL_BIND *bind_buffers;
  unsigned long bind_count;
  long i;

  Data_Get_Struct(self, MYSQL_STMT, 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));

    for (i = 0; i < argc; i++) {
      bind_buffers[i].buffer = NULL;

      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 = malloc(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 = malloc(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 = malloc(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 = malloc(sizeof(double));
          *(double*)(bind_buffers[i].buffer) = NUM2DBL(argv[i]);
          break;
        case T_STRING:
          bind_buffers[i].buffer_type = MYSQL_TYPE_STRING;
          bind_buffers[i].buffer = RSTRING_PTR(argv[i]);
          bind_buffers[i].buffer_length = RSTRING_LEN(argv[i]);
          unsigned long *len = malloc(sizeof(long));
          (*len) = RSTRING_LEN(argv[i]);
          bind_buffers[i].length = len;
          break;
        default:
          // TODO: what Ruby type should support MYSQL_TYPE_TIME
          if (CLASS_OF(argv[i]) == rb_cTime || CLASS_OF(argv[i]) == cDateTime) {
            bind_buffers[i].buffer_type = MYSQL_TYPE_DATETIME;
            bind_buffers[i].buffer = malloc(sizeof(MYSQL_TIME));

            MYSQL_TIME t;
            VALUE rb_time = argv[i];
            memset(&t, 0, sizeof(MYSQL_TIME));
            t.second_part = 0;
            t.neg = 0;
            t.second = FIX2INT(rb_funcall(rb_time, rb_intern("sec"), 0));
            t.minute = FIX2INT(rb_funcall(rb_time, rb_intern("min"), 0));
            t.hour = FIX2INT(rb_funcall(rb_time, rb_intern("hour"), 0));
            t.day = FIX2INT(rb_funcall(rb_time, rb_intern("day"), 0));
            t.month = FIX2INT(rb_funcall(rb_time, rb_intern("month"), 0));
            t.year = FIX2INT(rb_funcall(rb_time, rb_intern("year"), 0));

            *(MYSQL_TIME*)(bind_buffers[i].buffer) = t;
          } else if (CLASS_OF(argv[i]) == cDate) {

            bind_buffers[i].buffer_type = MYSQL_TYPE_DATE;

            bind_buffers[i].buffer = malloc(sizeof(MYSQL_TIME));

            MYSQL_TIME t;
            VALUE rb_time = argv[i];
            memset(&t, 0, sizeof(MYSQL_TIME));
            t.second_part = 0;
            t.neg = 0;
            t.day = FIX2INT(rb_funcall(rb_time, rb_intern("day"), 0));
            t.month = FIX2INT(rb_funcall(rb_time, rb_intern("month"), 0));
            t.year = FIX2INT(rb_funcall(rb_time, rb_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(cMysql2Error, "%s", mysql_stmt_error(stmt));
    }
  }

  if (rb_thread_blocking_region(nogvl_execute, stmt, RUBY_UBF_IO, 0) == Qfalse) {
    FREE_BINDS;
    rb_raise(cMysql2Error, "%s", mysql_stmt_error(stmt));
  }

  if (bind_count > 0) {
    FREE_BINDS;
  }

  return self;
}
예제 #6
0
/* ruby 1.9 */
sword oci8_call_without_gvl(oci8_svcctx_t *svcctx, void *(*func)(void *), void *data)
{
    OCIError *errhp = oci8_errhp;

    if (!NIL_P(svcctx->executing_thread)) {
        rb_raise(rb_eRuntimeError /* FIXME */, "executing in another thread");
    }

    if (!svcctx->suppress_free_temp_lobs) {
        oci8_temp_lob_t *lob = svcctx->temp_lobs;
        while (lob != NULL) {
            oci8_temp_lob_t *lob_next = lob->next;

            if (svcctx->non_blocking) {
                free_temp_lob_arg_t arg;
                sword rv;

                arg.svcctx = svcctx;
                arg.svchp = svcctx->base.hp.svc;
                arg.errhp = errhp;
                arg.lob = lob->lob;

                svcctx->executing_thread = rb_thread_current();
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
                rv = (sword)(VALUE)rb_thread_call_without_gvl(free_temp_lob, &arg, oci8_unblock_func, svcctx);
#else
                rv = (sword)rb_thread_blocking_region((VALUE(*)(void*))free_temp_lob, &arg, oci8_unblock_func, svcctx);
#endif
                if (rv == OCI_ERROR) {
                    if (oci8_get_error_code(errhp) == 1013) {
                        rb_raise(eOCIBreak, "Canceled by user request.");
                    }
                }
            } else {
                OCILobFreeTemporary(svcctx->base.hp.svc, errhp, lob->lob);
            }
            OCIDescriptorFree(lob->lob, OCI_DTYPE_LOB);

            xfree(lob);
            svcctx->temp_lobs = lob = lob_next;
        }
    }

    if (svcctx->non_blocking) {
        sword rv;

        svcctx->executing_thread = rb_thread_current();
        /* Note: executing_thread is cleard at the end of the blocking function. */
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
        rv = (sword)(VALUE)rb_thread_call_without_gvl(func, data, oci8_unblock_func, svcctx);
#else
        rv = (sword)rb_thread_blocking_region((VALUE(*)(void*))func, data, oci8_unblock_func, svcctx);
#endif
        if (rv == OCI_ERROR) {
            if (oci8_get_error_code(errhp) == 1013) {
                rb_raise(eOCIBreak, "Canceled by user request.");
            }
        }
        return rv;
    } else {
        return (sword)(VALUE)func(data);
    }
}
예제 #7
0
파일: rb_monitor.c 프로젝트: caisong/wdm
static VALUE
rb_monitor_run_bang(VALUE self)
{
    BOOL already_running,
         waiting_succeeded;
    WDM_PMonitor monitor;

    WDM_DEBUG("Running the monitor!");

    Data_Get_Struct(self, WDM_Monitor, monitor);
    already_running = FALSE;

    EnterCriticalSection(&monitor->lock);
        if ( monitor->running ) {
            already_running = TRUE;
        }
        else {
            monitor->running = TRUE;
        }
    LeaveCriticalSection(&monitor->lock);

    if (already_running) {
        WDM_DEBUG("Not doing anything because the monitor is already running!");
        return Qnil;
    }

    // Reset events
    ResetEvent(monitor->process_event);
    ResetEvent(monitor->stop_event);

    monitor->monitoring_thread = CreateThread(
        NULL,                     // default security attributes
        0,                        // use default stack size
        start_monitoring,         // thread function name
        monitor,                  // argument to thread function
        0,                        // use default creation flags
        NULL                      // Ignore thread identifier
    );

    if ( monitor->monitoring_thread == NULL ) {
        rb_raise(eWDM_Error, "Can't create a thread for the monitor!");
    }

    while ( monitor->running ) {
        waiting_succeeded = rb_thread_blocking_region(wait_for_changes, monitor->process_event, stop_monitoring, monitor);

        if ( waiting_succeeded == Qfalse ) {
            rb_raise(eWDM_Error, "Failed while waiting for a change in the watched directories!");
        }

        if ( ! monitor->running ) {
            wdm_queue_empty(monitor->changes);
            return Qnil;
        }

        process_changes(monitor->changes);

        if ( ! ResetEvent(monitor->process_event) ) {
            rb_raise(eWDM_Error, "Couldn't reset system events to watch for changes!");
        }
    }

    return Qnil;
}
    static VALUE
loop_run_poll(VALUE argp)
{
    lp_arg *args = (lp_arg*)argp;
    rb_mt_loop *loop = args->loop;
    hrtime_t now, next_time;

    if (loop->events.count) {
        uint32_t i;
        args->fds = calloc(loop->events.count, sizeof(struct pollfd));
        if (args->fds == NULL) {
            rb_raise(cb_eClientNoMemoryError, "failed to allocate memory for pollfd");
        }
        for(i = 0; i < loop->events.count; i++) {
            rb_mt_socket_list *list = &loop->events.sockets[i];
            args->fds[i].fd = list->socket;
            args->fds[i].events =
                (list->flags & LCB_READ_EVENT ? POLLIN : 0) |
                (list->flags & LCB_WRITE_EVENT ? POLLOUT : 0);
        }
        args->nfd = loop->events.count;
    }

retry:
    next_time = timers_minimum(&loop->timers);
    if (next_time) {
        now = gethrtime();
        args->ts = next_time <= now ? 0 : next_time - now;
    } else {
        args->ts = HRTIME_INFINITY;
    }

#ifdef HAVE_RB_THREAD_BLOCKING_REGION
    rb_thread_blocking_region(loop_blocking_poll, args, RUBY_UBF_PROCESS, NULL);
#else
    if (rb_thread_alone()) {
        TRAP_BEG;
        args->result = xpoll(args->fds, args->nfd, args->ts);
        if (args->result < 0) args->lerrno = errno;
        TRAP_END;
    } else {
        /* 5 millisecond pause */
        hrtime_t mini_pause = 5000000;
        int exact = 0;
        if (args->ts != HRTIME_INFINITY && args->ts < mini_pause) {
            mini_pause = args->ts;
            exact = 1;
        }
        TRAP_BEG;
        args->result = xpoll(args->fds, args->nfd, mini_pause);
        if (args->result < 0) args->lerrno = errno;
        TRAP_END;
        if (args->result == 0 && !exact) {
            args->result = -1;
            args->lerrno = EINTR;
        }
    }
#endif

    if (args->result < 0) {
        errno = args->lerrno;
        switch (errno) {
            case EINTR:
#ifdef ERESTART
            case ERESTART:
#endif
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
                rb_thread_schedule();
#endif
                goto retry;
        }
        rb_sys_fail("poll");
        return Qnil;
    }

    if (next_time) {
        now = gethrtime();
    }

    if (args->result > 0) {
        uint32_t cnt = args->result;
        uint32_t fd_n = 0, ev_n = 0;
        while (cnt && fd_n < args->nfd && ev_n < loop->events.count) {
            struct pollfd *res = args->fds + fd_n;
            rb_mt_socket_list *list = loop->events.sockets + ev_n;
            rb_mt_event *sock = list->first;

            /* if plugin used correctly, this checks are noop */
            if (res->fd < list->socket) {
                fd_n++;
                continue;
            } else if (res->fd > list->socket) {
                ev_n++;
                continue;
            }

            if (res->revents) {
                short flags =
                    ((res->revents & POLLIN_SET) ? LCB_READ_EVENT : 0) |
                    ((res->revents & POLLOUT_SET) ? LCB_WRITE_EVENT : 0);
                cnt--;
                loop_enque_events(&loop->callbacks, sock, flags);
            }
            fd_n++;
            ev_n++;
        }
        callbacks_run(&loop->callbacks);
    }

    if (next_time) {
        timers_run(&loop->timers, now);
    }
    if (loop->events.count == 0 && loop->timers.count == 0) {
        loop->run = 0;
    }
    return Qnil;
}
예제 #9
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;
    }
}
예제 #10
0
static int sedna_non_blocking_execute(SQ *q)
{
	return rb_thread_blocking_region((void*)sedna_blocking_execute, q, RUBY_UBF_IO, NULL);
}
예제 #11
0
static int sedna_non_blocking_connect(SCA *c)
{
	return rb_thread_blocking_region((void*)sedna_blocking_connect, c, RUBY_UBF_IO, NULL);
}
예제 #12
0
파일: result.c 프로젝트: donnoman/mysql2
static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool) {
  VALUE rowVal;
  mysql2_result_wrapper * wrapper;
  MYSQL_ROW row;
  MYSQL_FIELD * fields = NULL;
  unsigned int i = 0;
  unsigned long * fieldLengths;
  void * ptr;

  GetMysql2Result(self, wrapper);

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

  ptr = wrapper->result;
  row = (MYSQL_ROW)rb_thread_blocking_region(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
  if (row == NULL) {
    return Qnil;
  }

  if (asArray) {
    rowVal = rb_ary_new2(wrapper->numberOfFields);
  } else {
    rowVal = rb_hash_new();
  }
  fields = mysql_fetch_fields(wrapper->result);
  fieldLengths = mysql_fetch_lengths(wrapper->result);
  if (wrapper->fields == Qnil) {
    wrapper->numberOfFields = mysql_num_fields(wrapper->result);
    wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
  }

  for (i = 0; i < wrapper->numberOfFields; i++) {
    VALUE field = rb_mysql_result_fetch_field(self, i, symbolizeKeys);
    if (row[i]) {
      VALUE val = Qnil;
      switch(fields[i].type) {
        case MYSQL_TYPE_NULL:       // NULL-type field
          val = Qnil;
          break;
        case MYSQL_TYPE_BIT:        // BIT field (MySQL 5.0.3 and up)
          val = rb_str_new(row[i], fieldLengths[i]);
          break;
        case MYSQL_TYPE_TINY:       // TINYINT field
          if (castBool && fields[i].length == 1) {
            val = *row[i] == '1' ? Qtrue : Qfalse;
            break;
          }
        case MYSQL_TYPE_SHORT:      // SMALLINT field
        case MYSQL_TYPE_LONG:       // INTEGER field
        case MYSQL_TYPE_INT24:      // MEDIUMINT field
        case MYSQL_TYPE_LONGLONG:   // BIGINT field
        case MYSQL_TYPE_YEAR:       // YEAR field
          val = rb_cstr2inum(row[i], 10);
          break;
        case MYSQL_TYPE_DECIMAL:    // DECIMAL or NUMERIC field
        case MYSQL_TYPE_NEWDECIMAL: // Precision math DECIMAL or NUMERIC field (MySQL 5.0.3 and up)
          if (strtod(row[i], NULL) == 0.000000){
            val = rb_funcall(cBigDecimal, intern_new, 1, opt_decimal_zero);
          }else{
            val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(row[i], fieldLengths[i]));
          }
          break;
        case MYSQL_TYPE_FLOAT:      // FLOAT field
        case MYSQL_TYPE_DOUBLE: {     // DOUBLE or REAL field
          double column_to_double;
          column_to_double = strtod(row[i], NULL);
          if (column_to_double == 0.000000){
            val = opt_float_zero;
          }else{
            val = rb_float_new(column_to_double);
          }
          break;
        }
        case MYSQL_TYPE_TIME: {     // TIME field
          int hour, min, sec, tokens;
          tokens = sscanf(row[i], "%2d:%2d:%2d", &hour, &min, &sec);
          val = rb_funcall(rb_cTime, db_timezone, 6, opt_time_year, opt_time_month, opt_time_month, INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
          if (!NIL_P(app_timezone)) {
            if (app_timezone == intern_local) {
              val = rb_funcall(val, intern_localtime, 0);
            } else { // utc
              val = rb_funcall(val, intern_utc, 0);
            }
          }
          break;
        }
        case MYSQL_TYPE_TIMESTAMP:  // TIMESTAMP field
        case MYSQL_TYPE_DATETIME: { // DATETIME field
          int year, month, day, hour, min, sec, tokens;
          tokens = sscanf(row[i], "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
          if (year+month+day+hour+min+sec == 0) {
            val = Qnil;
          } else {
            if (month < 1 || day < 1) {
              rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
              val = Qnil;
            } else {
              if (year < 1902 || year+month+day > 2058) { // use DateTime instead
                VALUE offset = INT2NUM(0);
                if (db_timezone == intern_local) {
                  offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
                }
                val = rb_funcall(cDateTime, intern_civil, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), offset);
                if (!NIL_P(app_timezone)) {
                  if (app_timezone == intern_local) {
                    offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
                    val = rb_funcall(val, intern_new_offset, 1, offset);
                  } else { // utc
                    val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
                  }
                }
              } else {
                val = rb_funcall(rb_cTime, db_timezone, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
                if (!NIL_P(app_timezone)) {
                  if (app_timezone == intern_local) {
                    val = rb_funcall(val, intern_localtime, 0);
                  } else { // utc
                    val = rb_funcall(val, intern_utc, 0);
                  }
                }
              }
            }
          }
          break;
        }
        case MYSQL_TYPE_DATE:       // DATE field
        case MYSQL_TYPE_NEWDATE: {  // Newer const used > 5.0
          int year, month, day, tokens;
          tokens = sscanf(row[i], "%4d-%2d-%2d", &year, &month, &day);
          if (year+month+day == 0) {
            val = Qnil;
          } else {
            if (month < 1 || day < 1) {
              rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
              val = Qnil;
            } else {
              val = rb_funcall(cDate, intern_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
            }
          }
          break;
        }
        case MYSQL_TYPE_TINY_BLOB:
        case MYSQL_TYPE_MEDIUM_BLOB:
        case MYSQL_TYPE_LONG_BLOB:
        case MYSQL_TYPE_BLOB:
        case MYSQL_TYPE_VAR_STRING:
        case MYSQL_TYPE_VARCHAR:
        case MYSQL_TYPE_STRING:     // CHAR or BINARY field
        case MYSQL_TYPE_SET:        // SET field
        case MYSQL_TYPE_ENUM:       // ENUM field
        case MYSQL_TYPE_GEOMETRY:   // Spatial fielda
        default:
          val = rb_str_new(row[i], fieldLengths[i]);
#ifdef HAVE_RUBY_ENCODING_H
          // if binary flag is set, respect it's wishes
          if (fields[i].flags & BINARY_FLAG) {
            rb_enc_associate(val, binaryEncoding);
          } else {
            // lookup the encoding configured on this field
            VALUE new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset_code, 1, INT2NUM(fields[i].charsetnr));
            if (new_encoding != Qnil) {
              // use the field encoding we were able to match
              rb_encoding *enc = rb_to_encoding(new_encoding);
              rb_enc_associate(val, enc);
            } else {
              // otherwise fall-back to the connection's encoding
              rb_enc_associate(val, conn_enc);
            }
            if (default_internal_enc) {
              val = rb_str_export_to_enc(val, default_internal_enc);
            }
          }
#endif
          break;
      }
      if (asArray) {
        rb_ary_push(rowVal, val);
      } else {
        rb_hash_aset(rowVal, field, val);
      }
    } else {
      if (asArray) {
        rb_ary_push(rowVal, Qnil);
      } else {
        rb_hash_aset(rowVal, field, Qnil);
      }
    }
  }
  return rowVal;
}
예제 #13
0
파일: client.c 프로젝트: JonathonMA/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;

  // 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);
  }

#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
}
예제 #14
0
파일: client.c 프로젝트: brupm/mysql2
static VALUE rb_mysql_client_ping(VALUE self) {
  GET_CLIENT(self);

  return rb_thread_blocking_region(nogvl_ping, wrapper->client, RUBY_UBF_IO, 0);
}
예제 #15
0
static VALUE
f_generic_writev(VALUE fd, VALUE *array_of_components, unsigned int count) {
	VALUE components, str;
	unsigned int total_size, total_components, ngroups;
	IOVectorGroup *groups;
	unsigned int i, j, group_offset, vector_offset;
	unsigned long long ssize_max;
	ssize_t ret;
	int done, fd_num, e;
	#ifndef TRAP_BEG
		WritevWrapperData writev_wrapper_data;
	#endif
	
	/* First determine the number of components that we have. */
	total_components   = 0;
	for (i = 0; i < count; i++) {
	        Check_Type(array_of_components[i], T_ARRAY);
		total_components += (unsigned int) RARRAY_LEN(array_of_components[i]);
	}
	if (total_components == 0) {
		return NUM2INT(0);
	}
	
	/* A single writev() call can only accept IOV_MAX vectors, so we
	 * may have to split the components into groups and perform
	 * multiple writev() calls, one per group. Determine the number
	 * of groups needed, how big each group should be and allocate
	 * memory for them.
	 */
	if (total_components % IOV_MAX == 0) {
		ngroups = total_components / IOV_MAX;
		groups  = alloca(ngroups * sizeof(IOVectorGroup));
		if (groups == NULL) {
			rb_raise(rb_eNoMemError, "Insufficient stack space.");
		}
		memset(groups, 0, ngroups * sizeof(IOVectorGroup));
		for (i = 0; i < ngroups; i++) {
			groups[i].io_vectors = alloca(IOV_MAX * sizeof(struct iovec));
			if (groups[i].io_vectors == NULL) {
				rb_raise(rb_eNoMemError, "Insufficient stack space.");
			}
			groups[i].count = IOV_MAX;
		}
	} else {
		ngroups = total_components / IOV_MAX + 1;
		groups  = alloca(ngroups * sizeof(IOVectorGroup));
		if (groups == NULL) {
			rb_raise(rb_eNoMemError, "Insufficient stack space.");
		}
		memset(groups, 0, ngroups * sizeof(IOVectorGroup));
		for (i = 0; i < ngroups - 1; i++) {
			groups[i].io_vectors = alloca(IOV_MAX * sizeof(struct iovec));
			if (groups[i].io_vectors == NULL) {
				rb_raise(rb_eNoMemError, "Insufficient stack space.");
			}
			groups[i].count = IOV_MAX;
		}
		groups[ngroups - 1].io_vectors = alloca((total_components % IOV_MAX) * sizeof(struct iovec));
		if (groups[ngroups - 1].io_vectors == NULL) {
			rb_raise(rb_eNoMemError, "Insufficient stack space.");
		}
		groups[ngroups - 1].count = total_components % IOV_MAX;
	}
	
	/* Now distribute the components among the groups, filling the iovec
	 * array in each group. Also calculate the total data size while we're
	 * at it.
	 */
	total_size    = 0;
	group_offset  = 0;
	vector_offset = 0;
	for (i = 0; i < count; i++) {
		components = array_of_components[i];
		for (j = 0; j < (unsigned int) RARRAY_LEN(components); j++) {
			str = rb_ary_entry(components, j);
			str = rb_obj_as_string(str);
			total_size += (unsigned int) RSTRING_LEN(str);
			/* I know writev() doesn't write to iov_base, but on some
			 * platforms it's still defined as non-const char *
			 * :-(
			 */
			groups[group_offset].io_vectors[vector_offset].iov_base = (char *) RSTRING_PTR(str);
			groups[group_offset].io_vectors[vector_offset].iov_len  = RSTRING_LEN(str);
			groups[group_offset].total_size += RSTRING_LEN(str);
			vector_offset++;
			if (vector_offset == groups[group_offset].count) {
				group_offset++;
				vector_offset = 0;
			}
		}
	}
	
	/* We don't compare to SSIZE_MAX directly in order to shut up a compiler warning on OS X Snow Leopard. */
	ssize_max = SSIZE_MAX;
	if (total_size > ssize_max) {
		rb_raise(rb_eArgError, "The total size of the components may not be larger than SSIZE_MAX.");
	}
	
	/* Write the data. */
	fd_num = NUM2INT(fd);
	for (i = 0; i < ngroups; i++) {
		/* Wait until the file descriptor becomes writable before writing things. */
		rb_thread_fd_writable(fd_num);
		
		done = 0;
		while (!done) {
			#ifdef TRAP_BEG
				TRAP_BEG;
				ret = writev(fd_num, groups[i].io_vectors, groups[i].count);
				TRAP_END;
			#else
				writev_wrapper_data.filedes = fd_num;
				writev_wrapper_data.iov     = groups[i].io_vectors;
				writev_wrapper_data.iovcnt  = groups[i].count;
				ret = (int) rb_thread_blocking_region(writev_wrapper,
					&writev_wrapper_data, RUBY_UBF_IO, 0);
			#endif
			if (ret == -1) {
				/* If the error is something like EAGAIN, yield to another
				 * thread until the file descriptor becomes writable again.
				 * In case of other errors, raise an exception.
				 */
				if (!rb_io_wait_writable(fd_num)) {
					rb_sys_fail("writev()");
				}
			} else if (ret < groups[i].total_size) {
				/* Not everything in this group has been written. Retry without
				 * writing the bytes that been successfully written.
				 */
				e = errno;
				update_group_written_info(&groups[i], ret);
				errno = e;
				rb_io_wait_writable(fd_num);
			} else {
				done = 1;
			}
		}
	}
	return INT2NUM(total_size);
}
예제 #16
0
static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool, int cast, MYSQL_FIELD * fields) {
  VALUE rowVal;
  mysql2_result_wrapper * wrapper;
  MYSQL_ROW row;
  unsigned int i = 0;
  unsigned long * fieldLengths;
  void * ptr;
#ifdef HAVE_RUBY_ENCODING_H
  rb_encoding *default_internal_enc;
  rb_encoding *conn_enc;
#endif
  GetMysql2Result(self, wrapper);

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

  ptr = wrapper->result;
  row = (MYSQL_ROW)rb_thread_blocking_region(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
  if (row == NULL) {
    return Qnil;
  }

  if (asArray) {
    rowVal = rb_ary_new2(wrapper->numberOfFields);
  } else {
    rowVal = rb_hash_new();
  }
  fieldLengths = mysql_fetch_lengths(wrapper->result);
  if (wrapper->fields == Qnil) {
    wrapper->numberOfFields = mysql_num_fields(wrapper->result);
    wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
  }

  for (i = 0; i < wrapper->numberOfFields; i++) {
    VALUE field = rb_mysql_result_fetch_field(self, i, symbolizeKeys);
    if (row[i]) {
      VALUE val = Qnil;
      enum enum_field_types type = fields[i].type;

      if(!cast) {
        if (type == MYSQL_TYPE_NULL) {
          val = Qnil;
        } else {
          val = rb_str_new(row[i], fieldLengths[i]);
#ifdef HAVE_RUBY_ENCODING_H
          val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
#endif
        }
      } else {
        switch(type) {
        case MYSQL_TYPE_NULL:       // NULL-type field
          val = Qnil;
          break;
        case MYSQL_TYPE_BIT:        // BIT field (MySQL 5.0.3 and up)
          val = rb_str_new(row[i], fieldLengths[i]);
          break;
        case MYSQL_TYPE_TINY:       // TINYINT field
          if (castBool && fields[i].length == 1) {
            val = *row[i] == '1' ? Qtrue : Qfalse;
            break;
          }
        case MYSQL_TYPE_SHORT:      // SMALLINT field
        case MYSQL_TYPE_LONG:       // INTEGER field
        case MYSQL_TYPE_INT24:      // MEDIUMINT field
        case MYSQL_TYPE_LONGLONG:   // BIGINT field
        case MYSQL_TYPE_YEAR:       // YEAR field
          val = rb_cstr2inum(row[i], 10);
          break;
        case MYSQL_TYPE_DECIMAL:    // DECIMAL or NUMERIC field
        case MYSQL_TYPE_NEWDECIMAL: // Precision math DECIMAL or NUMERIC field (MySQL 5.0.3 and up)
          if (fields[i].decimals == 0) {
            val = rb_cstr2inum(row[i], 10);
          } else if (strtod(row[i], NULL) == 0.000000){
            val = rb_funcall(cBigDecimal, intern_new, 1, opt_decimal_zero);
          }else{
            val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(row[i], fieldLengths[i]));
          }
          break;
        case MYSQL_TYPE_FLOAT:      // FLOAT field
        case MYSQL_TYPE_DOUBLE: {     // DOUBLE or REAL field
          double column_to_double;
          column_to_double = strtod(row[i], NULL);
          if (column_to_double == 0.000000){
            val = opt_float_zero;
          }else{
            val = rb_float_new(column_to_double);
          }
          break;
        }
        case MYSQL_TYPE_TIME: {     // TIME field
          int hour, min, sec, tokens;
          tokens = sscanf(row[i], "%2d:%2d:%2d", &hour, &min, &sec);
          val = rb_funcall(rb_cTime, db_timezone, 6, opt_time_year, opt_time_month, opt_time_month, INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
          if (!NIL_P(app_timezone)) {
            if (app_timezone == intern_local) {
              val = rb_funcall(val, intern_localtime, 0);
            } else { // utc
              val = rb_funcall(val, intern_utc, 0);
            }
          }
          break;
        }
        case MYSQL_TYPE_TIMESTAMP:  // TIMESTAMP field
        case MYSQL_TYPE_DATETIME: { // DATETIME field
          unsigned int year, month, day, hour, min, sec, tokens;
          uint64_t seconds;

          tokens = sscanf(row[i], "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
          seconds = (year*31557600ULL) + (month*2592000ULL) + (day*86400ULL) + (hour*3600ULL) + (min*60ULL) + sec;

          if (seconds == 0) {
            val = Qnil;
          } else {
            if (month < 1 || day < 1) {
              rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
              val = Qnil;
            } else {
              if (seconds < MYSQL2_MIN_TIME || seconds >= MYSQL2_MAX_TIME) { // use DateTime instead
                VALUE offset = INT2NUM(0);
                if (db_timezone == intern_local) {
                  offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
                }
                val = rb_funcall(cDateTime, intern_civil, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), offset);
                if (!NIL_P(app_timezone)) {
                  if (app_timezone == intern_local) {
                    offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
                    val = rb_funcall(val, intern_new_offset, 1, offset);
                  } else { // utc
                    val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
                  }
                }
              } else {
                val = rb_funcall(rb_cTime, db_timezone, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
                if (!NIL_P(app_timezone)) {
                  if (app_timezone == intern_local) {
                    val = rb_funcall(val, intern_localtime, 0);
                  } else { // utc
                    val = rb_funcall(val, intern_utc, 0);
                  }
                }
              }
            }
          }
          break;
        }
        case MYSQL_TYPE_DATE:       // DATE field
        case MYSQL_TYPE_NEWDATE: {  // Newer const used > 5.0
          int year, month, day, tokens;
          tokens = sscanf(row[i], "%4d-%2d-%2d", &year, &month, &day);
          if (year+month+day == 0) {
            val = Qnil;
          } else {
            if (month < 1 || day < 1) {
              rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
              val = Qnil;
            } else {
              val = rb_funcall(cDate, intern_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
            }
          }
          break;
        }
        case MYSQL_TYPE_TINY_BLOB:
        case MYSQL_TYPE_MEDIUM_BLOB:
        case MYSQL_TYPE_LONG_BLOB:
        case MYSQL_TYPE_BLOB:
        case MYSQL_TYPE_VAR_STRING:
        case MYSQL_TYPE_VARCHAR:
        case MYSQL_TYPE_STRING:     // CHAR or BINARY field
        case MYSQL_TYPE_SET:        // SET field
        case MYSQL_TYPE_ENUM:       // ENUM field
        case MYSQL_TYPE_GEOMETRY:   // Spatial fielda
        default:
          val = rb_str_new(row[i], fieldLengths[i]);
#ifdef HAVE_RUBY_ENCODING_H
          val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
#endif
          break;
        }
      }
      if (asArray) {
        rb_ary_push(rowVal, val);
      } else {
        rb_hash_aset(rowVal, field, val);
      }
    } else {
      if (asArray) {
        rb_ary_push(rowVal, Qnil);
      } else {
        rb_hash_aset(rowVal, field, Qnil);
      }
    }
  }
  return rowVal;
}
예제 #17
0
/*
 * IO.writev(fd, %w(hello world))
 *
 * This method writes the contents of an array of strings to the given +fd+.
 * It can be useful to avoid generating a temporary string via Array#join
 * when writing out large arrays of strings.
 *
 * The given array should have fewer elements than the IO::IOV_MAX constant.
 *
 * Returns the number of bytes written.
 */
static VALUE s_io_writev(VALUE klass, VALUE fd, VALUE ary) {
   ssize_t result = 0;
   ssize_t left;
   struct writev_args args;

   args.fd = NUM2INT(fd);
   ARY2IOVEC(args.iov, args.iovcnt, left, ary);

   for(;;) {
#ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
      ssize_t w = (ssize_t)rb_thread_call_without_gvl(
        (void*)nogvl_writev, &args, RUBY_UBF_IO, 0
      );
#else
      ssize_t w = (ssize_t)rb_thread_blocking_region(
        nogvl_writev, &args, RUBY_UBF_IO, 0
      );
#endif

      if(w == -1) {
         if (rb_io_wait_writable(args.fd)) {
            continue;
         } else {
            if (result > 0) {
               /*
                * unlikely to hit this case, return the already written bytes,
                * we'll let the next write (or close) fail instead
                */
               break;
            }
            rb_sys_fail("writev");
         }
      }

      result += w;
      if(w == left) {
         break;
      } else { /* partial write, this can get tricky */
         int i;
         struct iovec *new_iov = args.iov;

         left -= w;

         /* skip over iovecs we've already written completely */
         for (i = 0; i < args.iovcnt; i++, new_iov++) {
            if (w == 0)
               break;

            /*
             * partially written iov,
             * modify and retry with current iovec in front
             */
            if (new_iov->iov_len > (size_t)w) {
               VALUE base = (VALUE)new_iov->iov_base;

               new_iov->iov_len -= w;
               new_iov->iov_base = (void *)(base + w);
               break;
            }

            w -= new_iov->iov_len;
         }

         /* retry without the already-written iovecs */
         args.iovcnt -= i;
         args.iov = new_iov;
      }
   }

   return LONG2NUM(result);
}
예제 #18
0
            .command    = CSTRING(sql),
            .n_args     = RARRAY_LEN(bind),
            .data       = bind_args_data,
            .size       = bind_args_size,
            .format     = bind_args_fmt
        };

        result = (PGresult *)rb_thread_blocking_region(nogvl_pq_exec_params, &q, RUBY_UBF_IO, 0);
        rb_gc_unregister_address(&bind);
        free(bind_args_size);
        free(bind_args_data);
        free(bind_args_fmt);
    }
    else {
        Query q = {.connection = a->connection, .command = CSTRING(sql)};
        result = (PGresult *)rb_thread_blocking_region(nogvl_pq_exec, &q, RUBY_UBF_IO, 0);
    }

    db_postgres_check_result(result);
    return db_postgres_result_load(db_postgres_result_allocate(cDPR), result);
}

VALUE db_postgres_adapter_begin(int argc, VALUE *argv, VALUE self) {
    char command[256];
    VALUE savepoint;
    PGresult *result;

    Adapter *a = db_postgres_adapter_handle_safe(self);
    rb_scan_args(argc, argv, "01", &savepoint);

    if (a->t_nesting == 0) {
예제 #19
0
// There is really no way to know we're unlocked. So just make sure the arguments
// go through fine.
static VALUE thread_spec_rb_thread_blocking_region() {
  VALUE ret = rb_thread_blocking_region(do_unlocked, (void*)1, 0, 0);
  if(ret == (VALUE)1) return Qtrue;
  return Qfalse;
}
예제 #20
0
파일: rb_monitor.c 프로젝트: dan-bryant/wdm
static VALUE
rb_monitor_run_bang(VALUE self)
{
    BOOL already_running,
         waiting_succeeded;
    WDM_PMonitor monitor;

    WDM_DEBUG("Running the monitor!");

    Data_Get_Struct(self, WDM_Monitor, monitor);
    already_running = FALSE;

    EnterCriticalSection(&monitor->lock);
        if ( monitor->running ) {
            already_running = TRUE;
        }
        else {
            monitor->running = TRUE;
        }
    LeaveCriticalSection(&monitor->lock);

    if (already_running) {
        WDM_DEBUG("Not doing anything because the monitor is already running!");
        return Qnil;
    }

    // Reset events
    ResetEvent(monitor->process_event);
    ResetEvent(monitor->stop_event);

    monitor->monitoring_thread = CreateThread(
        NULL,                     // default security attributes
        0,                        // use default stack size
        start_monitoring,         // thread function name
        monitor,                  // argument to thread function
        0,                        // use default creation flags
        NULL                      // Ignore thread identifier
    );

    if ( monitor->monitoring_thread == NULL ) {
        rb_raise(eWDM_Error, "Can't create a thread for the monitor!");
    }

    while ( monitor->running ) {

        // Ruby 2.2 removed the 'rb_thread_blocking_region' function. Hence, we now need
        // to check if the replacement function is defined and use it if it's available.
        #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
        waiting_succeeded = rb_thread_call_without_gvl(wait_for_changes, monitor->process_event, stop_monitoring, monitor);
        #else
        waiting_succeeded = rb_thread_blocking_region(wait_for_changes, monitor->process_event, stop_monitoring, monitor);
        #endif

        if ( waiting_succeeded == Qfalse ) {
            rb_raise(eWDM_Error, "Failed while waiting for a change in the watched directories!");
        }

        if ( ! monitor->running ) {
            wdm_queue_empty(monitor->changes);
            return Qnil;
        }

        process_changes(monitor->changes);

        if ( ! ResetEvent(monitor->process_event) ) {
            rb_raise(eWDM_Error, "Couldn't reset system events to watch for changes!");
        }
    }

    return Qnil;
}
예제 #21
0
파일: loop.c 프로젝트: Adios/cool.io
static void Coolio_Loop_ev_loop_oneshot(struct Coolio_Loop *loop_data)
{
  /* Use Ruby 1.9's rb_thread_blocking_region call to make a blocking system call */
  rb_thread_blocking_region(Coolio_Loop_ev_loop_oneshot_blocking, loop_data, RUBY_UBF_IO, 0);
}
예제 #22
0
/*
 * call-seq:
 * multi = Curl::Multi.new
 * easy1 = Curl::Easy.new('url')
 * easy2 = Curl::Easy.new('url')
 *
 * multi.add(easy1)
 * multi.add(easy2)
 *
 * multi.perform do
 *  # while idle other code my execute here
 * end
 *
 * Run multi handles, looping selecting when data can be transfered
 */
VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
  CURLMcode mcode;
  ruby_curl_multi *rbcm;
  int maxfd, rc;
  fd_set fdread, fdwrite, fdexcep;
#ifdef _WIN32
  fd_set crt_fdread, crt_fdwrite, crt_fdexcep;
#endif
  long timeout_milliseconds;
  struct timeval tv = {0, 0};
  VALUE block = Qnil;
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
  struct _select_set fdset_args;
#endif

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

  Data_Get_Struct(self, ruby_curl_multi, rbcm);

  timeout_milliseconds = cCurlMutiDefaulttimeout;

  rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
  rb_curl_multi_read_info( self, rbcm->handle );
  if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self);  }
 
  do {
    while (rbcm->running) {

#ifdef HAVE_CURL_MULTI_TIMEOUT
      /* get the curl suggested time out */
      mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds);
      if (mcode != CURLM_OK) {
        raise_curl_multi_error_exception(mcode);
      }
#else
      /* libcurl doesn't have a timeout method defined, initialize to -1 we'll pick up the default later */
      timeout_milliseconds = -1;
#endif

      if (timeout_milliseconds == 0) { /* no delay */
        rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
        rb_curl_multi_read_info( self, rbcm->handle );
        if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self);  }
        continue;
      }

      if (timeout_milliseconds < 0 || timeout_milliseconds > cCurlMutiDefaulttimeout) {
        timeout_milliseconds = cCurlMutiDefaulttimeout; /* libcurl doesn't know how long to wait, use a default timeout */
                                                        /* or buggy versions libcurl sometimes reports huge timeouts... let's cap it */
      }

      tv.tv_sec  = 0; /* never wait longer than 1 second */
      tv.tv_usec = (int)(timeout_milliseconds * 1000); /* XXX: int is the right type for OSX, what about linux? */

      FD_ZERO(&fdread);
      FD_ZERO(&fdwrite);
      FD_ZERO(&fdexcep);

      /* load the fd sets from the multi handle */
      mcode = curl_multi_fdset(rbcm->handle, &fdread, &fdwrite, &fdexcep, &maxfd);
      if (mcode != CURLM_OK) {
        raise_curl_multi_error_exception(mcode);
      }

#ifdef _WIN32
      create_crt_fd(&fdread, &crt_fdread);
      create_crt_fd(&fdwrite, &crt_fdwrite);
      create_crt_fd(&fdexcep, &crt_fdexcep);
#endif

#ifdef HAVE_RB_THREAD_BLOCKING_REGION
      fdset_args.maxfd = maxfd+1;
      fdset_args.fdread = &fdread;
      fdset_args.fdwrite = &fdwrite;
      fdset_args.fdexcep = &fdexcep;
      fdset_args.tv = &tv;
      rc = rb_thread_blocking_region(curb_select, &fdset_args, RUBY_UBF_IO, 0);
#else
      rc = rb_thread_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tv);
#endif

#ifdef _WIN32
      cleanup_crt_fd(&fdread, &crt_fdread);
      cleanup_crt_fd(&fdwrite, &crt_fdwrite);
      cleanup_crt_fd(&fdexcep, &crt_fdexcep);
#endif

      switch(rc) {
      case -1:
        if(errno != EINTR) {
          rb_raise(rb_eRuntimeError, "select(): %s", strerror(errno));
          break;
        }
      case 0: /* timeout */
      default: /* action */
        rb_curl_multi_run( self, rbcm->handle, &(rbcm->running) );
        rb_curl_multi_read_info( self, rbcm->handle );
        if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self);  }
        break;
      }
    }

  } while( rbcm->running );

  rb_curl_multi_read_info( self, rbcm->handle );
  if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self);  }
    
  return Qtrue;
}