コード例 #1
0
ファイル: do_mysql.c プロジェクト: NZX/do
static VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
  VALUE query;

  MYSQL_RES *response = 0;

  my_ulonglong affected_rows;
  my_ulonglong insert_id;
  VALUE connection = rb_iv_get(self, "@connection");
  VALUE mysql_connection = rb_iv_get(connection, "@connection");
  if (Qnil == mysql_connection) {
    rb_raise(eConnectionError, "This connection has already been closed.");
  }

  MYSQL *db = DATA_PTR(mysql_connection);
  query = build_query_from_args(self, argc, argv);

  response = cCommand_execute(self, connection, db, query);

  affected_rows = mysql_affected_rows(db);
  insert_id     = mysql_insert_id(db);
  mysql_free_result(response);

  if ((my_ulonglong)-1 == affected_rows) {
    return Qnil;
  }

  return rb_funcall(cResult, ID_NEW, 3, self, INT2NUM(affected_rows), insert_id == 0 ? Qnil : INT2NUM(insert_id));
}
コード例 #2
0
ファイル: do_postgres_ext.c プロジェクト: matthewd/do
static VALUE cCommand_execute_reader(int argc, VALUE *argv[], VALUE self) {
  VALUE reader, query;
  VALUE field_names, field_types;

  int i;
  int field_count;
  int infer_types = 0;

  VALUE connection = rb_iv_get(self, "@connection");
  VALUE postgres_connection = rb_iv_get(connection, "@connection");
  if (Qnil == postgres_connection) {
    rb_raise(eConnectionError, "This connection has already been closed.");
  }

  PGconn *db = DATA_PTR(postgres_connection);
  PGresult *response;

  query = build_query_from_args(self, argc, argv);

  response = cCommand_execute(self, db, query);

  if ( PQresultStatus(response) != PGRES_TUPLES_OK ) {
    raise_error(self, response, query);
  }

  field_count = PQnfields(response);

  reader = rb_funcall(cReader, ID_NEW, 0);
  rb_iv_set(reader, "@connection", connection);
  rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, response));
  rb_iv_set(reader, "@field_count", INT2NUM(field_count));
  rb_iv_set(reader, "@row_count", INT2NUM(PQntuples(response)));

  field_names = rb_ary_new();
  field_types = rb_iv_get(self, "@field_types");

  if ( field_types == Qnil || 0 == RARRAY_LEN(field_types) ) {
    field_types = rb_ary_new();
    infer_types = 1;
  } else if (RARRAY_LEN(field_types) != field_count) {
    // Whoops...  wrong number of types passed to set_types.  Close the reader and raise
    // and error
    rb_funcall(reader, rb_intern("close"), 0);
    rb_raise(eArgumentError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
  }

  for ( i = 0; i < field_count; i++ ) {
    rb_ary_push(field_names, rb_str_new2(PQfname(response, i)));
    if ( infer_types == 1 ) {
      rb_ary_push(field_types, infer_ruby_type(PQftype(response, i)));
    }
  }

  rb_iv_set(reader, "@position", INT2NUM(0));
  rb_iv_set(reader, "@fields", field_names);
  rb_iv_set(reader, "@field_types", field_types);

  return reader;
}
コード例 #3
0
ファイル: do_postgres_ext.c プロジェクト: matthewd/do
static VALUE cCommand_execute_non_query(int argc, VALUE *argv[], VALUE self) {
  VALUE connection = rb_iv_get(self, "@connection");
  VALUE postgres_connection = rb_iv_get(connection, "@connection");
  if (Qnil == postgres_connection) {
    rb_raise(eConnectionError, "This connection has already been closed.");
  }

  PGconn *db = DATA_PTR(postgres_connection);
  PGresult *response;
  int status;

  VALUE affected_rows = Qnil;
  VALUE insert_id = Qnil;

  VALUE query = build_query_from_args(self, argc, argv);

  response = cCommand_execute(self, db, query);

  status = PQresultStatus(response);

  if ( status == PGRES_TUPLES_OK ) {
    insert_id = INT2NUM(atoi(PQgetvalue(response, 0, 0)));
    affected_rows = INT2NUM(atoi(PQcmdTuples(response)));
  }
  else if ( status == PGRES_COMMAND_OK ) {
    insert_id = Qnil;
    affected_rows = INT2NUM(atoi(PQcmdTuples(response)));
  }
  else {
    raise_error(self, response, query);
  }

  PQclear(response);

  return rb_funcall(cResult, ID_NEW, 3, self, affected_rows, insert_id);
}
コード例 #4
0
ファイル: do_postgres_ext.c プロジェクト: matthewd/do
static void full_connect(VALUE self, PGconn *db) {

  PGresult *result = NULL;
  VALUE r_host, r_user, r_password, r_path, r_port, r_query, r_options;
  char *host = NULL, *user = NULL, *password = NULL, *path;
  char *database = "", *port = "5432";
  VALUE encoding = Qnil;
  char *search_path = NULL;
  char *search_path_query = NULL;
  char *backslash_off = "SET backslash_quote = off";
  char *standard_strings_on = "SET standard_conforming_strings = on";
  char *warning_messages = "SET client_min_messages = warning";

  if((r_host = rb_iv_get(self, "@host")) != Qnil) {
    host     = StringValuePtr(r_host);
  }

  if((r_user = rb_iv_get(self, "@user")) != Qnil) {
    user     = StringValuePtr(r_user);
  }

  if((r_password = rb_iv_get(self, "@password")) != Qnil) {
    password = StringValuePtr(r_password);
  }

  if((r_port = rb_iv_get(self, "@port")) != Qnil) {
    port = StringValuePtr(r_port);
  }

  if((r_path = rb_iv_get(self, "@path")) != Qnil) {
    path = StringValuePtr(r_path);
    database = strtok(path, "/");
  }

  if (NULL == database || 0 == strlen(database)) {
    rb_raise(eConnectionError, "Database must be specified");
  }

  r_query        = rb_iv_get(self, "@query");

  search_path = get_uri_option(r_query, "search_path");

  db = PQsetdbLogin(
    host,
    port,
    NULL,
    NULL,
    database,
    user,
    password
  );

  if ( PQstatus(db) == CONNECTION_BAD ) {
    rb_raise(eConnectionError, PQerrorMessage(db));
  }

  if (search_path != NULL) {
    search_path_query = (char *)calloc(256, sizeof(char));
    snprintf(search_path_query, 256, "set search_path to %s;", search_path);
    r_query = rb_str_new2(search_path_query);
    result = cCommand_execute(self, db, r_query);

    if (PQresultStatus(result) != PGRES_COMMAND_OK) {
      free(search_path_query);
      raise_error(self, result, r_query);
    }

    free(search_path_query);
  }

  r_options = rb_str_new2(backslash_off);
  result = cCommand_execute(self, db, r_options);

  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
    rb_warn(PQresultErrorMessage(result));
  }

  r_options = rb_str_new2(standard_strings_on);
  result = cCommand_execute(self, db, r_options);

  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
    rb_warn(PQresultErrorMessage(result));
  }

  r_options = rb_str_new2(warning_messages);
  result = cCommand_execute(self, db, r_options);

  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
    rb_warn(PQresultErrorMessage(result));
  }

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

#ifdef HAVE_PQSETCLIENTENCODING
  VALUE pg_encoding = rb_hash_aref(CONST_GET(mEncoding, "MAP"), encoding);
  if(pg_encoding != Qnil) {
    if(PQsetClientEncoding(db, RSTRING_PTR(pg_encoding))) {
      rb_raise(eConnectionError, "Couldn't set encoding: %s", RSTRING_PTR(encoding));
    } else {
#ifdef HAVE_RUBY_ENCODING_H
      rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index(RSTRING_PTR(encoding))));
#endif
      rb_iv_set(self, "@pg_encoding", pg_encoding);
    }
  } else {
    rb_warn("Encoding %s is not a known Ruby encoding for PostgreSQL\n", RSTRING_PTR(encoding));
    rb_iv_set(self, "@encoding", rb_str_new2("UTF-8"));
#ifdef HAVE_RUBY_ENCODING_H
    rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index("UTF-8")));
#endif
    rb_iv_set(self, "@pg_encoding", rb_str_new2("UTF8"));
  }
#endif
  rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
}
コード例 #5
0
ファイル: do_mysql.c プロジェクト: NZX/do
static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
  VALUE query, reader;
  VALUE field_names, field_types;

  unsigned int field_count;
  unsigned int i;

  char guess_default_field_types = 0;
  VALUE connection = rb_iv_get(self, "@connection");
  VALUE mysql_connection = rb_iv_get(connection, "@connection");
  if (Qnil == mysql_connection) {
    rb_raise(eConnectionError, "This connection has already been closed.");
  }

  MYSQL *db = DATA_PTR(mysql_connection);

  MYSQL_RES *response = 0;
  MYSQL_FIELD *field;

  query = build_query_from_args(self, argc, argv);

  response = cCommand_execute(self, connection, db, query);

  if (!response) {
    return Qnil;
  }

  field_count = mysql_field_count(db);

  reader = rb_funcall(cReader, ID_NEW, 0);
  rb_iv_set(reader, "@connection", connection);
  rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, response));
  rb_iv_set(reader, "@opened", Qfalse);
  rb_iv_set(reader, "@field_count", INT2NUM(field_count));

  field_names = rb_ary_new();
  field_types = rb_iv_get(self, "@field_types");

  if ( field_types == Qnil || 0 == RARRAY_LEN(field_types) ) {
    field_types = rb_ary_new();
    guess_default_field_types = 1;
  } else if (RARRAY_LEN(field_types) != field_count) {
    // Whoops...  wrong number of types passed to set_types.  Close the reader and raise
    // and error
    rb_funcall(reader, rb_intern("close"), 0);
    rb_raise(rb_eArgError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
  }

  for(i = 0; i < field_count; i++) {
    field = mysql_fetch_field_direct(response, i);
    rb_ary_push(field_names, rb_str_new2(field->name));

    if (1 == guess_default_field_types) {
      rb_ary_push(field_types, infer_ruby_type(field));
    }
  }

  rb_iv_set(reader, "@fields", field_names);
  rb_iv_set(reader, "@field_types", field_types);

  if (rb_block_given_p()) {
    rb_yield(reader);
    rb_funcall(reader, rb_intern("close"), 0);
  }

  return reader;
}
コード例 #6
0
ファイル: do_mysql.c プロジェクト: NZX/do
static void full_connect(VALUE self, MYSQL* db) {
  // Check to see if we're on the db machine.  If so, try to use the socket
  VALUE r_host, r_user, r_password, r_path, r_query, r_port;

  const char *host = "localhost", *user = "******"; 
  char *database = NULL, *socket = NULL, *password = NULL, *path = NULL;
  VALUE encoding = Qnil;

  MYSQL *result;

  int port = 3306;
  unsigned long client_flags = 0;
  int encoding_error;

  if((r_host = rb_iv_get(self, "@host")) != Qnil) {
    host     = StringValuePtr(r_host);
  }

  if((r_user = rb_iv_get(self, "@user")) != Qnil) {
    user     = StringValuePtr(r_user);
  }

  if((r_password = rb_iv_get(self, "@password")) != Qnil) {
    password = StringValuePtr(r_password);
  }

  if((r_port = rb_iv_get(self, "@port")) != Qnil) {
    port = NUM2INT(r_port);
  }

  if((r_path = rb_iv_get(self, "@path")) != Qnil) {
    path = StringValuePtr(r_path);
    database = strtok(path, "/");
  }

  if (NULL == database || 0 == strlen(database)) {
    rb_raise(eConnectionError, "Database must be specified");
  }

  r_query        = rb_iv_get(self, "@query");

  if (0 == strcasecmp(host, "localhost")) {
    socket = get_uri_option(r_query, "socket");
    if (NULL != socket) {
      rb_iv_set(self, "@using_socket", Qtrue);
    }
  }

#ifdef HAVE_MYSQL_SSL_SET
  char *ssl_client_key, *ssl_client_cert, *ssl_ca_cert, *ssl_ca_path, *ssl_cipher;
  VALUE r_ssl;

  if(rb_obj_is_kind_of(r_query, rb_cHash)) {
    r_ssl = rb_hash_aref(r_query, rb_str_new2("ssl"));

    if(rb_obj_is_kind_of(r_ssl, rb_cHash)) {
      ssl_client_key  = get_uri_option(r_ssl, "client_key");
      ssl_client_cert = get_uri_option(r_ssl, "client_cert");
      ssl_ca_cert     = get_uri_option(r_ssl, "ca_cert");
      ssl_ca_path     = get_uri_option(r_ssl, "ca_path");
      ssl_cipher      = get_uri_option(r_ssl, "cipher");

      assert_file_exists(ssl_client_key,  "client_key doesn't exist");
      assert_file_exists(ssl_client_cert, "client_cert doesn't exist");
      assert_file_exists(ssl_ca_cert,     "ca_cert doesn't exist");

      mysql_ssl_set(db, ssl_client_key, ssl_client_cert, ssl_ca_cert, ssl_ca_path, ssl_cipher);
    } else if(r_ssl != Qnil) {
      rb_raise(rb_eArgError, "ssl must be passed a hash");
    }
  }
#endif

  result = (MYSQL *)mysql_real_connect(
    db,
    host,
    user,
    password,
    database,
    port,
    socket,
    client_flags
  );

  if (NULL == result) {
    raise_error(self, db, Qnil);
  }

#ifdef HAVE_MYSQL_SSL_SET
  const char *ssl_cipher_used = mysql_get_ssl_cipher(db);

  if (NULL != ssl_cipher_used) {
    rb_iv_set(self, "@ssl_cipher", rb_str_new2(ssl_cipher_used));
  }
#endif

#ifdef MYSQL_OPT_RECONNECT
  my_bool reconnect = 1;
  mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect);
#endif

  // Set the connections character set
  encoding = rb_iv_get(self, "@encoding");

  VALUE my_encoding = rb_hash_aref(CONST_GET(mEncoding, "MAP"), encoding);
  if(my_encoding != Qnil) {
    encoding_error = mysql_set_character_set(db, rb_str_ptr_readonly(my_encoding));
    if (0 != encoding_error) {
      raise_error(self, db, Qnil);
    } else {
#ifdef HAVE_RUBY_ENCODING_H
      rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index(rb_str_ptr_readonly(encoding))));
#endif
      rb_iv_set(self, "@my_encoding", my_encoding);
    }
  } else {
    rb_warn("Encoding %s is not a known Ruby encoding for MySQL\n", rb_str_ptr_readonly(encoding));
    rb_iv_set(self, "@encoding", rb_str_new2("UTF-8"));
#ifdef HAVE_RUBY_ENCODING_H
    rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index("UTF-8")));
#endif
    rb_iv_set(self, "@my_encoding", rb_str_new2("utf8"));
  }

  // Disable sql_auto_is_null
  cCommand_execute(Qnil, self, db, rb_str_new2("SET sql_auto_is_null = 0"));
  // removed NO_AUTO_VALUE_ON_ZERO because of MySQL bug http://bugs.mysql.com/bug.php?id=42270
  // added NO_BACKSLASH_ESCAPES so that backslashes should not be escaped as in other databases
   
  //4.x versions do not support certain session parameters  
  if(mysql_get_server_version(db) < 50000 ){
    cCommand_execute(Qnil, self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_DIR_IN_CREATE,NO_UNSIGNED_SUBTRACTION'"));
  }else{
    cCommand_execute(Qnil, self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_UNSIGNED_SUBTRACTION,TRADITIONAL'"));
  }
 
  rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
}
コード例 #7
0
ファイル: do_mysql.c プロジェクト: postmodern/do
void full_connect(VALUE self, MYSQL *db) {
  VALUE r_host = rb_iv_get(self, "@host");
  const char *host = "localhost";

  if (r_host != Qnil) {
    host = StringValuePtr(r_host);
  }

  VALUE r_user = rb_iv_get(self, "@user");
  const char *user = "******";

  if (r_user != Qnil) {
    user = StringValuePtr(r_user);
  }

  VALUE r_password = rb_iv_get(self, "@password");
  char *password = NULL;

  if (r_password != Qnil) {
    password = StringValuePtr(r_password);
  }

  VALUE r_port = rb_iv_get(self, "@port");
  int port = 3306;

  if (r_port != Qnil) {
    port = NUM2INT(r_port);
  }

  VALUE r_path = rb_iv_get(self, "@path");
  char *path = NULL;
  char *database = NULL;

  if (r_path != Qnil) {
    path = StringValuePtr(r_path);
    database = strtok(path, "/"); // not threadsafe
  }

  if (!database || !*database) {
    rb_raise(eConnectionError, "Database must be specified");
  }

  VALUE r_query = rb_iv_get(self, "@query");
  char *socket = NULL;

  // Check to see if we're on the db machine.  If so, try to use the socket
  if (strcasecmp(host, "localhost") == 0) {
    socket = get_uri_option(r_query, "socket");

    if (socket) {
      rb_iv_set(self, "@using_socket", Qtrue);
    }
  }

#ifdef HAVE_MYSQL_SSL_SET
  char *ssl_client_key, *ssl_client_cert, *ssl_ca_cert, *ssl_ca_path, *ssl_cipher;
  VALUE r_ssl;

  if (rb_obj_is_kind_of(r_query, rb_cHash)) {
    r_ssl = rb_hash_aref(r_query, rb_str_new2("ssl"));

    if (rb_obj_is_kind_of(r_ssl, rb_cHash)) {
      ssl_client_key  = get_uri_option(r_ssl, "client_key");
      ssl_client_cert = get_uri_option(r_ssl, "client_cert");
      ssl_ca_cert     = get_uri_option(r_ssl, "ca_cert");
      ssl_ca_path     = get_uri_option(r_ssl, "ca_path");
      ssl_cipher      = get_uri_option(r_ssl, "cipher");

      assert_file_exists(ssl_client_key,  "client_key doesn't exist");
      assert_file_exists(ssl_client_cert, "client_cert doesn't exist");
      assert_file_exists(ssl_ca_cert,     "ca_cert doesn't exist");

      mysql_ssl_set(db, ssl_client_key, ssl_client_cert, ssl_ca_cert, ssl_ca_path, ssl_cipher);
    }
    else if (r_ssl != Qnil) {
      rb_raise(rb_eArgError, "ssl must be passed a hash");
    }
  }
#endif

  unsigned long client_flags = 0;

  MYSQL *result = mysql_real_connect(
    db,
    host,
    user,
    password,
    database,
    port,
    socket,
    client_flags
  );

  if (!result) {
    raise_error(self, db, Qnil);
  }

#ifdef HAVE_MYSQL_GET_SSL_CIPHER
  const char *ssl_cipher_used = mysql_get_ssl_cipher(db);

  if (ssl_cipher_used) {
    rb_iv_set(self, "@ssl_cipher", rb_str_new2(ssl_cipher_used));
  }
#endif

#ifdef MYSQL_OPT_RECONNECT
  my_bool reconnect = 1;
  mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect);
#endif

  // We only support encoding for MySQL versions providing mysql_set_character_set.
  // Without this function there are potential issues with mysql_real_escape_string
  // since that doesn't take the character set into consideration when setting it
  // using a SET CHARACTER SET query. Since we don't want to stimulate these possible
  // issues we simply ignore it and assume the user has configured this correctly.

#ifdef HAVE_MYSQL_SET_CHARACTER_SET
  // Set the connections character set
  VALUE encoding = rb_iv_get(self, "@encoding");
  VALUE my_encoding = rb_hash_aref(do_const_get(mEncoding, "MAP"), encoding);

  if (my_encoding != Qnil) {
    int encoding_error = mysql_set_character_set(db, rb_str_ptr_readonly(my_encoding));

    if (encoding_error != 0) {
      raise_error(self, db, Qnil);
    }
    else {
#ifdef HAVE_RUBY_ENCODING_H
      rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index(rb_str_ptr_readonly(encoding))));
#endif

      rb_iv_set(self, "@my_encoding", my_encoding);
    }
  }
  else {
    rb_warn("Encoding %s is not a known Ruby encoding for MySQL\n", rb_str_ptr_readonly(encoding));
    rb_iv_set(self, "@encoding", rb_str_new2("UTF-8"));
#ifdef HAVE_RUBY_ENCODING_H
    rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index("UTF-8")));
#endif
    rb_iv_set(self, "@my_encoding", rb_str_new2("utf8"));
  }
#endif

  // Disable sql_auto_is_null
  cCommand_execute(Qnil, self, db, rb_str_new2("SET sql_auto_is_null = 0"));
  // removed NO_AUTO_VALUE_ON_ZERO because of MySQL bug http://bugs.mysql.com/bug.php?id=42270
  // added NO_BACKSLASH_ESCAPES so that backslashes should not be escaped as in other databases

// For really anscient MySQL versions we don't attempt any strictness
#ifdef HAVE_MYSQL_GET_SERVER_VERSION
  //4.x versions do not support certain session parameters
  if (mysql_get_server_version(db) < 50000) {
    cCommand_execute(Qnil, self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_DIR_IN_CREATE,NO_UNSIGNED_SUBTRACTION'"));
  }
  else {
    cCommand_execute(Qnil, self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_BACKSLASH_ESCAPES,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_UNSIGNED_SUBTRACTION,TRADITIONAL'"));
  }
#endif

  rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
}