sequel_pg 1.15.0 → 1.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +8 -0
- data/README.rdoc +10 -3
- data/Rakefile +23 -2
- data/ext/sequel_pg/extconf.rb +1 -0
- data/ext/sequel_pg/sequel_pg.c +33 -30
- data/lib/sequel/extensions/pg_streaming.rb +6 -0
- data/lib/sequel_pg/sequel_pg.rb +4 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7bcc241985851b36df5d4e199e1edc08626fa8dcd23065aefd13b4cafd135a9
|
4
|
+
data.tar.gz: 8816059db9824f1396cb9d734c1b12f1c4ccb38c13ebc4a9c953a78cfff90fdd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2220c53c58d8bd549f66849529584dcf836495f0f55dc5819bd01841131e213f24cdcda089ae63a9703ae08c6c5ae5514160b1ce1f181e1277d099765d2f683b
|
7
|
+
data.tar.gz: 6ac01c39dddb568d29100e9bcd3a326d8bcc1b0cd4a54a4c507793fd0817d0709bfabbe6252873c7b422e8ed68f8a6b6d8f77f13b69d1012965b314611734a9c
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 1.16.0 (2022-08-16)
|
2
|
+
|
3
|
+
* Fix memory leak when using streaming with 1.3.4+ (jeremyevans) (#48)
|
4
|
+
|
5
|
+
* Modify LDFLAGS when building on MacOS arm64 to allow undefined functions (maxsz) (#46)
|
6
|
+
|
7
|
+
* Adjust many internal C types to fix compilation warnings (jeremyevans)
|
8
|
+
|
1
9
|
=== 1.15.0 (2022-03-16)
|
2
10
|
|
3
11
|
* Avoid deprecation warning in the pg_streaming extension on pg 1.3+ when streaming a query with bound parameters (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -77,9 +77,16 @@ variables to specify the shared library and header directories.
|
|
77
77
|
|
78
78
|
== Running the specs
|
79
79
|
|
80
|
-
sequel_pg
|
81
|
-
|
82
|
-
|
80
|
+
sequel_pg is designed to replace a part of Sequel, so it shold be tested
|
81
|
+
using Sequel's specs (the spec_postgres rake task). There is a spec_cov
|
82
|
+
task that assumes you have Sequel checked out at ../sequel, and uses a
|
83
|
+
small spec suite for parts of sequel_pg not covered by Sequel's specs.
|
84
|
+
It sets the SEQUEL_PG_STREAM environment variable when running Sequel's
|
85
|
+
specs, make sure that spec/spec_config.rb in Sequel is set to connect
|
86
|
+
to PostgreSQL and use the following additional settings:
|
87
|
+
|
88
|
+
DB.extension(:pg_streaming)
|
89
|
+
DB.stream_all_queries = true
|
83
90
|
|
84
91
|
== Reporting issues/bugs
|
85
92
|
|
data/Rakefile
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
require "rake"
|
2
1
|
require "rake/clean"
|
3
2
|
|
4
|
-
CLEAN.include %w'**.rbc rdoc'
|
3
|
+
CLEAN.include %w'**.rbc rdoc coverage'
|
5
4
|
|
6
5
|
desc "Do a full cleaning"
|
7
6
|
task :distclean do
|
@@ -19,3 +18,25 @@ begin
|
|
19
18
|
Rake::ExtensionTask.new('sequel_pg')
|
20
19
|
rescue LoadError
|
21
20
|
end
|
21
|
+
|
22
|
+
# This assumes you have sequel checked out in ../sequel, and that
|
23
|
+
# spec_postgres is setup to run Sequel's PostgreSQL specs.
|
24
|
+
desc "Run tests with coverage"
|
25
|
+
task :spec_cov=>:compile do
|
26
|
+
ENV['RUBYLIB'] = "#{__dir__}/lib:#{ENV['RUBYLIB']}"
|
27
|
+
ENV['RUBYOPT'] = "-r #{__dir__}/spec/coverage_helper.rb #{ENV['RUBYOPT']}"
|
28
|
+
ENV['SIMPLECOV_COMMAND_NAME'] = "sequel_pg"
|
29
|
+
sh %'#{FileUtils::RUBY} -I ../sequel/lib spec/sequel_pg_spec.rb'
|
30
|
+
|
31
|
+
ENV['RUBYOPT'] = "-I lib -r sequel -r sequel/extensions/pg_array #{ENV['RUBYOPT']}"
|
32
|
+
ENV['SEQUEL_PG_STREAM'] = "1"
|
33
|
+
ENV['SIMPLECOV_COMMAND_NAME'] = "sequel"
|
34
|
+
sh %'cd ../sequel && #{FileUtils::RUBY} spec/adapter_spec.rb postgres'
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Run CI tests"
|
38
|
+
task :spec_ci=>:compile do
|
39
|
+
ENV['SEQUEL_PG_SPEC_URL'] = ENV['SEQUEL_POSTGRES_URL'] = "postgres://localhost/?user=postgres&password=postgres"
|
40
|
+
sh %'#{FileUtils::RUBY} -I lib -I sequel/lib spec/sequel_pg_spec.rb'
|
41
|
+
sh %'cd sequel && #{FileUtils::RUBY} -I lib -I ../lib spec/adapter_spec.rb postgres'
|
42
|
+
end
|
data/ext/sequel_pg/extconf.rb
CHANGED
@@ -2,6 +2,7 @@ require 'mkmf'
|
|
2
2
|
$CFLAGS << " -O0 -g" if ENV['DEBUG']
|
3
3
|
$CFLAGS << " -Drb_tainted_str_new=rb_str_new -DNO_TAINT" if RUBY_VERSION >= '2.7'
|
4
4
|
$CFLAGS << " -Wall " unless RUBY_PLATFORM =~ /solaris/
|
5
|
+
$LDFLAGS += " -Wl,-U,_pg_get_pgconn -Wl,-U,_pg_get_result_enc_idx -Wl,-U,_pgresult_get -Wl,-U,_pgresult_stream_any " if RUBY_PLATFORM =~ /arm64-darwin/
|
5
6
|
dir_config('pg', ENV["POSTGRES_INCLUDE"] || (IO.popen("pg_config --includedir").readline.chomp rescue nil),
|
6
7
|
ENV["POSTGRES_LIB"] || (IO.popen("pg_config --libdir").readline.chomp rescue nil))
|
7
8
|
|
data/ext/sequel_pg/sequel_pg.c
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#define SEQUEL_PG_VERSION_INTEGER
|
1
|
+
#define SEQUEL_PG_VERSION_INTEGER 11600
|
2
2
|
|
3
3
|
#include <string.h>
|
4
4
|
#include <stdio.h>
|
@@ -199,10 +199,10 @@ static int enc_get_index(VALUE val) {
|
|
199
199
|
} while(0)
|
200
200
|
|
201
201
|
static VALUE
|
202
|
-
pg_text_dec_integer(char *val,
|
202
|
+
pg_text_dec_integer(char *val, size_t len)
|
203
203
|
{
|
204
204
|
long i;
|
205
|
-
|
205
|
+
size_t max_len;
|
206
206
|
|
207
207
|
if( sizeof(i) >= 8 && FIXNUM_MAX >= 1000000000000000000LL ){
|
208
208
|
/* 64 bit system can safely handle all numbers up to 18 digits as Fixnum */
|
@@ -257,7 +257,7 @@ pg_text_dec_integer(char *val, int len)
|
|
257
257
|
|
258
258
|
static VALUE spg__array_col_value(char *v, size_t length, VALUE converter, int enc_index, int oid, VALUE db);
|
259
259
|
|
260
|
-
static VALUE read_array(int *index, char *c_pg_array_string,
|
260
|
+
static VALUE read_array(int *index, char *c_pg_array_string, long array_string_length, VALUE buf, VALUE converter, int enc_index, int oid, VALUE db) {
|
261
261
|
int word_index = 0;
|
262
262
|
char *word = RSTRING_PTR(buf);
|
263
263
|
|
@@ -353,7 +353,7 @@ static VALUE read_array(int *index, char *c_pg_array_string, int array_string_le
|
|
353
353
|
return array;
|
354
354
|
}
|
355
355
|
|
356
|
-
static VALUE check_pg_array(int* index, char *c_pg_array_string,
|
356
|
+
static VALUE check_pg_array(int* index, char *c_pg_array_string, long array_string_length) {
|
357
357
|
if (array_string_length == 0) {
|
358
358
|
rb_raise(rb_eArgError, "unexpected PostgreSQL array format, empty");
|
359
359
|
} else if (array_string_length == 2 && c_pg_array_string[0] == '{' && c_pg_array_string[0] == '}') {
|
@@ -384,7 +384,7 @@ static VALUE parse_pg_array(VALUE self, VALUE pg_array_string, VALUE converter)
|
|
384
384
|
/* convert to c-string, create additional ruby string buffer of
|
385
385
|
* the same length, as that will be the worst case. */
|
386
386
|
char *c_pg_array_string = StringValueCStr(pg_array_string);
|
387
|
-
|
387
|
+
long array_string_length = RSTRING_LEN(pg_array_string);
|
388
388
|
int index = 1;
|
389
389
|
VALUE ary;
|
390
390
|
|
@@ -1012,12 +1012,12 @@ static int spg_timestamp_info_bitmask(VALUE self) {
|
|
1012
1012
|
return tz;
|
1013
1013
|
}
|
1014
1014
|
|
1015
|
-
static VALUE spg__col_value(VALUE self, PGresult *res,
|
1015
|
+
static VALUE spg__col_value(VALUE self, PGresult *res, int i, int j, VALUE* colconvert, int enc_index) {
|
1016
1016
|
char *v;
|
1017
1017
|
VALUE rv;
|
1018
1018
|
int ftype = PQftype(res, j);
|
1019
1019
|
VALUE array_type;
|
1020
|
-
|
1020
|
+
int scalar_oid;
|
1021
1021
|
struct spg_blob_initialization bi;
|
1022
1022
|
|
1023
1023
|
if(PQgetisnull(res, i, j)) {
|
@@ -1251,20 +1251,20 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co
|
|
1251
1251
|
return rv;
|
1252
1252
|
}
|
1253
1253
|
|
1254
|
-
static VALUE spg__col_values(VALUE self, VALUE v, VALUE *colsyms, long nfields, PGresult *res,
|
1254
|
+
static VALUE spg__col_values(VALUE self, VALUE v, VALUE *colsyms, long nfields, PGresult *res, int i, VALUE *colconvert, int enc_index) {
|
1255
1255
|
long j;
|
1256
1256
|
VALUE cur;
|
1257
1257
|
long len = RARRAY_LEN(v);
|
1258
1258
|
VALUE a = rb_ary_new2(len);
|
1259
1259
|
for (j=0; j<len; j++) {
|
1260
1260
|
cur = rb_ary_entry(v, j);
|
1261
|
-
rb_ary_store(a, j, cur == Qnil ? Qnil : spg__col_value(self, res, i,
|
1261
|
+
rb_ary_store(a, j, cur == Qnil ? Qnil : spg__col_value(self, res, i, NUM2INT(cur), colconvert, enc_index));
|
1262
1262
|
}
|
1263
1263
|
return a;
|
1264
1264
|
}
|
1265
1265
|
|
1266
|
-
static
|
1267
|
-
|
1266
|
+
static int spg__field_id(VALUE v, VALUE *colsyms, long nfields) {
|
1267
|
+
int j;
|
1268
1268
|
for (j=0; j<nfields; j++) {
|
1269
1269
|
if (colsyms[j] == v) {
|
1270
1270
|
return j;
|
@@ -1275,7 +1275,7 @@ static long spg__field_id(VALUE v, VALUE *colsyms, long nfields) {
|
|
1275
1275
|
|
1276
1276
|
static VALUE spg__field_ids(VALUE v, VALUE *colsyms, long nfields) {
|
1277
1277
|
long i;
|
1278
|
-
|
1278
|
+
int j;
|
1279
1279
|
VALUE cur;
|
1280
1280
|
long len = RARRAY_LEN(v);
|
1281
1281
|
VALUE pg_columns = rb_ary_new2(len);
|
@@ -1288,9 +1288,9 @@ static VALUE spg__field_ids(VALUE v, VALUE *colsyms, long nfields) {
|
|
1288
1288
|
}
|
1289
1289
|
|
1290
1290
|
static void spg_set_column_info(VALUE self, PGresult *res, VALUE *colsyms, VALUE *colconvert, int enc_index) {
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1291
|
+
int i;
|
1292
|
+
int j;
|
1293
|
+
int nfields;
|
1294
1294
|
int timestamp_info = 0;
|
1295
1295
|
int time_info = 0;
|
1296
1296
|
VALUE conv_procs = 0;
|
@@ -1380,10 +1380,10 @@ static void spg_set_column_info(VALUE self, PGresult *res, VALUE *colsyms, VALUE
|
|
1380
1380
|
}
|
1381
1381
|
|
1382
1382
|
static VALUE spg_yield_hash_rows_internal(VALUE self, PGresult *res, int enc_index, VALUE* colsyms, VALUE* colconvert) {
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1383
|
+
int ntuples;
|
1384
|
+
int nfields;
|
1385
|
+
int i;
|
1386
|
+
int j;
|
1387
1387
|
VALUE h;
|
1388
1388
|
VALUE opts;
|
1389
1389
|
VALUE pg_type;
|
@@ -1483,7 +1483,7 @@ static VALUE spg_yield_hash_rows_internal(VALUE self, PGresult *res, int enc_ind
|
|
1483
1483
|
case SPG_YIELD_KV_HASH_GROUPS:
|
1484
1484
|
/* Hash with single key and single value */
|
1485
1485
|
{
|
1486
|
-
|
1486
|
+
int k, v;
|
1487
1487
|
h = rb_hash_new();
|
1488
1488
|
k = spg__field_id(rb_ary_entry(pg_value, 0), colsyms, nfields);
|
1489
1489
|
v = spg__field_id(rb_ary_entry(pg_value, 1), colsyms, nfields);
|
@@ -1511,7 +1511,8 @@ static VALUE spg_yield_hash_rows_internal(VALUE self, PGresult *res, int enc_ind
|
|
1511
1511
|
case SPG_YIELD_MKV_HASH_GROUPS:
|
1512
1512
|
/* Hash with array of keys and single value */
|
1513
1513
|
{
|
1514
|
-
VALUE k
|
1514
|
+
VALUE k;
|
1515
|
+
int v;
|
1515
1516
|
h = rb_hash_new();
|
1516
1517
|
k = spg__field_ids(rb_ary_entry(pg_value, 0), colsyms, nfields);
|
1517
1518
|
v = spg__field_id(rb_ary_entry(pg_value, 1), colsyms, nfields);
|
@@ -1539,7 +1540,8 @@ static VALUE spg_yield_hash_rows_internal(VALUE self, PGresult *res, int enc_ind
|
|
1539
1540
|
case SPG_YIELD_KMV_HASH_GROUPS:
|
1540
1541
|
/* Hash with single keys and array of values */
|
1541
1542
|
{
|
1542
|
-
VALUE
|
1543
|
+
VALUE v;
|
1544
|
+
int k;
|
1543
1545
|
h = rb_hash_new();
|
1544
1546
|
k = spg__field_id(rb_ary_entry(pg_value, 0), colsyms, nfields);
|
1545
1547
|
v = spg__field_ids(rb_ary_entry(pg_value, 1), colsyms, nfields);
|
@@ -1621,7 +1623,7 @@ def_spg_yield_hash_rows(1664)
|
|
1621
1623
|
|
1622
1624
|
static VALUE spg_yield_hash_rows(VALUE self, VALUE rres, VALUE ignore) {
|
1623
1625
|
PGresult *res;
|
1624
|
-
|
1626
|
+
int nfields;
|
1625
1627
|
int enc_index;
|
1626
1628
|
|
1627
1629
|
if (!RTEST(rres)) {
|
@@ -1636,7 +1638,7 @@ static VALUE spg_yield_hash_rows(VALUE self, VALUE rres, VALUE ignore) {
|
|
1636
1638
|
else if (nfields <= 64) return spg_yield_hash_rows_64(self, res, enc_index);
|
1637
1639
|
else if (nfields <= 256) return spg_yield_hash_rows_256(self, res, enc_index);
|
1638
1640
|
else if (nfields <= 1664) return spg_yield_hash_rows_1664(self, res, enc_index);
|
1639
|
-
else rb_raise(rb_eRangeError, "more than 1664 columns in query (%
|
1641
|
+
else rb_raise(rb_eRangeError, "more than 1664 columns in query (%d columns detected)", nfields);
|
1640
1642
|
|
1641
1643
|
/* UNREACHABLE */
|
1642
1644
|
return self;
|
@@ -1678,7 +1680,7 @@ static void spg__yield_each_row_stream(VALUE rres, int ntuples, int nfields, voi
|
|
1678
1680
|
VALUE *colconvert= data->colconvert;
|
1679
1681
|
PGresult *res = pgresult_get(rres);
|
1680
1682
|
int enc_index = data->enc_index;
|
1681
|
-
|
1683
|
+
int j;
|
1682
1684
|
|
1683
1685
|
for(j=0; j<nfields; j++) {
|
1684
1686
|
rb_hash_aset(h, colsyms[j], spg__col_value(self, res, 0, j, colconvert , enc_index));
|
@@ -1691,11 +1693,12 @@ static void spg__yield_each_row_stream(VALUE rres, int ntuples, int nfields, voi
|
|
1691
1693
|
} else {
|
1692
1694
|
rb_yield(h);
|
1693
1695
|
}
|
1696
|
+
PQclear(res);
|
1694
1697
|
}
|
1695
1698
|
|
1696
1699
|
static VALUE spg__yield_each_row_internal(VALUE self, VALUE rconn, VALUE rres, PGresult *res, int enc_index, VALUE *colsyms, VALUE *colconvert) {
|
1697
|
-
|
1698
|
-
|
1700
|
+
int nfields;
|
1701
|
+
int j;
|
1699
1702
|
VALUE h;
|
1700
1703
|
VALUE opts;
|
1701
1704
|
VALUE pg_type;
|
@@ -1776,7 +1779,7 @@ static VALUE spg__yield_each_row(VALUE self) {
|
|
1776
1779
|
VALUE rres;
|
1777
1780
|
VALUE rconn;
|
1778
1781
|
int enc_index;
|
1779
|
-
|
1782
|
+
int nfields;
|
1780
1783
|
|
1781
1784
|
rconn = rb_ary_entry(self, 1);
|
1782
1785
|
self = rb_ary_entry(self, 0);
|
@@ -1797,7 +1800,7 @@ static VALUE spg__yield_each_row(VALUE self) {
|
|
1797
1800
|
else if (nfields <= 1664) return spg__yield_each_row_1664(self, rconn, rres, res, enc_index);
|
1798
1801
|
else {
|
1799
1802
|
rb_funcall(rres, spg_id_clear, 0);
|
1800
|
-
rb_raise(rb_eRangeError, "more than 1664 columns in query (%
|
1803
|
+
rb_raise(rb_eRangeError, "more than 1664 columns in query (%d columns detected)", nfields);
|
1801
1804
|
}
|
1802
1805
|
|
1803
1806
|
/* UNREACHABLE */
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# :nocov:
|
1
2
|
unless Sequel::Postgres.respond_to?(:supports_streaming?)
|
2
3
|
raise LoadError, "either sequel_pg not loaded, or an old version of sequel_pg loaded"
|
3
4
|
end
|
4
5
|
unless Sequel::Postgres.supports_streaming?
|
5
6
|
raise LoadError, "streaming is not supported by the version of libpq in use"
|
6
7
|
end
|
8
|
+
# :nocov:
|
7
9
|
|
8
10
|
# Database methods necessary to support streaming. You should load this extension
|
9
11
|
# into your database object:
|
@@ -73,11 +75,13 @@ module Sequel::Postgres::Streaming
|
|
73
75
|
|
74
76
|
private
|
75
77
|
|
78
|
+
# :nocov:
|
76
79
|
unless Sequel::Postgres::Adapter.method_defined?(:send_query_params)
|
77
80
|
def send_query_params(*args)
|
78
81
|
send_query(*args)
|
79
82
|
end
|
80
83
|
end
|
84
|
+
# :nocov:
|
81
85
|
|
82
86
|
if Sequel::Database.instance_methods.map(&:to_s).include?('log_connection_yield')
|
83
87
|
# If using single row mode, send the query instead of executing it.
|
@@ -93,6 +97,7 @@ module Sequel::Postgres::Streaming
|
|
93
97
|
end
|
94
98
|
end
|
95
99
|
else
|
100
|
+
# :nocov:
|
96
101
|
def execute_query(sql, args)
|
97
102
|
if @single_row_mode
|
98
103
|
@single_row_mode = false
|
@@ -104,6 +109,7 @@ module Sequel::Postgres::Streaming
|
|
104
109
|
super
|
105
110
|
end
|
106
111
|
end
|
112
|
+
# :nocov:
|
107
113
|
end
|
108
114
|
end
|
109
115
|
|
data/lib/sequel_pg/sequel_pg.rb
CHANGED
@@ -53,11 +53,13 @@ class Sequel::Postgres::Dataset
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
# :nocov:
|
56
57
|
unless Sequel::Dataset.method_defined?(:as_hash)
|
57
58
|
# Handle previous versions of Sequel that use to_hash instead of as_hash
|
58
59
|
alias to_hash as_hash
|
59
60
|
remove_method :as_hash
|
60
61
|
end
|
62
|
+
# :nocov:
|
61
63
|
|
62
64
|
# In the case where both arguments given, use an optimized version.
|
63
65
|
def to_hash_groups(key_column, value_column = nil, opts = Sequel::OPTS)
|
@@ -120,8 +122,10 @@ if defined?(Sequel::Postgres::PGArray)
|
|
120
122
|
# pg_array extension previously loaded
|
121
123
|
|
122
124
|
class Sequel::Postgres::PGArray::Creator
|
125
|
+
# :nocov:
|
123
126
|
# Avoid method redefined verbose warning
|
124
127
|
alias call call if method_defined?(:call)
|
128
|
+
# :nocov:
|
125
129
|
|
126
130
|
# Override Creator to use sequel_pg's C-based parser instead of the pure ruby parser.
|
127
131
|
def call(string)
|
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.16.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: 2022-
|
11
|
+
date: 2022-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|