pg 1.3.3 → 1.5.3
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 +43 -12
- data/.github/workflows/source-gem.yml +28 -20
- data/.gitignore +11 -2
- data/.travis.yml +2 -2
- data/{History.rdoc → History.md} +302 -115
- data/README.ja.md +276 -0
- data/README.md +286 -0
- data/Rakefile +15 -6
- data/Rakefile.cross +7 -11
- data/certs/larskanis-2023.pem +24 -0
- data/ext/errorcodes.def +4 -0
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +2 -1
- data/ext/extconf.rb +0 -0
- data/ext/pg.c +14 -54
- data/ext/pg.h +12 -5
- 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 +385 -266
- data/ext/pg_copy_coder.c +307 -18
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +12 -9
- data/ext/pg_result.c +117 -34
- data/ext/pg_text_decoder.c +28 -10
- data/ext/pg_text_encoder.c +23 -10
- data/ext/pg_tuple.c +36 -39
- 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 +13 -8
- data/lib/pg/basic_type_map_for_results.rb +26 -3
- data/lib/pg/basic_type_registry.rb +36 -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 +269 -139
- data/lib/pg/exceptions.rb +14 -1
- 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 +59 -19
- data/misc/openssl-pg-segfault.rb +0 -0
- data/pg.gemspec +4 -2
- data/rakelib/task_extension.rb +1 -1
- data/sample/array_insert.rb +0 -0
- data/sample/async_api.rb +3 -7
- data/sample/async_copyto.rb +0 -0
- data/sample/async_mixed.rb +0 -0
- data/sample/check_conn.rb +0 -0
- data/sample/copydata.rb +0 -0
- data/sample/copyfrom.rb +0 -0
- data/sample/copyto.rb +0 -0
- data/sample/cursor.rb +0 -0
- data/sample/disk_usage_report.rb +0 -0
- data/sample/issue-119.rb +0 -0
- data/sample/losample.rb +0 -0
- data/sample/minimal-testcase.rb +0 -0
- data/sample/notify_wait.rb +0 -0
- data/sample/pg_statistics.rb +0 -0
- data/sample/replication_monitor.rb +0 -0
- data/sample/test_binary_values.rb +0 -0
- data/sample/wal_shipper.rb +0 -0
- data/sample/warehouse_partitions.rb +0 -0
- data/translation/.po4a-version +7 -0
- data/translation/po/all.pot +910 -0
- data/translation/po/ja.po +1047 -0
- data/translation/po4a.cfg +12 -0
- data.tar.gz.sig +0 -0
- metadata +101 -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
|
+
VALUE
|
396
|
+
static 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,22 +1447,21 @@ pgresult_type_map_get(VALUE self)
|
|
1382
1447
|
}
|
1383
1448
|
|
1384
1449
|
|
1385
|
-
static
|
1386
|
-
yield_hash(VALUE self, int ntuples, int nfields)
|
1450
|
+
static int
|
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
|
1400
|
-
yield_array(VALUE self, int ntuples, int nfields)
|
1463
|
+
static int
|
1464
|
+
yield_array(VALUE self, int ntuples, int nfields, void *data)
|
1401
1465
|
{
|
1402
1466
|
int row;
|
1403
1467
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -1413,11 +1477,11 @@ yield_array(VALUE self, int ntuples, int nfields)
|
|
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
|
1420
|
-
yield_tuple(VALUE self, int ntuples, int nfields)
|
1483
|
+
static int
|
1484
|
+
yield_tuple(VALUE self, int ntuples, int nfields, void *data)
|
1421
1485
|
{
|
1422
1486
|
int tuple_num;
|
1423
1487
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -1434,16 +1498,19 @@ yield_tuple(VALUE self, int ntuples, int nfields)
|
|
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
|
-
static
|
1440
|
-
|
1504
|
+
/* Non-static, and data pointer for use by sequel_pg */
|
1505
|
+
VALUE
|
1506
|
+
pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* data)
|
1441
1507
|
{
|
1442
1508
|
t_pg_result *this;
|
1443
|
-
int nfields;
|
1509
|
+
int nfields, nfields2;
|
1444
1510
|
PGconn *pgconn;
|
1445
1511
|
PGresult *pgresult;
|
1446
1512
|
|
1513
|
+
rb_check_frozen(self);
|
1447
1514
|
RETURN_ENUMERATOR(self, 0, NULL);
|
1448
1515
|
|
1449
1516
|
this = pgresult_get_this_safe(self);
|
@@ -1456,6 +1523,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
1456
1523
|
|
1457
1524
|
switch( PQresultStatus(pgresult) ){
|
1458
1525
|
case PGRES_TUPLES_OK:
|
1526
|
+
case PGRES_COMMAND_OK:
|
1459
1527
|
if( ntuples == 0 )
|
1460
1528
|
return self;
|
1461
1529
|
rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
|
@@ -1465,14 +1533,24 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
1465
1533
|
pg_result_check( self );
|
1466
1534
|
}
|
1467
1535
|
|
1468
|
-
|
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
|
+
}
|
1545
|
+
|
1546
|
+
if( gvl_PQisBusy(pgconn) ){
|
1547
|
+
/* wait for input (without blocking) before reading each result */
|
1548
|
+
pgconn_block( 0, NULL, this->connection );
|
1549
|
+
}
|
1469
1550
|
|
1470
1551
|
pgresult = gvl_PQgetResult(pgconn);
|
1471
1552
|
if( pgresult == NULL )
|
1472
|
-
rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another
|
1473
|
-
|
1474
|
-
if( nfields != PQnfields(pgresult) )
|
1475
|
-
rb_raise( rb_eInvalidChangeOfResultFields, "number of fields must not change in single row mode");
|
1553
|
+
rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another query");
|
1476
1554
|
|
1477
1555
|
this->pgresult = pgresult;
|
1478
1556
|
}
|
@@ -1516,7 +1594,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
1516
1594
|
static VALUE
|
1517
1595
|
pgresult_stream_each(VALUE self)
|
1518
1596
|
{
|
1519
|
-
return pgresult_stream_any(self, yield_hash);
|
1597
|
+
return pgresult_stream_any(self, yield_hash, NULL);
|
1520
1598
|
}
|
1521
1599
|
|
1522
1600
|
/*
|
@@ -1532,7 +1610,7 @@ pgresult_stream_each(VALUE self)
|
|
1532
1610
|
static VALUE
|
1533
1611
|
pgresult_stream_each_row(VALUE self)
|
1534
1612
|
{
|
1535
|
-
return pgresult_stream_any(self, yield_array);
|
1613
|
+
return pgresult_stream_any(self, yield_array, NULL);
|
1536
1614
|
}
|
1537
1615
|
|
1538
1616
|
/*
|
@@ -1549,7 +1627,7 @@ pgresult_stream_each_tuple(VALUE self)
|
|
1549
1627
|
/* allocate VALUEs that are shared between all streamed tuples */
|
1550
1628
|
ensure_init_for_tuple(self);
|
1551
1629
|
|
1552
|
-
return pgresult_stream_any(self, yield_tuple);
|
1630
|
+
return pgresult_stream_any(self, yield_tuple, NULL);
|
1553
1631
|
}
|
1554
1632
|
|
1555
1633
|
/*
|
@@ -1577,6 +1655,8 @@ static VALUE
|
|
1577
1655
|
pgresult_field_name_type_set(VALUE self, VALUE sym)
|
1578
1656
|
{
|
1579
1657
|
t_pg_result *this = pgresult_get_this(self);
|
1658
|
+
|
1659
|
+
rb_check_frozen(self);
|
1580
1660
|
if( this->nfields != -1 ) rb_raise(rb_eArgError, "field names are already materialized");
|
1581
1661
|
|
1582
1662
|
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
@@ -1610,7 +1690,7 @@ pgresult_field_name_type_get(VALUE self)
|
|
1610
1690
|
}
|
1611
1691
|
|
1612
1692
|
void
|
1613
|
-
init_pg_result()
|
1693
|
+
init_pg_result(void)
|
1614
1694
|
{
|
1615
1695
|
sym_string = ID2SYM(rb_intern("string"));
|
1616
1696
|
sym_symbol = ID2SYM(rb_intern("symbol"));
|
@@ -1623,7 +1703,8 @@ init_pg_result()
|
|
1623
1703
|
|
1624
1704
|
/****** PG::Result INSTANCE METHODS: libpq ******/
|
1625
1705
|
rb_define_method(rb_cPGresult, "result_status", pgresult_result_status, 0);
|
1626
|
-
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);
|
1627
1708
|
rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
|
1628
1709
|
rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
|
1629
1710
|
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
@@ -1633,12 +1714,14 @@ init_pg_result()
|
|
1633
1714
|
rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
|
1634
1715
|
rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
|
1635
1716
|
rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
|
1717
|
+
rb_define_method(rb_cPGresult, "freeze", pg_result_freeze, 0 );
|
1636
1718
|
rb_define_method(rb_cPGresult, "check", pg_result_check, 0);
|
1637
1719
|
rb_define_alias (rb_cPGresult, "check_result", "check");
|
1638
1720
|
rb_define_method(rb_cPGresult, "ntuples", pgresult_ntuples, 0);
|
1639
1721
|
rb_define_alias(rb_cPGresult, "num_tuples", "ntuples");
|
1640
1722
|
rb_define_method(rb_cPGresult, "nfields", pgresult_nfields, 0);
|
1641
1723
|
rb_define_alias(rb_cPGresult, "num_fields", "nfields");
|
1724
|
+
rb_define_method(rb_cPGresult, "binary_tuples", pgresult_binary_tuples, 0);
|
1642
1725
|
rb_define_method(rb_cPGresult, "fname", pgresult_fname, 1);
|
1643
1726
|
rb_define_method(rb_cPGresult, "fnumber", pgresult_fnumber, 1);
|
1644
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 ); */
|