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