pg 1.4.1 → 1.5.6
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
- checksums.yaml.gz.sig +0 -0
- data/.appveyor.yml +15 -9
- data/.github/workflows/binary-gems.yml +45 -14
- data/.github/workflows/source-gem.yml +35 -23
- data/.gitignore +11 -2
- data/.travis.yml +2 -2
- data/Gemfile +3 -0
- data/{History.rdoc → History.md} +285 -140
- data/README.ja.md +300 -0
- data/README.md +286 -0
- data/Rakefile +18 -6
- data/Rakefile.cross +8 -11
- data/certs/kanis@comcard.de.pem +20 -0
- data/certs/larskanis-2023.pem +24 -0
- data/certs/larskanis-2024.pem +24 -0
- data/ext/errorcodes.def +4 -0
- data/ext/errorcodes.txt +2 -1
- data/ext/extconf.rb +4 -0
- data/ext/pg.c +15 -55
- data/ext/pg.h +11 -6
- data/ext/pg_binary_decoder.c +80 -1
- data/ext/pg_binary_encoder.c +225 -1
- data/ext/pg_coder.c +17 -8
- data/ext/pg_connection.c +201 -73
- data/ext/pg_copy_coder.c +307 -18
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +6 -5
- data/ext/pg_result.c +102 -26
- data/ext/pg_text_decoder.c +28 -10
- data/ext/pg_text_encoder.c +23 -10
- data/ext/pg_tuple.c +35 -32
- data/ext/pg_type_map.c +4 -3
- data/ext/pg_type_map_all_strings.c +3 -3
- data/ext/pg_type_map_by_class.c +6 -4
- data/ext/pg_type_map_by_column.c +9 -5
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +8 -5
- data/ext/pg_type_map_in_ruby.c +6 -3
- data/lib/pg/basic_type_map_based_on_result.rb +21 -1
- data/lib/pg/basic_type_map_for_queries.rb +19 -10
- data/lib/pg/basic_type_map_for_results.rb +26 -3
- data/lib/pg/basic_type_registry.rb +35 -33
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/coder.rb +15 -13
- data/lib/pg/connection.rb +186 -104
- data/lib/pg/exceptions.rb +7 -0
- data/lib/pg/text_decoder/date.rb +18 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +14 -0
- data/lib/pg/text_decoder/numeric.rb +9 -0
- data/lib/pg/text_decoder/timestamp.rb +30 -0
- data/lib/pg/text_encoder/date.rb +12 -0
- data/lib/pg/text_encoder/inet.rb +28 -0
- data/lib/pg/text_encoder/json.rb +14 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/version.rb +1 -1
- data/lib/pg.rb +55 -15
- data/pg.gemspec +5 -3
- data/rakelib/task_extension.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +96 -32
- metadata.gz.sig +0 -0
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -214
- data/lib/pg/binary_decoder.rb +0 -23
- data/lib/pg/constants.rb +0 -12
- data/lib/pg/text_decoder.rb +0 -46
- data/lib/pg/text_encoder.rb +0 -59
data/ext/pg_result.c
CHANGED
@@ -183,7 +183,7 @@ static const rb_data_type_t pgresult_type = {
|
|
183
183
|
pg_compact_callback(pgresult_gc_compact),
|
184
184
|
},
|
185
185
|
0, 0,
|
186
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
186
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
187
187
|
};
|
188
188
|
|
189
189
|
/* Needed by sequel_pg gem, do not delete */
|
@@ -208,6 +208,8 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
|
|
208
208
|
|
209
209
|
this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
|
210
210
|
this->pgresult = result;
|
211
|
+
/* Initialize connection and typemap prior to any object allocations,
|
212
|
+
* to make sure valid objects are marked. */
|
211
213
|
this->connection = rb_pgconn;
|
212
214
|
this->typemap = pg_typemap_all_strings;
|
213
215
|
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
@@ -224,7 +226,8 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
|
|
224
226
|
t_typemap *p_typemap = RTYPEDDATA_DATA(typemap);
|
225
227
|
|
226
228
|
this->enc_idx = p_conn->enc_idx;
|
227
|
-
|
229
|
+
typemap = p_typemap->funcs.fit_to_result( typemap, self );
|
230
|
+
RB_OBJ_WRITE(self, &this->typemap, typemap);
|
228
231
|
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
229
232
|
this->flags = p_conn->flags;
|
230
233
|
} else {
|
@@ -374,17 +377,37 @@ VALUE
|
|
374
377
|
pg_result_clear(VALUE self)
|
375
378
|
{
|
376
379
|
t_pg_result *this = pgresult_get_this(self);
|
380
|
+
rb_check_frozen(self);
|
377
381
|
pgresult_clear( this );
|
378
382
|
return Qnil;
|
379
383
|
}
|
380
384
|
|
385
|
+
/*
|
386
|
+
* call-seq:
|
387
|
+
* res.freeze
|
388
|
+
*
|
389
|
+
* Freeze the PG::Result object and unlink the result from the related PG::Connection.
|
390
|
+
*
|
391
|
+
* A frozen PG::Result object doesn't allow any streaming and it can't be cleared.
|
392
|
+
* It also denies setting a type_map or field_name_type.
|
393
|
+
*
|
394
|
+
*/
|
395
|
+
static VALUE
|
396
|
+
pg_result_freeze(VALUE self)
|
397
|
+
{
|
398
|
+
t_pg_result *this = pgresult_get_this(self);
|
399
|
+
|
400
|
+
RB_OBJ_WRITE(self, &this->connection, Qnil);
|
401
|
+
return rb_call_super(0, NULL);
|
402
|
+
}
|
403
|
+
|
381
404
|
/*
|
382
405
|
* call-seq:
|
383
406
|
* res.cleared? -> boolean
|
384
407
|
*
|
385
408
|
* Returns +true+ if the backend result memory has been freed.
|
386
409
|
*/
|
387
|
-
VALUE
|
410
|
+
static VALUE
|
388
411
|
pgresult_cleared_p( VALUE self )
|
389
412
|
{
|
390
413
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -401,7 +424,7 @@ pgresult_cleared_p( VALUE self )
|
|
401
424
|
* All other Result objects are automatically cleared by the GC when the object is no longer in use or manually by PG::Result#clear .
|
402
425
|
*
|
403
426
|
*/
|
404
|
-
VALUE
|
427
|
+
static VALUE
|
405
428
|
pgresult_autoclear_p( VALUE self )
|
406
429
|
{
|
407
430
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -477,7 +500,8 @@ static void pgresult_init_fnames(VALUE self)
|
|
477
500
|
|
478
501
|
for( i=0; i<nfields; i++ ){
|
479
502
|
char *cfname = PQfname(this->pgresult, i);
|
480
|
-
|
503
|
+
VALUE fname = pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
|
504
|
+
RB_OBJ_WRITE(self, &this->fnames[i], fname);
|
481
505
|
this->nfields = i + 1;
|
482
506
|
}
|
483
507
|
this->nfields = nfields;
|
@@ -527,6 +551,8 @@ static void pgresult_init_fnames(VALUE self)
|
|
527
551
|
* * +PGRES_SINGLE_TUPLE+
|
528
552
|
* * +PGRES_PIPELINE_SYNC+
|
529
553
|
* * +PGRES_PIPELINE_ABORTED+
|
554
|
+
*
|
555
|
+
* Use <tt>res.res_status</tt> to retrieve the string representation.
|
530
556
|
*/
|
531
557
|
static VALUE
|
532
558
|
pgresult_result_status(VALUE self)
|
@@ -536,16 +562,38 @@ pgresult_result_status(VALUE self)
|
|
536
562
|
|
537
563
|
/*
|
538
564
|
* call-seq:
|
539
|
-
*
|
565
|
+
* PG::Result.res_status( status ) -> String
|
540
566
|
*
|
541
567
|
* Returns the string representation of +status+.
|
542
568
|
*
|
543
569
|
*/
|
544
570
|
static VALUE
|
545
|
-
|
571
|
+
pgresult_s_res_status(VALUE self, VALUE status)
|
572
|
+
{
|
573
|
+
return rb_utf8_str_new_cstr(PQresStatus(NUM2INT(status)));
|
574
|
+
}
|
575
|
+
|
576
|
+
/*
|
577
|
+
* call-seq:
|
578
|
+
* res.res_status -> String
|
579
|
+
* res.res_status( status ) -> String
|
580
|
+
*
|
581
|
+
* Returns the string representation of the status of the result or of the provided +status+.
|
582
|
+
*
|
583
|
+
*/
|
584
|
+
static VALUE
|
585
|
+
pgresult_res_status(int argc, VALUE *argv, VALUE self)
|
546
586
|
{
|
547
587
|
t_pg_result *this = pgresult_get_this_safe(self);
|
548
|
-
VALUE ret
|
588
|
+
VALUE ret;
|
589
|
+
|
590
|
+
if( argc == 0 ){
|
591
|
+
ret = rb_str_new2(PQresStatus(PQresultStatus(this->pgresult)));
|
592
|
+
}else if( argc == 1 ){
|
593
|
+
ret = rb_str_new2(PQresStatus(NUM2INT(argv[0])));
|
594
|
+
}else{
|
595
|
+
rb_raise(rb_eArgError, "only 0 or 1 arguments expected");
|
596
|
+
}
|
549
597
|
PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
|
550
598
|
return ret;
|
551
599
|
}
|
@@ -685,6 +733,21 @@ pgresult_nfields(VALUE self)
|
|
685
733
|
return INT2NUM(PQnfields(pgresult_get(self)));
|
686
734
|
}
|
687
735
|
|
736
|
+
/*
|
737
|
+
* call-seq:
|
738
|
+
* res.binary_tuples() -> Integer
|
739
|
+
*
|
740
|
+
* Returns 1 if the PGresult contains binary data and 0 if it contains text data.
|
741
|
+
*
|
742
|
+
* This function is deprecated (except for its use in connection with COPY), because it is possible for a single PGresult to contain text data in some columns and binary data in others.
|
743
|
+
* Result#fformat is preferred. binary_tuples returns 1 only if all columns of the result are binary (format 1).
|
744
|
+
*/
|
745
|
+
static VALUE
|
746
|
+
pgresult_binary_tuples(VALUE self)
|
747
|
+
{
|
748
|
+
return INT2NUM(PQbinaryTuples(pgresult_get(self)));
|
749
|
+
}
|
750
|
+
|
688
751
|
/*
|
689
752
|
* call-seq:
|
690
753
|
* res.fname( index ) -> String or Symbol
|
@@ -1087,7 +1150,7 @@ pgresult_aref(VALUE self, VALUE index)
|
|
1087
1150
|
}
|
1088
1151
|
/* Store a copy of the filled hash for use at the next row. */
|
1089
1152
|
if( num_tuples > 10 )
|
1090
|
-
this->tuple_hash
|
1153
|
+
RB_OBJ_WRITE(self, &this->tuple_hash, rb_hash_dup(tuple));
|
1091
1154
|
|
1092
1155
|
return tuple;
|
1093
1156
|
}
|
@@ -1269,7 +1332,7 @@ static void ensure_init_for_tuple(VALUE self)
|
|
1269
1332
|
rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
|
1270
1333
|
}
|
1271
1334
|
rb_obj_freeze(field_map);
|
1272
|
-
this->field_map
|
1335
|
+
RB_OBJ_WRITE(self, &this->field_map, field_map);
|
1273
1336
|
}
|
1274
1337
|
}
|
1275
1338
|
|
@@ -1357,11 +1420,13 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
|
|
1357
1420
|
t_pg_result *this = pgresult_get_this(self);
|
1358
1421
|
t_typemap *p_typemap;
|
1359
1422
|
|
1423
|
+
rb_check_frozen(self);
|
1360
1424
|
/* Check type of method param */
|
1361
1425
|
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, p_typemap);
|
1362
1426
|
|
1363
|
-
|
1364
|
-
|
1427
|
+
typemap = p_typemap->funcs.fit_to_result( typemap, self );
|
1428
|
+
RB_OBJ_WRITE(self, &this->typemap, typemap);
|
1429
|
+
this->p_typemap = RTYPEDDATA_DATA( typemap );
|
1365
1430
|
|
1366
1431
|
return typemap;
|
1367
1432
|
}
|
@@ -1382,21 +1447,20 @@ pgresult_type_map_get(VALUE self)
|
|
1382
1447
|
}
|
1383
1448
|
|
1384
1449
|
|
1385
|
-
static
|
1450
|
+
static int
|
1386
1451
|
yield_hash(VALUE self, int ntuples, int nfields, void *data)
|
1387
1452
|
{
|
1388
1453
|
int tuple_num;
|
1389
|
-
t_pg_result *this = pgresult_get_this(self);
|
1390
1454
|
UNUSED(nfields);
|
1391
1455
|
|
1392
1456
|
for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
|
1393
1457
|
rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
|
1394
1458
|
}
|
1395
1459
|
|
1396
|
-
|
1460
|
+
return 1; /* clear the result */
|
1397
1461
|
}
|
1398
1462
|
|
1399
|
-
static
|
1463
|
+
static int
|
1400
1464
|
yield_array(VALUE self, int ntuples, int nfields, void *data)
|
1401
1465
|
{
|
1402
1466
|
int row;
|
@@ -1413,10 +1477,10 @@ yield_array(VALUE self, int ntuples, int nfields, void *data)
|
|
1413
1477
|
rb_yield( rb_ary_new4( nfields, row_values ));
|
1414
1478
|
}
|
1415
1479
|
|
1416
|
-
|
1480
|
+
return 1; /* clear the result */
|
1417
1481
|
}
|
1418
1482
|
|
1419
|
-
static
|
1483
|
+
static int
|
1420
1484
|
yield_tuple(VALUE self, int ntuples, int nfields, void *data)
|
1421
1485
|
{
|
1422
1486
|
int tuple_num;
|
@@ -1434,17 +1498,19 @@ yield_tuple(VALUE self, int ntuples, int nfields, void *data)
|
|
1434
1498
|
VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
|
1435
1499
|
rb_yield( tuple );
|
1436
1500
|
}
|
1501
|
+
return 0; /* don't clear the result */
|
1437
1502
|
}
|
1438
1503
|
|
1439
1504
|
/* Non-static, and data pointer for use by sequel_pg */
|
1440
1505
|
VALUE
|
1441
|
-
pgresult_stream_any(VALUE self,
|
1506
|
+
pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* data)
|
1442
1507
|
{
|
1443
1508
|
t_pg_result *this;
|
1444
|
-
int nfields;
|
1509
|
+
int nfields, nfields2;
|
1445
1510
|
PGconn *pgconn;
|
1446
1511
|
PGresult *pgresult;
|
1447
1512
|
|
1513
|
+
rb_check_frozen(self);
|
1448
1514
|
RETURN_ENUMERATOR(self, 0, NULL);
|
1449
1515
|
|
1450
1516
|
this = pgresult_get_this_safe(self);
|
@@ -1467,7 +1533,15 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int, void*), void* d
|
|
1467
1533
|
pg_result_check( self );
|
1468
1534
|
}
|
1469
1535
|
|
1470
|
-
|
1536
|
+
nfields2 = PQnfields(pgresult);
|
1537
|
+
if( nfields != nfields2 ){
|
1538
|
+
pgresult_clear( this );
|
1539
|
+
rb_raise( rb_eInvalidChangeOfResultFields, "number of fields changed in single row mode from %d to %d - this is a sign for intersection with another query", nfields, nfields2);
|
1540
|
+
}
|
1541
|
+
|
1542
|
+
if( yielder( self, ntuples, nfields, data ) ){
|
1543
|
+
pgresult_clear( this );
|
1544
|
+
}
|
1471
1545
|
|
1472
1546
|
if( gvl_PQisBusy(pgconn) ){
|
1473
1547
|
/* wait for input (without blocking) before reading each result */
|
@@ -1478,9 +1552,6 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int, void*), void* d
|
|
1478
1552
|
if( pgresult == NULL )
|
1479
1553
|
rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another query");
|
1480
1554
|
|
1481
|
-
if( nfields != PQnfields(pgresult) )
|
1482
|
-
rb_raise( rb_eInvalidChangeOfResultFields, "number of fields changed in single row mode from %d to %d - this is a sign for intersection with another query", nfields, PQnfields(pgresult));
|
1483
|
-
|
1484
1555
|
this->pgresult = pgresult;
|
1485
1556
|
}
|
1486
1557
|
|
@@ -1584,6 +1655,8 @@ static VALUE
|
|
1584
1655
|
pgresult_field_name_type_set(VALUE self, VALUE sym)
|
1585
1656
|
{
|
1586
1657
|
t_pg_result *this = pgresult_get_this(self);
|
1658
|
+
|
1659
|
+
rb_check_frozen(self);
|
1587
1660
|
if( this->nfields != -1 ) rb_raise(rb_eArgError, "field names are already materialized");
|
1588
1661
|
|
1589
1662
|
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
@@ -1617,7 +1690,7 @@ pgresult_field_name_type_get(VALUE self)
|
|
1617
1690
|
}
|
1618
1691
|
|
1619
1692
|
void
|
1620
|
-
init_pg_result()
|
1693
|
+
init_pg_result(void)
|
1621
1694
|
{
|
1622
1695
|
sym_string = ID2SYM(rb_intern("string"));
|
1623
1696
|
sym_symbol = ID2SYM(rb_intern("symbol"));
|
@@ -1630,7 +1703,8 @@ init_pg_result()
|
|
1630
1703
|
|
1631
1704
|
/****** PG::Result INSTANCE METHODS: libpq ******/
|
1632
1705
|
rb_define_method(rb_cPGresult, "result_status", pgresult_result_status, 0);
|
1633
|
-
rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
|
1706
|
+
rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, -1);
|
1707
|
+
rb_define_singleton_method(rb_cPGresult, "res_status", pgresult_s_res_status, 1);
|
1634
1708
|
rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
|
1635
1709
|
rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
|
1636
1710
|
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
@@ -1640,12 +1714,14 @@ init_pg_result()
|
|
1640
1714
|
rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
|
1641
1715
|
rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
|
1642
1716
|
rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
|
1717
|
+
rb_define_method(rb_cPGresult, "freeze", pg_result_freeze, 0 );
|
1643
1718
|
rb_define_method(rb_cPGresult, "check", pg_result_check, 0);
|
1644
1719
|
rb_define_alias (rb_cPGresult, "check_result", "check");
|
1645
1720
|
rb_define_method(rb_cPGresult, "ntuples", pgresult_ntuples, 0);
|
1646
1721
|
rb_define_alias(rb_cPGresult, "num_tuples", "ntuples");
|
1647
1722
|
rb_define_method(rb_cPGresult, "nfields", pgresult_nfields, 0);
|
1648
1723
|
rb_define_alias(rb_cPGresult, "num_fields", "nfields");
|
1724
|
+
rb_define_method(rb_cPGresult, "binary_tuples", pgresult_binary_tuples, 0);
|
1649
1725
|
rb_define_method(rb_cPGresult, "fname", pgresult_fname, 1);
|
1650
1726
|
rb_define_method(rb_cPGresult, "fnumber", pgresult_fnumber, 1);
|
1651
1727
|
rb_define_method(rb_cPGresult, "ftable", pgresult_ftable, 1);
|
data/ext/pg_text_decoder.c
CHANGED
@@ -43,7 +43,6 @@
|
|
43
43
|
#include <string.h>
|
44
44
|
|
45
45
|
VALUE rb_mPG_TextDecoder;
|
46
|
-
static ID s_id_decode;
|
47
46
|
static ID s_id_Rational;
|
48
47
|
static ID s_id_new;
|
49
48
|
static ID s_id_utc;
|
@@ -171,6 +170,19 @@ pg_text_dec_numeric(t_pg_coder *conv, const char *val, int len, int tuple, int f
|
|
171
170
|
return rb_funcall(rb_cObject, s_id_BigDecimal, 1, rb_str_new(val, len));
|
172
171
|
}
|
173
172
|
|
173
|
+
/* called per autoload when TextDecoder::Numeric is used */
|
174
|
+
static VALUE
|
175
|
+
init_pg_text_decoder_numeric(VALUE rb_mPG_TextDecoder)
|
176
|
+
{
|
177
|
+
rb_require("bigdecimal");
|
178
|
+
s_id_BigDecimal = rb_intern("BigDecimal");
|
179
|
+
|
180
|
+
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
|
181
|
+
pg_define_coder( "Numeric", pg_text_dec_numeric, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
182
|
+
|
183
|
+
return Qnil;
|
184
|
+
}
|
185
|
+
|
174
186
|
/*
|
175
187
|
* Document-class: PG::TextDecoder::Float < PG::SimpleDecoder
|
176
188
|
*
|
@@ -922,8 +934,9 @@ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
|
|
922
934
|
return ip;
|
923
935
|
}
|
924
936
|
|
925
|
-
|
926
|
-
|
937
|
+
/* called per autoload when TextDecoder::Inet is used */
|
938
|
+
static VALUE
|
939
|
+
init_pg_text_decoder_inet(VALUE rb_mPG_TextDecoder)
|
927
940
|
{
|
928
941
|
rb_require("ipaddr");
|
929
942
|
s_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));
|
@@ -942,14 +955,21 @@ init_pg_text_decoder()
|
|
942
955
|
s_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");
|
943
956
|
rb_global_variable(&s_vmasks6);
|
944
957
|
|
945
|
-
|
958
|
+
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
|
959
|
+
pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
960
|
+
|
961
|
+
return Qnil;
|
962
|
+
}
|
963
|
+
|
964
|
+
|
965
|
+
void
|
966
|
+
init_pg_text_decoder(void)
|
967
|
+
{
|
946
968
|
s_id_Rational = rb_intern("Rational");
|
947
969
|
s_id_new = rb_intern("new");
|
948
970
|
s_id_utc = rb_intern("utc");
|
949
971
|
s_id_getlocal = rb_intern("getlocal");
|
950
972
|
|
951
|
-
rb_require("bigdecimal");
|
952
|
-
s_id_BigDecimal = rb_intern("BigDecimal");
|
953
973
|
s_nan = rb_eval_string("0.0/0.0");
|
954
974
|
rb_global_variable(&s_nan);
|
955
975
|
s_pos_inf = rb_eval_string("1.0/0.0");
|
@@ -959,6 +979,8 @@ init_pg_text_decoder()
|
|
959
979
|
|
960
980
|
/* This module encapsulates all decoder classes with text input format */
|
961
981
|
rb_mPG_TextDecoder = rb_define_module_under( rb_mPG, "TextDecoder" );
|
982
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_inet", init_pg_text_decoder_inet, 0);
|
983
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_numeric", init_pg_text_decoder_numeric, 0);
|
962
984
|
|
963
985
|
/* Make RDoc aware of the decoder classes... */
|
964
986
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
|
@@ -967,8 +989,6 @@ init_pg_text_decoder()
|
|
967
989
|
pg_define_coder( "Integer", pg_text_dec_integer, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
968
990
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Float", rb_cPG_SimpleDecoder ); */
|
969
991
|
pg_define_coder( "Float", pg_text_dec_float, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
970
|
-
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
|
971
|
-
pg_define_coder( "Numeric", pg_text_dec_numeric, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
972
992
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "String", rb_cPG_SimpleDecoder ); */
|
973
993
|
pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
974
994
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
|
@@ -977,8 +997,6 @@ init_pg_text_decoder()
|
|
977
997
|
pg_define_coder( "Identifier", pg_text_dec_identifier, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
978
998
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
|
979
999
|
pg_define_coder( "Timestamp", pg_text_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
980
|
-
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
|
981
|
-
pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
982
1000
|
|
983
1001
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Array", rb_cPG_CompositeDecoder ); */
|
984
1002
|
pg_define_coder( "Array", pg_text_dec_array, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
|
data/ext/pg_text_encoder.c
CHANGED
@@ -371,6 +371,21 @@ pg_text_enc_numeric(t_pg_coder *this, VALUE value, char *out, VALUE *intermediat
|
|
371
371
|
}
|
372
372
|
}
|
373
373
|
|
374
|
+
/* called per autoload when TextEncoder::Numeric is used */
|
375
|
+
static VALUE
|
376
|
+
init_pg_text_encoder_numeric(VALUE rb_mPG_TextDecoder)
|
377
|
+
{
|
378
|
+
s_str_F = rb_str_freeze(rb_str_new_cstr("F"));
|
379
|
+
rb_global_variable(&s_str_F);
|
380
|
+
rb_require("bigdecimal");
|
381
|
+
s_cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
382
|
+
|
383
|
+
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Numeric", rb_cPG_SimpleEncoder ); */
|
384
|
+
pg_define_coder( "Numeric", pg_text_enc_numeric, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
385
|
+
|
386
|
+
return Qnil;
|
387
|
+
}
|
388
|
+
|
374
389
|
|
375
390
|
static const char hextab[] = {
|
376
391
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
@@ -383,8 +398,12 @@ static const char hextab[] = {
|
|
383
398
|
*
|
384
399
|
* The binary String is converted to hexadecimal representation for transmission
|
385
400
|
* in text format. For query bind parameters it is recommended to use
|
386
|
-
* PG::BinaryEncoder::Bytea
|
387
|
-
* CPU usage.
|
401
|
+
* PG::BinaryEncoder::Bytea or the hash form <tt>{value: binary_string, format: 1}</tt> instead,
|
402
|
+
* in order to decrease network traffic and CPU usage.
|
403
|
+
* See PG::Connection#exec_params for using the hash form.
|
404
|
+
*
|
405
|
+
* This encoder is particular useful when PG::TextEncoder::CopyRow is used with the COPY command.
|
406
|
+
* In this case there's no way to change the format of a single column to binary, so that the data have to be converted to bytea hex representation.
|
388
407
|
*
|
389
408
|
*/
|
390
409
|
static int
|
@@ -775,19 +794,15 @@ pg_text_enc_to_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermedi
|
|
775
794
|
|
776
795
|
|
777
796
|
void
|
778
|
-
init_pg_text_encoder()
|
797
|
+
init_pg_text_encoder(void)
|
779
798
|
{
|
780
799
|
s_id_encode = rb_intern("encode");
|
781
800
|
s_id_to_i = rb_intern("to_i");
|
782
801
|
s_id_to_s = rb_intern("to_s");
|
783
|
-
s_str_F = rb_str_freeze(rb_str_new_cstr("F"));
|
784
|
-
rb_global_variable(&s_str_F);
|
785
|
-
rb_require("bigdecimal");
|
786
|
-
s_cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
787
|
-
|
788
802
|
|
789
803
|
/* This module encapsulates all encoder classes with text output format */
|
790
804
|
rb_mPG_TextEncoder = rb_define_module_under( rb_mPG, "TextEncoder" );
|
805
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextEncoder), "init_numeric", init_pg_text_encoder_numeric, 0);
|
791
806
|
|
792
807
|
/* Make RDoc aware of the encoder classes... */
|
793
808
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Boolean", rb_cPG_SimpleEncoder ); */
|
@@ -796,8 +811,6 @@ init_pg_text_encoder()
|
|
796
811
|
pg_define_coder( "Integer", pg_text_enc_integer, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
797
812
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Float", rb_cPG_SimpleEncoder ); */
|
798
813
|
pg_define_coder( "Float", pg_text_enc_float, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
799
|
-
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Numeric", rb_cPG_SimpleEncoder ); */
|
800
|
-
pg_define_coder( "Numeric", pg_text_enc_numeric, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
801
814
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "String", rb_cPG_SimpleEncoder ); */
|
802
815
|
pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
803
816
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
|
data/ext/pg_tuple.c
CHANGED
@@ -128,7 +128,7 @@ static const rb_data_type_t pg_tuple_type = {
|
|
128
128
|
pg_compact_callback(pg_tuple_gc_compact),
|
129
129
|
},
|
130
130
|
0, 0,
|
131
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
131
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
132
132
|
};
|
133
133
|
|
134
134
|
/*
|
@@ -159,9 +159,9 @@ pg_tuple_new(VALUE result, int row_num)
|
|
159
159
|
sizeof(*this->values) * num_fields +
|
160
160
|
sizeof(*this->values) * (dup_names ? 1 : 0));
|
161
161
|
|
162
|
-
this->result
|
163
|
-
this->typemap
|
164
|
-
this->field_map
|
162
|
+
RB_OBJ_WRITE(self, &this->result, result);
|
163
|
+
RB_OBJ_WRITE(self, &this->typemap, p_result->typemap);
|
164
|
+
RB_OBJ_WRITE(self, &this->field_map, field_map);
|
165
165
|
this->row_num = row_num;
|
166
166
|
this->num_fields = num_fields;
|
167
167
|
|
@@ -173,7 +173,8 @@ pg_tuple_new(VALUE result, int row_num)
|
|
173
173
|
/* Some of the column names are duplicated -> we need the keys as Array in addition.
|
174
174
|
* Store it behind the values to save the space in the common case of no dups.
|
175
175
|
*/
|
176
|
-
|
176
|
+
VALUE keys_array = rb_obj_freeze(rb_ary_new4(num_fields, p_result->fnames));
|
177
|
+
RB_OBJ_WRITE(self, &this->values[num_fields], keys_array);
|
177
178
|
}
|
178
179
|
|
179
180
|
RTYPEDDATA_DATA(self) = this;
|
@@ -193,8 +194,9 @@ pg_tuple_get_this( VALUE self )
|
|
193
194
|
}
|
194
195
|
|
195
196
|
static VALUE
|
196
|
-
pg_tuple_materialize_field(
|
197
|
+
pg_tuple_materialize_field(VALUE self, int col)
|
197
198
|
{
|
199
|
+
t_pg_tuple *this = RTYPEDDATA_DATA( self );
|
198
200
|
VALUE value = this->values[col];
|
199
201
|
|
200
202
|
if( value == Qundef ){
|
@@ -202,29 +204,31 @@ pg_tuple_materialize_field(t_pg_tuple *this, int col)
|
|
202
204
|
|
203
205
|
pgresult_get(this->result); /* make sure we have a valid PGresult object */
|
204
206
|
value = p_typemap->funcs.typecast_result_value(p_typemap, this->result, this->row_num, col);
|
205
|
-
this->values[col]
|
207
|
+
RB_OBJ_WRITE(self, &this->values[col], value);
|
206
208
|
}
|
207
209
|
|
208
210
|
return value;
|
209
211
|
}
|
210
212
|
|
211
213
|
static void
|
212
|
-
pg_tuple_detach(
|
214
|
+
pg_tuple_detach(VALUE self)
|
213
215
|
{
|
214
|
-
this
|
215
|
-
this->
|
216
|
+
t_pg_tuple *this = RTYPEDDATA_DATA( self );
|
217
|
+
RB_OBJ_WRITE(self, &this->result, Qnil);
|
218
|
+
RB_OBJ_WRITE(self, &this->typemap, Qnil);
|
216
219
|
this->row_num = -1;
|
217
220
|
}
|
218
221
|
|
219
222
|
static void
|
220
|
-
pg_tuple_materialize(
|
223
|
+
pg_tuple_materialize(VALUE self)
|
221
224
|
{
|
225
|
+
t_pg_tuple *this = RTYPEDDATA_DATA( self );
|
222
226
|
int field_num;
|
223
227
|
for(field_num = 0; field_num < this->num_fields; field_num++) {
|
224
|
-
pg_tuple_materialize_field(
|
228
|
+
pg_tuple_materialize_field(self, field_num);
|
225
229
|
}
|
226
230
|
|
227
|
-
pg_tuple_detach(
|
231
|
+
pg_tuple_detach(self);
|
228
232
|
}
|
229
233
|
|
230
234
|
/*
|
@@ -286,7 +290,7 @@ pg_tuple_fetch(int argc, VALUE *argv, VALUE self)
|
|
286
290
|
field_num = NUM2INT(index);
|
287
291
|
}
|
288
292
|
|
289
|
-
return pg_tuple_materialize_field(
|
293
|
+
return pg_tuple_materialize_field(self, field_num);
|
290
294
|
}
|
291
295
|
|
292
296
|
/*
|
@@ -324,7 +328,7 @@ pg_tuple_aref(VALUE self, VALUE key)
|
|
324
328
|
field_num = NUM2INT(index);
|
325
329
|
}
|
326
330
|
|
327
|
-
return pg_tuple_materialize_field(
|
331
|
+
return pg_tuple_materialize_field(self, field_num);
|
328
332
|
}
|
329
333
|
|
330
334
|
static VALUE
|
@@ -335,10 +339,9 @@ pg_tuple_num_fields_for_enum(VALUE self, VALUE args, VALUE eobj)
|
|
335
339
|
}
|
336
340
|
|
337
341
|
static int
|
338
|
-
pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE
|
342
|
+
pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE self)
|
339
343
|
{
|
340
|
-
|
341
|
-
VALUE value = pg_tuple_materialize_field(this, NUM2INT(index));
|
344
|
+
VALUE value = pg_tuple_materialize_field(self, NUM2INT(index));
|
342
345
|
rb_yield_values(2, key, value);
|
343
346
|
return ST_CONTINUE;
|
344
347
|
}
|
@@ -360,16 +363,16 @@ pg_tuple_each(VALUE self)
|
|
360
363
|
field_names = pg_tuple_get_field_names(this);
|
361
364
|
|
362
365
|
if( field_names == Qfalse ){
|
363
|
-
rb_hash_foreach(this->field_map, pg_tuple_yield_key_value,
|
366
|
+
rb_hash_foreach(this->field_map, pg_tuple_yield_key_value, self);
|
364
367
|
} else {
|
365
368
|
int i;
|
366
369
|
for( i = 0; i < this->num_fields; i++ ){
|
367
|
-
VALUE value = pg_tuple_materialize_field(
|
370
|
+
VALUE value = pg_tuple_materialize_field(self, i);
|
368
371
|
rb_yield_values(2, RARRAY_AREF(field_names, i), value);
|
369
372
|
}
|
370
373
|
}
|
371
374
|
|
372
|
-
pg_tuple_detach(
|
375
|
+
pg_tuple_detach(self);
|
373
376
|
return self;
|
374
377
|
}
|
375
378
|
|
@@ -388,11 +391,11 @@ pg_tuple_each_value(VALUE self)
|
|
388
391
|
RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
|
389
392
|
|
390
393
|
for(field_num = 0; field_num < this->num_fields; field_num++) {
|
391
|
-
VALUE value = pg_tuple_materialize_field(
|
394
|
+
VALUE value = pg_tuple_materialize_field(self, field_num);
|
392
395
|
rb_yield(value);
|
393
396
|
}
|
394
397
|
|
395
|
-
pg_tuple_detach(
|
398
|
+
pg_tuple_detach(self);
|
396
399
|
return self;
|
397
400
|
}
|
398
401
|
|
@@ -409,7 +412,7 @@ pg_tuple_values(VALUE self)
|
|
409
412
|
{
|
410
413
|
t_pg_tuple *this = pg_tuple_get_this(self);
|
411
414
|
|
412
|
-
pg_tuple_materialize(
|
415
|
+
pg_tuple_materialize(self);
|
413
416
|
return rb_ary_new4(this->num_fields, &this->values[0]);
|
414
417
|
}
|
415
418
|
|
@@ -462,7 +465,7 @@ pg_tuple_dump(VALUE self)
|
|
462
465
|
VALUE a;
|
463
466
|
t_pg_tuple *this = pg_tuple_get_this(self);
|
464
467
|
|
465
|
-
pg_tuple_materialize(
|
468
|
+
pg_tuple_materialize(self);
|
466
469
|
|
467
470
|
field_names = pg_tuple_get_field_names(this);
|
468
471
|
if( field_names == Qfalse )
|
@@ -520,32 +523,32 @@ pg_tuple_load(VALUE self, VALUE a)
|
|
520
523
|
sizeof(*this->values) * num_fields +
|
521
524
|
sizeof(*this->values) * (dup_names ? 1 : 0));
|
522
525
|
|
523
|
-
this->result
|
524
|
-
this->typemap
|
526
|
+
RB_OBJ_WRITE(self, &this->result, Qnil);
|
527
|
+
RB_OBJ_WRITE(self, &this->typemap, Qnil);
|
525
528
|
this->row_num = -1;
|
526
529
|
this->num_fields = num_fields;
|
527
|
-
this->field_map
|
530
|
+
RB_OBJ_WRITE(self, &this->field_map, field_map);
|
528
531
|
|
529
532
|
for( i = 0; i < num_fields; i++ ){
|
530
533
|
VALUE v = RARRAY_AREF(values, i);
|
531
534
|
if( v == Qundef )
|
532
535
|
rb_raise(rb_eTypeError, "field %d is not materialized", i);
|
533
|
-
this->values[i]
|
536
|
+
RB_OBJ_WRITE(self, &this->values[i], v);
|
534
537
|
}
|
535
538
|
|
536
539
|
if( dup_names ){
|
537
|
-
this->values[num_fields]
|
540
|
+
RB_OBJ_WRITE(self, &this->values[num_fields], field_names);
|
538
541
|
}
|
539
542
|
|
540
543
|
RTYPEDDATA_DATA(self) = this;
|
541
544
|
|
542
|
-
|
545
|
+
rb_copy_generic_ivar(self, a);
|
543
546
|
|
544
547
|
return self;
|
545
548
|
}
|
546
549
|
|
547
550
|
void
|
548
|
-
init_pg_tuple()
|
551
|
+
init_pg_tuple(void)
|
549
552
|
{
|
550
553
|
rb_cPG_Tuple = rb_define_class_under( rb_mPG, "Tuple", rb_cObject );
|
551
554
|
rb_define_alloc_func( rb_cPG_Tuple, pg_tuple_s_allocate );
|