do_mysql 0.10.3-x86-mswin32-60 → 0.10.4.rc1-x86-mswin32-60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +1 -1
- data/README.markdown +2 -9
- data/Rakefile +12 -45
- data/ext/do_mysql/do_common.c +526 -0
- data/ext/do_mysql/do_common.h +170 -0
- data/ext/do_mysql/do_mysql.c +200 -700
- data/ext/do_mysql/error.h +139 -263
- data/ext/do_mysql/extconf.rb +12 -14
- data/lib/do_mysql.rb +8 -3
- data/lib/do_mysql/1.8/do_mysql.so +0 -0
- data/lib/do_mysql/1.9/do_mysql.so +0 -0
- data/lib/do_mysql/version.rb +1 -1
- data/spec/command_spec.rb +3 -3
- data/spec/connection_spec.rb +17 -17
- data/spec/encoding_spec.rb +4 -4
- data/spec/error/sql_error_spec.rb +2 -2
- data/spec/reader_spec.rb +28 -2
- data/spec/result_spec.rb +5 -5
- data/spec/spec_helper.rb +14 -5
- data/spec/typecast/array_spec.rb +2 -2
- data/spec/typecast/bigdecimal_spec.rb +3 -3
- data/spec/typecast/boolean_spec.rb +3 -3
- data/spec/typecast/byte_array_spec.rb +2 -2
- data/spec/typecast/class_spec.rb +2 -2
- data/spec/typecast/date_spec.rb +3 -3
- data/spec/typecast/datetime_spec.rb +3 -3
- data/spec/typecast/float_spec.rb +3 -3
- data/spec/typecast/integer_spec.rb +2 -2
- data/spec/typecast/nil_spec.rb +4 -4
- data/spec/typecast/other_spec.rb +2 -2
- data/spec/typecast/range_spec.rb +2 -2
- data/spec/typecast/string_spec.rb +2 -2
- data/spec/typecast/time_spec.rb +2 -2
- data/tasks/compile.rake +30 -31
- data/tasks/spec.rake +8 -19
- metadata +49 -46
| @@ -0,0 +1,170 @@ | |
| 1 | 
            +
            #ifndef _DO_COMMON_H_
         | 
| 2 | 
            +
            #define _DO_COMMON_H_
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            #include <ruby.h>
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            #ifdef _WIN32
         | 
| 7 | 
            +
            #define cCommand_execute cCommand_execute_sync
         | 
| 8 | 
            +
            typedef signed __int64 do_int64;
         | 
| 9 | 
            +
            #else
         | 
| 10 | 
            +
            #define cCommand_execute cCommand_execute_async
         | 
| 11 | 
            +
            typedef signed long long int do_int64;
         | 
| 12 | 
            +
            #endif
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 15 | 
            +
            #include <ruby/encoding.h>
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            #define DO_STR_NEW2(str, encoding, internal_encoding) \
         | 
| 18 | 
            +
              ({ \
         | 
| 19 | 
            +
                VALUE _string = rb_str_new2((const char *)str); \
         | 
| 20 | 
            +
                if(encoding != -1) { \
         | 
| 21 | 
            +
                  rb_enc_associate_index(_string, encoding); \
         | 
| 22 | 
            +
                } \
         | 
| 23 | 
            +
                if(internal_encoding) { \
         | 
| 24 | 
            +
                  _string = rb_str_export_to_enc(_string, internal_encoding); \
         | 
| 25 | 
            +
                } \
         | 
| 26 | 
            +
                _string; \
         | 
| 27 | 
            +
              })
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            #define DO_STR_NEW(str, len, encoding, internal_encoding) \
         | 
| 30 | 
            +
              ({ \
         | 
| 31 | 
            +
                VALUE _string = rb_str_new((const char *)str, (long)len); \
         | 
| 32 | 
            +
                if(encoding != -1) { \
         | 
| 33 | 
            +
                  rb_enc_associate_index(_string, encoding); \
         | 
| 34 | 
            +
                } \
         | 
| 35 | 
            +
                if(internal_encoding) { \
         | 
| 36 | 
            +
                  _string = rb_str_export_to_enc(_string, internal_encoding); \
         | 
| 37 | 
            +
                } \
         | 
| 38 | 
            +
                _string; \
         | 
| 39 | 
            +
              })
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            # else
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            #define DO_STR_NEW2(str, encoding, internal_encoding) \
         | 
| 44 | 
            +
              rb_str_new2((const char *)str)
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            #define DO_STR_NEW(str, len, encoding, internal_encoding) \
         | 
| 47 | 
            +
              rb_str_new((const char *)str, (long)len)
         | 
| 48 | 
            +
            #endif
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            // Needed for defining error.h
         | 
| 51 | 
            +
            struct errcodes {
         | 
| 52 | 
            +
              int error_no;
         | 
| 53 | 
            +
              const char *error_name;
         | 
| 54 | 
            +
              const char *exception;
         | 
| 55 | 
            +
            };
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            #define ERRCODE(name,message)   {name, #name, message}
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            // To store rb_intern values
         | 
| 60 | 
            +
            extern ID ID_NEW;
         | 
| 61 | 
            +
            extern ID ID_NEW_DATE;
         | 
| 62 | 
            +
            extern ID ID_CONST_GET;
         | 
| 63 | 
            +
            extern ID ID_RATIONAL;
         | 
| 64 | 
            +
            extern ID ID_ESCAPE;
         | 
| 65 | 
            +
            extern ID ID_STRFTIME;
         | 
| 66 | 
            +
            extern ID ID_LOG;
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            // Reference to Extlib module
         | 
| 69 | 
            +
            extern VALUE mExtlib;
         | 
| 70 | 
            +
            extern VALUE rb_cByteArray;
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            // References to DataObjects base classes
         | 
| 73 | 
            +
            extern VALUE mDO;
         | 
| 74 | 
            +
            extern VALUE mEncoding;
         | 
| 75 | 
            +
            extern VALUE cDO_Quoting;
         | 
| 76 | 
            +
            extern VALUE cDO_Connection;
         | 
| 77 | 
            +
            extern VALUE cDO_Command;
         | 
| 78 | 
            +
            extern VALUE cDO_Result;
         | 
| 79 | 
            +
            extern VALUE cDO_Reader;
         | 
| 80 | 
            +
            extern VALUE cDO_Logger;
         | 
| 81 | 
            +
            extern VALUE cDO_Logger_Message;
         | 
| 82 | 
            +
            extern VALUE cDO_Extension;
         | 
| 83 | 
            +
            extern VALUE eConnectionError;
         | 
| 84 | 
            +
            extern VALUE eDataError;
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            // References to Ruby classes that we'll need
         | 
| 87 | 
            +
            extern VALUE rb_cDate;
         | 
| 88 | 
            +
            extern VALUE rb_cDateTime;
         | 
| 89 | 
            +
            extern VALUE rb_cBigDecimal;
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            extern void data_objects_debug(VALUE connection, VALUE string, struct timeval *start);
         | 
| 92 | 
            +
            extern char *get_uri_option(VALUE query_hash, const char *key);
         | 
| 93 | 
            +
            extern void assert_file_exists(char *file, const char *message);
         | 
| 94 | 
            +
            extern VALUE build_query_from_args(VALUE klass, int count, VALUE *args);
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            extern void reduce(do_int64 *numerator, do_int64 *denominator);
         | 
| 97 | 
            +
            extern int jd_from_date(int year, int month, int day);
         | 
| 98 | 
            +
            extern VALUE seconds_to_offset(long seconds_offset);
         | 
| 99 | 
            +
            extern VALUE timezone_to_offset(int hour_offset, int minute_offset);
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            extern VALUE parse_date(const char *date);
         | 
| 102 | 
            +
            extern VALUE parse_time(const char *date);
         | 
| 103 | 
            +
            extern VALUE parse_date_time(const char *date);
         | 
| 104 | 
            +
             | 
| 105 | 
            +
            extern VALUE cConnection_character_set(VALUE self);
         | 
| 106 | 
            +
            extern VALUE cConnection_is_using_socket(VALUE self);
         | 
| 107 | 
            +
            extern VALUE cConnection_ssl_cipher(VALUE self);
         | 
| 108 | 
            +
            extern VALUE cConnection_quote_time(VALUE self, VALUE value);
         | 
| 109 | 
            +
            extern VALUE cConnection_quote_date_time(VALUE self, VALUE value);
         | 
| 110 | 
            +
            extern VALUE cConnection_quote_date(VALUE self, VALUE value);
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            extern VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self);
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            extern VALUE cReader_values(VALUE self);
         | 
| 115 | 
            +
            extern VALUE cReader_fields(VALUE self);
         | 
| 116 | 
            +
            extern VALUE cReader_field_count(VALUE self);
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            extern void common_init(void);
         | 
| 119 | 
            +
             | 
| 120 | 
            +
            static inline VALUE do_const_get(VALUE scope, const char *constant) {
         | 
| 121 | 
            +
              return rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant));
         | 
| 122 | 
            +
            }
         | 
| 123 | 
            +
             | 
| 124 | 
            +
            static inline VALUE do_str_new(const void *string, long length, int encoding, void *internal_encoding) {
         | 
| 125 | 
            +
              VALUE new_string = rb_str_new(string, length);
         | 
| 126 | 
            +
             | 
| 127 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 128 | 
            +
              if(encoding != -1) {
         | 
| 129 | 
            +
                rb_enc_associate_index(new_string, encoding);
         | 
| 130 | 
            +
              }
         | 
| 131 | 
            +
             | 
| 132 | 
            +
              if(internal_encoding) {
         | 
| 133 | 
            +
                new_string = rb_str_export_to_enc(new_string, internal_encoding);
         | 
| 134 | 
            +
              }
         | 
| 135 | 
            +
            #endif
         | 
| 136 | 
            +
             | 
| 137 | 
            +
              return new_string;
         | 
| 138 | 
            +
            }
         | 
| 139 | 
            +
             | 
| 140 | 
            +
            static inline VALUE do_str_new2(const void *string, int encoding, void *internal_encoding) {
         | 
| 141 | 
            +
                VALUE new_string = rb_str_new2(string);
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 144 | 
            +
                if(encoding != -1) {
         | 
| 145 | 
            +
                  rb_enc_associate_index(new_string, encoding);
         | 
| 146 | 
            +
                }
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                if(internal_encoding) {
         | 
| 149 | 
            +
                  new_string = rb_str_export_to_enc(new_string, internal_encoding);
         | 
| 150 | 
            +
                }
         | 
| 151 | 
            +
            #endif
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                return new_string;
         | 
| 154 | 
            +
            }
         | 
| 155 | 
            +
             | 
| 156 | 
            +
            static inline void do_define_errors(VALUE scope, const struct errcodes *errors) {
         | 
| 157 | 
            +
              const struct errcodes *e;
         | 
| 158 | 
            +
             | 
| 159 | 
            +
              for (e = errors; e->error_name; e++) {
         | 
| 160 | 
            +
                rb_const_set(scope, rb_intern(e->error_name), INT2NUM(e->error_no));
         | 
| 161 | 
            +
              }
         | 
| 162 | 
            +
            }
         | 
| 163 | 
            +
             | 
| 164 | 
            +
            extern void do_raise_error(VALUE self, const struct errcodes *errors, int errnum, const char *message, VALUE query, VALUE state);
         | 
| 165 | 
            +
             | 
| 166 | 
            +
            extern VALUE do_typecast(const char *value, long length, const VALUE type, int encoding);
         | 
| 167 | 
            +
             | 
| 168 | 
            +
            #define RSTRING_NOT_MODIFIED
         | 
| 169 | 
            +
             | 
| 170 | 
            +
            #endif
         | 
    
        data/ext/do_mysql/do_mysql.c
    CHANGED
    
    | @@ -1,8 +1,6 @@ | |
| 1 1 | 
             
            #include <ruby.h>
         | 
| 2 | 
            -
            #include <string.h>
         | 
| 3 | 
            -
            #include <math.h>
         | 
| 4 | 
            -
            #include <ctype.h>
         | 
| 5 2 | 
             
            #include <time.h>
         | 
| 3 | 
            +
            #include <string.h>
         | 
| 6 4 |  | 
| 7 5 | 
             
            #include <mysql.h>
         | 
| 8 6 | 
             
            #include <errmsg.h>
         | 
| @@ -12,100 +10,27 @@ | |
| 12 10 | 
             
            #include "compat.h"
         | 
| 13 11 | 
             
            #include "error.h"
         | 
| 14 12 |  | 
| 13 | 
            +
            #include "do_common.h"
         | 
| 14 | 
            +
             | 
| 15 15 | 
             
            #ifndef HAVE_CONST_MYSQL_TYPE_STRING
         | 
| 16 16 | 
             
            #define HAVE_OLD_MYSQL_VERSION
         | 
| 17 17 | 
             
            #endif
         | 
| 18 18 |  | 
| 19 | 
            -
            #define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
         | 
| 20 | 
            -
            #define DRIVER_CLASS(klass, parent) (rb_define_class_under(mMysql, klass, parent))
         | 
| 21 19 | 
             
            #define CHECK_AND_RAISE(mysql_result_value, query) if (0 != mysql_result_value) { raise_error(self, db, query); }
         | 
| 22 20 |  | 
| 23 | 
            -
             | 
| 24 | 
            -
            #define cCommand_execute cCommand_execute_sync
         | 
| 25 | 
            -
            #define do_int64 signed __int64
         | 
| 26 | 
            -
            #else
         | 
| 27 | 
            -
            #define cCommand_execute cCommand_execute_async
         | 
| 28 | 
            -
            #define do_int64 signed long long int
         | 
| 29 | 
            -
            #endif
         | 
| 30 | 
            -
             | 
| 31 | 
            -
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 32 | 
            -
            #include <ruby/encoding.h>
         | 
| 33 | 
            -
             | 
| 34 | 
            -
            #define DO_STR_NEW2(str, encoding, internal_encoding) \
         | 
| 35 | 
            -
              ({ \
         | 
| 36 | 
            -
                VALUE _string = rb_str_new2((const char *)str); \
         | 
| 37 | 
            -
                if(encoding != -1) { \
         | 
| 38 | 
            -
                  rb_enc_associate_index(_string, encoding); \
         | 
| 39 | 
            -
                } \
         | 
| 40 | 
            -
                if(internal_encoding) { \
         | 
| 41 | 
            -
                  _string = rb_str_export_to_enc(_string, internal_encoding); \
         | 
| 42 | 
            -
                } \
         | 
| 43 | 
            -
                _string; \
         | 
| 44 | 
            -
              })
         | 
| 45 | 
            -
             | 
| 46 | 
            -
            #define DO_STR_NEW(str, len, encoding, internal_encoding) \
         | 
| 47 | 
            -
              ({ \
         | 
| 48 | 
            -
                VALUE _string = rb_str_new((const char *)str, (long)len); \
         | 
| 49 | 
            -
                if(encoding != -1) { \
         | 
| 50 | 
            -
                  rb_enc_associate_index(_string, encoding); \
         | 
| 51 | 
            -
                } \
         | 
| 52 | 
            -
                if(internal_encoding) { \
         | 
| 53 | 
            -
                  _string = rb_str_export_to_enc(_string, internal_encoding); \
         | 
| 54 | 
            -
                } \
         | 
| 55 | 
            -
                _string; \
         | 
| 56 | 
            -
              })
         | 
| 57 | 
            -
             | 
| 58 | 
            -
            #else
         | 
| 59 | 
            -
             | 
| 60 | 
            -
            #define DO_STR_NEW2(str, encoding, internal_encoding) \
         | 
| 61 | 
            -
              rb_str_new2((const char *)str)
         | 
| 62 | 
            -
             | 
| 63 | 
            -
            #define DO_STR_NEW(str, len, encoding, internal_encoding) \
         | 
| 64 | 
            -
              rb_str_new((const char *)str, (long)len)
         | 
| 65 | 
            -
            #endif
         | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
            // To store rb_intern values
         | 
| 69 | 
            -
            static ID ID_NEW;
         | 
| 70 | 
            -
            static ID ID_NEW_DATE;
         | 
| 71 | 
            -
            static ID ID_CONST_GET;
         | 
| 72 | 
            -
            static ID ID_RATIONAL;
         | 
| 73 | 
            -
            static ID ID_ESCAPE;
         | 
| 74 | 
            -
            static ID ID_STRFTIME;
         | 
| 75 | 
            -
            static ID ID_LOG;
         | 
| 76 | 
            -
             | 
| 77 | 
            -
            // Reference to Extlib module
         | 
| 78 | 
            -
            static VALUE mExtlib;
         | 
| 79 | 
            -
             | 
| 80 | 
            -
            // References to DataObjects base classes
         | 
| 81 | 
            -
            static VALUE mDO;
         | 
| 82 | 
            -
            static VALUE mEncoding;
         | 
| 83 | 
            -
            static VALUE cDO_Quoting;
         | 
| 84 | 
            -
            static VALUE cDO_Connection;
         | 
| 85 | 
            -
            static VALUE cDO_Command;
         | 
| 86 | 
            -
            static VALUE cDO_Result;
         | 
| 87 | 
            -
            static VALUE cDO_Reader;
         | 
| 88 | 
            -
            static VALUE cDO_Logger;
         | 
| 89 | 
            -
            static VALUE cDO_Logger_Message;
         | 
| 90 | 
            -
             | 
| 91 | 
            -
            // References to Ruby classes that we'll need
         | 
| 92 | 
            -
            static VALUE rb_cDate;
         | 
| 93 | 
            -
            static VALUE rb_cDateTime;
         | 
| 94 | 
            -
            static VALUE rb_cBigDecimal;
         | 
| 95 | 
            -
            static VALUE rb_cByteArray;
         | 
| 21 | 
            +
            void full_connect(VALUE self, MYSQL *db);
         | 
| 96 22 |  | 
| 97 23 | 
             
            // Classes that we'll build in Init
         | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
            static VALUE eDataError;
         | 
| 24 | 
            +
            VALUE mMysql;
         | 
| 25 | 
            +
            VALUE mEncoding;
         | 
| 26 | 
            +
            VALUE cConnection;
         | 
| 27 | 
            +
            VALUE cCommand;
         | 
| 28 | 
            +
            VALUE cResult;
         | 
| 29 | 
            +
            VALUE cReader;
         | 
| 105 30 |  | 
| 106 31 | 
             
            // Figures out what we should cast a given mysql field type to
         | 
| 107 | 
            -
             | 
| 108 | 
            -
              switch(field->type) {
         | 
| 32 | 
            +
            VALUE infer_ruby_type(const MYSQL_FIELD *field) {
         | 
| 33 | 
            +
              switch (field->type) {
         | 
| 109 34 | 
             
                case MYSQL_TYPE_NULL:
         | 
| 110 35 | 
             
                  return Qnil;
         | 
| 111 36 | 
             
                case MYSQL_TYPE_TINY:
         | 
| @@ -140,9 +65,10 @@ static VALUE infer_ruby_type(MYSQL_FIELD *field) { | |
| 140 65 | 
             
                case MYSQL_TYPE_LONG_BLOB:
         | 
| 141 66 | 
             
                case MYSQL_TYPE_BLOB:
         | 
| 142 67 | 
             
            #ifdef HAVE_ST_CHARSETNR
         | 
| 143 | 
            -
                  if(field->charsetnr == 63) {
         | 
| 68 | 
            +
                  if (field->charsetnr == 63) {
         | 
| 144 69 | 
             
                    return rb_cByteArray;
         | 
| 145 | 
            -
                  } | 
| 70 | 
            +
                  }
         | 
| 71 | 
            +
                  else {
         | 
| 146 72 | 
             
                    return rb_cString;
         | 
| 147 73 | 
             
                  }
         | 
| 148 74 | 
             
            #else
         | 
| @@ -154,331 +80,48 @@ static VALUE infer_ruby_type(MYSQL_FIELD *field) { | |
| 154 80 | 
             
              }
         | 
| 155 81 | 
             
            }
         | 
| 156 82 |  | 
| 157 | 
            -
            // Find the greatest common denominator and reduce the provided numerator and denominator.
         | 
| 158 | 
            -
            // This replaces calles to Rational.reduce! which does the same thing, but really slowly.
         | 
| 159 | 
            -
            static void reduce( do_int64 *numerator, do_int64 *denominator ) {
         | 
| 160 | 
            -
              do_int64 a, b, c;
         | 
| 161 | 
            -
              a = *numerator;
         | 
| 162 | 
            -
              b = *denominator;
         | 
| 163 | 
            -
              while ( a != 0 ) {
         | 
| 164 | 
            -
              c = a; a = b % a; b = c;
         | 
| 165 | 
            -
              }
         | 
| 166 | 
            -
              *numerator = *numerator / b;
         | 
| 167 | 
            -
              *denominator = *denominator / b;
         | 
| 168 | 
            -
            }
         | 
| 169 | 
            -
             | 
| 170 | 
            -
            // Generate the date integer which Date.civil_to_jd returns
         | 
| 171 | 
            -
            static int jd_from_date(int year, int month, int day) {
         | 
| 172 | 
            -
              int a, b;
         | 
| 173 | 
            -
              if ( month <= 2 ) {
         | 
| 174 | 
            -
              year -= 1;
         | 
| 175 | 
            -
              month += 12;
         | 
| 176 | 
            -
              }
         | 
| 177 | 
            -
              a = year / 100;
         | 
| 178 | 
            -
              b = 2 - a + (a / 4);
         | 
| 179 | 
            -
              return (int) (floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) + day + b - 1524);
         | 
| 180 | 
            -
            }
         | 
| 181 | 
            -
             | 
| 182 | 
            -
            static VALUE seconds_to_offset(long seconds_offset) {
         | 
| 183 | 
            -
              do_int64 num = seconds_offset, den = 86400;
         | 
| 184 | 
            -
              reduce(&num, &den);
         | 
| 185 | 
            -
              return rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ll2inum(num), rb_ll2inum(den));
         | 
| 186 | 
            -
            }
         | 
| 187 | 
            -
             | 
| 188 | 
            -
            static VALUE timezone_to_offset(int hour_offset, int minute_offset) {
         | 
| 189 | 
            -
              do_int64 seconds = 0;
         | 
| 190 | 
            -
             | 
| 191 | 
            -
              seconds += hour_offset * 3600;
         | 
| 192 | 
            -
              seconds += minute_offset * 60;
         | 
| 193 | 
            -
             | 
| 194 | 
            -
              return seconds_to_offset(seconds);
         | 
| 195 | 
            -
            }
         | 
| 196 | 
            -
             | 
| 197 | 
            -
            static VALUE parse_date(const char *date) {
         | 
| 198 | 
            -
              int year, month, day;
         | 
| 199 | 
            -
              int jd, ajd;
         | 
| 200 | 
            -
              VALUE rational;
         | 
| 201 | 
            -
             | 
| 202 | 
            -
              sscanf(date, "%4d-%2d-%2d", &year, &month, &day);
         | 
| 203 | 
            -
             | 
| 204 | 
            -
              jd = jd_from_date(year, month, day);
         | 
| 205 | 
            -
             | 
| 206 | 
            -
              // Math from Date.jd_to_ajd
         | 
| 207 | 
            -
              ajd = jd * 2 - 1;
         | 
| 208 | 
            -
              rational = rb_funcall(rb_mKernel, ID_RATIONAL, 2, INT2NUM(ajd), INT2NUM(2));
         | 
| 209 | 
            -
              return rb_funcall(rb_cDate, ID_NEW_DATE, 3, rational, INT2NUM(0), INT2NUM(2299161));
         | 
| 210 | 
            -
            }
         | 
| 211 | 
            -
             | 
| 212 | 
            -
            static VALUE parse_time(const char *date) {
         | 
| 213 | 
            -
             | 
| 214 | 
            -
              int year, month, day, hour, min, sec, usec, tokens;
         | 
| 215 | 
            -
              char subsec[7];
         | 
| 216 | 
            -
             | 
| 217 | 
            -
              if (0 != strchr(date, '.')) {
         | 
| 218 | 
            -
                // right padding usec with 0. e.g. '012' will become 12000 microsecond, since Time#local use microsecond
         | 
| 219 | 
            -
                sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d.%s", &year, &month, &day, &hour, &min, &sec, subsec);
         | 
| 220 | 
            -
                sscanf(subsec, "%d", &usec);
         | 
| 221 | 
            -
              } else {
         | 
| 222 | 
            -
                tokens = sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
         | 
| 223 | 
            -
                if (tokens == 3) {
         | 
| 224 | 
            -
                  hour = 0;
         | 
| 225 | 
            -
                  min  = 0;
         | 
| 226 | 
            -
                  sec  = 0;
         | 
| 227 | 
            -
                }
         | 
| 228 | 
            -
                usec = 0;
         | 
| 229 | 
            -
              }
         | 
| 230 | 
            -
             | 
| 231 | 
            -
              if ( year + month + day + hour + min + sec + usec == 0 ) { // Mysql TIMESTAMPS can default to 0
         | 
| 232 | 
            -
                return Qnil;
         | 
| 233 | 
            -
              }
         | 
| 234 | 
            -
             | 
| 235 | 
            -
              return rb_funcall(rb_cTime, rb_intern("local"), 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
         | 
| 236 | 
            -
            }
         | 
| 237 | 
            -
             | 
| 238 | 
            -
            static VALUE parse_date_time(const char *date) {
         | 
| 239 | 
            -
              VALUE ajd, offset;
         | 
| 240 | 
            -
             | 
| 241 | 
            -
              int year, month, day, hour, min, sec, usec, hour_offset, minute_offset;
         | 
| 242 | 
            -
              int jd;
         | 
| 243 | 
            -
              do_int64 num, den;
         | 
| 244 | 
            -
             | 
| 245 | 
            -
             | 
| 246 | 
            -
              time_t gmt_offset;
         | 
| 247 | 
            -
              int dst_adjustment;
         | 
| 248 | 
            -
             | 
| 249 | 
            -
              time_t rawtime;
         | 
| 250 | 
            -
              struct tm timeinfo;
         | 
| 251 | 
            -
             | 
| 252 | 
            -
              int tokens_read, max_tokens;
         | 
| 253 | 
            -
             | 
| 254 | 
            -
              if ( strcmp(date, "") == 0 ) {
         | 
| 255 | 
            -
                return Qnil;
         | 
| 256 | 
            -
              }
         | 
| 257 | 
            -
             | 
| 258 | 
            -
              if (0 != strchr(date, '.')) {
         | 
| 259 | 
            -
                // This is a datetime with sub-second precision
         | 
| 260 | 
            -
                tokens_read = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d.%d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &usec, &hour_offset, &minute_offset);
         | 
| 261 | 
            -
                max_tokens = 9;
         | 
| 262 | 
            -
              } else {
         | 
| 263 | 
            -
                // This is a datetime second precision
         | 
| 264 | 
            -
                tokens_read = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &hour_offset, &minute_offset);
         | 
| 265 | 
            -
                max_tokens = 8;
         | 
| 266 | 
            -
              }
         | 
| 267 | 
            -
             | 
| 268 | 
            -
              if (max_tokens == tokens_read) {
         | 
| 269 | 
            -
                // We read the Date, Time, and Timezone info
         | 
| 270 | 
            -
                minute_offset *= hour_offset < 0 ? -1 : 1;
         | 
| 271 | 
            -
              } else if ((max_tokens - 1) == tokens_read) {
         | 
| 272 | 
            -
                // We read the Date and Time, but no Minute Offset
         | 
| 273 | 
            -
                minute_offset = 0;
         | 
| 274 | 
            -
              } else if (tokens_read == 3 || tokens_read >= (max_tokens - 3)) {
         | 
| 275 | 
            -
                if (tokens_read == 3) {
         | 
| 276 | 
            -
                  hour = 0;
         | 
| 277 | 
            -
                  min = 0;
         | 
| 278 | 
            -
                  hour_offset = 0;
         | 
| 279 | 
            -
                  minute_offset = 0;
         | 
| 280 | 
            -
                  sec = 0;
         | 
| 281 | 
            -
                }
         | 
| 282 | 
            -
                // We read the Date and Time, default to the current locale's offset
         | 
| 283 | 
            -
             | 
| 284 | 
            -
                tzset();
         | 
| 285 | 
            -
             | 
| 286 | 
            -
                // Get localtime
         | 
| 287 | 
            -
                time(&rawtime);
         | 
| 288 | 
            -
            #ifdef HAVE_LOCALTIME_R
         | 
| 289 | 
            -
                localtime_r(&rawtime, &timeinfo);
         | 
| 290 | 
            -
            #else
         | 
| 291 | 
            -
                timeinfo = *localtime(&rawtime);
         | 
| 292 | 
            -
            #endif
         | 
| 293 | 
            -
             | 
| 294 | 
            -
                timeinfo.tm_sec = sec;
         | 
| 295 | 
            -
                timeinfo.tm_min = min;
         | 
| 296 | 
            -
                timeinfo.tm_hour = hour;
         | 
| 297 | 
            -
                timeinfo.tm_mday = day;
         | 
| 298 | 
            -
                timeinfo.tm_mon = month;
         | 
| 299 | 
            -
                timeinfo.tm_year = year - 1900;
         | 
| 300 | 
            -
                timeinfo.tm_isdst = -1;
         | 
| 301 | 
            -
             | 
| 302 | 
            -
                // Update tm_isdst
         | 
| 303 | 
            -
                mktime(&timeinfo);
         | 
| 304 | 
            -
             | 
| 305 | 
            -
                if (timeinfo.tm_isdst) {
         | 
| 306 | 
            -
                  dst_adjustment = 3600;
         | 
| 307 | 
            -
                } else {
         | 
| 308 | 
            -
                  dst_adjustment = 0;
         | 
| 309 | 
            -
                }
         | 
| 310 | 
            -
             | 
| 311 | 
            -
                // Reset to GM Time
         | 
| 312 | 
            -
            #ifdef HAVE_GMTIME_R
         | 
| 313 | 
            -
                gmtime_r(&rawtime, &timeinfo);
         | 
| 314 | 
            -
            #else
         | 
| 315 | 
            -
                timeinfo = *gmtime(&rawtime);
         | 
| 316 | 
            -
            #endif
         | 
| 317 | 
            -
             | 
| 318 | 
            -
                gmt_offset = rawtime - mktime(&timeinfo);
         | 
| 319 | 
            -
             | 
| 320 | 
            -
                if (dst_adjustment) {
         | 
| 321 | 
            -
                  gmt_offset += dst_adjustment;
         | 
| 322 | 
            -
                }
         | 
| 323 | 
            -
             | 
| 324 | 
            -
                hour_offset = ((int)gmt_offset / 3600);
         | 
| 325 | 
            -
                minute_offset = ((int)gmt_offset % 3600 / 60);
         | 
| 326 | 
            -
             | 
| 327 | 
            -
              } else {
         | 
| 328 | 
            -
                // Something went terribly wrong
         | 
| 329 | 
            -
                rb_raise(eDataError, "Couldn't parse date: %s", date);
         | 
| 330 | 
            -
              }
         | 
| 331 | 
            -
             | 
| 332 | 
            -
              jd = jd_from_date(year, month, day);
         | 
| 333 | 
            -
             | 
| 334 | 
            -
              // Generate ajd with fractional days for the time
         | 
| 335 | 
            -
              // Extracted from Date#jd_to_ajd, Date#day_fraction_to_time, and Rational#+ and #-
         | 
| 336 | 
            -
              num = (hour * 1440) + (min * 24);
         | 
| 337 | 
            -
             | 
| 338 | 
            -
              // Modify the numerator so when we apply the timezone everything works out
         | 
| 339 | 
            -
              num -= (hour_offset * 1440) + (minute_offset * 24);
         | 
| 340 | 
            -
             | 
| 341 | 
            -
              den = (24 * 1440);
         | 
| 342 | 
            -
              reduce(&num, &den);
         | 
| 343 | 
            -
             | 
| 344 | 
            -
              num = (num * 86400) + (sec * den);
         | 
| 345 | 
            -
              den = den * 86400;
         | 
| 346 | 
            -
              reduce(&num, &den);
         | 
| 347 | 
            -
             | 
| 348 | 
            -
              num = (jd * den) + num;
         | 
| 349 | 
            -
             | 
| 350 | 
            -
              num = num * 2;
         | 
| 351 | 
            -
              num = num - den;
         | 
| 352 | 
            -
              den = den * 2;
         | 
| 353 | 
            -
             | 
| 354 | 
            -
              reduce(&num, &den);
         | 
| 355 | 
            -
             | 
| 356 | 
            -
              ajd = rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ull2inum(num), rb_ull2inum(den));
         | 
| 357 | 
            -
              offset = timezone_to_offset(hour_offset, minute_offset);
         | 
| 358 | 
            -
             | 
| 359 | 
            -
              return rb_funcall(rb_cDateTime, ID_NEW_DATE, 3, ajd, offset, INT2NUM(2299161));
         | 
| 360 | 
            -
            }
         | 
| 361 | 
            -
             | 
| 362 83 | 
             
            // Convert C-string to a Ruby instance of Ruby type "type"
         | 
| 363 | 
            -
             | 
| 364 | 
            -
             | 
| 365 | 
            -
              if(NULL == value) {
         | 
| 84 | 
            +
            VALUE typecast(const char *value, long length, const VALUE type, int encoding) {
         | 
| 85 | 
            +
              if (!value) {
         | 
| 366 86 | 
             
                return Qnil;
         | 
| 367 87 | 
             
              }
         | 
| 368 88 |  | 
| 369 | 
            -
             | 
| 370 | 
            -
             | 
| 371 | 
            -
             | 
| 372 | 
            -
               | 
| 373 | 
            -
            #endif
         | 
| 374 | 
            -
             | 
| 375 | 
            -
              if (type == rb_cInteger) {
         | 
| 376 | 
            -
                return rb_cstr2inum(value, 10);
         | 
| 377 | 
            -
              } else if (type == rb_cString) {
         | 
| 378 | 
            -
                return DO_STR_NEW(value, length, encoding, internal_encoding);
         | 
| 379 | 
            -
              } else if (type == rb_cFloat) {
         | 
| 380 | 
            -
                return rb_float_new(rb_cstr_to_dbl(value, Qfalse));
         | 
| 381 | 
            -
              } else if (type == rb_cBigDecimal) {
         | 
| 382 | 
            -
                return rb_funcall(rb_cBigDecimal, ID_NEW, 1, rb_str_new(value, length));
         | 
| 383 | 
            -
              } else if (type == rb_cDate) {
         | 
| 384 | 
            -
                return parse_date(value);
         | 
| 385 | 
            -
              } else if (type == rb_cDateTime) {
         | 
| 386 | 
            -
                return parse_date_time(value);
         | 
| 387 | 
            -
              } else if (type == rb_cTime) {
         | 
| 388 | 
            -
                return parse_time(value);
         | 
| 389 | 
            -
              } else if (type == rb_cTrueClass) {
         | 
| 390 | 
            -
                return (0 == value || 0 == strcmp("0", value)) ? Qfalse : Qtrue;
         | 
| 391 | 
            -
              } else if (type == rb_cByteArray) {
         | 
| 89 | 
            +
              if (type == rb_cTrueClass) {
         | 
| 90 | 
            +
                return (value == 0 || strcmp("0", value) == 0) ? Qfalse : Qtrue;
         | 
| 91 | 
            +
              }
         | 
| 92 | 
            +
              else if (type == rb_cByteArray) {
         | 
| 392 93 | 
             
                return rb_funcall(rb_cByteArray, ID_NEW, 1, rb_str_new(value, length));
         | 
| 393 | 
            -
              } else if (type == rb_cClass) {
         | 
| 394 | 
            -
                return rb_funcall(mDO, rb_intern("full_const_get"), 1, rb_str_new(value, length));
         | 
| 395 | 
            -
              } else if (type == rb_cNilClass) {
         | 
| 396 | 
            -
                return Qnil;
         | 
| 397 | 
            -
              } else {
         | 
| 398 | 
            -
                return DO_STR_NEW(value, length, encoding, internal_encoding);
         | 
| 399 94 | 
             
              }
         | 
| 400 | 
            -
             | 
| 401 | 
            -
             | 
| 402 | 
            -
             | 
| 403 | 
            -
            static void data_objects_debug(VALUE connection, VALUE string, struct timeval* start) {
         | 
| 404 | 
            -
              struct timeval stop;
         | 
| 405 | 
            -
              VALUE message;
         | 
| 406 | 
            -
             | 
| 407 | 
            -
              gettimeofday(&stop, NULL);
         | 
| 408 | 
            -
              do_int64 duration = (stop.tv_sec - start->tv_sec) * 1000000 + stop.tv_usec - start->tv_usec;
         | 
| 409 | 
            -
             | 
| 410 | 
            -
              message = rb_funcall(cDO_Logger_Message, ID_NEW, 3, string, rb_time_new(start->tv_sec, start->tv_usec), INT2NUM(duration));
         | 
| 411 | 
            -
             | 
| 412 | 
            -
              rb_funcall(connection, ID_LOG, 1, message);
         | 
| 413 | 
            -
            }
         | 
| 414 | 
            -
             | 
| 415 | 
            -
            static void raise_error(VALUE self, MYSQL *db, VALUE query) {
         | 
| 416 | 
            -
              VALUE exception;
         | 
| 417 | 
            -
              const char *exception_type = "SQLError";
         | 
| 418 | 
            -
              char *mysql_error_message = (char *)mysql_error(db);
         | 
| 419 | 
            -
              int mysql_error_code = mysql_errno(db);
         | 
| 420 | 
            -
             | 
| 421 | 
            -
              struct errcodes *errs;
         | 
| 422 | 
            -
             | 
| 423 | 
            -
              for (errs = errors; errs->error_name; errs++) {
         | 
| 424 | 
            -
                if(errs->error_no == mysql_error_code) {
         | 
| 425 | 
            -
                  exception_type = errs->exception;
         | 
| 426 | 
            -
                  break;
         | 
| 427 | 
            -
                }
         | 
| 95 | 
            +
              else {
         | 
| 96 | 
            +
                return do_typecast(value, length, type, encoding);
         | 
| 428 97 | 
             
              }
         | 
| 98 | 
            +
            }
         | 
| 429 99 |  | 
| 430 | 
            -
             | 
| 431 | 
            -
             | 
| 100 | 
            +
            void raise_error(VALUE self, MYSQL *db, VALUE query) {
         | 
| 101 | 
            +
              int errnum = mysql_errno(db);
         | 
| 102 | 
            +
              const char *message = mysql_error(db);
         | 
| 432 103 | 
             
              VALUE sql_state = Qnil;
         | 
| 104 | 
            +
             | 
| 433 105 | 
             
            #ifdef HAVE_MYSQL_SQLSTATE
         | 
| 434 106 | 
             
              sql_state = rb_str_new2(mysql_sqlstate(db));
         | 
| 435 107 | 
             
            #endif
         | 
| 436 108 |  | 
| 437 | 
            -
               | 
| 438 | 
            -
                                     rb_str_new2(mysql_error_message),
         | 
| 439 | 
            -
                                     INT2NUM(mysql_error_code),
         | 
| 440 | 
            -
                                     sql_state,
         | 
| 441 | 
            -
                                     query,
         | 
| 442 | 
            -
                                     uri);
         | 
| 443 | 
            -
              rb_exc_raise(exception);
         | 
| 444 | 
            -
            }
         | 
| 445 | 
            -
             | 
| 446 | 
            -
            static char * get_uri_option(VALUE query_hash, const char * key) {
         | 
| 447 | 
            -
              VALUE query_value;
         | 
| 448 | 
            -
              char * value = NULL;
         | 
| 449 | 
            -
             | 
| 450 | 
            -
              if(!rb_obj_is_kind_of(query_hash, rb_cHash)) { return NULL; }
         | 
| 451 | 
            -
             | 
| 452 | 
            -
              query_value = rb_hash_aref(query_hash, rb_str_new2(key));
         | 
| 453 | 
            -
             | 
| 454 | 
            -
              if (Qnil != query_value) {
         | 
| 455 | 
            -
                value = StringValuePtr(query_value);
         | 
| 456 | 
            -
              }
         | 
| 457 | 
            -
             | 
| 458 | 
            -
              return value;
         | 
| 459 | 
            -
            }
         | 
| 460 | 
            -
             | 
| 461 | 
            -
            static void assert_file_exists(char * file, const char * message) {
         | 
| 462 | 
            -
              if (file == NULL) { return; }
         | 
| 463 | 
            -
              if (rb_funcall(rb_cFile, rb_intern("exist?"), 1, rb_str_new2(file)) == Qfalse) {
         | 
| 464 | 
            -
                rb_raise(rb_eArgError, "%s", message);
         | 
| 465 | 
            -
              }
         | 
| 109 | 
            +
              do_raise_error(self, errors, errnum, message, query, sql_state);
         | 
| 466 110 | 
             
            }
         | 
| 467 111 |  | 
| 468 | 
            -
            static void full_connect(VALUE self, MYSQL *db);
         | 
| 469 | 
            -
             | 
| 470 112 | 
             
            #ifdef _WIN32
         | 
| 471 | 
            -
             | 
| 113 | 
            +
            MYSQL_RES *cCommand_execute_sync(VALUE self, VALUE connection, MYSQL *db, VALUE query) {
         | 
| 472 114 | 
             
              int retval;
         | 
| 473 115 | 
             
              struct timeval start;
         | 
| 474 | 
            -
              const char* | 
| 475 | 
            -
               | 
| 116 | 
            +
              const char *str = rb_str_ptr_readonly(query);
         | 
| 117 | 
            +
              long len = rb_str_len(query);
         | 
| 476 118 |  | 
| 477 | 
            -
              if(mysql_ping(db) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
         | 
| 119 | 
            +
              if (mysql_ping(db) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
         | 
| 478 120 | 
             
                // Ok, we do one more try here by doing a full connect
         | 
| 479 121 | 
             
                VALUE connection = rb_iv_get(self, "@connection");
         | 
| 480 122 | 
             
                full_connect(connection, db);
         | 
| 481 123 | 
             
              }
         | 
| 124 | 
            +
             | 
| 482 125 | 
             
              gettimeofday(&start, NULL);
         | 
| 483 126 | 
             
              retval = mysql_real_query(db, str, len);
         | 
| 484 127 | 
             
              data_objects_debug(connection, query, &start);
         | 
| @@ -488,38 +131,37 @@ static MYSQL_RES* cCommand_execute_sync(VALUE self, VALUE connection, MYSQL* db, | |
| 488 131 | 
             
              return mysql_store_result(db);
         | 
| 489 132 | 
             
            }
         | 
| 490 133 | 
             
            #else
         | 
| 491 | 
            -
             | 
| 492 | 
            -
              int socket_fd;
         | 
| 134 | 
            +
            MYSQL_RES *cCommand_execute_async(VALUE self, VALUE connection, MYSQL *db, VALUE query) {
         | 
| 493 135 | 
             
              int retval;
         | 
| 494 | 
            -
              fd_set rset;
         | 
| 495 | 
            -
              struct timeval start;
         | 
| 496 | 
            -
              const char* str = rb_str_ptr_readonly(query);
         | 
| 497 | 
            -
              size_t len      = rb_str_len(query);
         | 
| 498 | 
            -
              MYSQL_RES* result;
         | 
| 499 136 |  | 
| 500 | 
            -
              if((retval = mysql_ping(db)) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
         | 
| 137 | 
            +
              if ((retval = mysql_ping(db)) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
         | 
| 501 138 | 
             
                full_connect(connection, db);
         | 
| 502 139 | 
             
              }
         | 
| 503 | 
            -
              gettimeofday(&start, NULL);
         | 
| 504 140 |  | 
| 141 | 
            +
              struct timeval start;
         | 
| 142 | 
            +
              const char *str = rb_str_ptr_readonly(query);
         | 
| 143 | 
            +
              long len = rb_str_len(query);
         | 
| 144 | 
            +
             | 
| 145 | 
            +
              gettimeofday(&start, NULL);
         | 
| 505 146 | 
             
              retval = mysql_send_query(db, str, len);
         | 
| 506 147 |  | 
| 507 148 | 
             
              CHECK_AND_RAISE(retval, query);
         | 
| 508 149 |  | 
| 509 | 
            -
              socket_fd = db->net.fd;
         | 
| 150 | 
            +
              int socket_fd = db->net.fd;
         | 
| 151 | 
            +
              fd_set rset;
         | 
| 510 152 |  | 
| 511 | 
            -
               | 
| 153 | 
            +
              while (1) {
         | 
| 512 154 | 
             
                FD_ZERO(&rset);
         | 
| 513 155 | 
             
                FD_SET(socket_fd, &rset);
         | 
| 514 156 |  | 
| 515 157 | 
             
                retval = rb_thread_select(socket_fd + 1, &rset, NULL, NULL, NULL);
         | 
| 516 158 |  | 
| 517 159 | 
             
                if (retval < 0) {
         | 
| 518 | 
            -
             | 
| 160 | 
            +
                  rb_sys_fail(0);
         | 
| 519 161 | 
             
                }
         | 
| 520 162 |  | 
| 521 163 | 
             
                if (retval == 0) {
         | 
| 522 | 
            -
             | 
| 164 | 
            +
                  continue;
         | 
| 523 165 | 
             
                }
         | 
| 524 166 |  | 
| 525 167 | 
             
                if (db->status == MYSQL_STATUS_READY) {
         | 
| @@ -531,60 +173,66 @@ static MYSQL_RES* cCommand_execute_async(VALUE self, VALUE connection, MYSQL* db | |
| 531 173 | 
             
              CHECK_AND_RAISE(retval, query);
         | 
| 532 174 | 
             
              data_objects_debug(connection, query, &start);
         | 
| 533 175 |  | 
| 534 | 
            -
              result = mysql_store_result(db);
         | 
| 176 | 
            +
              MYSQL_RES *result = mysql_store_result(db);
         | 
| 535 177 |  | 
| 536 | 
            -
              if (!result)
         | 
| 178 | 
            +
              if (!result) {
         | 
| 537 179 | 
             
                CHECK_AND_RAISE(mysql_errno(db), query);
         | 
| 180 | 
            +
              }
         | 
| 538 181 |  | 
| 539 182 | 
             
              return result;
         | 
| 540 183 | 
             
            }
         | 
| 541 184 | 
             
            #endif
         | 
| 542 185 |  | 
| 186 | 
            +
            void full_connect(VALUE self, MYSQL *db) {
         | 
| 187 | 
            +
              VALUE r_host = rb_iv_get(self, "@host");
         | 
| 188 | 
            +
              const char *host = "localhost";
         | 
| 543 189 |  | 
| 544 | 
            -
             | 
| 545 | 
            -
             | 
| 546 | 
            -
               | 
| 547 | 
            -
             | 
| 548 | 
            -
              const char *host = "localhost", *user = "root";
         | 
| 549 | 
            -
              char *database = NULL, *socket = NULL, *password = NULL, *path = NULL;
         | 
| 550 | 
            -
              VALUE encoding = Qnil;
         | 
| 551 | 
            -
             | 
| 552 | 
            -
              MYSQL *result;
         | 
| 190 | 
            +
              if (r_host != Qnil) {
         | 
| 191 | 
            +
                host = StringValuePtr(r_host);
         | 
| 192 | 
            +
              }
         | 
| 553 193 |  | 
| 554 | 
            -
               | 
| 555 | 
            -
               | 
| 556 | 
            -
              int encoding_error;
         | 
| 194 | 
            +
              VALUE r_user = rb_iv_get(self, "@user");
         | 
| 195 | 
            +
              const char *user = "root";
         | 
| 557 196 |  | 
| 558 | 
            -
              if | 
| 559 | 
            -
                 | 
| 197 | 
            +
              if (r_user != Qnil) {
         | 
| 198 | 
            +
                user = StringValuePtr(r_user);
         | 
| 560 199 | 
             
              }
         | 
| 561 200 |  | 
| 562 | 
            -
               | 
| 563 | 
            -
             | 
| 564 | 
            -
              }
         | 
| 201 | 
            +
              VALUE r_password = rb_iv_get(self, "@password");
         | 
| 202 | 
            +
              char *password = NULL;
         | 
| 565 203 |  | 
| 566 | 
            -
              if( | 
| 204 | 
            +
              if (r_password != Qnil) {
         | 
| 567 205 | 
             
                password = StringValuePtr(r_password);
         | 
| 568 206 | 
             
              }
         | 
| 569 207 |  | 
| 570 | 
            -
               | 
| 208 | 
            +
              VALUE r_port = rb_iv_get(self, "@port");
         | 
| 209 | 
            +
              int port = 3306;
         | 
| 210 | 
            +
             | 
| 211 | 
            +
              if (r_port != Qnil) {
         | 
| 571 212 | 
             
                port = NUM2INT(r_port);
         | 
| 572 213 | 
             
              }
         | 
| 573 214 |  | 
| 574 | 
            -
               | 
| 215 | 
            +
              VALUE r_path = rb_iv_get(self, "@path");
         | 
| 216 | 
            +
              char *path = NULL;
         | 
| 217 | 
            +
              char *database = NULL;
         | 
| 218 | 
            +
             | 
| 219 | 
            +
              if (r_path != Qnil) {
         | 
| 575 220 | 
             
                path = StringValuePtr(r_path);
         | 
| 576 | 
            -
                database = strtok(path, "/");
         | 
| 221 | 
            +
                database = strtok(path, "/"); // not threadsafe
         | 
| 577 222 | 
             
              }
         | 
| 578 223 |  | 
| 579 | 
            -
              if ( | 
| 224 | 
            +
              if (!database || !*database) {
         | 
| 580 225 | 
             
                rb_raise(eConnectionError, "Database must be specified");
         | 
| 581 226 | 
             
              }
         | 
| 582 227 |  | 
| 583 | 
            -
              r_query | 
| 228 | 
            +
              VALUE r_query = rb_iv_get(self, "@query");
         | 
| 229 | 
            +
              char *socket = NULL;
         | 
| 584 230 |  | 
| 585 | 
            -
              if  | 
| 231 | 
            +
              // Check to see if we're on the db machine.  If so, try to use the socket
         | 
| 232 | 
            +
              if (strcasecmp(host, "localhost") == 0) {
         | 
| 586 233 | 
             
                socket = get_uri_option(r_query, "socket");
         | 
| 587 | 
            -
             | 
| 234 | 
            +
             | 
| 235 | 
            +
                if (socket) {
         | 
| 588 236 | 
             
                  rb_iv_set(self, "@using_socket", Qtrue);
         | 
| 589 237 | 
             
                }
         | 
| 590 238 | 
             
              }
         | 
| @@ -593,10 +241,10 @@ static void full_connect(VALUE self, MYSQL* db) { | |
| 593 241 | 
             
              char *ssl_client_key, *ssl_client_cert, *ssl_ca_cert, *ssl_ca_path, *ssl_cipher;
         | 
| 594 242 | 
             
              VALUE r_ssl;
         | 
| 595 243 |  | 
| 596 | 
            -
              if(rb_obj_is_kind_of(r_query, rb_cHash)) {
         | 
| 244 | 
            +
              if (rb_obj_is_kind_of(r_query, rb_cHash)) {
         | 
| 597 245 | 
             
                r_ssl = rb_hash_aref(r_query, rb_str_new2("ssl"));
         | 
| 598 246 |  | 
| 599 | 
            -
                if(rb_obj_is_kind_of(r_ssl, rb_cHash)) {
         | 
| 247 | 
            +
                if (rb_obj_is_kind_of(r_ssl, rb_cHash)) {
         | 
| 600 248 | 
             
                  ssl_client_key  = get_uri_option(r_ssl, "client_key");
         | 
| 601 249 | 
             
                  ssl_client_cert = get_uri_option(r_ssl, "client_cert");
         | 
| 602 250 | 
             
                  ssl_ca_cert     = get_uri_option(r_ssl, "ca_cert");
         | 
| @@ -608,13 +256,16 @@ static void full_connect(VALUE self, MYSQL* db) { | |
| 608 256 | 
             
                  assert_file_exists(ssl_ca_cert,     "ca_cert doesn't exist");
         | 
| 609 257 |  | 
| 610 258 | 
             
                  mysql_ssl_set(db, ssl_client_key, ssl_client_cert, ssl_ca_cert, ssl_ca_path, ssl_cipher);
         | 
| 611 | 
            -
                } | 
| 259 | 
            +
                }
         | 
| 260 | 
            +
                else if (r_ssl != Qnil) {
         | 
| 612 261 | 
             
                  rb_raise(rb_eArgError, "ssl must be passed a hash");
         | 
| 613 262 | 
             
                }
         | 
| 614 263 | 
             
              }
         | 
| 615 264 | 
             
            #endif
         | 
| 616 265 |  | 
| 617 | 
            -
               | 
| 266 | 
            +
              unsigned long client_flags = 0;
         | 
| 267 | 
            +
             | 
| 268 | 
            +
              MYSQL *result = mysql_real_connect(
         | 
| 618 269 | 
             
                db,
         | 
| 619 270 | 
             
                host,
         | 
| 620 271 | 
             
                user,
         | 
| @@ -625,14 +276,14 @@ static void full_connect(VALUE self, MYSQL* db) { | |
| 625 276 | 
             
                client_flags
         | 
| 626 277 | 
             
              );
         | 
| 627 278 |  | 
| 628 | 
            -
              if ( | 
| 279 | 
            +
              if (!result) {
         | 
| 629 280 | 
             
                raise_error(self, db, Qnil);
         | 
| 630 281 | 
             
              }
         | 
| 631 282 |  | 
| 632 283 | 
             
            #ifdef HAVE_MYSQL_GET_SSL_CIPHER
         | 
| 633 284 | 
             
              const char *ssl_cipher_used = mysql_get_ssl_cipher(db);
         | 
| 634 285 |  | 
| 635 | 
            -
              if ( | 
| 286 | 
            +
              if (ssl_cipher_used) {
         | 
| 636 287 | 
             
                rb_iv_set(self, "@ssl_cipher", rb_str_new2(ssl_cipher_used));
         | 
| 637 288 | 
             
              }
         | 
| 638 289 | 
             
            #endif
         | 
| @@ -642,7 +293,6 @@ static void full_connect(VALUE self, MYSQL* db) { | |
| 642 293 | 
             
              mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect);
         | 
| 643 294 | 
             
            #endif
         | 
| 644 295 |  | 
| 645 | 
            -
             | 
| 646 296 | 
             
              // We only support encoding for MySQL versions providing mysql_set_character_set.
         | 
| 647 297 | 
             
              // Without this function there are potential issues with mysql_real_escape_string
         | 
| 648 298 | 
             
              // since that doesn't take the character set into consideration when setting it
         | 
| @@ -651,21 +301,24 @@ static void full_connect(VALUE self, MYSQL* db) { | |
| 651 301 |  | 
| 652 302 | 
             
            #ifdef HAVE_MYSQL_SET_CHARACTER_SET
         | 
| 653 303 | 
             
              // Set the connections character set
         | 
| 654 | 
            -
              encoding = rb_iv_get(self, "@encoding");
         | 
| 304 | 
            +
              VALUE encoding = rb_iv_get(self, "@encoding");
         | 
| 305 | 
            +
              VALUE my_encoding = rb_hash_aref(do_const_get(mEncoding, "MAP"), encoding);
         | 
| 655 306 |  | 
| 656 | 
            -
               | 
| 657 | 
            -
             | 
| 307 | 
            +
              if (my_encoding != Qnil) {
         | 
| 308 | 
            +
                int encoding_error = mysql_set_character_set(db, rb_str_ptr_readonly(my_encoding));
         | 
| 658 309 |  | 
| 659 | 
            -
                encoding_error  | 
| 660 | 
            -
                if (0 != encoding_error) {
         | 
| 310 | 
            +
                if (encoding_error != 0) {
         | 
| 661 311 | 
             
                  raise_error(self, db, Qnil);
         | 
| 662 | 
            -
                } | 
| 312 | 
            +
                }
         | 
| 313 | 
            +
                else {
         | 
| 663 314 | 
             
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 664 315 | 
             
                  rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index(rb_str_ptr_readonly(encoding))));
         | 
| 665 316 | 
             
            #endif
         | 
| 317 | 
            +
             | 
| 666 318 | 
             
                  rb_iv_set(self, "@my_encoding", my_encoding);
         | 
| 667 319 | 
             
                }
         | 
| 668 | 
            -
              } | 
| 320 | 
            +
              }
         | 
| 321 | 
            +
              else {
         | 
| 669 322 | 
             
                rb_warn("Encoding %s is not a known Ruby encoding for MySQL\n", rb_str_ptr_readonly(encoding));
         | 
| 670 323 | 
             
                rb_iv_set(self, "@encoding", rb_str_new2("UTF-8"));
         | 
| 671 324 | 
             
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| @@ -673,7 +326,6 @@ static void full_connect(VALUE self, MYSQL* db) { | |
| 673 326 | 
             
            #endif
         | 
| 674 327 | 
             
                rb_iv_set(self, "@my_encoding", rb_str_new2("utf8"));
         | 
| 675 328 | 
             
              }
         | 
| 676 | 
            -
             | 
| 677 329 | 
             
            #endif
         | 
| 678 330 |  | 
| 679 331 | 
             
              // Disable sql_auto_is_null
         | 
| @@ -684,9 +336,10 @@ static void full_connect(VALUE self, MYSQL* db) { | |
| 684 336 | 
             
            // For really anscient MySQL versions we don't attempt any strictness
         | 
| 685 337 | 
             
            #ifdef HAVE_MYSQL_GET_SERVER_VERSION
         | 
| 686 338 | 
             
              //4.x versions do not support certain session parameters
         | 
| 687 | 
            -
              if(mysql_get_server_version(db) < 50000  | 
| 339 | 
            +
              if (mysql_get_server_version(db) < 50000) {
         | 
| 688 340 | 
             
                cCommand_execute(Qnil, self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_DIR_IN_CREATE,NO_UNSIGNED_SUBTRACTION'"));
         | 
| 689 | 
            -
              } | 
| 341 | 
            +
              }
         | 
| 342 | 
            +
              else {
         | 
| 690 343 | 
             
                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'"));
         | 
| 691 344 | 
             
              }
         | 
| 692 345 | 
             
            #endif
         | 
| @@ -694,153 +347,104 @@ static void full_connect(VALUE self, MYSQL* db) { | |
| 694 347 | 
             
              rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
         | 
| 695 348 | 
             
            }
         | 
| 696 349 |  | 
| 697 | 
            -
             | 
| 698 | 
            -
              VALUE r_host, r_user, r_password, r_path, r_query, r_port;
         | 
| 699 | 
            -
             | 
| 700 | 
            -
              MYSQL *db = 0;
         | 
| 701 | 
            -
              db = (MYSQL *)mysql_init(NULL);
         | 
| 702 | 
            -
             | 
| 350 | 
            +
            VALUE cConnection_initialize(VALUE self, VALUE uri) {
         | 
| 703 351 | 
             
              rb_iv_set(self, "@using_socket", Qfalse);
         | 
| 704 352 | 
             
              rb_iv_set(self, "@ssl_cipher", Qnil);
         | 
| 705 353 |  | 
| 706 | 
            -
              r_host = rb_funcall(uri, rb_intern("host"), 0);
         | 
| 707 | 
            -
             | 
| 354 | 
            +
              VALUE r_host = rb_funcall(uri, rb_intern("host"), 0);
         | 
| 355 | 
            +
             | 
| 356 | 
            +
              if (r_host != Qnil) {
         | 
| 708 357 | 
             
                rb_iv_set(self, "@host", r_host);
         | 
| 709 358 | 
             
              }
         | 
| 710 359 |  | 
| 711 | 
            -
              r_user = rb_funcall(uri, rb_intern("user"), 0);
         | 
| 712 | 
            -
             | 
| 360 | 
            +
              VALUE r_user = rb_funcall(uri, rb_intern("user"), 0);
         | 
| 361 | 
            +
             | 
| 362 | 
            +
              if (r_user != Qnil) {
         | 
| 713 363 | 
             
                rb_iv_set(self, "@user", r_user);
         | 
| 714 364 | 
             
              }
         | 
| 715 365 |  | 
| 716 | 
            -
              r_password = rb_funcall(uri, rb_intern("password"), 0);
         | 
| 717 | 
            -
             | 
| 366 | 
            +
              VALUE r_password = rb_funcall(uri, rb_intern("password"), 0);
         | 
| 367 | 
            +
             | 
| 368 | 
            +
              if (r_password != Qnil) {
         | 
| 718 369 | 
             
                rb_iv_set(self, "@password", r_password);
         | 
| 719 370 | 
             
              }
         | 
| 720 371 |  | 
| 721 | 
            -
              r_path = rb_funcall(uri, rb_intern("path"), 0);
         | 
| 722 | 
            -
             | 
| 372 | 
            +
              VALUE r_path = rb_funcall(uri, rb_intern("path"), 0);
         | 
| 373 | 
            +
             | 
| 374 | 
            +
              if (r_path != Qnil) {
         | 
| 723 375 | 
             
                rb_iv_set(self, "@path", r_path);
         | 
| 724 376 | 
             
              }
         | 
| 725 377 |  | 
| 726 | 
            -
              r_port = rb_funcall(uri, rb_intern("port"), 0);
         | 
| 727 | 
            -
             | 
| 378 | 
            +
              VALUE r_port = rb_funcall(uri, rb_intern("port"), 0);
         | 
| 379 | 
            +
             | 
| 380 | 
            +
              if (r_port != Qnil) {
         | 
| 728 381 | 
             
                rb_iv_set(self, "@port", r_port);
         | 
| 729 382 | 
             
              }
         | 
| 730 383 |  | 
| 731 384 | 
             
              // Pull the querystring off the URI
         | 
| 732 | 
            -
              r_query = rb_funcall(uri, rb_intern("query"), 0);
         | 
| 385 | 
            +
              VALUE r_query = rb_funcall(uri, rb_intern("query"), 0);
         | 
| 386 | 
            +
             | 
| 733 387 | 
             
              rb_iv_set(self, "@query", r_query);
         | 
| 734 388 |  | 
| 735 | 
            -
              const char* | 
| 736 | 
            -
             | 
| 737 | 
            -
              if (!encoding) { | 
| 389 | 
            +
              const char *encoding = get_uri_option(r_query, "encoding");
         | 
| 390 | 
            +
             | 
| 391 | 
            +
              if (!encoding) {
         | 
| 392 | 
            +
                encoding = get_uri_option(r_query, "charset");
         | 
| 393 | 
            +
             | 
| 394 | 
            +
                if (!encoding) { encoding = "UTF-8"; }
         | 
| 395 | 
            +
              }
         | 
| 738 396 |  | 
| 739 397 | 
             
              rb_iv_set(self, "@encoding", rb_str_new2(encoding));
         | 
| 740 398 |  | 
| 741 | 
            -
               | 
| 399 | 
            +
              MYSQL *db = mysql_init(NULL);
         | 
| 742 400 |  | 
| 401 | 
            +
              full_connect(self, db);
         | 
| 743 402 | 
             
              rb_iv_set(self, "@uri", uri);
         | 
| 744 | 
            -
             | 
| 745 403 | 
             
              return Qtrue;
         | 
| 746 404 | 
             
            }
         | 
| 747 405 |  | 
| 748 | 
            -
             | 
| 749 | 
            -
              return rb_iv_get(self, "@encoding");
         | 
| 750 | 
            -
            }
         | 
| 751 | 
            -
             | 
| 752 | 
            -
            static VALUE cConnection_is_using_socket(VALUE self) {
         | 
| 753 | 
            -
              return rb_iv_get(self, "@using_socket");
         | 
| 754 | 
            -
            }
         | 
| 755 | 
            -
             | 
| 756 | 
            -
            static VALUE cConnection_ssl_cipher(VALUE self) {
         | 
| 757 | 
            -
              return rb_iv_get(self, "@ssl_cipher");
         | 
| 758 | 
            -
            }
         | 
| 759 | 
            -
             | 
| 760 | 
            -
            static VALUE cConnection_dispose(VALUE self) {
         | 
| 406 | 
            +
            VALUE cConnection_dispose(VALUE self) {
         | 
| 761 407 | 
             
              VALUE connection_container = rb_iv_get(self, "@connection");
         | 
| 762 408 |  | 
| 763 409 | 
             
              MYSQL *db;
         | 
| 764 410 |  | 
| 765 | 
            -
              if ( | 
| 411 | 
            +
              if (connection_container == Qnil) {
         | 
| 766 412 | 
             
                return Qfalse;
         | 
| 413 | 
            +
              }
         | 
| 767 414 |  | 
| 768 415 | 
             
              db = DATA_PTR(connection_container);
         | 
| 769 416 |  | 
| 770 | 
            -
              if ( | 
| 417 | 
            +
              if (!db) {
         | 
| 771 418 | 
             
                return Qfalse;
         | 
| 419 | 
            +
              }
         | 
| 772 420 |  | 
| 773 421 | 
             
              mysql_close(db);
         | 
| 774 422 | 
             
              rb_iv_set(self, "@connection", Qnil);
         | 
| 775 | 
            -
             | 
| 776 423 | 
             
              return Qtrue;
         | 
| 777 424 | 
             
            }
         | 
| 778 425 |  | 
| 779 | 
            -
             | 
| 780 | 
            -
            Accepts an array of Ruby types (Fixnum, Float, String, etc...) and turns them
         | 
| 781 | 
            -
            into Ruby-strings so we can easily typecast later
         | 
| 782 | 
            -
            */
         | 
| 783 | 
            -
            static VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self) {
         | 
| 784 | 
            -
              VALUE type_strings = rb_ary_new();
         | 
| 785 | 
            -
              VALUE array = rb_ary_new();
         | 
| 786 | 
            -
             | 
| 787 | 
            -
              int i, j;
         | 
| 788 | 
            -
             | 
| 789 | 
            -
              for ( i = 0; i < argc; i++) {
         | 
| 790 | 
            -
                rb_ary_push(array, argv[i]);
         | 
| 791 | 
            -
              }
         | 
| 792 | 
            -
             | 
| 793 | 
            -
              for (i = 0; i < RARRAY_LEN(array); i++) {
         | 
| 794 | 
            -
                VALUE entry = rb_ary_entry(array, i);
         | 
| 795 | 
            -
                if(TYPE(entry) == T_CLASS) {
         | 
| 796 | 
            -
                  rb_ary_push(type_strings, entry);
         | 
| 797 | 
            -
                } else if (TYPE(entry) == T_ARRAY) {
         | 
| 798 | 
            -
                  for (j = 0; j < RARRAY_LEN(entry); j++) {
         | 
| 799 | 
            -
                    VALUE sub_entry = rb_ary_entry(entry, j);
         | 
| 800 | 
            -
                    if(TYPE(sub_entry) == T_CLASS) {
         | 
| 801 | 
            -
                      rb_ary_push(type_strings, sub_entry);
         | 
| 802 | 
            -
                    } else {
         | 
| 803 | 
            -
                      rb_raise(rb_eArgError, "Invalid type given");
         | 
| 804 | 
            -
                    }
         | 
| 805 | 
            -
                  }
         | 
| 806 | 
            -
                } else {
         | 
| 807 | 
            -
                  rb_raise(rb_eArgError, "Invalid type given");
         | 
| 808 | 
            -
                }
         | 
| 809 | 
            -
              }
         | 
| 810 | 
            -
             | 
| 811 | 
            -
              rb_iv_set(self, "@field_types", type_strings);
         | 
| 812 | 
            -
             | 
| 813 | 
            -
              return array;
         | 
| 814 | 
            -
            }
         | 
| 815 | 
            -
             | 
| 816 | 
            -
            VALUE cConnection_quote_time(VALUE self, VALUE value) {
         | 
| 817 | 
            -
              return rb_funcall(value, ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d %H:%M:%S'"));
         | 
| 818 | 
            -
            }
         | 
| 819 | 
            -
             | 
| 820 | 
            -
             | 
| 821 | 
            -
            VALUE cConnection_quote_date_time(VALUE self, VALUE value) {
         | 
| 822 | 
            -
              // TODO: Support non-local dates. we need to call #new_offset on the date to be
         | 
| 823 | 
            -
              // quoted and pass in the current locale's date offset (self.new_offset((hours * 3600).to_r / 86400)
         | 
| 824 | 
            -
              return rb_funcall(value, ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d %H:%M:%S'"));
         | 
| 825 | 
            -
            }
         | 
| 826 | 
            -
             | 
| 827 | 
            -
            VALUE cConnection_quote_date(VALUE self, VALUE value) {
         | 
| 828 | 
            -
              return rb_funcall(value, ID_STRFTIME, 1, rb_str_new2("'%Y-%m-%d'"));
         | 
| 829 | 
            -
            }
         | 
| 830 | 
            -
             | 
| 831 | 
            -
            static VALUE cConnection_quote_string(VALUE self, VALUE string) {
         | 
| 426 | 
            +
            VALUE cConnection_quote_string(VALUE self, VALUE string) {
         | 
| 832 427 | 
             
              MYSQL *db = DATA_PTR(rb_iv_get(self, "@connection"));
         | 
| 833 428 | 
             
              const char *source = rb_str_ptr_readonly(string);
         | 
| 834 | 
            -
               | 
| 835 | 
            -
               | 
| 836 | 
            -
              VALUE result;
         | 
| 429 | 
            +
              long source_len = rb_str_len(string);
         | 
| 430 | 
            +
              long buffer_len = source_len * 2 + 3;
         | 
| 837 431 |  | 
| 838 | 
            -
               | 
| 432 | 
            +
              // Overflow check
         | 
| 433 | 
            +
              if(buffer_len <= source_len) {
         | 
| 434 | 
            +
                rb_raise(rb_eArgError, "Input string is too large to be safely quoted");
         | 
| 435 | 
            +
              }
         | 
| 839 436 |  | 
| 840 437 | 
             
              // Allocate space for the escaped version of 'string'.  Use + 3 allocate space for null term.
         | 
| 841 438 | 
             
              // and the leading and trailing single-quotes.
         | 
| 842 439 | 
             
              // Thanks to http://www.browardphp.com/mysql_manual_en/manual_MySQL_APIs.html#mysql_real_escape_string
         | 
| 843 | 
            -
              escaped =  | 
| 440 | 
            +
              char *escaped = calloc(buffer_len, sizeof(char));
         | 
| 441 | 
            +
             | 
| 442 | 
            +
              if (!escaped) {
         | 
| 443 | 
            +
                rb_memerror();
         | 
| 444 | 
            +
              }
         | 
| 445 | 
            +
             | 
| 446 | 
            +
              unsigned long quoted_length;
         | 
| 447 | 
            +
              VALUE result;
         | 
| 844 448 |  | 
| 845 449 | 
             
              // Escape 'source' using the current encoding in use on the conection 'db'
         | 
| 846 450 | 
             
              quoted_length = mysql_real_escape_string(db, escaped + 1, source, source_len);
         | 
| @@ -855,101 +459,78 @@ static VALUE cConnection_quote_string(VALUE self, VALUE string) { | |
| 855 459 | 
             
              return result;
         | 
| 856 460 | 
             
            }
         | 
| 857 461 |  | 
| 858 | 
            -
             | 
| 859 | 
            -
              VALUE query = rb_iv_get(klass, "@text");
         | 
| 860 | 
            -
             | 
| 861 | 
            -
              int i;
         | 
| 862 | 
            -
              VALUE array = rb_ary_new();
         | 
| 863 | 
            -
              for ( i = 0; i < count; i++) {
         | 
| 864 | 
            -
                rb_ary_push(array, (VALUE)args[i]);
         | 
| 865 | 
            -
              }
         | 
| 866 | 
            -
              query = rb_funcall(klass, ID_ESCAPE, 1, array);
         | 
| 867 | 
            -
             | 
| 868 | 
            -
              return query;
         | 
| 869 | 
            -
            }
         | 
| 870 | 
            -
             | 
| 871 | 
            -
            static VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
         | 
| 872 | 
            -
              VALUE query;
         | 
| 873 | 
            -
             | 
| 874 | 
            -
              MYSQL_RES *response = 0;
         | 
| 875 | 
            -
             | 
| 876 | 
            -
              my_ulonglong affected_rows;
         | 
| 877 | 
            -
              my_ulonglong insert_id;
         | 
| 462 | 
            +
            VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
         | 
| 878 463 | 
             
              VALUE connection = rb_iv_get(self, "@connection");
         | 
| 879 464 | 
             
              VALUE mysql_connection = rb_iv_get(connection, "@connection");
         | 
| 880 | 
            -
             | 
| 465 | 
            +
             | 
| 466 | 
            +
              if (mysql_connection == Qnil) {
         | 
| 881 467 | 
             
                rb_raise(eConnectionError, "This connection has already been closed.");
         | 
| 882 468 | 
             
              }
         | 
| 883 469 |  | 
| 884 470 | 
             
              MYSQL *db = DATA_PTR(mysql_connection);
         | 
| 885 | 
            -
              query = build_query_from_args(self, argc, argv);
         | 
| 471 | 
            +
              VALUE query = build_query_from_args(self, argc, argv);
         | 
| 472 | 
            +
              MYSQL_RES *response = cCommand_execute(self, connection, db, query);
         | 
| 886 473 |  | 
| 887 | 
            -
               | 
| 474 | 
            +
              my_ulonglong affected_rows = mysql_affected_rows(db);
         | 
| 475 | 
            +
              my_ulonglong insert_id = mysql_insert_id(db);
         | 
| 888 476 |  | 
| 889 | 
            -
              affected_rows = mysql_affected_rows(db);
         | 
| 890 | 
            -
              insert_id     = mysql_insert_id(db);
         | 
| 891 477 | 
             
              mysql_free_result(response);
         | 
| 892 478 |  | 
| 893 | 
            -
              if ((my_ulonglong)-1 == affected_rows) {
         | 
| 479 | 
            +
              if (((my_ulonglong)-1) == affected_rows) {
         | 
| 894 480 | 
             
                return Qnil;
         | 
| 895 481 | 
             
              }
         | 
| 896 482 |  | 
| 897 483 | 
             
              return rb_funcall(cResult, ID_NEW, 3, self, INT2NUM(affected_rows), insert_id == 0 ? Qnil : INT2NUM(insert_id));
         | 
| 898 484 | 
             
            }
         | 
| 899 485 |  | 
| 900 | 
            -
             | 
| 901 | 
            -
              VALUE query, reader;
         | 
| 902 | 
            -
              VALUE field_names, field_types;
         | 
| 903 | 
            -
             | 
| 904 | 
            -
              unsigned int field_count;
         | 
| 905 | 
            -
              unsigned int i;
         | 
| 906 | 
            -
             | 
| 907 | 
            -
              char guess_default_field_types = 0;
         | 
| 486 | 
            +
            VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
         | 
| 908 487 | 
             
              VALUE connection = rb_iv_get(self, "@connection");
         | 
| 909 488 | 
             
              VALUE mysql_connection = rb_iv_get(connection, "@connection");
         | 
| 910 | 
            -
             | 
| 489 | 
            +
             | 
| 490 | 
            +
              if (mysql_connection == Qnil) {
         | 
| 911 491 | 
             
                rb_raise(eConnectionError, "This connection has already been closed.");
         | 
| 912 492 | 
             
              }
         | 
| 913 493 |  | 
| 494 | 
            +
              VALUE query = build_query_from_args(self, argc, argv);
         | 
| 914 495 | 
             
              MYSQL *db = DATA_PTR(mysql_connection);
         | 
| 915 | 
            -
             | 
| 916 | 
            -
              MYSQL_RES *response = 0;
         | 
| 917 | 
            -
              MYSQL_FIELD *field;
         | 
| 918 | 
            -
             | 
| 919 | 
            -
              query = build_query_from_args(self, argc, argv);
         | 
| 920 | 
            -
             | 
| 921 | 
            -
              response = cCommand_execute(self, connection, db, query);
         | 
| 496 | 
            +
              MYSQL_RES *response = cCommand_execute(self, connection, db, query);
         | 
| 922 497 |  | 
| 923 498 | 
             
              if (!response) {
         | 
| 924 | 
            -
                 | 
| 499 | 
            +
                rb_raise(eConnectionError, "No result set received for a query that should yield one.");
         | 
| 925 500 | 
             
              }
         | 
| 926 501 |  | 
| 927 | 
            -
              field_count = mysql_field_count(db);
         | 
| 502 | 
            +
              unsigned int field_count = mysql_field_count(db);
         | 
| 503 | 
            +
              VALUE reader = rb_funcall(cReader, ID_NEW, 0);
         | 
| 928 504 |  | 
| 929 | 
            -
              reader = rb_funcall(cReader, ID_NEW, 0);
         | 
| 930 505 | 
             
              rb_iv_set(reader, "@connection", connection);
         | 
| 931 506 | 
             
              rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, response));
         | 
| 932 507 | 
             
              rb_iv_set(reader, "@opened", Qfalse);
         | 
| 933 508 | 
             
              rb_iv_set(reader, "@field_count", INT2NUM(field_count));
         | 
| 934 509 |  | 
| 935 | 
            -
              field_names = rb_ary_new();
         | 
| 936 | 
            -
              field_types = rb_iv_get(self, "@field_types");
         | 
| 510 | 
            +
              VALUE field_names = rb_ary_new();
         | 
| 511 | 
            +
              VALUE field_types = rb_iv_get(self, "@field_types");
         | 
| 512 | 
            +
             | 
| 513 | 
            +
              char guess_default_field_types = 0;
         | 
| 937 514 |  | 
| 938 | 
            -
              if ( | 
| 515 | 
            +
              if (field_types == Qnil || RARRAY_LEN(field_types) == 0) {
         | 
| 939 516 | 
             
                field_types = rb_ary_new();
         | 
| 940 517 | 
             
                guess_default_field_types = 1;
         | 
| 941 | 
            -
              } | 
| 942 | 
            -
             | 
| 518 | 
            +
              }
         | 
| 519 | 
            +
              else if (RARRAY_LEN(field_types) != field_count) {
         | 
| 520 | 
            +
                // Whoops... wrong number of types passed to set_types. Close the reader and raise
         | 
| 943 521 | 
             
                // and error
         | 
| 944 522 | 
             
                rb_funcall(reader, rb_intern("close"), 0);
         | 
| 945 523 | 
             
                rb_raise(rb_eArgError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
         | 
| 946 524 | 
             
              }
         | 
| 947 525 |  | 
| 526 | 
            +
              MYSQL_FIELD *field;
         | 
| 527 | 
            +
              unsigned int i;
         | 
| 528 | 
            +
             | 
| 948 529 | 
             
              for(i = 0; i < field_count; i++) {
         | 
| 949 530 | 
             
                field = mysql_fetch_field_direct(response, i);
         | 
| 950 531 | 
             
                rb_ary_push(field_names, rb_str_new2(field->name));
         | 
| 951 532 |  | 
| 952 | 
            -
                if ( | 
| 533 | 
            +
                if (guess_default_field_types == 1) {
         | 
| 953 534 | 
             
                  rb_ary_push(field_types, infer_ruby_type(field));
         | 
| 954 535 | 
             
                }
         | 
| 955 536 | 
             
              }
         | 
| @@ -966,51 +547,43 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) { | |
| 966 547 | 
             
            }
         | 
| 967 548 |  | 
| 968 549 | 
             
            // This should be called to ensure that the internal result reader is freed
         | 
| 969 | 
            -
             | 
| 550 | 
            +
            VALUE cReader_close(VALUE self) {
         | 
| 970 551 | 
             
              // Get the reader from the instance variable, maybe refactor this?
         | 
| 971 552 | 
             
              VALUE reader_container = rb_iv_get(self, "@reader");
         | 
| 972 553 |  | 
| 973 | 
            -
               | 
| 974 | 
            -
             | 
| 975 | 
            -
              if (Qnil == reader_container)
         | 
| 554 | 
            +
              if (reader_container == Qnil) {
         | 
| 976 555 | 
             
                return Qfalse;
         | 
| 556 | 
            +
              }
         | 
| 977 557 |  | 
| 978 | 
            -
              reader = DATA_PTR(reader_container);
         | 
| 558 | 
            +
              MYSQL_RES *reader = DATA_PTR(reader_container);
         | 
| 979 559 |  | 
| 980 560 | 
             
              // The Meat
         | 
| 981 | 
            -
              if ( | 
| 561 | 
            +
              if (!reader) {
         | 
| 982 562 | 
             
                return Qfalse;
         | 
| 563 | 
            +
              }
         | 
| 983 564 |  | 
| 984 565 | 
             
              mysql_free_result(reader);
         | 
| 985 566 | 
             
              rb_iv_set(self, "@reader", Qnil);
         | 
| 986 567 | 
             
              rb_iv_set(self, "@opened", Qfalse);
         | 
| 987 | 
            -
             | 
| 988 568 | 
             
              return Qtrue;
         | 
| 989 569 | 
             
            }
         | 
| 990 570 |  | 
| 991 571 | 
             
            // Retrieve a single row
         | 
| 992 | 
            -
             | 
| 572 | 
            +
            VALUE cReader_next(VALUE self) {
         | 
| 993 573 | 
             
              // Get the reader from the instance variable, maybe refactor this?
         | 
| 994 574 | 
             
              VALUE reader_container = rb_iv_get(self, "@reader");
         | 
| 995 | 
            -
              VALUE field_types, field_type, row;
         | 
| 996 | 
            -
             | 
| 997 | 
            -
              MYSQL_RES *reader;
         | 
| 998 | 
            -
              MYSQL_ROW result;
         | 
| 999 | 
            -
              unsigned long *lengths;
         | 
| 1000 | 
            -
             | 
| 1001 | 
            -
              unsigned int i;
         | 
| 1002 575 |  | 
| 1003 | 
            -
              if ( | 
| 576 | 
            +
              if (reader_container == Qnil) {
         | 
| 1004 577 | 
             
                return Qfalse;
         | 
| 1005 578 | 
             
              }
         | 
| 1006 579 |  | 
| 1007 | 
            -
              reader = DATA_PTR(reader_container);
         | 
| 580 | 
            +
              MYSQL_RES *reader = DATA_PTR(reader_container);
         | 
| 581 | 
            +
              MYSQL_ROW result = mysql_fetch_row(reader);
         | 
| 1008 582 |  | 
| 1009 583 | 
             
              // The Meat
         | 
| 1010 | 
            -
              field_types = rb_iv_get(self, "@field_types");
         | 
| 1011 | 
            -
              row = rb_ary_new();
         | 
| 1012 | 
            -
               | 
| 1013 | 
            -
              lengths = mysql_fetch_lengths(reader);
         | 
| 584 | 
            +
              VALUE field_types = rb_iv_get(self, "@field_types");
         | 
| 585 | 
            +
              VALUE row = rb_ary_new();
         | 
| 586 | 
            +
              unsigned long *lengths = mysql_fetch_lengths(reader);
         | 
| 1014 587 |  | 
| 1015 588 | 
             
              rb_iv_set(self, "@opened", result ? Qtrue : Qfalse);
         | 
| 1016 589 |  | 
| @@ -1021,11 +594,15 @@ static VALUE cReader_next(VALUE self) { | |
| 1021 594 | 
             
              int enc = -1;
         | 
| 1022 595 | 
             
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 1023 596 | 
             
              VALUE encoding_id = rb_iv_get(rb_iv_get(self, "@connection"), "@encoding_id");
         | 
| 597 | 
            +
             | 
| 1024 598 | 
             
              if (encoding_id != Qnil) {
         | 
| 1025 599 | 
             
                enc = FIX2INT(encoding_id);
         | 
| 1026 600 | 
             
              }
         | 
| 1027 601 | 
             
            #endif
         | 
| 1028 602 |  | 
| 603 | 
            +
              VALUE field_type;
         | 
| 604 | 
            +
              unsigned int i;
         | 
| 605 | 
            +
             | 
| 1029 606 | 
             
              for (i = 0; i < reader->field_count; i++) {
         | 
| 1030 607 | 
             
                // The field_type data could be cached in a c-array
         | 
| 1031 608 | 
             
                field_type = rb_ary_entry(field_types, i);
         | 
| @@ -1033,72 +610,17 @@ static VALUE cReader_next(VALUE self) { | |
| 1033 610 | 
             
              }
         | 
| 1034 611 |  | 
| 1035 612 | 
             
              rb_iv_set(self, "@values", row);
         | 
| 1036 | 
            -
             | 
| 1037 613 | 
             
              return Qtrue;
         | 
| 1038 614 | 
             
            }
         | 
| 1039 615 |  | 
| 1040 | 
            -
            static VALUE cReader_values(VALUE self) {
         | 
| 1041 | 
            -
              VALUE state = rb_iv_get(self, "@opened");
         | 
| 1042 | 
            -
              if ( state == Qnil || state == Qfalse ) {
         | 
| 1043 | 
            -
                rb_raise(eDataError, "Reader is not initialized");
         | 
| 1044 | 
            -
              }
         | 
| 1045 | 
            -
              return rb_iv_get(self, "@values");
         | 
| 1046 | 
            -
            }
         | 
| 1047 | 
            -
             | 
| 1048 | 
            -
            static VALUE cReader_fields(VALUE self) {
         | 
| 1049 | 
            -
              return rb_iv_get(self, "@fields");
         | 
| 1050 | 
            -
            }
         | 
| 1051 | 
            -
             | 
| 1052 | 
            -
            static VALUE cReader_field_count(VALUE self) {
         | 
| 1053 | 
            -
              return rb_iv_get(self, "@field_count");
         | 
| 1054 | 
            -
            }
         | 
| 1055 | 
            -
             | 
| 1056 616 | 
             
            void Init_do_mysql() {
         | 
| 1057 | 
            -
               | 
| 1058 | 
            -
              rb_require("rational");
         | 
| 1059 | 
            -
              rb_require("date");
         | 
| 1060 | 
            -
              rb_require("data_objects");
         | 
| 1061 | 
            -
             | 
| 1062 | 
            -
              ID_CONST_GET = rb_intern("const_get");
         | 
| 1063 | 
            -
             | 
| 1064 | 
            -
              // Get references classes needed for Date/Time parsing
         | 
| 1065 | 
            -
              rb_cDate = CONST_GET(rb_mKernel, "Date");
         | 
| 1066 | 
            -
              rb_cDateTime = CONST_GET(rb_mKernel, "DateTime");
         | 
| 1067 | 
            -
              rb_cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
         | 
| 1068 | 
            -
             | 
| 1069 | 
            -
              ID_NEW = rb_intern("new");
         | 
| 1070 | 
            -
            #ifdef RUBY_LESS_THAN_186
         | 
| 1071 | 
            -
              ID_NEW_DATE = rb_intern("new0");
         | 
| 1072 | 
            -
            #else
         | 
| 1073 | 
            -
              ID_NEW_DATE = rb_intern("new!");
         | 
| 1074 | 
            -
            #endif
         | 
| 1075 | 
            -
              ID_CONST_GET = rb_intern("const_get");
         | 
| 1076 | 
            -
              ID_RATIONAL = rb_intern("Rational");
         | 
| 1077 | 
            -
              ID_ESCAPE = rb_intern("escape_sql");
         | 
| 1078 | 
            -
              ID_STRFTIME = rb_intern("strftime");
         | 
| 1079 | 
            -
              ID_LOG = rb_intern("log");
         | 
| 1080 | 
            -
             | 
| 1081 | 
            -
              // Get references to the Extlib module
         | 
| 1082 | 
            -
              mExtlib = CONST_GET(rb_mKernel, "Extlib");
         | 
| 1083 | 
            -
              rb_cByteArray = CONST_GET(mExtlib, "ByteArray");
         | 
| 1084 | 
            -
             | 
| 1085 | 
            -
              // Get references to the DataObjects module and its classes
         | 
| 1086 | 
            -
              mDO = CONST_GET(rb_mKernel, "DataObjects");
         | 
| 1087 | 
            -
              cDO_Quoting = CONST_GET(mDO, "Quoting");
         | 
| 1088 | 
            -
              cDO_Connection = CONST_GET(mDO, "Connection");
         | 
| 1089 | 
            -
              cDO_Command = CONST_GET(mDO, "Command");
         | 
| 1090 | 
            -
              cDO_Result = CONST_GET(mDO, "Result");
         | 
| 1091 | 
            -
              cDO_Reader = CONST_GET(mDO, "Reader");
         | 
| 1092 | 
            -
              cDO_Logger = CONST_GET(mDO, "Logger");
         | 
| 1093 | 
            -
              cDO_Logger_Message = CONST_GET(cDO_Logger, "Message");
         | 
| 617 | 
            +
              common_init();
         | 
| 1094 618 |  | 
| 1095 619 | 
             
              // Top Level Module that all the classes live under
         | 
| 1096 | 
            -
              mMysql | 
| 1097 | 
            -
              eConnectionError = CONST_GET(mDO, "ConnectionError");
         | 
| 1098 | 
            -
              eDataError = CONST_GET(mDO, "DataError");
         | 
| 620 | 
            +
              mMysql    = rb_define_module_under(mDO, "Mysql");
         | 
| 1099 621 | 
             
              mEncoding = rb_define_module_under(mMysql, "Encoding");
         | 
| 1100 622 |  | 
| 1101 | 
            -
              cConnection =  | 
| 623 | 
            +
              cConnection = rb_define_class_under(mMysql, "Connection", cDO_Connection);
         | 
| 1102 624 | 
             
              rb_define_method(cConnection, "initialize", cConnection_initialize, 1);
         | 
| 1103 625 | 
             
              rb_define_method(cConnection, "using_socket?", cConnection_is_using_socket, 0);
         | 
| 1104 626 | 
             
              rb_define_method(cConnection, "ssl_cipher", cConnection_ssl_cipher, 0);
         | 
| @@ -1109,46 +631,24 @@ void Init_do_mysql() { | |
| 1109 631 | 
             
              rb_define_method(cConnection, "quote_time", cConnection_quote_time, 1);
         | 
| 1110 632 | 
             
              rb_define_method(cConnection, "quote_datetime", cConnection_quote_date_time, 1);
         | 
| 1111 633 |  | 
| 1112 | 
            -
              cCommand =  | 
| 634 | 
            +
              cCommand = rb_define_class_under(mMysql, "Command", cDO_Command);
         | 
| 1113 635 | 
             
              rb_define_method(cCommand, "set_types", cCommand_set_types, -1);
         | 
| 1114 636 | 
             
              rb_define_method(cCommand, "execute_non_query", cCommand_execute_non_query, -1);
         | 
| 1115 637 | 
             
              rb_define_method(cCommand, "execute_reader", cCommand_execute_reader, -1);
         | 
| 1116 638 |  | 
| 1117 639 | 
             
              // Non-Query result
         | 
| 1118 | 
            -
              cResult =  | 
| 640 | 
            +
              cResult = rb_define_class_under(mMysql, "Result", cDO_Result);
         | 
| 1119 641 |  | 
| 1120 642 | 
             
              // Query result
         | 
| 1121 | 
            -
              cReader =  | 
| 643 | 
            +
              cReader = rb_define_class_under(mMysql, "Reader", cDO_Reader);
         | 
| 1122 644 | 
             
              rb_define_method(cReader, "close", cReader_close, 0);
         | 
| 1123 645 | 
             
              rb_define_method(cReader, "next!", cReader_next, 0);
         | 
| 1124 646 | 
             
              rb_define_method(cReader, "values", cReader_values, 0);
         | 
| 1125 647 | 
             
              rb_define_method(cReader, "fields", cReader_fields, 0);
         | 
| 1126 648 | 
             
              rb_define_method(cReader, "field_count", cReader_field_count, 0);
         | 
| 1127 649 |  | 
| 1128 | 
            -
              rb_global_variable(&ID_NEW_DATE);
         | 
| 1129 | 
            -
              rb_global_variable(&ID_RATIONAL);
         | 
| 1130 | 
            -
              rb_global_variable(&ID_CONST_GET);
         | 
| 1131 | 
            -
              rb_global_variable(&ID_ESCAPE);
         | 
| 1132 | 
            -
              rb_global_variable(&ID_LOG);
         | 
| 1133 | 
            -
              rb_global_variable(&ID_NEW);
         | 
| 1134 | 
            -
             | 
| 1135 | 
            -
              rb_global_variable(&rb_cDate);
         | 
| 1136 | 
            -
              rb_global_variable(&rb_cDateTime);
         | 
| 1137 | 
            -
              rb_global_variable(&rb_cBigDecimal);
         | 
| 1138 | 
            -
              rb_global_variable(&rb_cByteArray);
         | 
| 1139 | 
            -
             | 
| 1140 | 
            -
              rb_global_variable(&mDO);
         | 
| 1141 | 
            -
              rb_global_variable(&cDO_Logger_Message);
         | 
| 1142 | 
            -
             | 
| 1143 650 | 
             
              rb_global_variable(&cResult);
         | 
| 1144 651 | 
             
              rb_global_variable(&cReader);
         | 
| 1145 652 |  | 
| 1146 | 
            -
               | 
| 1147 | 
            -
              rb_global_variable(&eDataError);
         | 
| 1148 | 
            -
             | 
| 1149 | 
            -
              struct errcodes *errs;
         | 
| 1150 | 
            -
             | 
| 1151 | 
            -
              for (errs = errors; errs->error_name; errs++) {
         | 
| 1152 | 
            -
                rb_const_set(mMysql, rb_intern(errs->error_name), INT2NUM(errs->error_no));
         | 
| 1153 | 
            -
              }
         | 
| 653 | 
            +
              do_define_errors(mMysql, errors);
         | 
| 1154 654 | 
             
            }
         |