sequel_pg 1.9.0 → 1.10.0
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 +4 -4
- data/CHANGELOG +20 -0
- data/ext/sequel_pg/extconf.rb +1 -0
- data/ext/sequel_pg/sequel_pg.c +625 -194
- metadata +5 -5
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d5e59a1152aaf6b21d44b1d57ce4653b6248a61db684a443bcdbbb86fb7c7ff8
         | 
| 4 | 
            +
              data.tar.gz: 5f3392deba2a7286b6fa24a8c3b93ea8ee362f027c6df75a55574910b62a4c7c
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 04d3ac1ba009d05ba2dd46d32865926a79a3cae63ef3f29a9d26d5874409fedfc54e6855a0a9ea9e7dd4dd9ef5e8603bda134368e040d9e3858f00b063ca8363
         | 
| 7 | 
            +
              data.tar.gz: 0d147bca275b89d70255430fdadf4c7afc0a83a5f48414a656c1b583297ac05dea61b0d03d43a78b6bcff31f27adc8d62462e98de4228348171131f4e71144be
         | 
    
        data/CHANGELOG
    CHANGED
    
    | @@ -1,3 +1,23 @@ | |
| 1 | 
            +
            === 1.10.0 (2018-06-25)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            * Add native inet/cidr parsers (jeremyevans)
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            * Don't leak memory if unable to create a Sequel::SQL::Blob string when parsing bytea (jeremyevans)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            * Improve performance of bytea parsing (jeremyevans)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            * Drop Sequel <4.38.0 support (jeremyevans)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            * Respect Sequel.application_timezone setting when parsing values for time and timetz columns (jeremyevans)
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            * Respect Sequel::SQLTime.date setting when parsing values for time and timetz columns (jeremyevans)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            * Improve performance of time parsing (jeremyevans)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            * Improve performance of date parsing (jeremyevans)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            * Improve performance of timestamp parsing by borrowing and optimizing ruby-pg's parser (jeremyevans)
         | 
| 20 | 
            +
             | 
| 1 21 | 
             
            === 1.9.0 (2018-06-06)
         | 
| 2 22 |  | 
| 3 23 | 
             
            * Return arrays of common data types as PGArray instances automatically with much improved performance (jeremyevans)
         | 
    
        data/ext/sequel_pg/extconf.rb
    CHANGED
    
    | @@ -6,6 +6,7 @@ dir_config('pg', ENV["POSTGRES_INCLUDE"] || (IO.popen("pg_config --includedir"). | |
| 6 6 |  | 
| 7 7 | 
             
            if (have_library('pq') || have_library('libpq') || have_library('ms/libpq')) && have_header('libpq-fe.h')
         | 
| 8 8 | 
             
              have_func 'PQsetSingleRowMode'
         | 
| 9 | 
            +
              have_func 'timegm'
         | 
| 9 10 | 
             
              create_makefile("sequel_pg")
         | 
| 10 11 | 
             
            else
         | 
| 11 12 | 
             
              puts 'Could not find PostgreSQL build environment (libraries & headers): Makefile not created'
         | 
    
        data/ext/sequel_pg/sequel_pg.c
    CHANGED
    
    | @@ -1,11 +1,18 @@ | |
| 1 | 
            -
            #define SEQUEL_PG_VERSION_INTEGER  | 
| 1 | 
            +
            #define SEQUEL_PG_VERSION_INTEGER 11000
         | 
| 2 2 |  | 
| 3 3 | 
             
            #include <string.h>
         | 
| 4 4 | 
             
            #include <stdio.h>
         | 
| 5 5 | 
             
            #include <math.h>
         | 
| 6 6 | 
             
            #include <libpq-fe.h>
         | 
| 7 7 | 
             
            #include <ruby.h>
         | 
| 8 | 
            +
            #include <ctype.h>
         | 
| 9 | 
            +
            #include <sys/types.h>
         | 
| 10 | 
            +
            #include <time.h>
         | 
| 11 | 
            +
            #include <arpa/inet.h>
         | 
| 12 | 
            +
            #include <sys/socket.h>
         | 
| 13 | 
            +
            #include <string.h>
         | 
| 8 14 |  | 
| 15 | 
            +
            #include <ruby/version.h>
         | 
| 9 16 | 
             
            #include <ruby/encoding.h>
         | 
| 10 17 |  | 
| 11 18 | 
             
            #ifndef SPG_MAX_FIELDS
         | 
| @@ -16,11 +23,36 @@ | |
| 16 23 |  | 
| 17 24 | 
             
            #define SPG_DT_ADD_USEC if (usec != 0) { dt = rb_funcall(dt, spg_id_op_plus, 1, rb_Rational2(INT2NUM(usec), spg_usec_per_day)); }
         | 
| 18 25 |  | 
| 19 | 
            -
            # | 
| 20 | 
            -
            #define  | 
| 21 | 
            -
            # | 
| 22 | 
            -
             | 
| 23 | 
            -
            #define  | 
| 26 | 
            +
            #ifndef RARRAY_AREF
         | 
| 27 | 
            +
            #define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
         | 
| 28 | 
            +
            #endif
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            #define ntohll(c) ((uint64_t)( \
         | 
| 31 | 
            +
                (((uint64_t)(*((unsigned char*)(c)+0)))<<56LL) | \
         | 
| 32 | 
            +
                (((uint64_t)(*((unsigned char*)(c)+1)))<<48LL) | \
         | 
| 33 | 
            +
                (((uint64_t)(*((unsigned char*)(c)+2)))<<40LL) | \
         | 
| 34 | 
            +
                (((uint64_t)(*((unsigned char*)(c)+3)))<<32LL) | \
         | 
| 35 | 
            +
                (((uint64_t)(*((unsigned char*)(c)+4)))<<24LL) | \
         | 
| 36 | 
            +
                (((uint64_t)(*((unsigned char*)(c)+5)))<<16LL) | \
         | 
| 37 | 
            +
                (((uint64_t)(*((unsigned char*)(c)+6)))<< 8LL) | \
         | 
| 38 | 
            +
                (((uint64_t)(*((unsigned char*)(c)+7)))      ) \
         | 
| 39 | 
            +
              ))
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            #define SPG_DB_LOCAL       (1)
         | 
| 42 | 
            +
            #define SPG_DB_UTC         (1<<1)
         | 
| 43 | 
            +
            #define SPG_DB_CUSTOM      (1<<2)
         | 
| 44 | 
            +
            #define SPG_APP_LOCAL      (1<<3)
         | 
| 45 | 
            +
            #define SPG_APP_UTC        (1<<4)
         | 
| 46 | 
            +
            #define SPG_APP_CUSTOM     (1<<5)
         | 
| 47 | 
            +
            #define SPG_TZ_INITIALIZED (1<<6)
         | 
| 48 | 
            +
            #define SPG_USE_TIME       (1<<7)
         | 
| 49 | 
            +
            #define SPG_HAS_TIMEZONE   (1<<8)
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            #define SPG_YEAR_SHIFT  16
         | 
| 52 | 
            +
            #define SPG_MONTH_SHIFT 8
         | 
| 53 | 
            +
            #define SPG_MONTH_MASK  0x0000ffff
         | 
| 54 | 
            +
            #define SPG_DAY_MASK    0x0000001f
         | 
| 55 | 
            +
            #define SPG_TIME_UTC    32
         | 
| 24 56 |  | 
| 25 57 | 
             
            #define SPG_YIELD_NORMAL 0
         | 
| 26 58 | 
             
            #define SPG_YIELD_COLUMN 1
         | 
| @@ -37,17 +69,24 @@ | |
| 37 69 | 
             
            #define SPG_YIELD_KMV_HASH_GROUPS 12
         | 
| 38 70 | 
             
            #define SPG_YIELD_MKMV_HASH_GROUPS 13
         | 
| 39 71 |  | 
| 40 | 
            -
            /* External functions defined by ruby-pg  | 
| 72 | 
            +
            /* External functions defined by ruby-pg */
         | 
| 41 73 | 
             
            PGconn* pg_get_pgconn(VALUE);
         | 
| 42 74 | 
             
            PGresult* pgresult_get(VALUE);
         | 
| 43 75 |  | 
| 76 | 
            +
            static int spg_use_ipaddr_alloc;
         | 
| 77 | 
            +
             | 
| 44 78 | 
             
            static VALUE spg_Sequel;
         | 
| 45 79 | 
             
            static VALUE spg_PGArray;
         | 
| 46 80 | 
             
            static VALUE spg_Blob;
         | 
| 81 | 
            +
            static VALUE spg_Blob_instance;
         | 
| 47 82 | 
             
            static VALUE spg_Kernel;
         | 
| 48 83 | 
             
            static VALUE spg_Date;
         | 
| 84 | 
            +
            static VALUE spg_DateTime;
         | 
| 49 85 | 
             
            static VALUE spg_SQLTime;
         | 
| 50 86 | 
             
            static VALUE spg_PGError;
         | 
| 87 | 
            +
            static VALUE spg_IPAddr;
         | 
| 88 | 
            +
            static VALUE spg_vmasks4;
         | 
| 89 | 
            +
            static VALUE spg_vmasks6;
         | 
| 51 90 |  | 
| 52 91 | 
             
            static VALUE spg_sym_utc;
         | 
| 53 92 | 
             
            static VALUE spg_sym_local;
         | 
| @@ -86,6 +125,8 @@ static VALUE spg_sym_cid; | |
| 86 125 | 
             
            static VALUE spg_sym_name;
         | 
| 87 126 | 
             
            static VALUE spg_sym_tid;
         | 
| 88 127 | 
             
            static VALUE spg_sym_int2vector;
         | 
| 128 | 
            +
            static VALUE spg_sym_inet;
         | 
| 129 | 
            +
            static VALUE spg_sym_cidr;
         | 
| 89 130 |  | 
| 90 131 | 
             
            static VALUE spg_nan;
         | 
| 91 132 | 
             
            static VALUE spg_pos_inf;
         | 
| @@ -94,6 +135,7 @@ static VALUE spg_usec_per_day; | |
| 94 135 |  | 
| 95 136 | 
             
            static ID spg_id_BigDecimal;
         | 
| 96 137 | 
             
            static ID spg_id_new;
         | 
| 138 | 
            +
            static ID spg_id_date;
         | 
| 97 139 | 
             
            static ID spg_id_local;
         | 
| 98 140 | 
             
            static ID spg_id_year;
         | 
| 99 141 | 
             
            static ID spg_id_month;
         | 
| @@ -123,12 +165,23 @@ static ID spg_id_columns; | |
| 123 165 | 
             
            static ID spg_id_encoding;
         | 
| 124 166 | 
             
            static ID spg_id_values;
         | 
| 125 167 |  | 
| 168 | 
            +
            static ID spg_id_lshift;
         | 
| 169 | 
            +
            static ID spg_id_mask;
         | 
| 170 | 
            +
            static ID spg_id_family;
         | 
| 171 | 
            +
            static ID spg_id_addr;
         | 
| 172 | 
            +
            static ID spg_id_mask_addr;
         | 
| 173 | 
            +
             | 
| 126 174 | 
             
            #if HAVE_PQSETSINGLEROWMODE
         | 
| 127 175 | 
             
            static ID spg_id_get_result;
         | 
| 128 176 | 
             
            static ID spg_id_clear;
         | 
| 129 177 | 
             
            static ID spg_id_check;
         | 
| 130 178 | 
             
            #endif
         | 
| 131 179 |  | 
| 180 | 
            +
            struct spg_blob_initialization {
         | 
| 181 | 
            +
              char *blob_string;
         | 
| 182 | 
            +
              size_t length;
         | 
| 183 | 
            +
            };
         | 
| 184 | 
            +
             | 
| 132 185 | 
             
            static int enc_get_index(VALUE val) {
         | 
| 133 186 | 
             
              int i = ENCODING_GET_INLINED(val);
         | 
| 134 187 | 
             
              if (i == ENCODING_INLINE_MAX) {
         | 
| @@ -138,68 +191,68 @@ static int enc_get_index(VALUE val) { | |
| 138 191 | 
             
            }
         | 
| 139 192 |  | 
| 140 193 | 
             
            #define PG_ENCODING_SET_NOCHECK(obj,i) \
         | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 194 | 
            +
              do { \
         | 
| 195 | 
            +
                if ((i) < ENCODING_INLINE_MAX) \
         | 
| 196 | 
            +
                  ENCODING_SET_INLINED((obj), (i)); \
         | 
| 197 | 
            +
                else \
         | 
| 198 | 
            +
                  rb_enc_set_index((obj), (i)); \
         | 
| 199 | 
            +
              } while(0)
         | 
| 147 200 |  | 
| 148 201 | 
             
            static VALUE
         | 
| 149 202 | 
             
            pg_text_dec_integer(char *val, int len)
         | 
| 150 203 | 
             
            {
         | 
| 151 | 
            -
             | 
| 152 | 
            -
             | 
| 153 | 
            -
             | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 185 | 
            -
             | 
| 186 | 
            -
             | 
| 187 | 
            -
             | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 | 
            -
             | 
| 193 | 
            -
             | 
| 194 | 
            -
             | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 198 | 
            -
             | 
| 199 | 
            -
             | 
| 200 | 
            -
             | 
| 201 | 
            -
             | 
| 202 | 
            -
             | 
| 204 | 
            +
              long i;
         | 
| 205 | 
            +
              int max_len;
         | 
| 206 | 
            +
             | 
| 207 | 
            +
              if( sizeof(i) >= 8 && FIXNUM_MAX >= 1000000000000000000LL ){
         | 
| 208 | 
            +
                /* 64 bit system can safely handle all numbers up to 18 digits as Fixnum */
         | 
| 209 | 
            +
                max_len = 18;
         | 
| 210 | 
            +
              } else if( sizeof(i) >= 4 && FIXNUM_MAX >= 1000000000LL ){
         | 
| 211 | 
            +
                /* 32 bit system can safely handle all numbers up to 9 digits as Fixnum */
         | 
| 212 | 
            +
                max_len = 9;
         | 
| 213 | 
            +
              } else {
         | 
| 214 | 
            +
                /* unknown -> don't use fast path for int conversion */
         | 
| 215 | 
            +
                max_len = 0;
         | 
| 216 | 
            +
              }
         | 
| 217 | 
            +
             | 
| 218 | 
            +
              if( len <= max_len ){
         | 
| 219 | 
            +
                /* rb_cstr2inum() seems to be slow, so we do the int conversion by hand.
         | 
| 220 | 
            +
                 * This proved to be 40% faster by the following benchmark:
         | 
| 221 | 
            +
                 *
         | 
| 222 | 
            +
                 *   conn.type_mapping_for_results = PG::BasicTypeMapForResults.new conn
         | 
| 223 | 
            +
                 *   Benchmark.measure do
         | 
| 224 | 
            +
                 *     conn.exec("select generate_series(1,1000000)").values }
         | 
| 225 | 
            +
                 *   end
         | 
| 226 | 
            +
                 */
         | 
| 227 | 
            +
                char *val_pos = val;
         | 
| 228 | 
            +
                char digit = *val_pos;
         | 
| 229 | 
            +
                int neg;
         | 
| 230 | 
            +
                int error = 0;
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                if( digit=='-' ){
         | 
| 233 | 
            +
                  neg = 1;
         | 
| 234 | 
            +
                  i = 0;
         | 
| 235 | 
            +
                }else if( digit>='0' && digit<='9' ){
         | 
| 236 | 
            +
                  neg = 0;
         | 
| 237 | 
            +
                  i = digit - '0';
         | 
| 238 | 
            +
                } else {
         | 
| 239 | 
            +
                  error = 1;
         | 
| 240 | 
            +
                }
         | 
| 241 | 
            +
             | 
| 242 | 
            +
                while (!error && (digit=*++val_pos)) {
         | 
| 243 | 
            +
                  if( digit>='0' && digit<='9' ){
         | 
| 244 | 
            +
                    i = i * 10 + (digit - '0');
         | 
| 245 | 
            +
                  } else {
         | 
| 246 | 
            +
                    error = 1;
         | 
| 247 | 
            +
                  }
         | 
| 248 | 
            +
                }
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                if( !error ){
         | 
| 251 | 
            +
                  return LONG2FIX(neg ? -i : i);
         | 
| 252 | 
            +
                }
         | 
| 253 | 
            +
              }
         | 
| 254 | 
            +
              /* Fallback to ruby method if number too big or unrecognized. */
         | 
| 255 | 
            +
              return rb_cstr2inum(val, 10);
         | 
| 203 256 | 
             
            }
         | 
| 204 257 |  | 
| 205 258 | 
             
            static VALUE spg__array_col_value(char *v, size_t length, VALUE converter, int enc_index, int oid, VALUE db);
         | 
| @@ -349,43 +402,108 @@ static VALUE parse_pg_array(VALUE self, VALUE pg_array_string, VALUE converter) | |
| 349 402 | 
             
                Qnil);
         | 
| 350 403 | 
             
            }
         | 
| 351 404 |  | 
| 352 | 
            -
            static VALUE  | 
| 353 | 
            -
               | 
| 354 | 
            -
               | 
| 355 | 
            -
             | 
| 405 | 
            +
            static VALUE spg_timestamp_error(const char *s, VALUE self, const char *error_msg) {
         | 
| 406 | 
            +
              self = rb_funcall(self, spg_id_db, 0);
         | 
| 407 | 
            +
              if(RTEST(rb_funcall(self, spg_id_convert_infinite_timestamps, 0))) {
         | 
| 408 | 
            +
                if((strcmp(s, "infinity") == 0) || (strcmp(s, "-infinity") == 0)) {
         | 
| 409 | 
            +
                  return rb_funcall(self, spg_id_infinite_timestamp_value, 1, rb_tainted_str_new2(s));
         | 
| 410 | 
            +
                }
         | 
| 411 | 
            +
              }
         | 
| 412 | 
            +
              rb_raise(rb_eArgError, "%s", error_msg);
         | 
| 413 | 
            +
            }
         | 
| 414 | 
            +
             | 
| 415 | 
            +
            static inline int char_to_digit(char c)
         | 
| 416 | 
            +
            {
         | 
| 417 | 
            +
              return c - '0';
         | 
| 418 | 
            +
            }
         | 
| 419 | 
            +
             | 
| 420 | 
            +
            static int str4_to_int(const char *str)
         | 
| 421 | 
            +
            {
         | 
| 422 | 
            +
              return char_to_digit(str[0]) * 1000
         | 
| 423 | 
            +
                  + char_to_digit(str[1]) * 100
         | 
| 424 | 
            +
                  + char_to_digit(str[2]) * 10
         | 
| 425 | 
            +
                  + char_to_digit(str[3]);
         | 
| 426 | 
            +
            }
         | 
| 427 | 
            +
             | 
| 428 | 
            +
            static int str2_to_int(const char *str)
         | 
| 429 | 
            +
            {
         | 
| 430 | 
            +
              return char_to_digit(str[0]) * 10
         | 
| 431 | 
            +
                  + char_to_digit(str[1]);
         | 
| 432 | 
            +
            }
         | 
| 433 | 
            +
             | 
| 434 | 
            +
            static VALUE spg_time(const char *p, size_t length, int current) {
         | 
| 435 | 
            +
              int hour, minute, second, i;
         | 
| 356 436 | 
             
              int usec = 0;
         | 
| 437 | 
            +
              ID meth = spg_id_local;
         | 
| 438 | 
            +
             | 
| 439 | 
            +
              if (length < 8) {
         | 
| 440 | 
            +
                rb_raise(rb_eArgError, "unexpected time format, too short");
         | 
| 441 | 
            +
              }
         | 
| 442 | 
            +
             | 
| 443 | 
            +
              if (p[2] == ':' && p[5] == ':') {
         | 
| 444 | 
            +
                hour = str2_to_int(p);
         | 
| 445 | 
            +
                minute = str2_to_int(p+3);
         | 
| 446 | 
            +
                second = str2_to_int(p+6);
         | 
| 447 | 
            +
                p += 8;
         | 
| 357 448 |  | 
| 358 | 
            -
             | 
| 359 | 
            -
             | 
| 360 | 
            -
             | 
| 361 | 
            -
                   | 
| 362 | 
            -
             | 
| 449 | 
            +
                if (length >= 10 && p[0] == '.') {
         | 
| 450 | 
            +
                  static const int coef[6] = { 100000, 10000, 1000, 100, 10, 1 };
         | 
| 451 | 
            +
             | 
| 452 | 
            +
                  p++;
         | 
| 453 | 
            +
                  for (i = 0; i < 6 && isdigit(*p); i++) {
         | 
| 454 | 
            +
                    usec += coef[i] * char_to_digit(*p++);
         | 
| 363 455 | 
             
                  }
         | 
| 364 456 | 
             
                }
         | 
| 365 | 
            -
             | 
| 366 | 
            -
                usec *= (int) pow(10, (6 - strlen(subsec)));
         | 
| 367 | 
            -
              } else if(tokens < 3) {
         | 
| 457 | 
            +
              } else {
         | 
| 368 458 | 
             
                rb_raise(rb_eArgError, "unexpected time format");
         | 
| 369 459 | 
             
              }
         | 
| 370 460 |  | 
| 371 | 
            -
               | 
| 372 | 
            -
             | 
| 461 | 
            +
              if (current & SPG_TIME_UTC) {
         | 
| 462 | 
            +
                meth = spg_id_utc;
         | 
| 463 | 
            +
              }
         | 
| 464 | 
            +
              return rb_funcall(spg_SQLTime, meth, 7,
         | 
| 465 | 
            +
                INT2NUM(current >> SPG_YEAR_SHIFT),
         | 
| 466 | 
            +
                INT2NUM((current & SPG_MONTH_MASK) >> SPG_MONTH_SHIFT),
         | 
| 467 | 
            +
                INT2NUM(current & SPG_DAY_MASK),
         | 
| 468 | 
            +
                INT2NUM(hour),
         | 
| 469 | 
            +
                INT2NUM(minute),
         | 
| 470 | 
            +
                INT2NUM(second),
         | 
| 471 | 
            +
                INT2NUM(usec));
         | 
| 373 472 | 
             
            }
         | 
| 374 473 |  | 
| 375 | 
            -
             | 
| 376 | 
            -
             | 
| 377 | 
            -
               | 
| 378 | 
            -
             | 
| 379 | 
            -
             | 
| 380 | 
            -
             | 
| 474 | 
            +
            /* Caller should check length is at least 4 */
         | 
| 475 | 
            +
            static int parse_year(const char **str, size_t *length) {
         | 
| 476 | 
            +
              int year, i;
         | 
| 477 | 
            +
              size_t remaining = *length;
         | 
| 478 | 
            +
              const char * p = *str;
         | 
| 479 | 
            +
             | 
| 480 | 
            +
              year = str4_to_int(p);
         | 
| 481 | 
            +
              p += 4;
         | 
| 482 | 
            +
              remaining -= 4;
         | 
| 483 | 
            +
             | 
| 484 | 
            +
              for(i = 0; isdigit(*p) && i < 3; i++, p++, remaining--) {
         | 
| 485 | 
            +
                year = 10 * year + char_to_digit(*p);
         | 
| 381 486 | 
             
              }
         | 
| 382 | 
            -
             | 
| 487 | 
            +
             | 
| 488 | 
            +
              *str = p;
         | 
| 489 | 
            +
              *length = remaining;
         | 
| 490 | 
            +
              return year;
         | 
| 383 491 | 
             
            }
         | 
| 384 492 |  | 
| 385 | 
            -
            static VALUE spg_date(const char *s, VALUE self) {
         | 
| 493 | 
            +
            static VALUE spg_date(const char *s, VALUE self, size_t length) {
         | 
| 386 494 | 
             
              int year, month, day;
         | 
| 495 | 
            +
              const char *p = s;
         | 
| 387 496 |  | 
| 388 | 
            -
              if | 
| 497 | 
            +
              if (length < 10) {
         | 
| 498 | 
            +
                return spg_timestamp_error(s, self, "unexpected date format, too short");
         | 
| 499 | 
            +
              }
         | 
| 500 | 
            +
             | 
| 501 | 
            +
              year = parse_year(&p, &length);
         | 
| 502 | 
            +
             | 
| 503 | 
            +
              if (length >= 5 && p[0] == '-' && p[3] == '-') {
         | 
| 504 | 
            +
                month = str2_to_int(p+1);
         | 
| 505 | 
            +
                day = str2_to_int(p+4);
         | 
| 506 | 
            +
              } else {
         | 
| 389 507 | 
             
                return spg_timestamp_error(s, self, "unexpected date format");
         | 
| 390 508 | 
             
              }
         | 
| 391 509 |  | 
| @@ -397,85 +515,148 @@ static VALUE spg_date(const char *s, VALUE self) { | |
| 397 515 | 
             
              return rb_funcall(spg_Date, spg_id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
         | 
| 398 516 | 
             
            }
         | 
| 399 517 |  | 
| 400 | 
            -
            static VALUE spg_timestamp(const char *s, VALUE self) {
         | 
| 401 | 
            -
              VALUE  | 
| 402 | 
            -
              int  | 
| 403 | 
            -
              int year, month, day, hour, min, sec, usec, tokens, utc_offset, len;
         | 
| 404 | 
            -
              int usec_start, usec_stop;
         | 
| 518 | 
            +
            static VALUE spg_timestamp(const char *s, VALUE self, size_t length, int tz) {
         | 
| 519 | 
            +
              VALUE dt;
         | 
| 520 | 
            +
              int year, month, day, hour, min, sec, utc_offset;
         | 
| 405 521 | 
             
              char offset_sign = 0;
         | 
| 406 | 
            -
              int offset_hour = 0;
         | 
| 407 | 
            -
              int offset_minute = 0;
         | 
| 408 522 | 
             
              int offset_seconds = 0;
         | 
| 409 | 
            -
               | 
| 523 | 
            +
              int usec = 0;
         | 
| 524 | 
            +
              int i;
         | 
| 525 | 
            +
              const char *p = s;
         | 
| 526 | 
            +
              size_t remaining = length;
         | 
| 410 527 |  | 
| 411 | 
            -
               | 
| 412 | 
            -
             | 
| 413 | 
            -
              if (rtz != Qnil) {
         | 
| 414 | 
            -
                if (rtz == spg_sym_local) {
         | 
| 415 | 
            -
                  tz += SPG_DB_LOCAL;
         | 
| 416 | 
            -
                } else if (rtz == spg_sym_utc) {
         | 
| 417 | 
            -
                  tz += SPG_DB_UTC;
         | 
| 418 | 
            -
                } else {
         | 
| 419 | 
            -
                  return rb_funcall(db, spg_id_to_application_timestamp, 1, rb_str_new2(s)); 
         | 
| 420 | 
            -
                }
         | 
| 528 | 
            +
              if (tz & SPG_DB_CUSTOM || tz & SPG_APP_CUSTOM) {
         | 
| 529 | 
            +
                return rb_funcall(rb_funcall(self, spg_id_db, 0), spg_id_to_application_timestamp, 1, rb_str_new2(s)); 
         | 
| 421 530 | 
             
              }
         | 
| 422 531 |  | 
| 423 | 
            -
               | 
| 424 | 
            -
             | 
| 425 | 
            -
                if (rtz == spg_sym_local) {
         | 
| 426 | 
            -
                  tz += SPG_APP_LOCAL;
         | 
| 427 | 
            -
                } else if (rtz == spg_sym_utc) {
         | 
| 428 | 
            -
                  tz += SPG_APP_UTC;
         | 
| 429 | 
            -
                } else {
         | 
| 430 | 
            -
                  return rb_funcall(db, spg_id_to_application_timestamp, 1, rb_str_new2(s)); 
         | 
| 431 | 
            -
                }
         | 
| 532 | 
            +
              if (remaining < 19) {
         | 
| 533 | 
            +
                return spg_timestamp_error(s, self, "unexpected timetamp format, too short");
         | 
| 432 534 | 
             
              }
         | 
| 433 535 |  | 
| 434 | 
            -
               | 
| 435 | 
            -
             | 
| 436 | 
            -
             | 
| 437 | 
            -
             | 
| 438 | 
            -
             | 
| 439 | 
            -
                 | 
| 440 | 
            -
             | 
| 536 | 
            +
              year = parse_year(&p, &remaining);
         | 
| 537 | 
            +
             | 
| 538 | 
            +
              if (remaining >= 15 && p[0] == '-' && p[3] == '-' && p[6] == ' ' && p[9] == ':' && p[12] == ':') {
         | 
| 539 | 
            +
                month = str2_to_int(p+1);
         | 
| 540 | 
            +
                day = str2_to_int(p+4);
         | 
| 541 | 
            +
                hour = str2_to_int(p+7);
         | 
| 542 | 
            +
                min = str2_to_int(p+10);
         | 
| 543 | 
            +
                sec = str2_to_int(p+13);
         | 
| 544 | 
            +
                p += 15;
         | 
| 545 | 
            +
                remaining -= 15;
         | 
| 546 | 
            +
             | 
| 547 | 
            +
                if (remaining >= 2 && p[0] == '.') {
         | 
| 548 | 
            +
                  /* microsecond part, up to 6 digits */
         | 
| 549 | 
            +
                  static const int coef[6] = { 100000, 10000, 1000, 100, 10, 1 };
         | 
| 550 | 
            +
             | 
| 551 | 
            +
                  p++;
         | 
| 552 | 
            +
                  remaining--;
         | 
| 553 | 
            +
                  for (i = 0; i < 6 && isdigit(*p); i++)
         | 
| 554 | 
            +
                  {
         | 
| 555 | 
            +
                    usec += coef[i] * char_to_digit(*p++);
         | 
| 556 | 
            +
                    remaining--;
         | 
| 557 | 
            +
                  }
         | 
| 441 558 | 
             
                }
         | 
| 442 | 
            -
             | 
| 443 | 
            -
             | 
| 444 | 
            -
             | 
| 445 | 
            -
             | 
| 446 | 
            -
             | 
| 447 | 
            -
             | 
| 448 | 
            -
             | 
| 449 | 
            -
                   | 
| 450 | 
            -
             | 
| 451 | 
            -
             | 
| 452 | 
            -
                   | 
| 559 | 
            +
             | 
| 560 | 
            +
                if ((tz & SPG_HAS_TIMEZONE) && remaining >= 3 && (p[0] == '+' || p[0] == '-')) {
         | 
| 561 | 
            +
                  offset_sign = p[0];
         | 
| 562 | 
            +
                  offset_seconds += str2_to_int(p+1)*3600;
         | 
| 563 | 
            +
                  p += 3;
         | 
| 564 | 
            +
                  remaining -= 3;
         | 
| 565 | 
            +
             | 
| 566 | 
            +
                  if (p[0] == ':') {
         | 
| 567 | 
            +
                    p++;
         | 
| 568 | 
            +
                    remaining--;
         | 
| 569 | 
            +
                  }
         | 
| 570 | 
            +
                  if (remaining >= 2 && isdigit(p[0]) && isdigit(p[1]))
         | 
| 571 | 
            +
                  {
         | 
| 572 | 
            +
                    offset_seconds += str2_to_int(p)*60;
         | 
| 573 | 
            +
                    p += 2;
         | 
| 574 | 
            +
                    remaining -= 2;
         | 
| 575 | 
            +
                  }
         | 
| 576 | 
            +
                  if (p[0] == ':')
         | 
| 577 | 
            +
                  {
         | 
| 578 | 
            +
                    p++;
         | 
| 579 | 
            +
                    remaining--;
         | 
| 580 | 
            +
                  }
         | 
| 581 | 
            +
                  if (remaining >= 2 && isdigit(p[0]) && isdigit(p[1]))
         | 
| 582 | 
            +
                  {
         | 
| 583 | 
            +
                    offset_seconds += str2_to_int(p);
         | 
| 584 | 
            +
                    p += 2;
         | 
| 585 | 
            +
                    remaining -= 2;
         | 
| 586 | 
            +
                  }
         | 
| 587 | 
            +
                  if (offset_sign == '-') {
         | 
| 588 | 
            +
                    offset_seconds *= -1;
         | 
| 589 | 
            +
                  }
         | 
| 453 590 | 
             
                }
         | 
| 454 | 
            -
                usec = 0;
         | 
| 455 | 
            -
              }
         | 
| 456 591 |  | 
| 457 | 
            -
             | 
| 458 | 
            -
             | 
| 459 | 
            -
             | 
| 460 | 
            -
                 | 
| 592 | 
            +
                if (remaining == 3 && p[0] == ' ' && p[1] == 'B' && p[2] == 'C') {
         | 
| 593 | 
            +
                  year = -year;
         | 
| 594 | 
            +
                  year++;
         | 
| 595 | 
            +
                } else if (remaining != 0) {
         | 
| 596 | 
            +
                  return spg_timestamp_error(s, self, "unexpected timestamp format, remaining data left");
         | 
| 597 | 
            +
                }
         | 
| 598 | 
            +
              } else {
         | 
| 599 | 
            +
                return spg_timestamp_error(s, self, "unexpected timestamp format");
         | 
| 461 600 | 
             
              }
         | 
| 601 | 
            +
              
         | 
| 462 602 |  | 
| 463 | 
            -
              if ( | 
| 464 | 
            -
             | 
| 465 | 
            -
                 | 
| 466 | 
            -
                 | 
| 467 | 
            -
             | 
| 603 | 
            +
              if (tz & SPG_USE_TIME) {
         | 
| 604 | 
            +
            #if (RUBY_API_VERSION_MAJOR > 2 || (RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR >= 3)) && defined(HAVE_TIMEGM)
         | 
| 605 | 
            +
                /* Fast path for time conversion */
         | 
| 606 | 
            +
                struct tm tm;
         | 
| 607 | 
            +
                struct timespec ts;
         | 
| 608 | 
            +
                time_t time;
         | 
| 468 609 |  | 
| 469 | 
            -
             | 
| 610 | 
            +
                tm.tm_year = year - 1900;
         | 
| 611 | 
            +
                tm.tm_mon = month - 1;
         | 
| 612 | 
            +
                tm.tm_mday = day;
         | 
| 613 | 
            +
                tm.tm_hour = hour;
         | 
| 614 | 
            +
                tm.tm_min = min;
         | 
| 615 | 
            +
                tm.tm_sec = sec;
         | 
| 616 | 
            +
                tm.tm_isdst = -1;
         | 
| 617 | 
            +
             | 
| 618 | 
            +
                ts.tv_nsec = usec*1000;
         | 
| 619 | 
            +
             | 
| 620 | 
            +
                if (offset_sign) {
         | 
| 621 | 
            +
                  time = timegm(&tm);
         | 
| 622 | 
            +
                  if (time != -1) {
         | 
| 623 | 
            +
                    ts.tv_sec = time - offset_seconds;
         | 
| 624 | 
            +
                    dt = rb_time_timespec_new(&ts, offset_seconds);
         | 
| 625 | 
            +
             | 
| 626 | 
            +
                    if (tz & SPG_APP_UTC) {
         | 
| 627 | 
            +
                      dt = rb_funcall(dt, spg_id_utc, 0);
         | 
| 628 | 
            +
                    } else if (tz & SPG_APP_LOCAL) {
         | 
| 629 | 
            +
                      dt = rb_funcall(dt, spg_id_local, 0);
         | 
| 630 | 
            +
                    } 
         | 
| 631 | 
            +
             | 
| 632 | 
            +
                    return dt;
         | 
| 633 | 
            +
                  }
         | 
| 634 | 
            +
                } else {
         | 
| 635 | 
            +
                  if (tz & SPG_DB_UTC) {
         | 
| 636 | 
            +
                    time = timegm(&tm);
         | 
| 637 | 
            +
                  } else {
         | 
| 638 | 
            +
                    time = mktime(&tm);
         | 
| 639 | 
            +
                  }
         | 
| 640 | 
            +
             | 
| 641 | 
            +
                  if (time != -1) {
         | 
| 642 | 
            +
                    ts.tv_sec = time;
         | 
| 643 | 
            +
                    if (tz & SPG_APP_UTC) {
         | 
| 644 | 
            +
                      offset_seconds = INT_MAX-1;
         | 
| 645 | 
            +
                    } else {
         | 
| 646 | 
            +
                      offset_seconds = INT_MAX;
         | 
| 647 | 
            +
                    }
         | 
| 648 | 
            +
             | 
| 649 | 
            +
                    return rb_time_timespec_new(&ts, offset_seconds);
         | 
| 650 | 
            +
                  }
         | 
| 651 | 
            +
                }
         | 
| 652 | 
            +
            #endif
         | 
| 470 653 |  | 
| 471 | 
            -
              if (dtc == rb_cTime) {
         | 
| 472 654 | 
             
                if (offset_sign) {
         | 
| 473 655 | 
             
                  /* Offset given, convert to local time if not already in local time.
         | 
| 474 656 | 
             
                   * While PostgreSQL generally returns timestamps in local time, it's unwise to rely on this.
         | 
| 475 657 | 
             
                   */
         | 
| 476 658 | 
             
                  dt = rb_funcall(rb_cTime, spg_id_local, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
         | 
| 477 659 | 
             
                  utc_offset = NUM2INT(rb_funcall(dt, spg_id_utc_offset, 0));
         | 
| 478 | 
            -
                  offset_seconds += offset_hour * 3600 + offset_minute * 60;
         | 
| 479 660 | 
             
                  if (utc_offset != offset_seconds) {
         | 
| 480 661 | 
             
                    dt = rb_funcall(dt, spg_id_op_plus, 1, INT2NUM(utc_offset - offset_seconds));
         | 
| 481 662 | 
             
                  }
         | 
| @@ -484,7 +665,7 @@ static VALUE spg_timestamp(const char *s, VALUE self) { | |
| 484 665 | 
             
                    dt = rb_funcall(dt, spg_id_utc, 0);
         | 
| 485 666 | 
             
                  } 
         | 
| 486 667 | 
             
                  return dt;
         | 
| 487 | 
            -
                } else if (tz  | 
| 668 | 
            +
                } else if (!(tz & (SPG_APP_LOCAL|SPG_DB_LOCAL|SPG_APP_UTC|SPG_DB_UTC))) {
         | 
| 488 669 | 
             
                  return rb_funcall(rb_cTime, spg_id_local, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
         | 
| 489 670 | 
             
                }
         | 
| 490 671 |  | 
| @@ -506,12 +687,14 @@ static VALUE spg_timestamp(const char *s, VALUE self) { | |
| 506 687 | 
             
                }
         | 
| 507 688 | 
             
              } else {
         | 
| 508 689 | 
             
                /* datetime.class == DateTime */
         | 
| 690 | 
            +
                double offset_fraction;
         | 
| 691 | 
            +
             | 
| 509 692 | 
             
                if (offset_sign) {
         | 
| 510 693 | 
             
                  /* Offset given, handle correct local time.
         | 
| 511 694 | 
             
                   * While PostgreSQL generally returns timestamps in local time, it's unwise to rely on this.
         | 
| 512 695 | 
             
                   */
         | 
| 513 | 
            -
                  offset_fraction =  | 
| 514 | 
            -
                  dt = rb_funcall( | 
| 696 | 
            +
                  offset_fraction = offset_seconds/(double)SPG_SECONDS_PER_DAY;
         | 
| 697 | 
            +
                  dt = rb_funcall(spg_DateTime, spg_id_new, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), rb_float_new(offset_fraction));
         | 
| 515 698 | 
             
                  SPG_DT_ADD_USEC
         | 
| 516 699 |  | 
| 517 700 | 
             
                  if (tz & SPG_APP_LOCAL) {
         | 
| @@ -521,8 +704,8 @@ static VALUE spg_timestamp(const char *s, VALUE self) { | |
| 521 704 | 
             
                    dt = rb_funcall(dt, spg_id_new_offset, 1, INT2NUM(0));
         | 
| 522 705 | 
             
                  } 
         | 
| 523 706 | 
             
                  return dt;
         | 
| 524 | 
            -
                } else if (tz  | 
| 525 | 
            -
                  dt = rb_funcall( | 
| 707 | 
            +
                } else if (!(tz & (SPG_APP_LOCAL|SPG_DB_LOCAL|SPG_APP_UTC|SPG_DB_UTC))) {
         | 
| 708 | 
            +
                  dt = rb_funcall(spg_DateTime, spg_id_new, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
         | 
| 526 709 | 
             
                  SPG_DT_ADD_USEC
         | 
| 527 710 | 
             
                  return dt;
         | 
| 528 711 | 
             
                }
         | 
| @@ -530,7 +713,7 @@ static VALUE spg_timestamp(const char *s, VALUE self) { | |
| 530 713 | 
             
                /* No offset given, and some timezone combination given */
         | 
| 531 714 | 
             
                if (tz & SPG_DB_LOCAL) {
         | 
| 532 715 | 
             
                  offset_fraction = NUM2INT(rb_funcall(rb_funcall(rb_cTime, spg_id_local, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)), spg_id_utc_offset, 0))/SPG_SECONDS_PER_DAY;
         | 
| 533 | 
            -
                  dt = rb_funcall( | 
| 716 | 
            +
                  dt = rb_funcall(spg_DateTime, spg_id_new, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), rb_float_new(offset_fraction));
         | 
| 534 717 | 
             
                  SPG_DT_ADD_USEC
         | 
| 535 718 | 
             
                  if (tz & SPG_APP_UTC) {
         | 
| 536 719 | 
             
                    return rb_funcall(dt, spg_id_new_offset, 1, INT2NUM(0));
         | 
| @@ -538,11 +721,12 @@ static VALUE spg_timestamp(const char *s, VALUE self) { | |
| 538 721 | 
             
                    return dt;
         | 
| 539 722 | 
             
                  }
         | 
| 540 723 | 
             
                } else {
         | 
| 541 | 
            -
                  dt = rb_funcall( | 
| 724 | 
            +
                  dt = rb_funcall(spg_DateTime, spg_id_new, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
         | 
| 542 725 | 
             
                  SPG_DT_ADD_USEC
         | 
| 543 726 | 
             
                  if (tz & SPG_APP_LOCAL) {
         | 
| 544 727 | 
             
                    offset_fraction = NUM2INT(rb_funcall(rb_funcall(rb_cTime, spg_id_local, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)), spg_id_utc_offset, 0))/SPG_SECONDS_PER_DAY;
         | 
| 545 | 
            -
                     | 
| 728 | 
            +
                    dt = rb_funcall(dt, spg_id_new_offset, 1, rb_float_new(offset_fraction));
         | 
| 729 | 
            +
                    return dt;
         | 
| 546 730 | 
             
                  } else {
         | 
| 547 731 | 
             
                    return dt;
         | 
| 548 732 | 
             
                  }
         | 
| @@ -550,22 +734,144 @@ static VALUE spg_timestamp(const char *s, VALUE self) { | |
| 550 734 | 
             
              }
         | 
| 551 735 | 
             
            }
         | 
| 552 736 |  | 
| 737 | 
            +
            static VALUE spg_inet(char *val, size_t len)
         | 
| 738 | 
            +
            {
         | 
| 739 | 
            +
              VALUE ip;
         | 
| 740 | 
            +
              VALUE ip_int;
         | 
| 741 | 
            +
              VALUE vmasks;
         | 
| 742 | 
            +
              unsigned int dst[4];
         | 
| 743 | 
            +
              char buf[64];
         | 
| 744 | 
            +
              int af = strchr(val, '.') ? AF_INET : AF_INET6;
         | 
| 745 | 
            +
              int mask = -1;
         | 
| 746 | 
            +
             | 
| 747 | 
            +
              if (len >= 64) {
         | 
| 748 | 
            +
                rb_raise(rb_eTypeError, "unable to parse IP address, too long");
         | 
| 749 | 
            +
              }
         | 
| 750 | 
            +
             | 
| 751 | 
            +
              if (len >= 4) {
         | 
| 752 | 
            +
                if (val[len-2] == '/') {
         | 
| 753 | 
            +
                  mask = val[len-1] - '0';
         | 
| 754 | 
            +
                  memcpy(buf, val, len-2);
         | 
| 755 | 
            +
                  val = buf;
         | 
| 756 | 
            +
                  val[len-2] = '\0';
         | 
| 757 | 
            +
                } else if (val[len-3] == '/') {
         | 
| 758 | 
            +
                  mask = (val[len-2]- '0')*10 + val[len-1] - '0';
         | 
| 759 | 
            +
                  memcpy(buf, val, len-3);
         | 
| 760 | 
            +
                  val = buf;
         | 
| 761 | 
            +
                  val[len-3] = '\0';
         | 
| 762 | 
            +
                } else if (val[len-4] == '/') {
         | 
| 763 | 
            +
                  mask = (val[len-3]- '0')*100 + (val[len-2]- '0')*10 + val[len-1] - '0';
         | 
| 764 | 
            +
                  memcpy(buf, val, len-4);
         | 
| 765 | 
            +
                  val = buf;
         | 
| 766 | 
            +
                  val[len-4] = '\0';
         | 
| 767 | 
            +
                }
         | 
| 768 | 
            +
              }
         | 
| 769 | 
            +
             | 
| 770 | 
            +
              if (1 != inet_pton(af, val, (char *)dst)) {
         | 
| 771 | 
            +
                rb_raise(rb_eTypeError, "unable to parse IP address: %s", val);
         | 
| 772 | 
            +
              }
         | 
| 773 | 
            +
             | 
| 774 | 
            +
              if (af == AF_INET) {
         | 
| 775 | 
            +
                unsigned int ip_int_native;
         | 
| 776 | 
            +
             | 
| 777 | 
            +
                if (mask == -1) {
         | 
| 778 | 
            +
                  mask = 32;
         | 
| 779 | 
            +
                } else if (mask < 0 || mask > 32) {
         | 
| 780 | 
            +
                  rb_raise(rb_eTypeError, "invalid mask for IPv4: %d", mask);
         | 
| 781 | 
            +
                }
         | 
| 782 | 
            +
                vmasks = spg_vmasks4;
         | 
| 783 | 
            +
             | 
| 784 | 
            +
                ip_int_native = ntohl(*dst);
         | 
| 785 | 
            +
             | 
| 786 | 
            +
                /* Work around broken IPAddr behavior of convering portion
         | 
| 787 | 
            +
                   of address after netmask to 0 */
         | 
| 788 | 
            +
                switch (mask) {
         | 
| 789 | 
            +
                  case 0:
         | 
| 790 | 
            +
                    ip_int_native = 0;
         | 
| 791 | 
            +
                    break;
         | 
| 792 | 
            +
                  case 32:
         | 
| 793 | 
            +
                    /* nothing to do */
         | 
| 794 | 
            +
                    break;
         | 
| 795 | 
            +
                  default:
         | 
| 796 | 
            +
                    ip_int_native &= ~((1UL<<(32-mask))-1);
         | 
| 797 | 
            +
                    break;
         | 
| 798 | 
            +
                }
         | 
| 799 | 
            +
                ip_int = UINT2NUM(ip_int_native);
         | 
| 800 | 
            +
              } else {
         | 
| 801 | 
            +
                unsigned long long * dstllp = (unsigned long long *)dst;
         | 
| 802 | 
            +
                unsigned long long ip_int_native1;
         | 
| 803 | 
            +
                unsigned long long ip_int_native2;
         | 
| 804 | 
            +
             | 
| 805 | 
            +
                if (mask == -1) {
         | 
| 806 | 
            +
                  mask = 128;
         | 
| 807 | 
            +
                } else if (mask < 0 || mask > 128) {
         | 
| 808 | 
            +
                  rb_raise(rb_eTypeError, "invalid mask for IPv6: %d", mask);
         | 
| 809 | 
            +
                }
         | 
| 810 | 
            +
                vmasks = spg_vmasks6;
         | 
| 811 | 
            +
             | 
| 812 | 
            +
                ip_int_native1 = ntohll(dstllp);
         | 
| 813 | 
            +
                dstllp++;
         | 
| 814 | 
            +
                ip_int_native2 = ntohll(dstllp);
         | 
| 815 | 
            +
             | 
| 816 | 
            +
                if (mask == 128) {
         | 
| 817 | 
            +
                  /* nothing to do */
         | 
| 818 | 
            +
                } else if (mask == 64) {
         | 
| 819 | 
            +
                  ip_int_native2 = 0;
         | 
| 820 | 
            +
                } else if (mask == 0) {
         | 
| 821 | 
            +
                  ip_int_native1 = 0;
         | 
| 822 | 
            +
                  ip_int_native2 = 0;
         | 
| 823 | 
            +
                } else if (mask < 64) {
         | 
| 824 | 
            +
                  ip_int_native1 &= ~((1ULL<<(64-mask))-1);
         | 
| 825 | 
            +
                  ip_int_native2 = 0;
         | 
| 826 | 
            +
                } else {
         | 
| 827 | 
            +
                  ip_int_native2 &= ~((1ULL<<(128-mask))-1);
         | 
| 828 | 
            +
                }
         | 
| 829 | 
            +
             | 
| 830 | 
            +
                /* 4 Bignum allocations */
         | 
| 831 | 
            +
                ip_int = ULL2NUM(ip_int_native1);
         | 
| 832 | 
            +
                ip_int = rb_funcall(ip_int, spg_id_lshift, 1, INT2NUM(64));
         | 
| 833 | 
            +
                ip_int = rb_funcall(ip_int, spg_id_op_plus, 1, ULL2NUM(ip_int_native2));
         | 
| 834 | 
            +
              }
         | 
| 835 | 
            +
             | 
| 836 | 
            +
              if (spg_use_ipaddr_alloc) {
         | 
| 837 | 
            +
                ip = rb_obj_alloc(spg_IPAddr);
         | 
| 838 | 
            +
                rb_ivar_set(ip, spg_id_family, INT2NUM(af));
         | 
| 839 | 
            +
                rb_ivar_set(ip, spg_id_addr, ip_int);
         | 
| 840 | 
            +
                rb_ivar_set(ip, spg_id_mask_addr, RARRAY_AREF(vmasks, mask));
         | 
| 841 | 
            +
              } else {
         | 
| 842 | 
            +
                VALUE ip_args[2];
         | 
| 843 | 
            +
                ip_args[0] = ip_int;
         | 
| 844 | 
            +
                ip_args[1] = INT2NUM(af);
         | 
| 845 | 
            +
                ip = rb_class_new_instance(2, ip_args, spg_IPAddr);
         | 
| 846 | 
            +
                ip = rb_funcall(ip, spg_id_mask, 1, INT2NUM(mask));
         | 
| 847 | 
            +
              }
         | 
| 848 | 
            +
             | 
| 849 | 
            +
              return ip;
         | 
| 850 | 
            +
            }
         | 
| 851 | 
            +
             | 
| 852 | 
            +
            static VALUE spg_create_Blob(VALUE v) {
         | 
| 853 | 
            +
              struct spg_blob_initialization *bi = (struct spg_blob_initialization *)v;
         | 
| 854 | 
            +
              if (bi->blob_string == NULL) {
         | 
| 855 | 
            +
                rb_raise(rb_eNoMemError, "PQunescapeBytea failure: probably not enough memory");
         | 
| 856 | 
            +
              }
         | 
| 857 | 
            +
              return rb_obj_taint(rb_str_new_with_class(spg_Blob_instance, bi->blob_string, bi->length));
         | 
| 858 | 
            +
            }
         | 
| 859 | 
            +
             | 
| 553 860 | 
             
            static VALUE spg_fetch_rows_set_cols(VALUE self, VALUE ignore) {
         | 
| 554 861 | 
             
              return Qnil;
         | 
| 555 862 | 
             
            }
         | 
| 556 863 |  | 
| 557 864 | 
             
            static VALUE spg__array_col_value(char *v, size_t length, VALUE converter, int enc_index, int oid, VALUE db) {
         | 
| 558 865 | 
             
              VALUE rv;
         | 
| 559 | 
            -
               | 
| 866 | 
            +
              struct spg_blob_initialization bi;
         | 
| 560 867 |  | 
| 561 868 | 
             
              switch(oid) {
         | 
| 562 869 | 
             
                case 16: /* boolean */
         | 
| 563 870 | 
             
                  rv = *v == 't' ? Qtrue : Qfalse;
         | 
| 564 871 | 
             
                  break;
         | 
| 565 872 | 
             
                case 17: /* bytea */
         | 
| 566 | 
            -
                   | 
| 567 | 
            -
                  rv =  | 
| 568 | 
            -
                  PQfreemem(v);
         | 
| 873 | 
            +
                  bi.blob_string = (char *)PQunescapeBytea((unsigned char*)v, &bi.length);
         | 
| 874 | 
            +
                  rv = rb_ensure(spg_create_Blob, (VALUE)&bi, (VALUE(*)())PQfreemem, (VALUE)bi.blob_string);
         | 
| 569 875 | 
             
                  break;
         | 
| 570 876 | 
             
                case 20: /* integer */
         | 
| 571 877 | 
             
                case 21:
         | 
| @@ -589,15 +895,15 @@ static VALUE spg__array_col_value(char *v, size_t length, VALUE converter, int e | |
| 589 895 | 
             
                  rv = rb_funcall(spg_Kernel, spg_id_BigDecimal, 1, rb_str_new(v, length));
         | 
| 590 896 | 
             
                  break;
         | 
| 591 897 | 
             
                case 1082: /* date */
         | 
| 592 | 
            -
                  rv = spg_date(v, db);
         | 
| 898 | 
            +
                  rv = spg_date(v, db, length);
         | 
| 593 899 | 
             
                  break;
         | 
| 594 900 | 
             
                case 1083: /* time */
         | 
| 595 901 | 
             
                case 1266:
         | 
| 596 | 
            -
                  rv = spg_time(v);
         | 
| 902 | 
            +
                  rv = spg_time(v, length, (int)converter);
         | 
| 597 903 | 
             
                  break;
         | 
| 598 904 | 
             
                case 1114: /* timestamp */
         | 
| 599 905 | 
             
                case 1184:
         | 
| 600 | 
            -
                  rv = spg_timestamp(v, db);
         | 
| 906 | 
            +
                  rv = spg_timestamp(v, db, length, (int)converter);
         | 
| 601 907 | 
             
                  break;
         | 
| 602 908 | 
             
                case 18: /* char */
         | 
| 603 909 | 
             
                case 25: /* text */
         | 
| @@ -605,6 +911,10 @@ static VALUE spg__array_col_value(char *v, size_t length, VALUE converter, int e | |
| 605 911 | 
             
                  rv = rb_tainted_str_new(v, length);
         | 
| 606 912 | 
             
                  PG_ENCODING_SET_NOCHECK(rv, enc_index);
         | 
| 607 913 | 
             
                  break;
         | 
| 914 | 
            +
                case 869: /* inet */
         | 
| 915 | 
            +
                case 650: /* cidr */
         | 
| 916 | 
            +
                  rv = spg_inet(v, length);
         | 
| 917 | 
            +
                  break;
         | 
| 608 918 | 
             
                default:
         | 
| 609 919 | 
             
                  rv = rb_tainted_str_new(v, length);
         | 
| 610 920 | 
             
                  PG_ENCODING_SET_NOCHECK(rv, enc_index);
         | 
| @@ -629,13 +939,63 @@ static VALUE spg_array_value(char *c_pg_array_string, int array_string_length, V | |
| 629 939 | 
             
              return rb_class_new_instance(2, args, spg_PGArray);
         | 
| 630 940 | 
             
            }
         | 
| 631 941 |  | 
| 942 | 
            +
            static int spg_time_info_bitmask(void) {
         | 
| 943 | 
            +
              int info = 0;
         | 
| 944 | 
            +
              VALUE now = rb_funcall(spg_SQLTime, spg_id_date, 0);
         | 
| 945 | 
            +
             | 
| 946 | 
            +
              info = NUM2INT(rb_funcall(now, spg_id_year, 0)) << SPG_YEAR_SHIFT;
         | 
| 947 | 
            +
              info += NUM2INT(rb_funcall(now, spg_id_month, 0)) << SPG_MONTH_SHIFT;
         | 
| 948 | 
            +
              info += NUM2INT(rb_funcall(now, spg_id_day, 0));
         | 
| 949 | 
            +
             | 
| 950 | 
            +
              if (rb_funcall(spg_Sequel, spg_id_application_timezone, 0) == spg_sym_utc) {
         | 
| 951 | 
            +
                info += SPG_TIME_UTC;
         | 
| 952 | 
            +
              }
         | 
| 953 | 
            +
             | 
| 954 | 
            +
              return info;
         | 
| 955 | 
            +
            }
         | 
| 956 | 
            +
             | 
| 957 | 
            +
            static int spg_timestamp_info_bitmask(VALUE self) {
         | 
| 958 | 
            +
              VALUE db, rtz;
         | 
| 959 | 
            +
              int tz = 0;
         | 
| 960 | 
            +
             | 
| 961 | 
            +
              db = rb_funcall(self, spg_id_db, 0);
         | 
| 962 | 
            +
              rtz = rb_funcall(db, spg_id_timezone, 0);
         | 
| 963 | 
            +
              if (rtz != Qnil) {
         | 
| 964 | 
            +
                if (rtz == spg_sym_local) {
         | 
| 965 | 
            +
                  tz |= SPG_DB_LOCAL;
         | 
| 966 | 
            +
                } else if (rtz == spg_sym_utc) {
         | 
| 967 | 
            +
                  tz |= SPG_DB_UTC;
         | 
| 968 | 
            +
                } else {
         | 
| 969 | 
            +
                  tz |= SPG_DB_CUSTOM;
         | 
| 970 | 
            +
                }
         | 
| 971 | 
            +
              }
         | 
| 972 | 
            +
             | 
| 973 | 
            +
              rtz = rb_funcall(spg_Sequel, spg_id_application_timezone, 0);
         | 
| 974 | 
            +
              if (rtz != Qnil) {
         | 
| 975 | 
            +
                if (rtz == spg_sym_local) {
         | 
| 976 | 
            +
                  tz |= SPG_APP_LOCAL;
         | 
| 977 | 
            +
                } else if (rtz == spg_sym_utc) {
         | 
| 978 | 
            +
                  tz |= SPG_APP_UTC;
         | 
| 979 | 
            +
                } else {
         | 
| 980 | 
            +
                  tz |= SPG_APP_CUSTOM;
         | 
| 981 | 
            +
                }
         | 
| 982 | 
            +
              }
         | 
| 983 | 
            +
             | 
| 984 | 
            +
              if (rb_cTime == rb_funcall(spg_Sequel, spg_id_datetime_class, 0)) {
         | 
| 985 | 
            +
                tz |= SPG_USE_TIME;
         | 
| 986 | 
            +
              }
         | 
| 987 | 
            +
             | 
| 988 | 
            +
              tz |= SPG_TZ_INITIALIZED;
         | 
| 989 | 
            +
              return tz;
         | 
| 990 | 
            +
            }
         | 
| 991 | 
            +
             | 
| 632 992 | 
             
            static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* colconvert, int enc_index) {
         | 
| 633 993 | 
             
              char *v;
         | 
| 634 994 | 
             
              VALUE rv;
         | 
| 635 | 
            -
              size_t l;
         | 
| 636 995 | 
             
              int ftype = PQftype(res, j);
         | 
| 637 996 | 
             
              VALUE array_type;
         | 
| 638 997 | 
             
              VALUE scalar_oid;
         | 
| 998 | 
            +
              struct spg_blob_initialization bi;
         | 
| 639 999 |  | 
| 640 1000 | 
             
              if(PQgetisnull(res, i, j)) {
         | 
| 641 1001 | 
             
                rv = Qnil;
         | 
| @@ -647,9 +1007,8 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co | |
| 647 1007 | 
             
                    rv = *v == 't' ? Qtrue : Qfalse;
         | 
| 648 1008 | 
             
                    break;
         | 
| 649 1009 | 
             
                  case 17: /* bytea */
         | 
| 650 | 
            -
                     | 
| 651 | 
            -
                    rv =  | 
| 652 | 
            -
                    PQfreemem(v);
         | 
| 1010 | 
            +
                    bi.blob_string = (char *)PQunescapeBytea((unsigned char*)v, &bi.length);
         | 
| 1011 | 
            +
                    rv = rb_ensure(spg_create_Blob, (VALUE)&bi, (VALUE(*)())PQfreemem, (VALUE)bi.blob_string);
         | 
| 653 1012 | 
             
                    break;
         | 
| 654 1013 | 
             
                  case 20: /* integer */
         | 
| 655 1014 | 
             
                  case 21:
         | 
| @@ -673,15 +1032,15 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co | |
| 673 1032 | 
             
                    rv = rb_funcall(spg_Kernel, spg_id_BigDecimal, 1, rb_str_new(v, PQgetlength(res, i, j)));
         | 
| 674 1033 | 
             
                    break;
         | 
| 675 1034 | 
             
                  case 1082: /* date */
         | 
| 676 | 
            -
                    rv = spg_date(v, self);
         | 
| 1035 | 
            +
                    rv = spg_date(v, self, PQgetlength(res, i, j));
         | 
| 677 1036 | 
             
                    break;
         | 
| 678 1037 | 
             
                  case 1083: /* time */
         | 
| 679 1038 | 
             
                  case 1266:
         | 
| 680 | 
            -
                    rv = spg_time(v);
         | 
| 1039 | 
            +
                    rv = spg_time(v, PQgetlength(res, i, j), (int)colconvert[j]);
         | 
| 681 1040 | 
             
                    break;
         | 
| 682 1041 | 
             
                  case 1114: /* timestamp */
         | 
| 683 1042 | 
             
                  case 1184:
         | 
| 684 | 
            -
                    rv = spg_timestamp(v, self);
         | 
| 1043 | 
            +
                    rv = spg_timestamp(v, self, PQgetlength(res, i, j), (int)colconvert[j]);
         | 
| 685 1044 | 
             
                    break;
         | 
| 686 1045 | 
             
                  case 18: /* char */
         | 
| 687 1046 | 
             
                  case 25: /* text */
         | 
| @@ -689,6 +1048,10 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co | |
| 689 1048 | 
             
                    rv = rb_tainted_str_new(v, PQgetlength(res, i, j));
         | 
| 690 1049 | 
             
                    PG_ENCODING_SET_NOCHECK(rv, enc_index);
         | 
| 691 1050 | 
             
                    break;
         | 
| 1051 | 
            +
                  case 869: /* inet */
         | 
| 1052 | 
            +
                  case 650: /* cidr */
         | 
| 1053 | 
            +
                    rv = spg_inet(v, PQgetlength(res, i, j));
         | 
| 1054 | 
            +
                    break;
         | 
| 692 1055 | 
             
                  /* array types */
         | 
| 693 1056 | 
             
                  case 1009:
         | 
| 694 1057 | 
             
                  case 1014:
         | 
| @@ -717,6 +1080,8 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co | |
| 717 1080 | 
             
                  case 1003:
         | 
| 718 1081 | 
             
                  case 1010:
         | 
| 719 1082 | 
             
                  case 1006:
         | 
| 1083 | 
            +
                  case 1041:
         | 
| 1084 | 
            +
                  case 651:
         | 
| 720 1085 | 
             
                    switch(ftype) {
         | 
| 721 1086 | 
             
                      case 1009: 
         | 
| 722 1087 | 
             
                      case 1014:
         | 
| @@ -823,8 +1188,16 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co | |
| 823 1188 | 
             
                        array_type = spg_sym_int2vector;
         | 
| 824 1189 | 
             
                        scalar_oid = 22;
         | 
| 825 1190 | 
             
                        break;
         | 
| 1191 | 
            +
                      case 1041:
         | 
| 1192 | 
            +
                        array_type = spg_sym_inet;
         | 
| 1193 | 
            +
                        scalar_oid = 869;
         | 
| 1194 | 
            +
                        break;
         | 
| 1195 | 
            +
                      case 651:
         | 
| 1196 | 
            +
                        array_type = spg_sym_cidr;
         | 
| 1197 | 
            +
                        scalar_oid = 650;
         | 
| 1198 | 
            +
                        break;
         | 
| 826 1199 | 
             
                    }
         | 
| 827 | 
            -
                    rv = spg_array_value(v, PQgetlength(res, i, j),  | 
| 1200 | 
            +
                    rv = spg_array_value(v, PQgetlength(res, i, j), colconvert[j], enc_index, scalar_oid, self, array_type);
         | 
| 828 1201 | 
             
                    break;
         | 
| 829 1202 | 
             
                  default:
         | 
| 830 1203 | 
             
                    rv = rb_tainted_str_new(v, PQgetlength(res, i, j));
         | 
| @@ -877,6 +1250,8 @@ static void spg_set_column_info(VALUE self, PGresult *res, VALUE *colsyms, VALUE | |
| 877 1250 | 
             
              long i;
         | 
| 878 1251 | 
             
              long j;
         | 
| 879 1252 | 
             
              long nfields;
         | 
| 1253 | 
            +
              int timestamp_info = 0;
         | 
| 1254 | 
            +
              int time_info = 0;
         | 
| 880 1255 | 
             
              VALUE conv_procs = 0;
         | 
| 881 1256 |  | 
| 882 1257 | 
             
              nfields = PQnfields(res);
         | 
| @@ -885,6 +1260,7 @@ static void spg_set_column_info(VALUE self, PGresult *res, VALUE *colsyms, VALUE | |
| 885 1260 | 
             
                colsyms[j] = rb_funcall(self, spg_id_output_identifier, 1, rb_str_new2(PQfname(res, j)));
         | 
| 886 1261 | 
             
                i = PQftype(res, j);
         | 
| 887 1262 | 
             
                switch (i) {
         | 
| 1263 | 
            +
                  /* scalar types */
         | 
| 888 1264 | 
             
                  case 16:
         | 
| 889 1265 | 
             
                  case 17:
         | 
| 890 1266 | 
             
                  case 20:
         | 
| @@ -896,15 +1272,57 @@ static void spg_set_column_info(VALUE self, PGresult *res, VALUE *colsyms, VALUE | |
| 896 1272 | 
             
                  case 790:
         | 
| 897 1273 | 
             
                  case 1700:
         | 
| 898 1274 | 
             
                  case 1082:
         | 
| 899 | 
            -
                  case 1083:
         | 
| 900 | 
            -
                  case 1266:
         | 
| 901 | 
            -
                  case 1114:
         | 
| 902 | 
            -
                  case 1184:
         | 
| 903 1275 | 
             
                  case 18:
         | 
| 904 1276 | 
             
                  case 25:
         | 
| 905 1277 | 
             
                  case 1043:
         | 
| 1278 | 
            +
                  /* array types */
         | 
| 1279 | 
            +
                  case 1009:
         | 
| 1280 | 
            +
                  case 1014:
         | 
| 1281 | 
            +
                  case 1015:
         | 
| 1282 | 
            +
                  case 1007:
         | 
| 1283 | 
            +
                  case 1016:
         | 
| 1284 | 
            +
                  case 1231:
         | 
| 1285 | 
            +
                  case 1022:
         | 
| 1286 | 
            +
                  case 1000:
         | 
| 1287 | 
            +
                  case 1001:
         | 
| 1288 | 
            +
                  case 1182:
         | 
| 1289 | 
            +
                  case 1005:
         | 
| 1290 | 
            +
                  case 1028:
         | 
| 1291 | 
            +
                  case 1021:
         | 
| 1292 | 
            +
                  case 143:
         | 
| 1293 | 
            +
                  case 791:
         | 
| 1294 | 
            +
                  case 1561:
         | 
| 1295 | 
            +
                  case 1563:
         | 
| 1296 | 
            +
                  case 2951:
         | 
| 1297 | 
            +
                  case 1011:
         | 
| 1298 | 
            +
                  case 1012:
         | 
| 1299 | 
            +
                  case 1003:
         | 
| 1300 | 
            +
                  case 1010:
         | 
| 906 1301 | 
             
                    colconvert[j] = Qnil;
         | 
| 907 1302 | 
             
                    break;
         | 
| 1303 | 
            +
             | 
| 1304 | 
            +
                  /* time types */
         | 
| 1305 | 
            +
                  case 1183:
         | 
| 1306 | 
            +
                  case 1083:
         | 
| 1307 | 
            +
                  case 1270:
         | 
| 1308 | 
            +
                  case 1266:
         | 
| 1309 | 
            +
                    if (time_info == 0) {
         | 
| 1310 | 
            +
                      time_info = spg_time_info_bitmask();
         | 
| 1311 | 
            +
                    }
         | 
| 1312 | 
            +
                    colconvert[j] = time_info;
         | 
| 1313 | 
            +
                    break;
         | 
| 1314 | 
            +
             | 
| 1315 | 
            +
                  /* timestamp types */
         | 
| 1316 | 
            +
                  case 1115:
         | 
| 1317 | 
            +
                  case 1185:
         | 
| 1318 | 
            +
                  case 1114:
         | 
| 1319 | 
            +
                  case 1184:
         | 
| 1320 | 
            +
                    if (timestamp_info == 0) {
         | 
| 1321 | 
            +
                      timestamp_info = spg_timestamp_info_bitmask(self);
         | 
| 1322 | 
            +
                    }
         | 
| 1323 | 
            +
                    colconvert[j] = (VALUE)((i == 1184 || i == 1185) ? (timestamp_info | SPG_HAS_TIMEZONE) : timestamp_info);
         | 
| 1324 | 
            +
                    break;
         | 
| 1325 | 
            +
             | 
| 908 1326 | 
             
                  default:
         | 
| 909 1327 | 
             
                    if (conv_procs == 0) {
         | 
| 910 1328 | 
             
                      conv_procs = rb_funcall(rb_funcall(self, spg_id_db, 0), spg_id_conversion_procs, 0);
         | 
| @@ -930,14 +1348,13 @@ static VALUE spg_yield_hash_rows(VALUE self, VALUE rres, VALUE ignore) { | |
| 930 1348 | 
             
              VALUE pg_type;
         | 
| 931 1349 | 
             
              VALUE pg_value;
         | 
| 932 1350 | 
             
              char type = SPG_YIELD_NORMAL;
         | 
| 1351 | 
            +
              int enc_index;
         | 
| 933 1352 |  | 
| 934 1353 | 
             
              if (!RTEST(rres)) {
         | 
| 935 1354 | 
             
                return self;
         | 
| 936 1355 | 
             
              }
         | 
| 937 | 
            -
              Check_Type(rres, T_DATA);
         | 
| 938 1356 | 
             
              res = pgresult_get(rres);
         | 
| 939 1357 |  | 
| 940 | 
            -
              int enc_index;
         | 
| 941 1358 | 
             
              enc_index = enc_get_index(rres);
         | 
| 942 1359 |  | 
| 943 1360 | 
             
              ntuples = PQntuples(res);
         | 
| @@ -1174,7 +1591,6 @@ static VALUE spg_supports_streaming_p(VALUE self) { | |
| 1174 1591 | 
             
            #if HAVE_PQSETSINGLEROWMODE
         | 
| 1175 1592 | 
             
            static VALUE spg_set_single_row_mode(VALUE self) {
         | 
| 1176 1593 | 
             
              PGconn *conn;
         | 
| 1177 | 
            -
              Check_Type(self, T_DATA);
         | 
| 1178 1594 | 
             
              conn = pg_get_pgconn(self);
         | 
| 1179 1595 | 
             
              if (PQsetSingleRowMode(conn) != 1) {
         | 
| 1180 1596 | 
             
                  rb_raise(spg_PGError, "cannot set single row mode");
         | 
| @@ -1183,7 +1599,6 @@ static VALUE spg_set_single_row_mode(VALUE self) { | |
| 1183 1599 | 
             
            }
         | 
| 1184 1600 |  | 
| 1185 1601 | 
             
            static VALUE spg__yield_each_row(VALUE self) {
         | 
| 1186 | 
            -
              PGconn *conn;
         | 
| 1187 1602 | 
             
              PGresult *res;
         | 
| 1188 1603 | 
             
              VALUE rres;
         | 
| 1189 1604 | 
             
              VALUE rconn;
         | 
| @@ -1196,21 +1611,18 @@ static VALUE spg__yield_each_row(VALUE self) { | |
| 1196 1611 | 
             
              VALUE pg_type;
         | 
| 1197 1612 | 
             
              VALUE pg_value = Qnil;
         | 
| 1198 1613 | 
             
              char type = SPG_YIELD_NORMAL;
         | 
| 1614 | 
            +
              int enc_index;
         | 
| 1199 1615 |  | 
| 1200 1616 | 
             
              rconn = rb_ary_entry(self, 1);
         | 
| 1201 1617 | 
             
              self = rb_ary_entry(self, 0);
         | 
| 1202 | 
            -
              Check_Type(rconn, T_DATA);
         | 
| 1203 | 
            -
              conn = pg_get_pgconn(rconn);
         | 
| 1204 1618 |  | 
| 1205 1619 | 
             
              rres = rb_funcall(rconn, spg_id_get_result, 0);
         | 
| 1206 1620 | 
             
              if (rres == Qnil) {
         | 
| 1207 1621 | 
             
                goto end_yield_each_row;
         | 
| 1208 1622 | 
             
              }
         | 
| 1209 1623 | 
             
              rb_funcall(rres, spg_id_check, 0);
         | 
| 1210 | 
            -
              Check_Type(rres, T_DATA);
         | 
| 1211 1624 | 
             
              res = pgresult_get(rres);
         | 
| 1212 1625 |  | 
| 1213 | 
            -
              int enc_index;
         | 
| 1214 1626 | 
             
              enc_index = enc_get_index(rres);
         | 
| 1215 1627 |  | 
| 1216 1628 | 
             
              /* Only handle regular and model types.  All other types require compiling all
         | 
| @@ -1255,7 +1667,6 @@ static VALUE spg__yield_each_row(VALUE self) { | |
| 1255 1667 | 
             
                  goto end_yield_each_row;
         | 
| 1256 1668 | 
             
                }
         | 
| 1257 1669 | 
             
                rb_funcall(rres, spg_id_check, 0);
         | 
| 1258 | 
            -
                Check_Type(rres, T_DATA);
         | 
| 1259 1670 | 
             
                res = pgresult_get(rres);
         | 
| 1260 1671 | 
             
              }
         | 
| 1261 1672 | 
             
              rb_funcall(rres, spg_id_clear, 0);
         | 
| @@ -1268,7 +1679,6 @@ static VALUE spg__flush_results(VALUE rconn) { | |
| 1268 1679 | 
             
              PGconn *conn;
         | 
| 1269 1680 | 
             
              PGresult *res;
         | 
| 1270 1681 | 
             
              VALUE error = 0;
         | 
| 1271 | 
            -
              Check_Type(rconn, T_DATA);
         | 
| 1272 1682 | 
             
              conn = pg_get_pgconn(rconn);
         | 
| 1273 1683 |  | 
| 1274 1684 | 
             
              while ((res = PQgetResult(conn)) != NULL) {
         | 
| @@ -1310,6 +1720,7 @@ void Init_sequel_pg(void) { | |
| 1310 1720 |  | 
| 1311 1721 | 
             
              spg_Sequel = rb_funcall(rb_cObject, cg, 1, rb_str_new2("Sequel"));
         | 
| 1312 1722 | 
             
              spg_Postgres = rb_funcall(spg_Sequel, cg, 1, rb_str_new2("Postgres"));
         | 
| 1723 | 
            +
              rb_global_variable(&spg_Sequel);
         | 
| 1313 1724 |  | 
| 1314 1725 | 
             
              if(rb_obj_respond_to(spg_Postgres, rb_intern("sequel_pg_version_supported?"), 0)) {
         | 
| 1315 1726 | 
             
                if(!RTEST(rb_funcall(spg_Postgres, rb_intern("sequel_pg_version_supported?"), 1, INT2FIX(SEQUEL_PG_VERSION_INTEGER)))) {
         | 
| @@ -1321,6 +1732,7 @@ void Init_sequel_pg(void) { | |
| 1321 1732 |  | 
| 1322 1733 | 
             
              spg_id_BigDecimal = rb_intern("BigDecimal");
         | 
| 1323 1734 | 
             
              spg_id_new = rb_intern("new");
         | 
| 1735 | 
            +
              spg_id_date = rb_intern("date");
         | 
| 1324 1736 | 
             
              spg_id_local = rb_intern("local");
         | 
| 1325 1737 | 
             
              spg_id_year = rb_intern("year");
         | 
| 1326 1738 | 
             
              spg_id_month = rb_intern("month");
         | 
| @@ -1351,6 +1763,12 @@ void Init_sequel_pg(void) { | |
| 1351 1763 | 
             
              spg_id_encoding = rb_intern("@encoding");
         | 
| 1352 1764 | 
             
              spg_id_values = rb_intern("@values");
         | 
| 1353 1765 |  | 
| 1766 | 
            +
              spg_id_family = rb_intern("@family");
         | 
| 1767 | 
            +
              spg_id_addr = rb_intern("@addr");
         | 
| 1768 | 
            +
              spg_id_mask_addr = rb_intern("@mask_addr");
         | 
| 1769 | 
            +
              spg_id_lshift = rb_intern("<<");
         | 
| 1770 | 
            +
              spg_id_mask = rb_intern("mask");
         | 
| 1771 | 
            +
             | 
| 1354 1772 | 
             
              spg_sym_utc = ID2SYM(rb_intern("utc"));
         | 
| 1355 1773 | 
             
              spg_sym_local = ID2SYM(rb_intern("local"));
         | 
| 1356 1774 | 
             
              spg_sym_map = ID2SYM(rb_intern("map"));
         | 
| @@ -1388,29 +1806,42 @@ void Init_sequel_pg(void) { | |
| 1388 1806 | 
             
              spg_sym_name = ID2SYM(rb_intern("name"));
         | 
| 1389 1807 | 
             
              spg_sym_tid = ID2SYM(rb_intern("tid"));
         | 
| 1390 1808 | 
             
              spg_sym_int2vector = ID2SYM(rb_intern("int2vector"));
         | 
| 1809 | 
            +
              spg_sym_inet = ID2SYM(rb_intern("inet"));
         | 
| 1810 | 
            +
              spg_sym_cidr = ID2SYM(rb_intern("cidr"));
         | 
| 1391 1811 |  | 
| 1392 1812 | 
             
              spg_Blob = rb_funcall(rb_funcall(spg_Sequel, cg, 1, rb_str_new2("SQL")), cg, 1, rb_str_new2("Blob")); 
         | 
| 1813 | 
            +
              rb_global_variable(&spg_Blob);
         | 
| 1814 | 
            +
              spg_Blob_instance = rb_obj_freeze(rb_funcall(spg_Blob, spg_id_new, 0));
         | 
| 1815 | 
            +
              rb_global_variable(&spg_Blob_instance);
         | 
| 1393 1816 | 
             
              spg_SQLTime= rb_funcall(spg_Sequel, cg, 1, rb_str_new2("SQLTime")); 
         | 
| 1817 | 
            +
              rb_global_variable(&spg_SQLTime);
         | 
| 1394 1818 | 
             
              spg_Kernel = rb_funcall(rb_cObject, cg, 1, rb_str_new2("Kernel")); 
         | 
| 1819 | 
            +
              rb_global_variable(&spg_Kernel);
         | 
| 1395 1820 | 
             
              spg_Date = rb_funcall(rb_cObject, cg, 1, rb_str_new2("Date")); 
         | 
| 1821 | 
            +
              rb_global_variable(&spg_Date);
         | 
| 1822 | 
            +
              spg_DateTime = rb_funcall(rb_cObject, cg, 1, rb_str_new2("DateTime")); 
         | 
| 1823 | 
            +
              rb_global_variable(&spg_DateTime);
         | 
| 1396 1824 | 
             
              spg_PGError = rb_funcall(rb_funcall(rb_cObject, cg, 1, rb_str_new2("PG")), cg, 1, rb_str_new2("Error"));
         | 
| 1825 | 
            +
              rb_global_variable(&spg_PGError);
         | 
| 1397 1826 |  | 
| 1398 1827 | 
             
              spg_nan = rb_eval_string("0.0/0.0");
         | 
| 1399 | 
            -
              spg_pos_inf = rb_eval_string("1.0/0.0");
         | 
| 1400 | 
            -
              spg_neg_inf = rb_eval_string("-1.0/0.0");
         | 
| 1401 | 
            -
              spg_usec_per_day = ULL2NUM(86400000000ULL);
         | 
| 1402 | 
            -
             | 
| 1403 | 
            -
              rb_global_variable(&spg_Sequel);
         | 
| 1404 | 
            -
              rb_global_variable(&spg_Blob);
         | 
| 1405 | 
            -
              rb_global_variable(&spg_Kernel);
         | 
| 1406 | 
            -
              rb_global_variable(&spg_Date);
         | 
| 1407 | 
            -
              rb_global_variable(&spg_SQLTime);
         | 
| 1408 | 
            -
              rb_global_variable(&spg_PGError);
         | 
| 1409 1828 | 
             
              rb_global_variable(&spg_nan);
         | 
| 1829 | 
            +
              spg_pos_inf = rb_eval_string("1.0/0.0");
         | 
| 1410 1830 | 
             
              rb_global_variable(&spg_pos_inf);
         | 
| 1831 | 
            +
              spg_neg_inf = rb_eval_string("-1.0/0.0");
         | 
| 1411 1832 | 
             
              rb_global_variable(&spg_neg_inf);
         | 
| 1833 | 
            +
              spg_usec_per_day = ULL2NUM(86400000000ULL);
         | 
| 1412 1834 | 
             
              rb_global_variable(&spg_usec_per_day);
         | 
| 1413 1835 |  | 
| 1836 | 
            +
              rb_require("ipaddr");
         | 
| 1837 | 
            +
              spg_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));
         | 
| 1838 | 
            +
              rb_global_variable(&spg_IPAddr);
         | 
| 1839 | 
            +
              spg_use_ipaddr_alloc = RTEST(rb_eval_string("IPAddr.new.instance_variables.sort == [:@addr, :@family, :@mask_addr]"));
         | 
| 1840 | 
            +
              spg_vmasks4 = rb_eval_string("a = [0]*33; a[0] = 0; a[32] = 0xffffffff; 31.downto(1){|i| a[i] = a[i+1] - (1 << (31 - i))}; a.freeze");
         | 
| 1841 | 
            +
              rb_global_variable(&spg_vmasks4);
         | 
| 1842 | 
            +
              spg_vmasks6 = rb_eval_string("a = [0]*129; a[0] = 0; a[128] = 0xffffffffffffffffffffffffffffffff; 127.downto(1){|i| a[i] = a[i+1] - (1 << (127 - i))}; a.freeze");
         | 
| 1843 | 
            +
              rb_global_variable(&spg_vmasks6);
         | 
| 1844 | 
            +
             | 
| 1414 1845 | 
             
              c = rb_funcall(spg_Postgres, cg, 1, rb_str_new2("Dataset"));
         | 
| 1415 1846 | 
             
              rb_undef_method(c, "yield_hash_rows");
         | 
| 1416 1847 | 
             
              rb_define_private_method(c, "yield_hash_rows", spg_yield_hash_rows, 2);
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: sequel_pg
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.10.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Jeremy Evans
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2018-06- | 
| 11 | 
            +
            date: 2018-06-25 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: pg
         | 
| @@ -30,14 +30,14 @@ dependencies: | |
| 30 30 | 
             
                requirements:
         | 
| 31 31 | 
             
                - - ">="
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: 4. | 
| 33 | 
            +
                    version: 4.38.0
         | 
| 34 34 | 
             
              type: :runtime
         | 
| 35 35 | 
             
              prerelease: false
         | 
| 36 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 37 | 
             
                requirements:
         | 
| 38 38 | 
             
                - - ">="
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version: 4. | 
| 40 | 
            +
                    version: 4.38.0
         | 
| 41 41 | 
             
            description: |
         | 
| 42 42 | 
             
              sequel_pg overwrites the inner loop of the Sequel postgres
         | 
| 43 43 | 
             
              adapter row fetching code with a C version.  The C version
         | 
| @@ -91,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 91 91 | 
             
                  version: '0'
         | 
| 92 92 | 
             
            requirements: []
         | 
| 93 93 | 
             
            rubyforge_project: 
         | 
| 94 | 
            -
            rubygems_version:  | 
| 94 | 
            +
            rubygems_version: 2.7.6
         | 
| 95 95 | 
             
            signing_key: 
         | 
| 96 96 | 
             
            specification_version: 4
         | 
| 97 97 | 
             
            summary: Faster SELECTs when using Sequel with pg
         |