mysql2 0.3.11-x86-mingw32 → 0.3.18-x86-mingw32
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.
- checksums.yaml +15 -0
- data/README.md +280 -75
- data/ext/mysql2/client.c +721 -206
- data/ext/mysql2/client.h +26 -12
- data/ext/mysql2/extconf.rb +120 -16
- data/ext/mysql2/infile.c +122 -0
- data/ext/mysql2/infile.h +1 -0
- data/ext/mysql2/mysql2_ext.h +7 -4
- data/ext/mysql2/mysql_enc_name_to_ruby.h +168 -0
- data/ext/mysql2/mysql_enc_to_ruby.h +246 -0
- data/ext/mysql2/result.c +230 -112
- data/ext/mysql2/result.h +4 -1
- data/lib/mysql2.rb +46 -3
- data/lib/mysql2/1.8/mysql2.so +0 -0
- data/lib/mysql2/1.9/mysql2.so +0 -0
- data/lib/mysql2/2.0/mysql2.so +0 -0
- data/lib/mysql2/2.1/mysql2.so +0 -0
- data/lib/mysql2/client.rb +48 -200
- data/lib/mysql2/console.rb +5 -0
- data/lib/mysql2/em.rb +22 -3
- data/lib/mysql2/error.rb +71 -6
- data/lib/mysql2/mysql2.rb +2 -0
- data/lib/mysql2/version.rb +1 -1
- data/spec/configuration.yml.example +17 -0
- data/spec/em/em_spec.rb +90 -5
- data/spec/my.cnf.example +9 -0
- data/spec/mysql2/client_spec.rb +501 -69
- data/spec/mysql2/error_spec.rb +58 -44
- data/spec/mysql2/result_spec.rb +191 -74
- data/spec/spec_helper.rb +23 -3
- data/spec/test_data +1 -0
- data/support/libmysql.def +219 -0
- data/support/mysql_enc_to_ruby.rb +82 -0
- data/support/ruby_enc_to_mysql.rb +61 -0
- data/vendor/README +654 -0
- data/vendor/libmysql.dll +0 -0
- metadata +86 -221
- data/.gitignore +0 -12
- data/.rspec +0 -3
- data/.rvmrc +0 -1
- data/.travis.yml +0 -7
- data/CHANGELOG.md +0 -244
- data/Gemfile +0 -3
- data/MIT-LICENSE +0 -20
- data/Rakefile +0 -5
- data/benchmark/active_record.rb +0 -51
- data/benchmark/active_record_threaded.rb +0 -42
- data/benchmark/allocations.rb +0 -33
- data/benchmark/escape.rb +0 -36
- data/benchmark/query_with_mysql_casting.rb +0 -80
- data/benchmark/query_without_mysql_casting.rb +0 -56
- data/benchmark/sequel.rb +0 -37
- data/benchmark/setup_db.rb +0 -119
- data/benchmark/threaded.rb +0 -44
- data/mysql2.gemspec +0 -29
- data/tasks/benchmarks.rake +0 -20
- data/tasks/compile.rake +0 -71
- data/tasks/rspec.rake +0 -16
- data/tasks/vendor_mysql.rake +0 -40
| @@ -0,0 +1,246 @@ | |
| 1 | 
            +
            const char *mysql2_mysql_enc_to_rb[] = {
         | 
| 2 | 
            +
              "Big5",
         | 
| 3 | 
            +
              "ISO-8859-2",
         | 
| 4 | 
            +
              NULL,
         | 
| 5 | 
            +
              "CP850",
         | 
| 6 | 
            +
              "ISO-8859-1",
         | 
| 7 | 
            +
              NULL,
         | 
| 8 | 
            +
              "KOI8-R",
         | 
| 9 | 
            +
              "ISO-8859-1",
         | 
| 10 | 
            +
              "ISO-8859-2",
         | 
| 11 | 
            +
              NULL,
         | 
| 12 | 
            +
              "US-ASCII",
         | 
| 13 | 
            +
              "eucJP-ms",
         | 
| 14 | 
            +
              "Shift_JIS",
         | 
| 15 | 
            +
              "Windows-1251",
         | 
| 16 | 
            +
              "ISO-8859-1",
         | 
| 17 | 
            +
              "ISO-8859-8",
         | 
| 18 | 
            +
              NULL,
         | 
| 19 | 
            +
              "TIS-620",
         | 
| 20 | 
            +
              "EUC-KR",
         | 
| 21 | 
            +
              "ISO-8859-13",
         | 
| 22 | 
            +
              "ISO-8859-2",
         | 
| 23 | 
            +
              "KOI8-R",
         | 
| 24 | 
            +
              "Windows-1251",
         | 
| 25 | 
            +
              "GB2312",
         | 
| 26 | 
            +
              "ISO-8859-7",
         | 
| 27 | 
            +
              "Windows-1250",
         | 
| 28 | 
            +
              "ISO-8859-2",
         | 
| 29 | 
            +
              "GBK",
         | 
| 30 | 
            +
              "Windows-1257",
         | 
| 31 | 
            +
              "ISO-8859-9",
         | 
| 32 | 
            +
              "ISO-8859-1",
         | 
| 33 | 
            +
              NULL,
         | 
| 34 | 
            +
              "UTF-8",
         | 
| 35 | 
            +
              "Windows-1250",
         | 
| 36 | 
            +
              "UTF-16BE",
         | 
| 37 | 
            +
              "IBM866",
         | 
| 38 | 
            +
              NULL,
         | 
| 39 | 
            +
              "macCentEuro",
         | 
| 40 | 
            +
              "macRoman",
         | 
| 41 | 
            +
              "CP852",
         | 
| 42 | 
            +
              "ISO-8859-13",
         | 
| 43 | 
            +
              "ISO-8859-13",
         | 
| 44 | 
            +
              "macCentEuro",
         | 
| 45 | 
            +
              "Windows-1250",
         | 
| 46 | 
            +
              "UTF-8",
         | 
| 47 | 
            +
              "UTF-8",
         | 
| 48 | 
            +
              "ISO-8859-1",
         | 
| 49 | 
            +
              "ISO-8859-1",
         | 
| 50 | 
            +
              "ISO-8859-1",
         | 
| 51 | 
            +
              "Windows-1251",
         | 
| 52 | 
            +
              "Windows-1251",
         | 
| 53 | 
            +
              "Windows-1251",
         | 
| 54 | 
            +
              "macRoman",
         | 
| 55 | 
            +
              "UTF-16",
         | 
| 56 | 
            +
              "UTF-16",
         | 
| 57 | 
            +
              NULL,
         | 
| 58 | 
            +
              "Windows-1256",
         | 
| 59 | 
            +
              "Windows-1257",
         | 
| 60 | 
            +
              "Windows-1257",
         | 
| 61 | 
            +
              "UTF-32",
         | 
| 62 | 
            +
              "UTF-32",
         | 
| 63 | 
            +
              NULL,
         | 
| 64 | 
            +
              "ASCII-8BIT",
         | 
| 65 | 
            +
              NULL,
         | 
| 66 | 
            +
              "US-ASCII",
         | 
| 67 | 
            +
              "Windows-1250",
         | 
| 68 | 
            +
              "Windows-1256",
         | 
| 69 | 
            +
              "IBM866",
         | 
| 70 | 
            +
              NULL,
         | 
| 71 | 
            +
              "ISO-8859-7",
         | 
| 72 | 
            +
              "ISO-8859-8",
         | 
| 73 | 
            +
              NULL,
         | 
| 74 | 
            +
              NULL,
         | 
| 75 | 
            +
              "KOI8-R",
         | 
| 76 | 
            +
              "KOI8-R",
         | 
| 77 | 
            +
              NULL,
         | 
| 78 | 
            +
              "ISO-8859-2",
         | 
| 79 | 
            +
              "ISO-8859-9",
         | 
| 80 | 
            +
              "ISO-8859-13",
         | 
| 81 | 
            +
              "CP850",
         | 
| 82 | 
            +
              "CP852",
         | 
| 83 | 
            +
              NULL,
         | 
| 84 | 
            +
              "UTF-8",
         | 
| 85 | 
            +
              "Big5",
         | 
| 86 | 
            +
              "EUC-KR",
         | 
| 87 | 
            +
              "GB2312",
         | 
| 88 | 
            +
              "GBK",
         | 
| 89 | 
            +
              "Shift_JIS",
         | 
| 90 | 
            +
              "TIS-620",
         | 
| 91 | 
            +
              "UTF-16BE",
         | 
| 92 | 
            +
              "eucJP-ms",
         | 
| 93 | 
            +
              NULL,
         | 
| 94 | 
            +
              NULL,
         | 
| 95 | 
            +
              "ISO-8859-1",
         | 
| 96 | 
            +
              "Windows-31J",
         | 
| 97 | 
            +
              "Windows-31J",
         | 
| 98 | 
            +
              "eucJP-ms",
         | 
| 99 | 
            +
              "eucJP-ms",
         | 
| 100 | 
            +
              "Windows-1250",
         | 
| 101 | 
            +
              NULL,
         | 
| 102 | 
            +
              "UTF-16",
         | 
| 103 | 
            +
              "UTF-16",
         | 
| 104 | 
            +
              "UTF-16",
         | 
| 105 | 
            +
              "UTF-16",
         | 
| 106 | 
            +
              "UTF-16",
         | 
| 107 | 
            +
              "UTF-16",
         | 
| 108 | 
            +
              "UTF-16",
         | 
| 109 | 
            +
              "UTF-16",
         | 
| 110 | 
            +
              "UTF-16",
         | 
| 111 | 
            +
              "UTF-16",
         | 
| 112 | 
            +
              "UTF-16",
         | 
| 113 | 
            +
              "UTF-16",
         | 
| 114 | 
            +
              "UTF-16",
         | 
| 115 | 
            +
              "UTF-16",
         | 
| 116 | 
            +
              "UTF-16",
         | 
| 117 | 
            +
              "UTF-16",
         | 
| 118 | 
            +
              "UTF-16",
         | 
| 119 | 
            +
              "UTF-16",
         | 
| 120 | 
            +
              "UTF-16",
         | 
| 121 | 
            +
              "UTF-16",
         | 
| 122 | 
            +
              NULL,
         | 
| 123 | 
            +
              NULL,
         | 
| 124 | 
            +
              NULL,
         | 
| 125 | 
            +
              NULL,
         | 
| 126 | 
            +
              NULL,
         | 
| 127 | 
            +
              NULL,
         | 
| 128 | 
            +
              NULL,
         | 
| 129 | 
            +
              "UTF-16BE",
         | 
| 130 | 
            +
              "UTF-16BE",
         | 
| 131 | 
            +
              "UTF-16BE",
         | 
| 132 | 
            +
              "UTF-16BE",
         | 
| 133 | 
            +
              "UTF-16BE",
         | 
| 134 | 
            +
              "UTF-16BE",
         | 
| 135 | 
            +
              "UTF-16BE",
         | 
| 136 | 
            +
              "UTF-16BE",
         | 
| 137 | 
            +
              "UTF-16BE",
         | 
| 138 | 
            +
              "UTF-16BE",
         | 
| 139 | 
            +
              "UTF-16BE",
         | 
| 140 | 
            +
              "UTF-16BE",
         | 
| 141 | 
            +
              "UTF-16BE",
         | 
| 142 | 
            +
              "UTF-16BE",
         | 
| 143 | 
            +
              "UTF-16BE",
         | 
| 144 | 
            +
              "UTF-16BE",
         | 
| 145 | 
            +
              "UTF-16BE",
         | 
| 146 | 
            +
              "UTF-16BE",
         | 
| 147 | 
            +
              "UTF-16BE",
         | 
| 148 | 
            +
              "UTF-16BE",
         | 
| 149 | 
            +
              NULL,
         | 
| 150 | 
            +
              NULL,
         | 
| 151 | 
            +
              NULL,
         | 
| 152 | 
            +
              NULL,
         | 
| 153 | 
            +
              NULL,
         | 
| 154 | 
            +
              NULL,
         | 
| 155 | 
            +
              NULL,
         | 
| 156 | 
            +
              NULL,
         | 
| 157 | 
            +
              NULL,
         | 
| 158 | 
            +
              NULL,
         | 
| 159 | 
            +
              NULL,
         | 
| 160 | 
            +
              NULL,
         | 
| 161 | 
            +
              "UTF-32",
         | 
| 162 | 
            +
              "UTF-32",
         | 
| 163 | 
            +
              "UTF-32",
         | 
| 164 | 
            +
              "UTF-32",
         | 
| 165 | 
            +
              "UTF-32",
         | 
| 166 | 
            +
              "UTF-32",
         | 
| 167 | 
            +
              "UTF-32",
         | 
| 168 | 
            +
              "UTF-32",
         | 
| 169 | 
            +
              "UTF-32",
         | 
| 170 | 
            +
              "UTF-32",
         | 
| 171 | 
            +
              "UTF-32",
         | 
| 172 | 
            +
              "UTF-32",
         | 
| 173 | 
            +
              "UTF-32",
         | 
| 174 | 
            +
              "UTF-32",
         | 
| 175 | 
            +
              "UTF-32",
         | 
| 176 | 
            +
              "UTF-32",
         | 
| 177 | 
            +
              "UTF-32",
         | 
| 178 | 
            +
              "UTF-32",
         | 
| 179 | 
            +
              "UTF-32",
         | 
| 180 | 
            +
              "UTF-32",
         | 
| 181 | 
            +
              NULL,
         | 
| 182 | 
            +
              NULL,
         | 
| 183 | 
            +
              NULL,
         | 
| 184 | 
            +
              NULL,
         | 
| 185 | 
            +
              NULL,
         | 
| 186 | 
            +
              NULL,
         | 
| 187 | 
            +
              NULL,
         | 
| 188 | 
            +
              NULL,
         | 
| 189 | 
            +
              NULL,
         | 
| 190 | 
            +
              NULL,
         | 
| 191 | 
            +
              NULL,
         | 
| 192 | 
            +
              NULL,
         | 
| 193 | 
            +
              "UTF-8",
         | 
| 194 | 
            +
              "UTF-8",
         | 
| 195 | 
            +
              "UTF-8",
         | 
| 196 | 
            +
              "UTF-8",
         | 
| 197 | 
            +
              "UTF-8",
         | 
| 198 | 
            +
              "UTF-8",
         | 
| 199 | 
            +
              "UTF-8",
         | 
| 200 | 
            +
              "UTF-8",
         | 
| 201 | 
            +
              "UTF-8",
         | 
| 202 | 
            +
              "UTF-8",
         | 
| 203 | 
            +
              "UTF-8",
         | 
| 204 | 
            +
              "UTF-8",
         | 
| 205 | 
            +
              "UTF-8",
         | 
| 206 | 
            +
              "UTF-8",
         | 
| 207 | 
            +
              "UTF-8",
         | 
| 208 | 
            +
              "UTF-8",
         | 
| 209 | 
            +
              "UTF-8",
         | 
| 210 | 
            +
              "UTF-8",
         | 
| 211 | 
            +
              "UTF-8",
         | 
| 212 | 
            +
              "UTF-8",
         | 
| 213 | 
            +
              NULL,
         | 
| 214 | 
            +
              NULL,
         | 
| 215 | 
            +
              NULL,
         | 
| 216 | 
            +
              NULL,
         | 
| 217 | 
            +
              NULL,
         | 
| 218 | 
            +
              NULL,
         | 
| 219 | 
            +
              NULL,
         | 
| 220 | 
            +
              NULL,
         | 
| 221 | 
            +
              NULL,
         | 
| 222 | 
            +
              NULL,
         | 
| 223 | 
            +
              NULL,
         | 
| 224 | 
            +
              NULL,
         | 
| 225 | 
            +
              "UTF-8",
         | 
| 226 | 
            +
              "UTF-8",
         | 
| 227 | 
            +
              "UTF-8",
         | 
| 228 | 
            +
              "UTF-8",
         | 
| 229 | 
            +
              "UTF-8",
         | 
| 230 | 
            +
              "UTF-8",
         | 
| 231 | 
            +
              "UTF-8",
         | 
| 232 | 
            +
              "UTF-8",
         | 
| 233 | 
            +
              "UTF-8",
         | 
| 234 | 
            +
              "UTF-8",
         | 
| 235 | 
            +
              "UTF-8",
         | 
| 236 | 
            +
              "UTF-8",
         | 
| 237 | 
            +
              "UTF-8",
         | 
| 238 | 
            +
              "UTF-8",
         | 
| 239 | 
            +
              "UTF-8",
         | 
| 240 | 
            +
              "UTF-8",
         | 
| 241 | 
            +
              "UTF-8",
         | 
| 242 | 
            +
              "UTF-8",
         | 
| 243 | 
            +
              "UTF-8",
         | 
| 244 | 
            +
              "UTF-8"
         | 
| 245 | 
            +
            };
         | 
| 246 | 
            +
             | 
    
        data/ext/mysql2/result.c
    CHANGED
    
    | @@ -1,6 +1,9 @@ | |
| 1 1 | 
             
            #include <mysql2_ext.h>
         | 
| 2 | 
            +
             | 
| 2 3 | 
             
            #include <stdint.h>
         | 
| 3 4 |  | 
| 5 | 
            +
            #include "mysql_enc_to_ruby.h"
         | 
| 6 | 
            +
             | 
| 4 7 | 
             
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 5 8 | 
             
            static rb_encoding *binaryEncoding;
         | 
| 6 9 | 
             
            #endif
         | 
| @@ -27,7 +30,7 @@ static rb_encoding *binaryEncoding; | |
| 27 30 | 
             
             * (0*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 0
         | 
| 28 31 | 
             
             */
         | 
| 29 32 | 
             
            #define MYSQL2_MIN_TIME 2678400ULL
         | 
| 30 | 
            -
            #elif SIZEOF_INT < SIZEOF_LONG  | 
| 33 | 
            +
            #elif SIZEOF_INT < SIZEOF_LONG /* 64bit Ruby 1.8 */
         | 
| 31 34 | 
             
            /* 0139-1-1 00:00:00 UTC
         | 
| 32 35 | 
             
             *
         | 
| 33 36 | 
             
             * (139*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 0
         | 
| @@ -51,11 +54,9 @@ static VALUE cMysql2Result; | |
| 51 54 | 
             
            static VALUE cBigDecimal, cDate, cDateTime;
         | 
| 52 55 | 
             
            static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
         | 
| 53 56 | 
             
            extern VALUE mMysql2, cMysql2Client, cMysql2Error;
         | 
| 54 | 
            -
            static  | 
| 55 | 
            -
            static ID intern_new, intern_utc, intern_local, intern_encoding_from_charset_code,
         | 
| 56 | 
            -
                      intern_localtime, intern_local_offset, intern_civil, intern_new_offset;
         | 
| 57 | 
            +
            static ID intern_new, intern_utc, intern_local, intern_localtime, intern_local_offset, intern_civil, intern_new_offset;
         | 
| 57 58 | 
             
            static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone, sym_application_timezone,
         | 
| 58 | 
            -
                      sym_local, sym_utc, sym_cast_booleans, sym_cache_rows, sym_cast;
         | 
| 59 | 
            +
                      sym_local, sym_utc, sym_cast_booleans, sym_cache_rows, sym_cast, sym_stream, sym_name;
         | 
| 59 60 | 
             
            static ID intern_merge;
         | 
| 60 61 |  | 
| 61 62 | 
             
            static void rb_mysql_result_mark(void * wrapper) {
         | 
| @@ -64,22 +65,29 @@ static void rb_mysql_result_mark(void * wrapper) { | |
| 64 65 | 
             
                rb_gc_mark(w->fields);
         | 
| 65 66 | 
             
                rb_gc_mark(w->rows);
         | 
| 66 67 | 
             
                rb_gc_mark(w->encoding);
         | 
| 68 | 
            +
                rb_gc_mark(w->client);
         | 
| 67 69 | 
             
              }
         | 
| 68 70 | 
             
            }
         | 
| 69 71 |  | 
| 70 72 | 
             
            /* this may be called manually or during GC */
         | 
| 71 73 | 
             
            static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper) {
         | 
| 72 74 | 
             
              if (wrapper && wrapper->resultFreed != 1) {
         | 
| 75 | 
            +
                /* FIXME: this may call flush_use_result, which can hit the socket */
         | 
| 73 76 | 
             
                mysql_free_result(wrapper->result);
         | 
| 74 77 | 
             
                wrapper->resultFreed = 1;
         | 
| 75 78 | 
             
              }
         | 
| 76 79 | 
             
            }
         | 
| 77 80 |  | 
| 78 81 | 
             
            /* this is called during GC */
         | 
| 79 | 
            -
            static void rb_mysql_result_free(void * | 
| 80 | 
            -
              mysql2_result_wrapper *  | 
| 81 | 
            -
               | 
| 82 | 
            -
             | 
| 82 | 
            +
            static void rb_mysql_result_free(void *ptr) {
         | 
| 83 | 
            +
              mysql2_result_wrapper * wrapper = ptr;
         | 
| 84 | 
            +
              rb_mysql_result_free_result(wrapper);
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              // If the GC gets to client first it will be nil
         | 
| 87 | 
            +
              if (wrapper->client != Qnil) {
         | 
| 88 | 
            +
                decr_mysql2_client(wrapper->client_wrapper);
         | 
| 89 | 
            +
              }
         | 
| 90 | 
            +
             | 
| 83 91 | 
             
              xfree(wrapper);
         | 
| 84 92 | 
             
            }
         | 
| 85 93 |  | 
| @@ -88,10 +96,10 @@ static void rb_mysql_result_free(void * wrapper) { | |
| 88 96 | 
             
             * reliable way for us to tell this so we'll always release the GVL
         | 
| 89 97 | 
             
             * to be safe
         | 
| 90 98 | 
             
             */
         | 
| 91 | 
            -
            static  | 
| 99 | 
            +
            static void *nogvl_fetch_row(void *ptr) {
         | 
| 92 100 | 
             
              MYSQL_RES *result = ptr;
         | 
| 93 101 |  | 
| 94 | 
            -
              return  | 
| 102 | 
            +
              return mysql_fetch_row(result);
         | 
| 95 103 | 
             
            }
         | 
| 96 104 |  | 
| 97 105 | 
             
            static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int symbolize_keys) {
         | 
| @@ -114,15 +122,14 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int | |
| 114 122 |  | 
| 115 123 | 
             
                field = mysql_fetch_field_direct(wrapper->result, idx);
         | 
| 116 124 | 
             
                if (symbolize_keys) {
         | 
| 125 | 
            +
            #ifdef HAVE_RB_INTERN3
         | 
| 126 | 
            +
                  rb_field = rb_intern3(field->name, field->name_length, rb_utf8_encoding());
         | 
| 127 | 
            +
                  rb_field = ID2SYM(rb_field);
         | 
| 128 | 
            +
            #else
         | 
| 117 129 | 
             
                  VALUE colStr;
         | 
| 118 | 
            -
                   | 
| 119 | 
            -
                  memcpy(buf, field->name, field->name_length);
         | 
| 120 | 
            -
                  buf[field->name_length] = 0;
         | 
| 121 | 
            -
                  colStr = rb_str_new2(buf);
         | 
| 122 | 
            -
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 123 | 
            -
                  rb_enc_associate(colStr, rb_utf8_encoding());
         | 
| 124 | 
            -
            #endif
         | 
| 130 | 
            +
                  colStr = rb_str_new(field->name, field->name_length);
         | 
| 125 131 | 
             
                  rb_field = ID2SYM(rb_to_id(colStr));
         | 
| 132 | 
            +
            #endif
         | 
| 126 133 | 
             
                } else {
         | 
| 127 134 | 
             
                  rb_field = rb_str_new(field->name, field->name_length);
         | 
| 128 135 | 
             
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| @@ -140,20 +147,27 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int | |
| 140 147 |  | 
| 141 148 | 
             
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| 142 149 | 
             
            static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_encoding *default_internal_enc, rb_encoding *conn_enc) {
         | 
| 143 | 
            -
               | 
| 150 | 
            +
              /* if binary flag is set, respect it's wishes */
         | 
| 144 151 | 
             
              if (field.flags & BINARY_FLAG && field.charsetnr == 63) {
         | 
| 145 152 | 
             
                rb_enc_associate(val, binaryEncoding);
         | 
| 153 | 
            +
              } else if (!field.charsetnr) {
         | 
| 154 | 
            +
                /* MySQL 4.x may not provide an encoding, binary will get the bytes through */
         | 
| 155 | 
            +
                rb_enc_associate(val, binaryEncoding);
         | 
| 146 156 | 
             
              } else {
         | 
| 147 | 
            -
                 | 
| 148 | 
            -
                 | 
| 149 | 
            -
                 | 
| 150 | 
            -
             | 
| 151 | 
            -
             | 
| 152 | 
            -
             | 
| 157 | 
            +
                /* lookup the encoding configured on this field */
         | 
| 158 | 
            +
                const char *enc_name;
         | 
| 159 | 
            +
                int enc_index;
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                enc_name = mysql2_mysql_enc_to_rb[field.charsetnr-1];
         | 
| 162 | 
            +
                if (enc_name != NULL) {
         | 
| 163 | 
            +
                  /* use the field encoding we were able to match */
         | 
| 164 | 
            +
                  enc_index = rb_enc_find_index(enc_name);
         | 
| 165 | 
            +
                  rb_enc_set_index(val, enc_index);
         | 
| 153 166 | 
             
                } else {
         | 
| 154 | 
            -
                   | 
| 167 | 
            +
                  /* otherwise fall-back to the connection's encoding */
         | 
| 155 168 | 
             
                  rb_enc_associate(val, conn_enc);
         | 
| 156 169 | 
             
                }
         | 
| 170 | 
            +
             | 
| 157 171 | 
             
                if (default_internal_enc) {
         | 
| 158 172 | 
             
                  val = rb_str_export_to_enc(val, default_internal_enc);
         | 
| 159 173 | 
             
                }
         | 
| @@ -162,12 +176,25 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e | |
| 162 176 | 
             
            }
         | 
| 163 177 | 
             
            #endif
         | 
| 164 178 |  | 
| 179 | 
            +
            /* Interpret microseconds digits left-aligned in fixed-width field.
         | 
| 180 | 
            +
             * e.g. 10.123 seconds means 10 seconds and 123000 microseconds,
         | 
| 181 | 
            +
             * because the microseconds are to the right of the decimal point.
         | 
| 182 | 
            +
             */
         | 
| 183 | 
            +
            static unsigned int msec_char_to_uint(char *msec_char, size_t len)
         | 
| 184 | 
            +
            {
         | 
| 185 | 
            +
              int i;
         | 
| 186 | 
            +
              for (i = 0; i < (len - 1); i++) {
         | 
| 187 | 
            +
                if (msec_char[i] == '\0') {
         | 
| 188 | 
            +
                  msec_char[i] = '0';
         | 
| 189 | 
            +
                }
         | 
| 190 | 
            +
              }
         | 
| 191 | 
            +
              return (unsigned int)strtoul(msec_char, NULL, 10);
         | 
| 192 | 
            +
            }
         | 
| 165 193 |  | 
| 166 | 
            -
            static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool, int cast) {
         | 
| 194 | 
            +
            static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezone, int symbolizeKeys, int asArray, int castBool, int cast, MYSQL_FIELD * fields) {
         | 
| 167 195 | 
             
              VALUE rowVal;
         | 
| 168 196 | 
             
              mysql2_result_wrapper * wrapper;
         | 
| 169 197 | 
             
              MYSQL_ROW row;
         | 
| 170 | 
            -
              MYSQL_FIELD * fields = NULL;
         | 
| 171 198 | 
             
              unsigned int i = 0;
         | 
| 172 199 | 
             
              unsigned long * fieldLengths;
         | 
| 173 200 | 
             
              void * ptr;
         | 
| @@ -183,7 +210,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo | |
| 183 210 | 
             
            #endif
         | 
| 184 211 |  | 
| 185 212 | 
             
              ptr = wrapper->result;
         | 
| 186 | 
            -
              row = (MYSQL_ROW) | 
| 213 | 
            +
              row = (MYSQL_ROW)rb_thread_call_without_gvl(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
         | 
| 187 214 | 
             
              if (row == NULL) {
         | 
| 188 215 | 
             
                return Qnil;
         | 
| 189 216 | 
             
              }
         | 
| @@ -193,7 +220,6 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo | |
| 193 220 | 
             
              } else {
         | 
| 194 221 | 
             
                rowVal = rb_hash_new();
         | 
| 195 222 | 
             
              }
         | 
| 196 | 
            -
              fields = mysql_fetch_fields(wrapper->result);
         | 
| 197 223 | 
             
              fieldLengths = mysql_fetch_lengths(wrapper->result);
         | 
| 198 224 | 
             
              if (wrapper->fields == Qnil) {
         | 
| 199 225 | 
             
                wrapper->numberOfFields = mysql_num_fields(wrapper->result);
         | 
| @@ -206,7 +232,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo | |
| 206 232 | 
             
                  VALUE val = Qnil;
         | 
| 207 233 | 
             
                  enum enum_field_types type = fields[i].type;
         | 
| 208 234 |  | 
| 209 | 
            -
                  if(!cast) {
         | 
| 235 | 
            +
                  if (!cast) {
         | 
| 210 236 | 
             
                    if (type == MYSQL_TYPE_NULL) {
         | 
| 211 237 | 
             
                      val = Qnil;
         | 
| 212 238 | 
             
                    } else {
         | 
| @@ -217,34 +243,40 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo | |
| 217 243 | 
             
                    }
         | 
| 218 244 | 
             
                  } else {
         | 
| 219 245 | 
             
                    switch(type) {
         | 
| 220 | 
            -
                    case MYSQL_TYPE_NULL:        | 
| 246 | 
            +
                    case MYSQL_TYPE_NULL:       /* NULL-type field */
         | 
| 221 247 | 
             
                      val = Qnil;
         | 
| 222 248 | 
             
                      break;
         | 
| 223 | 
            -
                    case MYSQL_TYPE_BIT:         | 
| 224 | 
            -
                       | 
| 249 | 
            +
                    case MYSQL_TYPE_BIT:        /* BIT field (MySQL 5.0.3 and up) */
         | 
| 250 | 
            +
                      if (castBool && fields[i].length == 1) {
         | 
| 251 | 
            +
                        val = *row[i] == 1 ? Qtrue : Qfalse;
         | 
| 252 | 
            +
                      }else{
         | 
| 253 | 
            +
                        val = rb_str_new(row[i], fieldLengths[i]);
         | 
| 254 | 
            +
                      }
         | 
| 225 255 | 
             
                      break;
         | 
| 226 | 
            -
                    case MYSQL_TYPE_TINY:        | 
| 256 | 
            +
                    case MYSQL_TYPE_TINY:       /* TINYINT field */
         | 
| 227 257 | 
             
                      if (castBool && fields[i].length == 1) {
         | 
| 228 | 
            -
                        val = *row[i]  | 
| 258 | 
            +
                        val = *row[i] != '0' ? Qtrue : Qfalse;
         | 
| 229 259 | 
             
                        break;
         | 
| 230 260 | 
             
                      }
         | 
| 231 | 
            -
                    case MYSQL_TYPE_SHORT:       | 
| 232 | 
            -
                    case MYSQL_TYPE_LONG:        | 
| 233 | 
            -
                    case MYSQL_TYPE_INT24:       | 
| 234 | 
            -
                    case MYSQL_TYPE_LONGLONG:    | 
| 235 | 
            -
                    case MYSQL_TYPE_YEAR:        | 
| 261 | 
            +
                    case MYSQL_TYPE_SHORT:      /* SMALLINT field */
         | 
| 262 | 
            +
                    case MYSQL_TYPE_LONG:       /* INTEGER field */
         | 
| 263 | 
            +
                    case MYSQL_TYPE_INT24:      /* MEDIUMINT field */
         | 
| 264 | 
            +
                    case MYSQL_TYPE_LONGLONG:   /* BIGINT field */
         | 
| 265 | 
            +
                    case MYSQL_TYPE_YEAR:       /* YEAR field */
         | 
| 236 266 | 
             
                      val = rb_cstr2inum(row[i], 10);
         | 
| 237 267 | 
             
                      break;
         | 
| 238 | 
            -
                    case MYSQL_TYPE_DECIMAL:     | 
| 239 | 
            -
                    case MYSQL_TYPE_NEWDECIMAL:  | 
| 240 | 
            -
                      if ( | 
| 268 | 
            +
                    case MYSQL_TYPE_DECIMAL:    /* DECIMAL or NUMERIC field */
         | 
| 269 | 
            +
                    case MYSQL_TYPE_NEWDECIMAL: /* Precision math DECIMAL or NUMERIC field (MySQL 5.0.3 and up) */
         | 
| 270 | 
            +
                      if (fields[i].decimals == 0) {
         | 
| 271 | 
            +
                        val = rb_cstr2inum(row[i], 10);
         | 
| 272 | 
            +
                      } else if (strtod(row[i], NULL) == 0.000000){
         | 
| 241 273 | 
             
                        val = rb_funcall(cBigDecimal, intern_new, 1, opt_decimal_zero);
         | 
| 242 274 | 
             
                      }else{
         | 
| 243 275 | 
             
                        val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(row[i], fieldLengths[i]));
         | 
| 244 276 | 
             
                      }
         | 
| 245 277 | 
             
                      break;
         | 
| 246 | 
            -
                    case MYSQL_TYPE_FLOAT:       | 
| 247 | 
            -
                    case MYSQL_TYPE_DOUBLE: {      | 
| 278 | 
            +
                    case MYSQL_TYPE_FLOAT:      /* FLOAT field */
         | 
| 279 | 
            +
                    case MYSQL_TYPE_DOUBLE: {     /* DOUBLE or REAL field */
         | 
| 248 280 | 
             
                      double column_to_double;
         | 
| 249 281 | 
             
                      column_to_double = strtod(row[i], NULL);
         | 
| 250 282 | 
             
                      if (column_to_double == 0.000000){
         | 
| @@ -254,54 +286,69 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo | |
| 254 286 | 
             
                      }
         | 
| 255 287 | 
             
                      break;
         | 
| 256 288 | 
             
                    }
         | 
| 257 | 
            -
                    case MYSQL_TYPE_TIME: {      | 
| 258 | 
            -
                      int  | 
| 259 | 
            -
                       | 
| 260 | 
            -
                       | 
| 289 | 
            +
                    case MYSQL_TYPE_TIME: {     /* TIME field */
         | 
| 290 | 
            +
                      int tokens;
         | 
| 291 | 
            +
                      unsigned int hour=0, min=0, sec=0, msec=0;
         | 
| 292 | 
            +
                      char msec_char[7] = {'0','0','0','0','0','0','\0'};
         | 
| 293 | 
            +
             | 
| 294 | 
            +
                      tokens = sscanf(row[i], "%2u:%2u:%2u.%6s", &hour, &min, &sec, msec_char);
         | 
| 295 | 
            +
                      if (tokens < 3) {
         | 
| 296 | 
            +
                        val = Qnil;
         | 
| 297 | 
            +
                        break;
         | 
| 298 | 
            +
                      }
         | 
| 299 | 
            +
                      msec = msec_char_to_uint(msec_char, sizeof(msec_char));
         | 
| 300 | 
            +
                      val = rb_funcall(rb_cTime, db_timezone, 7, opt_time_year, opt_time_month, opt_time_month, UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
         | 
| 261 301 | 
             
                      if (!NIL_P(app_timezone)) {
         | 
| 262 302 | 
             
                        if (app_timezone == intern_local) {
         | 
| 263 303 | 
             
                          val = rb_funcall(val, intern_localtime, 0);
         | 
| 264 | 
            -
                        } else {  | 
| 304 | 
            +
                        } else { /* utc */
         | 
| 265 305 | 
             
                          val = rb_funcall(val, intern_utc, 0);
         | 
| 266 306 | 
             
                        }
         | 
| 267 307 | 
             
                      }
         | 
| 268 308 | 
             
                      break;
         | 
| 269 309 | 
             
                    }
         | 
| 270 | 
            -
                    case MYSQL_TYPE_TIMESTAMP:   | 
| 271 | 
            -
                    case MYSQL_TYPE_DATETIME: {  | 
| 272 | 
            -
                       | 
| 310 | 
            +
                    case MYSQL_TYPE_TIMESTAMP:  /* TIMESTAMP field */
         | 
| 311 | 
            +
                    case MYSQL_TYPE_DATETIME: { /* DATETIME field */
         | 
| 312 | 
            +
                      int tokens;
         | 
| 313 | 
            +
                      unsigned int year=0, month=0, day=0, hour=0, min=0, sec=0, msec=0;
         | 
| 314 | 
            +
                      char msec_char[7] = {'0','0','0','0','0','0','\0'};
         | 
| 273 315 | 
             
                      uint64_t seconds;
         | 
| 274 316 |  | 
| 275 | 
            -
                      tokens = sscanf(row[i], "% | 
| 317 | 
            +
                      tokens = sscanf(row[i], "%4u-%2u-%2u %2u:%2u:%2u.%6s", &year, &month, &day, &hour, &min, &sec, msec_char);
         | 
| 318 | 
            +
                      if (tokens < 6) { /* msec might be empty */
         | 
| 319 | 
            +
                        val = Qnil;
         | 
| 320 | 
            +
                        break;
         | 
| 321 | 
            +
                      }
         | 
| 276 322 | 
             
                      seconds = (year*31557600ULL) + (month*2592000ULL) + (day*86400ULL) + (hour*3600ULL) + (min*60ULL) + sec;
         | 
| 277 323 |  | 
| 278 324 | 
             
                      if (seconds == 0) {
         | 
| 279 325 | 
             
                        val = Qnil;
         | 
| 280 326 | 
             
                      } else {
         | 
| 281 327 | 
             
                        if (month < 1 || day < 1) {
         | 
| 282 | 
            -
                          rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
         | 
| 328 | 
            +
                          rb_raise(cMysql2Error, "Invalid date in field '%.*s': %s", fields[i].name_length, fields[i].name, row[i]);
         | 
| 283 329 | 
             
                          val = Qnil;
         | 
| 284 330 | 
             
                        } else {
         | 
| 285 | 
            -
                          if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) {  | 
| 331 | 
            +
                          if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { /* use DateTime for larger date range, does not support microseconds */
         | 
| 286 332 | 
             
                            VALUE offset = INT2NUM(0);
         | 
| 287 333 | 
             
                            if (db_timezone == intern_local) {
         | 
| 288 334 | 
             
                              offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
         | 
| 289 335 | 
             
                            }
         | 
| 290 | 
            -
                            val = rb_funcall(cDateTime, intern_civil, 7,  | 
| 336 | 
            +
                            val = rb_funcall(cDateTime, intern_civil, 7, UINT2NUM(year), UINT2NUM(month), UINT2NUM(day), UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), offset);
         | 
| 291 337 | 
             
                            if (!NIL_P(app_timezone)) {
         | 
| 292 338 | 
             
                              if (app_timezone == intern_local) {
         | 
| 293 339 | 
             
                                offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
         | 
| 294 340 | 
             
                                val = rb_funcall(val, intern_new_offset, 1, offset);
         | 
| 295 | 
            -
                              } else {  | 
| 341 | 
            +
                              } else { /* utc */
         | 
| 296 342 | 
             
                                val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
         | 
| 297 343 | 
             
                              }
         | 
| 298 344 | 
             
                            }
         | 
| 299 345 | 
             
                          } else {
         | 
| 300 | 
            -
                             | 
| 346 | 
            +
                            msec = msec_char_to_uint(msec_char, sizeof(msec_char));
         | 
| 347 | 
            +
                            val = rb_funcall(rb_cTime, db_timezone, 7, UINT2NUM(year), UINT2NUM(month), UINT2NUM(day), UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
         | 
| 301 348 | 
             
                            if (!NIL_P(app_timezone)) {
         | 
| 302 349 | 
             
                              if (app_timezone == intern_local) {
         | 
| 303 350 | 
             
                                val = rb_funcall(val, intern_localtime, 0);
         | 
| 304 | 
            -
                              } else {  | 
| 351 | 
            +
                              } else { /* utc */
         | 
| 305 352 | 
             
                                val = rb_funcall(val, intern_utc, 0);
         | 
| 306 353 | 
             
                              }
         | 
| 307 354 | 
             
                            }
         | 
| @@ -310,18 +357,23 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo | |
| 310 357 | 
             
                      }
         | 
| 311 358 | 
             
                      break;
         | 
| 312 359 | 
             
                    }
         | 
| 313 | 
            -
                    case MYSQL_TYPE_DATE:        | 
| 314 | 
            -
                    case MYSQL_TYPE_NEWDATE: {   | 
| 315 | 
            -
                      int  | 
| 316 | 
            -
                       | 
| 360 | 
            +
                    case MYSQL_TYPE_DATE:       /* DATE field */
         | 
| 361 | 
            +
                    case MYSQL_TYPE_NEWDATE: {  /* Newer const used > 5.0 */
         | 
| 362 | 
            +
                      int tokens;
         | 
| 363 | 
            +
                      unsigned int year=0, month=0, day=0;
         | 
| 364 | 
            +
                      tokens = sscanf(row[i], "%4u-%2u-%2u", &year, &month, &day);
         | 
| 365 | 
            +
                      if (tokens < 3) {
         | 
| 366 | 
            +
                        val = Qnil;
         | 
| 367 | 
            +
                        break;
         | 
| 368 | 
            +
                      }
         | 
| 317 369 | 
             
                      if (year+month+day == 0) {
         | 
| 318 370 | 
             
                        val = Qnil;
         | 
| 319 371 | 
             
                      } else {
         | 
| 320 372 | 
             
                        if (month < 1 || day < 1) {
         | 
| 321 | 
            -
                          rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
         | 
| 373 | 
            +
                          rb_raise(cMysql2Error, "Invalid date in field '%.*s': %s", fields[i].name_length, fields[i].name, row[i]);
         | 
| 322 374 | 
             
                          val = Qnil;
         | 
| 323 375 | 
             
                        } else {
         | 
| 324 | 
            -
                          val = rb_funcall(cDate, intern_new, 3,  | 
| 376 | 
            +
                          val = rb_funcall(cDate, intern_new, 3, UINT2NUM(year), UINT2NUM(month), UINT2NUM(day));
         | 
| 325 377 | 
             
                        }
         | 
| 326 378 | 
             
                      }
         | 
| 327 379 | 
             
                      break;
         | 
| @@ -332,10 +384,10 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo | |
| 332 384 | 
             
                    case MYSQL_TYPE_BLOB:
         | 
| 333 385 | 
             
                    case MYSQL_TYPE_VAR_STRING:
         | 
| 334 386 | 
             
                    case MYSQL_TYPE_VARCHAR:
         | 
| 335 | 
            -
                    case MYSQL_TYPE_STRING:      | 
| 336 | 
            -
                    case MYSQL_TYPE_SET:         | 
| 337 | 
            -
                    case MYSQL_TYPE_ENUM:        | 
| 338 | 
            -
                    case MYSQL_TYPE_GEOMETRY:    | 
| 387 | 
            +
                    case MYSQL_TYPE_STRING:     /* CHAR or BINARY field */
         | 
| 388 | 
            +
                    case MYSQL_TYPE_SET:        /* SET field */
         | 
| 389 | 
            +
                    case MYSQL_TYPE_ENUM:       /* ENUM field */
         | 
| 390 | 
            +
                    case MYSQL_TYPE_GEOMETRY:   /* Spatial fielda */
         | 
| 339 391 | 
             
                    default:
         | 
| 340 392 | 
             
                      val = rb_str_new(row[i], fieldLengths[i]);
         | 
| 341 393 | 
             
            #ifdef HAVE_RUBY_ENCODING_H
         | 
| @@ -369,6 +421,7 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) { | |
| 369 421 | 
             
              GetMysql2Result(self, wrapper);
         | 
| 370 422 |  | 
| 371 423 | 
             
              defaults = rb_iv_get(self, "@query_options");
         | 
| 424 | 
            +
              Check_Type(defaults, T_HASH);
         | 
| 372 425 | 
             
              if (rb_hash_aref(defaults, sym_symbolize_keys) == Qtrue) {
         | 
| 373 426 | 
             
                symbolizeKeys = 1;
         | 
| 374 427 | 
             
              }
         | 
| @@ -392,11 +445,14 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) { | |
| 392 445 | 
             
              ID db_timezone, app_timezone, dbTz, appTz;
         | 
| 393 446 | 
             
              mysql2_result_wrapper * wrapper;
         | 
| 394 447 | 
             
              unsigned long i;
         | 
| 395 | 
            -
               | 
| 448 | 
            +
              const char * errstr;
         | 
| 449 | 
            +
              int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1, cast = 1, streaming = 0;
         | 
| 450 | 
            +
              MYSQL_FIELD * fields = NULL;
         | 
| 396 451 |  | 
| 397 452 | 
             
              GetMysql2Result(self, wrapper);
         | 
| 398 453 |  | 
| 399 454 | 
             
              defaults = rb_iv_get(self, "@query_options");
         | 
| 455 | 
            +
              Check_Type(defaults, T_HASH);
         | 
| 400 456 | 
             
              if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1) {
         | 
| 401 457 | 
             
                opts = rb_funcall(defaults, intern_merge, 1, opts);
         | 
| 402 458 | 
             
              } else {
         | 
| @@ -423,6 +479,14 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) { | |
| 423 479 | 
             
                cast = 0;
         | 
| 424 480 | 
             
              }
         | 
| 425 481 |  | 
| 482 | 
            +
              if (rb_hash_aref(opts, sym_stream) == Qtrue) {
         | 
| 483 | 
            +
                streaming = 1;
         | 
| 484 | 
            +
              }
         | 
| 485 | 
            +
             | 
| 486 | 
            +
              if (streaming && cacheRows) {
         | 
| 487 | 
            +
                rb_warn("cacheRows is ignored if streaming is true");
         | 
| 488 | 
            +
              }
         | 
| 489 | 
            +
             | 
| 426 490 | 
             
              dbTz = rb_hash_aref(opts, sym_database_timezone);
         | 
| 427 491 | 
             
              if (dbTz == sym_local) {
         | 
| 428 492 | 
             
                db_timezone = intern_local;
         | 
| @@ -445,48 +509,88 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) { | |
| 445 509 | 
             
              }
         | 
| 446 510 |  | 
| 447 511 | 
             
              if (wrapper->lastRowProcessed == 0) {
         | 
| 448 | 
            -
                 | 
| 449 | 
            -
             | 
| 512 | 
            +
                if (streaming) {
         | 
| 513 | 
            +
                  /* We can't get number of rows if we're streaming, */
         | 
| 514 | 
            +
                  /* until we've finished fetching all rows */
         | 
| 515 | 
            +
                  wrapper->numberOfRows = 0;
         | 
| 450 516 | 
             
                  wrapper->rows = rb_ary_new();
         | 
| 451 | 
            -
             | 
| 517 | 
            +
                } else {
         | 
| 518 | 
            +
                  wrapper->numberOfRows = mysql_num_rows(wrapper->result);
         | 
| 519 | 
            +
                  if (wrapper->numberOfRows == 0) {
         | 
| 520 | 
            +
                    wrapper->rows = rb_ary_new();
         | 
| 521 | 
            +
                    return wrapper->rows;
         | 
| 522 | 
            +
                  }
         | 
| 523 | 
            +
                  wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
         | 
| 452 524 | 
             
                }
         | 
| 453 | 
            -
                wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
         | 
| 454 525 | 
             
              }
         | 
| 455 526 |  | 
| 456 | 
            -
              if ( | 
| 457 | 
            -
                 | 
| 458 | 
            -
                // internal array. Lets hand that over to the user since it's ready to go
         | 
| 459 | 
            -
                for (i = 0; i < wrapper->numberOfRows; i++) {
         | 
| 460 | 
            -
                  rb_yield(rb_ary_entry(wrapper->rows, i));
         | 
| 461 | 
            -
                }
         | 
| 462 | 
            -
              } else {
         | 
| 463 | 
            -
                unsigned long rowsProcessed = 0;
         | 
| 464 | 
            -
                rowsProcessed = RARRAY_LEN(wrapper->rows);
         | 
| 465 | 
            -
                for (i = 0; i < wrapper->numberOfRows; i++) {
         | 
| 527 | 
            +
              if (streaming) {
         | 
| 528 | 
            +
                if (!wrapper->streamingComplete) {
         | 
| 466 529 | 
             
                  VALUE row;
         | 
| 467 | 
            -
             | 
| 468 | 
            -
             | 
| 469 | 
            -
             | 
| 470 | 
            -
             | 
| 471 | 
            -
                     | 
| 472 | 
            -
             | 
| 530 | 
            +
             | 
| 531 | 
            +
                  fields = mysql_fetch_fields(wrapper->result);
         | 
| 532 | 
            +
             | 
| 533 | 
            +
                  do {
         | 
| 534 | 
            +
                    row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast, fields);
         | 
| 535 | 
            +
             | 
| 536 | 
            +
                    if (block != Qnil && row != Qnil) {
         | 
| 537 | 
            +
                      rb_yield(row);
         | 
| 538 | 
            +
                      wrapper->lastRowProcessed++;
         | 
| 473 539 | 
             
                    }
         | 
| 474 | 
            -
             | 
| 475 | 
            -
                  }
         | 
| 540 | 
            +
                  } while(row != Qnil);
         | 
| 476 541 |  | 
| 477 | 
            -
                   | 
| 478 | 
            -
             | 
| 479 | 
            -
             | 
| 480 | 
            -
             | 
| 481 | 
            -
                  }
         | 
| 542 | 
            +
                  rb_mysql_result_free_result(wrapper);
         | 
| 543 | 
            +
             | 
| 544 | 
            +
                  wrapper->numberOfRows = wrapper->lastRowProcessed;
         | 
| 545 | 
            +
                  wrapper->streamingComplete = 1;
         | 
| 482 546 |  | 
| 483 | 
            -
                   | 
| 484 | 
            -
             | 
| 547 | 
            +
                  // Check for errors, the connection might have gone out from under us
         | 
| 548 | 
            +
                  // mysql_error returns an empty string if there is no error
         | 
| 549 | 
            +
                  errstr = mysql_error(wrapper->client_wrapper->client);
         | 
| 550 | 
            +
                  if (errstr[0]) {
         | 
| 551 | 
            +
                    rb_raise(cMysql2Error, "%s", errstr);
         | 
| 485 552 | 
             
                  }
         | 
| 553 | 
            +
                } else {
         | 
| 554 | 
            +
                  rb_raise(cMysql2Error, "You have already fetched all the rows for this query and streaming is true. (to reiterate you must requery).");
         | 
| 486 555 | 
             
                }
         | 
| 487 | 
            -
             | 
| 488 | 
            -
             | 
| 489 | 
            -
                   | 
| 556 | 
            +
              } else {
         | 
| 557 | 
            +
                if (cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
         | 
| 558 | 
            +
                  /* we've already read the entire dataset from the C result into our */
         | 
| 559 | 
            +
                  /* internal array. Lets hand that over to the user since it's ready to go */
         | 
| 560 | 
            +
                  for (i = 0; i < wrapper->numberOfRows; i++) {
         | 
| 561 | 
            +
                    rb_yield(rb_ary_entry(wrapper->rows, i));
         | 
| 562 | 
            +
                  }
         | 
| 563 | 
            +
                } else {
         | 
| 564 | 
            +
                  unsigned long rowsProcessed = 0;
         | 
| 565 | 
            +
                  rowsProcessed = RARRAY_LEN(wrapper->rows);
         | 
| 566 | 
            +
                  fields = mysql_fetch_fields(wrapper->result);
         | 
| 567 | 
            +
             | 
| 568 | 
            +
                  for (i = 0; i < wrapper->numberOfRows; i++) {
         | 
| 569 | 
            +
                    VALUE row;
         | 
| 570 | 
            +
                    if (cacheRows && i < rowsProcessed) {
         | 
| 571 | 
            +
                      row = rb_ary_entry(wrapper->rows, i);
         | 
| 572 | 
            +
                    } else {
         | 
| 573 | 
            +
                      row = rb_mysql_result_fetch_row(self, db_timezone, app_timezone, symbolizeKeys, asArray, castBool, cast, fields);
         | 
| 574 | 
            +
                      if (cacheRows) {
         | 
| 575 | 
            +
                        rb_ary_store(wrapper->rows, i, row);
         | 
| 576 | 
            +
                      }
         | 
| 577 | 
            +
                      wrapper->lastRowProcessed++;
         | 
| 578 | 
            +
                    }
         | 
| 579 | 
            +
             | 
| 580 | 
            +
                    if (row == Qnil) {
         | 
| 581 | 
            +
                      /* we don't need the mysql C dataset around anymore, peace it */
         | 
| 582 | 
            +
                      rb_mysql_result_free_result(wrapper);
         | 
| 583 | 
            +
                      return Qnil;
         | 
| 584 | 
            +
                    }
         | 
| 585 | 
            +
             | 
| 586 | 
            +
                    if (block != Qnil) {
         | 
| 587 | 
            +
                      rb_yield(row);
         | 
| 588 | 
            +
                    }
         | 
| 589 | 
            +
                  }
         | 
| 590 | 
            +
                  if (wrapper->lastRowProcessed == wrapper->numberOfRows) {
         | 
| 591 | 
            +
                    /* we don't need the mysql C dataset around anymore, peace it */
         | 
| 592 | 
            +
                    rb_mysql_result_free_result(wrapper);
         | 
| 593 | 
            +
                  }
         | 
| 490 594 | 
             
                }
         | 
| 491 595 | 
             
              }
         | 
| 492 596 |  | 
| @@ -497,12 +601,19 @@ static VALUE rb_mysql_result_count(VALUE self) { | |
| 497 601 | 
             
              mysql2_result_wrapper *wrapper;
         | 
| 498 602 |  | 
| 499 603 | 
             
              GetMysql2Result(self, wrapper);
         | 
| 500 | 
            -
             | 
| 501 | 
            -
             | 
| 604 | 
            +
              if (wrapper->resultFreed) {
         | 
| 605 | 
            +
                if (wrapper->streamingComplete){
         | 
| 606 | 
            +
                  return LONG2NUM(wrapper->numberOfRows);
         | 
| 607 | 
            +
                } else {
         | 
| 608 | 
            +
                  return LONG2NUM(RARRAY_LEN(wrapper->rows));
         | 
| 609 | 
            +
                }
         | 
| 610 | 
            +
              } else {
         | 
| 611 | 
            +
                return INT2FIX(mysql_num_rows(wrapper->result));
         | 
| 612 | 
            +
              }
         | 
| 502 613 | 
             
            }
         | 
| 503 614 |  | 
| 504 615 | 
             
            /* Mysql2::Result */
         | 
| 505 | 
            -
            VALUE rb_mysql_result_to_obj(MYSQL_RES * | 
| 616 | 
            +
            VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r) {
         | 
| 506 617 | 
             
              VALUE obj;
         | 
| 507 618 | 
             
              mysql2_result_wrapper * wrapper;
         | 
| 508 619 | 
             
              obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
         | 
| @@ -513,8 +624,16 @@ VALUE rb_mysql_result_to_obj(MYSQL_RES * r) { | |
| 513 624 | 
             
              wrapper->result = r;
         | 
| 514 625 | 
             
              wrapper->fields = Qnil;
         | 
| 515 626 | 
             
              wrapper->rows = Qnil;
         | 
| 516 | 
            -
              wrapper->encoding =  | 
| 627 | 
            +
              wrapper->encoding = encoding;
         | 
| 628 | 
            +
              wrapper->streamingComplete = 0;
         | 
| 629 | 
            +
              wrapper->client = client;
         | 
| 630 | 
            +
              wrapper->client_wrapper = DATA_PTR(client);
         | 
| 631 | 
            +
              wrapper->client_wrapper->refcount++;
         | 
| 632 | 
            +
             | 
| 517 633 | 
             
              rb_obj_call_init(obj, 0, NULL);
         | 
| 634 | 
            +
             | 
| 635 | 
            +
              rb_iv_set(obj, "@query_options", options);
         | 
| 636 | 
            +
             | 
| 518 637 | 
             
              return obj;
         | 
| 519 638 | 
             
            }
         | 
| 520 639 |  | 
| @@ -529,9 +648,6 @@ void init_mysql2_result() { | |
| 529 648 | 
             
              rb_define_method(cMysql2Result, "count", rb_mysql_result_count, 0);
         | 
| 530 649 | 
             
              rb_define_alias(cMysql2Result, "size", "count");
         | 
| 531 650 |  | 
| 532 | 
            -
              intern_encoding_from_charset = rb_intern("encoding_from_charset");
         | 
| 533 | 
            -
              intern_encoding_from_charset_code = rb_intern("encoding_from_charset_code");
         | 
| 534 | 
            -
             | 
| 535 651 | 
             
              intern_new          = rb_intern("new");
         | 
| 536 652 | 
             
              intern_utc          = rb_intern("utc");
         | 
| 537 653 | 
             
              intern_local        = rb_intern("local");
         | 
| @@ -551,9 +667,11 @@ void init_mysql2_result() { | |
| 551 667 | 
             
              sym_application_timezone  = ID2SYM(rb_intern("application_timezone"));
         | 
| 552 668 | 
             
              sym_cache_rows     = ID2SYM(rb_intern("cache_rows"));
         | 
| 553 669 | 
             
              sym_cast           = ID2SYM(rb_intern("cast"));
         | 
| 670 | 
            +
              sym_stream         = ID2SYM(rb_intern("stream"));
         | 
| 671 | 
            +
              sym_name           = ID2SYM(rb_intern("name"));
         | 
| 554 672 |  | 
| 555 673 | 
             
              opt_decimal_zero = rb_str_new2("0.0");
         | 
| 556 | 
            -
              rb_global_variable(&opt_decimal_zero);  | 
| 674 | 
            +
              rb_global_variable(&opt_decimal_zero); /*never GC */
         | 
| 557 675 | 
             
              opt_float_zero = rb_float_new((double)0);
         | 
| 558 676 | 
             
              rb_global_variable(&opt_float_zero);
         | 
| 559 677 | 
             
              opt_time_year = INT2NUM(2000);
         |