Esempio n. 1
0
void data_objects_raise_error(VALUE self, const struct errcodes *errors, int errnum, const char *message, VALUE query, VALUE state) {
  const char *exception_type = "SQLError";
  const struct errcodes *e;
  VALUE uri, exception;

  for (e = errors; e->error_name; e++) {
    if (e->error_no == errnum) {
      // return the exception type for the matching error
      exception_type = e->exception;
      break;
    }
  }

  uri = rb_funcall(rb_iv_get(self, "@connection"), rb_intern("to_s"), 0);

  exception = rb_funcall(
    data_objects_const_get(mDO, exception_type),
    DO_ID_NEW,
    5,
    rb_str_new2(message),
    INT2NUM(errnum),
    state,
    query,
    uri
  );

  rb_exc_raise(exception);
}
Esempio n. 2
0
void do_postgres_full_connect(VALUE self, PGconn *db) {
  VALUE r_host;
  char *host = NULL;

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

  VALUE r_user;
  char *user = NULL;

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

  VALUE r_password;
  char *password = NULL;

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

  VALUE r_port;
  const char *port = "5432";

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

  VALUE r_path;
  char *path = NULL;
  char *database = NULL;

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

  if (!database || !*database) {
    database = NULL;
  }

  VALUE r_query = rb_iv_get(self, "@query");
  const char *search_path = data_objects_get_uri_option(r_query, "search_path");

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

  if (PQstatus(db) == CONNECTION_BAD) {
    rb_raise(eDO_ConnectionError, "%s", PQerrorMessage(db));
  }

  PGresult *result;

  if (search_path) {
    char *search_path_query;

    if (!(search_path_query = calloc(256, sizeof(char)))) {
      rb_memerror();
    }

    snprintf(search_path_query, 256, "set search_path to %s;", search_path);

    r_query = rb_str_new2(search_path_query);
    result = do_postgres_cCommand_execute(Qnil, self, db, r_query);

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

    free(search_path_query);
  }

  const char *backslash_off = "SET backslash_quote = off";
  const char *standard_strings_on = "SET standard_conforming_strings = on";
  const char *warning_messages = "SET client_min_messages = warning";
  const char *date_format = "SET datestyle = ISO";
  VALUE r_options;

  r_options = rb_str_new2(backslash_off);
  result = do_postgres_cCommand_execute(Qnil, self, db, r_options);

  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
    rb_warn("%s", PQresultErrorMessage(result));
  }

  r_options = rb_str_new2(standard_strings_on);
  result = do_postgres_cCommand_execute(Qnil, self, db, r_options);

  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
    rb_warn("%s", PQresultErrorMessage(result));
  }

  r_options = rb_str_new2(warning_messages);
  result = do_postgres_cCommand_execute(Qnil, self, db, r_options);

  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
    rb_warn("%s", PQresultErrorMessage(result));
  }

  r_options = rb_str_new2(date_format);
  result = do_postgres_cCommand_execute(Qnil, self, db, r_options);

  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
    rb_warn("%s", PQresultErrorMessage(result));
  }

  VALUE encoding = rb_iv_get(self, "@encoding");
#ifdef HAVE_PQSETCLIENTENCODING
  VALUE pg_encoding = rb_hash_aref(data_objects_const_get(mDO_PostgresEncoding, "MAP"), encoding);

  if (pg_encoding != Qnil) {
    if (PQsetClientEncoding(db, rb_str_ptr_readonly(pg_encoding))) {
      rb_raise(eDO_ConnectionError, "Couldn't set encoding: %s", rb_str_ptr_readonly(encoding));
    }
    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, "@pg_encoding", pg_encoding);
    }
  }
  else {
    rb_warn("Encoding %s is not a known Ruby encoding for PostgreSQL\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, "@pg_encoding", rb_str_new2("UTF8"));
  }
#endif

  rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
}
Esempio n. 3
0
void do_mysql_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 = data_objects_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  = data_objects_get_uri_option(r_ssl, "client_key");
      ssl_client_cert = data_objects_get_uri_option(r_ssl, "client_cert");
      ssl_ca_cert     = data_objects_get_uri_option(r_ssl, "ca_cert");
      ssl_ca_path     = data_objects_get_uri_option(r_ssl, "ca_path");
      ssl_cipher      = data_objects_get_uri_option(r_ssl, "cipher");

      data_objects_assert_file_exists(ssl_client_key,  "client_key doesn't exist");
      data_objects_assert_file_exists(ssl_client_cert, "client_cert doesn't exist");
      data_objects_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) {
    do_mysql_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(data_objects_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) {
      do_mysql_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
  do_mysql_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) {
    do_mysql_cCommand_execute(Qnil, self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_DIR_IN_CREATE,NO_UNSIGNED_SUBTRACTION'"));
  }
  else {
    do_mysql_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));
}
Esempio n. 4
0
void data_objects_common_init(void) {
  rb_require("bigdecimal");
  rb_require("rational");
  rb_require("date");
  rb_require("data_objects");

  // Needed by data_objects_const_get
  DO_ID_CONST_GET = rb_intern("const_get");

  // Get references classes needed for Date/Time parsing
  rb_cDate = data_objects_const_get(rb_mKernel, "Date");
  rb_cDateTime = data_objects_const_get(rb_mKernel, "DateTime");
  rb_cBigDecimal = data_objects_const_get(rb_mKernel, "BigDecimal");

  DO_ID_NEW = rb_intern("new");
#ifdef RUBY_LESS_THAN_186
  DO_ID_NEW_DATE = rb_intern("new0");
#else
  DO_ID_NEW_DATE = rb_intern("new!");
#endif
  DO_ID_CONST_GET = rb_intern("const_get");
  DO_ID_RATIONAL = rb_intern("Rational");
  DO_ID_ESCAPE = rb_intern("escape_sql");
  DO_ID_STRFTIME = rb_intern("strftime");
  DO_ID_LOG = rb_intern("log");

  // Get references to the Extlib module
  mExtlib = data_objects_const_get(rb_mKernel, "Extlib");
  rb_cByteArray = data_objects_const_get(mExtlib, "ByteArray");

  // Get references to the DataObjects module and its classes
  mDO = data_objects_const_get(rb_mKernel, "DataObjects");
  cDO_Quoting = data_objects_const_get(mDO, "Quoting");
  cDO_Connection = data_objects_const_get(mDO, "Connection");
  cDO_Command = data_objects_const_get(mDO, "Command");
  cDO_Result = data_objects_const_get(mDO, "Result");
  cDO_Reader = data_objects_const_get(mDO, "Reader");
  cDO_Logger = data_objects_const_get(mDO, "Logger");
  cDO_Logger_Message = data_objects_const_get(cDO_Logger, "Message");
  cDO_Extension = data_objects_const_get(mDO, "Extension");

  eDO_ConnectionError = data_objects_const_get(mDO, "ConnectionError");
  eDO_DataError = data_objects_const_get(mDO, "DataError");

  rb_global_variable(&DO_ID_NEW_DATE);
  rb_global_variable(&DO_ID_RATIONAL);
  rb_global_variable(&DO_ID_CONST_GET);
  rb_global_variable(&DO_ID_ESCAPE);
  rb_global_variable(&DO_ID_LOG);
  rb_global_variable(&DO_ID_NEW);

  rb_global_variable(&rb_cDate);
  rb_global_variable(&rb_cDateTime);
  rb_global_variable(&rb_cBigDecimal);
  rb_global_variable(&rb_cByteArray);

  rb_global_variable(&mDO);
  rb_global_variable(&cDO_Logger_Message);

  rb_global_variable(&eDO_ConnectionError);
  rb_global_variable(&eDO_DataError);

  tzset();
}