sequel_pg 1.5.1-x86-mingw32 → 1.6.1-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +8 -0
- data/README.rdoc +7 -4
- data/ext/sequel_pg/extconf.rb +1 -1
- data/ext/sequel_pg/sequel_pg.c +121 -172
- data/lib/1.8/sequel_pg.so +0 -0
- data/lib/1.9/sequel_pg.so +0 -0
- data/lib/sequel/extensions/pg_streaming.rb +130 -0
- metadata +8 -8
- data/lib/sequel_pg/streaming.rb +0 -82
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 1.6.1 (2012-10-25)
|
2
|
+
|
3
|
+
* Make PostgreSQL array parser handle string encodings correctly on ruby 1.9 (jeremyevans)
|
4
|
+
|
5
|
+
=== 1.6.0 (2012-09-04)
|
6
|
+
|
7
|
+
* Replace PQsetRowProcessor streaming with PQsetSingleRowMode streaming introduced in PostgreSQL 9.2beta3 (jeremyevans)
|
8
|
+
|
1
9
|
=== 1.5.1 (2012-08-02)
|
2
10
|
|
3
11
|
* Sprinkle some RB_GC_GUARD to work around segfaults in the PostgreSQL array parser (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -65,7 +65,7 @@ enable the model optimization via:
|
|
65
65
|
|
66
66
|
== Streaming
|
67
67
|
|
68
|
-
If you are using PostgreSQL 9.
|
68
|
+
If you are using PostgreSQL 9.2beta3 or higher on the client, then sequel_pg
|
69
69
|
should enable streaming support. This allows you to stream returned
|
70
70
|
rows one at a time, instead of collecting the entire result set in
|
71
71
|
memory (which is how PostgreSQL works by default). You can check
|
@@ -76,8 +76,7 @@ if streaming is supported by:
|
|
76
76
|
If streaming is supported, you can load the streaming support into the
|
77
77
|
database:
|
78
78
|
|
79
|
-
|
80
|
-
DB.extend Sequel::Postgres::Streaming
|
79
|
+
DB.extension(:pg_streaming)
|
81
80
|
|
82
81
|
Then you can call the Dataset#stream method to have the dataset use
|
83
82
|
the streaming support:
|
@@ -87,7 +86,11 @@ the streaming support:
|
|
87
86
|
If you want to enable streaming for all of a database's datasets, you
|
88
87
|
can do the following:
|
89
88
|
|
90
|
-
DB.
|
89
|
+
DB.stream_all_queries = true
|
90
|
+
|
91
|
+
Note that pg 0.14.1+ is required for streaming to work. This is not
|
92
|
+
required by the gem, as it is only a requirement for streaming, not
|
93
|
+
for general use.
|
91
94
|
|
92
95
|
== Installing the gem
|
93
96
|
|
data/ext/sequel_pg/extconf.rb
CHANGED
@@ -14,7 +14,7 @@ if enable_config("static-build")
|
|
14
14
|
end
|
15
15
|
|
16
16
|
if (have_library('pq') || have_library('libpq') || have_library('ms/libpq')) && have_header('libpq-fe.h')
|
17
|
-
have_func '
|
17
|
+
have_func 'PQsetSingleRowMode'
|
18
18
|
create_makefile("sequel_pg")
|
19
19
|
else
|
20
20
|
puts 'Could not find PostgreSQL build environment (libraries & headers): Makefile not created'
|
data/ext/sequel_pg/sequel_pg.c
CHANGED
@@ -103,6 +103,12 @@ static ID spg_id_columns;
|
|
103
103
|
static ID spg_id_encoding;
|
104
104
|
static ID spg_id_values;
|
105
105
|
|
106
|
+
#if HAVE_PQSETSINGLEROWMODE
|
107
|
+
static ID spg_id_get_result;
|
108
|
+
static ID spg_id_clear;
|
109
|
+
static ID spg_id_check;
|
110
|
+
#endif
|
111
|
+
|
106
112
|
#if SPG_ENCODING
|
107
113
|
static int enc_get_index(VALUE val)
|
108
114
|
{
|
@@ -114,7 +120,11 @@ static int enc_get_index(VALUE val)
|
|
114
120
|
}
|
115
121
|
#endif
|
116
122
|
|
117
|
-
static VALUE read_array(int *index, char *c_pg_array_string, int array_string_length, char *word, VALUE converter
|
123
|
+
static VALUE read_array(int *index, char *c_pg_array_string, int array_string_length, char *word, VALUE converter
|
124
|
+
#ifdef SPG_ENCODING
|
125
|
+
, int enc_index
|
126
|
+
#endif
|
127
|
+
)
|
118
128
|
{
|
119
129
|
int word_index = 0;
|
120
130
|
|
@@ -155,15 +165,20 @@ static VALUE read_array(int *index, char *c_pg_array_string, int array_string_le
|
|
155
165
|
{
|
156
166
|
rb_ary_push(array, Qnil);
|
157
167
|
}
|
158
|
-
else
|
168
|
+
else
|
159
169
|
{
|
160
|
-
VALUE rword =
|
170
|
+
VALUE rword = rb_tainted_str_new(word, word_index);
|
161
171
|
RB_GC_GUARD(rword);
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
172
|
+
|
173
|
+
#ifdef SPG_ENCODING
|
174
|
+
rb_enc_associate_index(rword, enc_index);
|
175
|
+
#endif
|
176
|
+
|
177
|
+
if (RTEST(converter)) {
|
178
|
+
rword = rb_funcall(converter, spg_id_call, 1, rword);
|
179
|
+
}
|
180
|
+
|
181
|
+
rb_ary_push(array, rword);
|
167
182
|
}
|
168
183
|
}
|
169
184
|
if(c == '}')
|
@@ -181,7 +196,11 @@ static VALUE read_array(int *index, char *c_pg_array_string, int array_string_le
|
|
181
196
|
else if(c == '{')
|
182
197
|
{
|
183
198
|
(*index)++;
|
184
|
-
rb_ary_push(array, read_array(index, c_pg_array_string, array_string_length, word, converter
|
199
|
+
rb_ary_push(array, read_array(index, c_pg_array_string, array_string_length, word, converter
|
200
|
+
#ifdef SPG_ENCODING
|
201
|
+
, enc_index
|
202
|
+
#endif
|
203
|
+
));
|
185
204
|
escapeNext = 1;
|
186
205
|
}
|
187
206
|
else
|
@@ -224,7 +243,11 @@ static VALUE parse_pg_array(VALUE self, VALUE pg_array_string, VALUE converter)
|
|
224
243
|
char *word = RSTRING_PTR(buf);
|
225
244
|
int index = 1;
|
226
245
|
|
227
|
-
return read_array(&index, c_pg_array_string, array_string_length, word, converter
|
246
|
+
return read_array(&index, c_pg_array_string, array_string_length, word, converter
|
247
|
+
#ifdef SPG_ENCODING
|
248
|
+
, enc_get_index(pg_array_string)
|
249
|
+
#endif
|
250
|
+
);
|
228
251
|
}
|
229
252
|
|
230
253
|
static VALUE spg_time(const char *s) {
|
@@ -403,7 +426,7 @@ static VALUE spg_timestamp(const char *s, VALUE self) {
|
|
403
426
|
}
|
404
427
|
|
405
428
|
static VALUE spg_fetch_rows_set_cols(VALUE self, VALUE ignore) {
|
406
|
-
return
|
429
|
+
return Qnil;
|
407
430
|
}
|
408
431
|
|
409
432
|
static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* colconvert
|
@@ -813,194 +836,115 @@ static VALUE spg_yield_hash_rows(VALUE self, VALUE rres, VALUE ignore) {
|
|
813
836
|
|
814
837
|
static VALUE spg_supports_streaming_p(VALUE self) {
|
815
838
|
return
|
816
|
-
#if
|
839
|
+
#if HAVE_PQSETSINGLEROWMODE
|
817
840
|
Qtrue;
|
818
841
|
#else
|
819
842
|
Qfalse;
|
820
843
|
#endif
|
821
844
|
}
|
822
845
|
|
823
|
-
#if
|
824
|
-
static VALUE
|
825
|
-
|
826
|
-
,
|
827
|
-
|
828
|
-
)
|
829
|
-
const char *v;
|
830
|
-
PGdataValue dv = dvs[j];
|
831
|
-
VALUE rv;
|
832
|
-
size_t l;
|
833
|
-
int len = dv.len;
|
834
|
-
|
835
|
-
if(len < 0) {
|
836
|
-
rv = Qnil;
|
837
|
-
} else {
|
838
|
-
v = dv.value;
|
839
|
-
|
840
|
-
switch(PQftype(res, j)) {
|
841
|
-
case 16: /* boolean */
|
842
|
-
rv = *v == 't' ? Qtrue : Qfalse;
|
843
|
-
break;
|
844
|
-
case 17: /* bytea */
|
845
|
-
v = PQunescapeBytea((unsigned char*)v, &l);
|
846
|
-
rv = rb_funcall(spg_Blob, spg_id_new, 1, rb_str_new(v, l));
|
847
|
-
PQfreemem((char *)v);
|
848
|
-
break;
|
849
|
-
case 20: /* integer */
|
850
|
-
case 21:
|
851
|
-
case 22:
|
852
|
-
case 23:
|
853
|
-
case 26:
|
854
|
-
rv = rb_str2inum(rb_str_new(v, len), 10);
|
855
|
-
break;
|
856
|
-
case 700: /* float */
|
857
|
-
case 701:
|
858
|
-
if (strncmp("NaN", v, 3) == 0) {
|
859
|
-
rv = spg_nan;
|
860
|
-
} else if (strncmp("Infinity", v, 8) == 0) {
|
861
|
-
rv = spg_pos_inf;
|
862
|
-
} else if (strncmp("-Infinity", v, 9) == 0) {
|
863
|
-
rv = spg_neg_inf;
|
864
|
-
} else {
|
865
|
-
rv = rb_float_new(rb_str_to_dbl(rb_str_new(v, len), Qfalse));
|
866
|
-
}
|
867
|
-
break;
|
868
|
-
case 790: /* numeric */
|
869
|
-
case 1700:
|
870
|
-
rv = rb_funcall(spg_BigDecimal, spg_id_new, 1, rb_str_new(v, len));
|
871
|
-
break;
|
872
|
-
case 1082: /* date */
|
873
|
-
rv = rb_str_new(v, len);
|
874
|
-
rv = spg_date(StringValuePtr(rv));
|
875
|
-
break;
|
876
|
-
case 1083: /* time */
|
877
|
-
case 1266:
|
878
|
-
rv = rb_str_new(v, len);
|
879
|
-
rv = spg_time(StringValuePtr(rv));
|
880
|
-
break;
|
881
|
-
case 1114: /* timestamp */
|
882
|
-
case 1184:
|
883
|
-
rv = rb_str_new(v, len);
|
884
|
-
rv = spg_timestamp(StringValuePtr(rv), self);
|
885
|
-
break;
|
886
|
-
case 18: /* char */
|
887
|
-
case 25: /* text */
|
888
|
-
case 1043: /* varchar*/
|
889
|
-
rv = rb_tainted_str_new(v, len);
|
890
|
-
#ifdef SPG_ENCODING
|
891
|
-
rb_enc_associate_index(rv, enc_index);
|
892
|
-
#endif
|
893
|
-
break;
|
894
|
-
default:
|
895
|
-
rv = rb_tainted_str_new(v, len);
|
896
|
-
#ifdef SPG_ENCODING
|
897
|
-
rb_enc_associate_index(rv, enc_index);
|
898
|
-
#endif
|
899
|
-
if (colconvert[j] != Qnil) {
|
900
|
-
rv = rb_funcall(colconvert[j], spg_id_call, 1, rv);
|
901
|
-
}
|
902
|
-
}
|
846
|
+
#if HAVE_PQSETSINGLEROWMODE
|
847
|
+
static VALUE spg_set_single_row_mode(VALUE self) {
|
848
|
+
PGconn *conn;
|
849
|
+
Data_Get_Struct(self, PGconn, conn);
|
850
|
+
if (PQsetSingleRowMode(conn) != 1) {
|
851
|
+
rb_raise(spg_PGError, "cannot set single row mode");
|
903
852
|
}
|
904
|
-
return
|
853
|
+
return Qnil;
|
905
854
|
}
|
906
855
|
|
907
|
-
static
|
856
|
+
static VALUE spg__yield_each_row(VALUE self) {
|
857
|
+
PGconn *conn;
|
858
|
+
PGresult *res;
|
859
|
+
VALUE rres;
|
860
|
+
VALUE rconn;
|
861
|
+
VALUE colsyms[SPG_MAX_FIELDS];
|
862
|
+
VALUE colconvert[SPG_MAX_FIELDS];
|
908
863
|
long nfields;
|
909
|
-
|
910
|
-
|
911
|
-
VALUE
|
912
|
-
VALUE
|
913
|
-
VALUE
|
864
|
+
long j;
|
865
|
+
VALUE h;
|
866
|
+
VALUE opts;
|
867
|
+
VALUE pg_type;
|
868
|
+
VALUE pg_value = Qnil;
|
869
|
+
char type = SPG_YIELD_NORMAL;
|
914
870
|
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
871
|
+
rconn = rb_ary_entry(self, 1);
|
872
|
+
self = rb_ary_entry(self, 0);
|
873
|
+
Data_Get_Struct(rconn, PGconn, conn);
|
874
|
+
|
875
|
+
rres = rb_funcall(rconn, spg_id_get_result, 0);
|
876
|
+
rb_funcall(rres, spg_id_check, 0);
|
877
|
+
Data_Get_Struct(rres, PGresult, res);
|
878
|
+
|
879
|
+
#ifdef SPG_ENCODING
|
880
|
+
int enc_index;
|
881
|
+
enc_index = enc_get_index(rres);
|
922
882
|
#endif
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
883
|
+
|
884
|
+
/* Only handle regular and model types. All other types require compiling all
|
885
|
+
* of the results at once, which is not a use case for streaming. The streaming
|
886
|
+
* code does not call this function for the other types. */
|
887
|
+
opts = rb_funcall(self, spg_id_opts, 0);
|
888
|
+
if (rb_type(opts) == T_HASH) {
|
889
|
+
pg_type = rb_hash_aref(opts, spg_sym__sequel_pg_type);
|
890
|
+
pg_value = rb_hash_aref(opts, spg_sym__sequel_pg_value);
|
891
|
+
if (SYMBOL_P(pg_type) && pg_type == spg_sym_model && rb_type(pg_value) == T_CLASS) {
|
892
|
+
type = SPG_YIELD_MODEL;
|
893
|
+
}
|
932
894
|
}
|
933
895
|
|
934
896
|
nfields = PQnfields(res);
|
935
|
-
if(
|
936
|
-
|
937
|
-
|
938
|
-
}
|
939
|
-
long j;
|
940
|
-
VALUE h, m;
|
941
|
-
h = rb_hash_new();
|
897
|
+
if (nfields > SPG_MAX_FIELDS) {
|
898
|
+
rb_funcall(rres, spg_id_clear, 0);
|
899
|
+
rb_raise(rb_eRangeError, "more than %d columns in query", SPG_MAX_FIELDS);
|
900
|
+
}
|
942
901
|
|
902
|
+
spg_set_column_info(self, res, colsyms, colconvert);
|
903
|
+
|
904
|
+
rb_ivar_set(self, spg_id_columns, rb_ary_new4(nfields, colsyms));
|
905
|
+
|
906
|
+
while (PQntuples(res) != 0) {
|
907
|
+
h = rb_hash_new();
|
943
908
|
for(j=0; j<nfields; j++) {
|
944
|
-
rb_hash_aset(h, colsyms[j],
|
945
|
-
#ifdef SPG_ENCODING
|
946
|
-
, info->enc_index
|
947
|
-
#endif
|
948
|
-
));
|
909
|
+
rb_hash_aset(h, colsyms[j], spg__col_value(self, res, 0, j, colconvert ENC_INDEX));
|
949
910
|
}
|
950
911
|
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
912
|
+
rb_funcall(rres, spg_id_clear, 0);
|
913
|
+
|
914
|
+
if(type == SPG_YIELD_MODEL) {
|
915
|
+
/* Abuse local variable */
|
916
|
+
pg_type = rb_obj_alloc(pg_value);
|
917
|
+
rb_ivar_set(pg_type, spg_id_values, h);
|
918
|
+
rb_yield(pg_type);
|
919
|
+
} else {
|
920
|
+
rb_yield(h);
|
956
921
|
}
|
957
922
|
|
958
|
-
rb_funcall(
|
923
|
+
rres = rb_funcall(rconn, spg_id_get_result, 0);
|
924
|
+
rb_funcall(rres, spg_id_check, 0);
|
925
|
+
Data_Get_Struct(rres, PGresult, res);
|
959
926
|
}
|
960
|
-
|
961
|
-
}
|
927
|
+
rb_funcall(rres, spg_id_clear, 0);
|
962
928
|
|
963
|
-
|
964
|
-
PGconn *conn;
|
965
|
-
Data_Get_Struct(rconn, PGconn, conn);
|
966
|
-
if ((PQskipResult(conn)) != NULL) {
|
967
|
-
/* Results remaining when row processor finished,
|
968
|
-
* either because an exception was raised or the iterator
|
969
|
-
* exited early, so skip all remaining rows. */
|
970
|
-
while(PQgetResult(conn) != NULL) {
|
971
|
-
/* Use a separate while loop as PQgetResult is faster than
|
972
|
-
* PQskipResult. */
|
973
|
-
}
|
974
|
-
}
|
975
|
-
PQsetRowProcessor(conn, NULL, NULL);
|
976
|
-
return Qnil;
|
929
|
+
return self;
|
977
930
|
}
|
978
931
|
|
979
|
-
static VALUE
|
980
|
-
struct spg_row_proc_info info;
|
932
|
+
static VALUE spg__flush_results(VALUE rconn) {
|
981
933
|
PGconn *conn;
|
934
|
+
PGresult *res;
|
982
935
|
Data_Get_Struct(rconn, PGconn, conn);
|
983
|
-
bzero(&info, sizeof(info));
|
984
936
|
|
985
|
-
|
986
|
-
|
987
|
-
info.model = 0;
|
988
|
-
#if SPG_ENCODING
|
989
|
-
info.enc_index = enc_get_index(rconn);
|
990
|
-
#endif
|
991
|
-
|
992
|
-
/* Abuse local variable, detect if optimize_model_load used */
|
993
|
-
block = rb_funcall(dataset, spg_id_opts, 0);
|
994
|
-
if (rb_type(block) == T_HASH && rb_hash_aref(block, spg_sym__sequel_pg_type) == spg_sym_model) {
|
995
|
-
block = rb_hash_aref(block, spg_sym__sequel_pg_value);
|
996
|
-
if (rb_type(block) == T_CLASS) {
|
997
|
-
info.model = block;
|
998
|
-
}
|
937
|
+
while ((res = PQgetResult(conn)) != NULL) {
|
938
|
+
PQclear(res);
|
999
939
|
}
|
1000
940
|
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
941
|
+
return rconn;
|
942
|
+
}
|
943
|
+
|
944
|
+
static VALUE spg_yield_each_row(VALUE self, VALUE rconn) {
|
945
|
+
VALUE v;
|
946
|
+
v = rb_ary_new3(2, self, rconn);
|
947
|
+
return rb_ensure(spg__yield_each_row, v, spg__flush_results, rconn);
|
1004
948
|
}
|
1005
949
|
#endif
|
1006
950
|
|
@@ -1081,9 +1025,14 @@ void Init_sequel_pg(void) {
|
|
1081
1025
|
|
1082
1026
|
rb_define_singleton_method(spg_Postgres, "supports_streaming?", spg_supports_streaming_p, 0);
|
1083
1027
|
|
1084
|
-
#if
|
1085
|
-
|
1086
|
-
|
1028
|
+
#if HAVE_PQSETSINGLEROWMODE
|
1029
|
+
spg_id_get_result = rb_intern("get_result");
|
1030
|
+
spg_id_clear = rb_intern("clear");
|
1031
|
+
spg_id_check = rb_intern("check");
|
1032
|
+
|
1033
|
+
rb_define_private_method(c, "yield_each_row", spg_yield_each_row, 1);
|
1034
|
+
c = rb_funcall(spg_Postgres, cg, 1, rb_str_new2("Adapter"));
|
1035
|
+
rb_define_private_method(c, "set_single_row_mode", spg_set_single_row_mode, 0);
|
1087
1036
|
#endif
|
1088
1037
|
|
1089
1038
|
rb_define_singleton_method(spg_Postgres, "parse_pg_array", parse_pg_array, 2);
|
data/lib/1.8/sequel_pg.so
CHANGED
Binary file
|
data/lib/1.9/sequel_pg.so
CHANGED
Binary file
|
@@ -0,0 +1,130 @@
|
|
1
|
+
unless Sequel::Postgres.respond_to?(:supports_streaming?)
|
2
|
+
raise LoadError, "either sequel_pg not loaded, or an old version of sequel_pg loaded"
|
3
|
+
end
|
4
|
+
unless Sequel::Postgres.supports_streaming?
|
5
|
+
raise LoadError, "streaming is not supported by the version of libpq in use"
|
6
|
+
end
|
7
|
+
|
8
|
+
# Database methods necessary to support streaming. You should load this extension
|
9
|
+
# into your database object:
|
10
|
+
#
|
11
|
+
# DB.extension(:pg_streaming)
|
12
|
+
#
|
13
|
+
# Then you can call #stream on your datasets to use the streaming support:
|
14
|
+
#
|
15
|
+
# DB[:table].stream.each{|row| ...}
|
16
|
+
#
|
17
|
+
# Or change a set so that all dataset calls use streaming:
|
18
|
+
#
|
19
|
+
# DB.stream_all_queries = true
|
20
|
+
module Sequel::Postgres::Streaming
|
21
|
+
attr_accessor :stream_all_queries
|
22
|
+
|
23
|
+
# Also extend the database's datasets to support streaming.
|
24
|
+
# This extension requires modifying connections, so disconnect
|
25
|
+
# so that new connections will get the methods.
|
26
|
+
def self.extended(db)
|
27
|
+
db.extend_datasets(DatasetMethods)
|
28
|
+
db.stream_all_queries = false
|
29
|
+
db.disconnect
|
30
|
+
end
|
31
|
+
|
32
|
+
# Make sure all new connections have the appropriate methods added.
|
33
|
+
def connect(server)
|
34
|
+
conn = super
|
35
|
+
conn.extend(AdapterMethods)
|
36
|
+
conn
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# If streaming is requested, and a prepared statement is not
|
42
|
+
# used, tell the connection to use single row mode for the query.
|
43
|
+
def _execute(conn, sql, opts={}, &block)
|
44
|
+
if opts[:stream] && !sql.is_a?(Symbol)
|
45
|
+
conn.single_row_mode = true
|
46
|
+
end
|
47
|
+
super
|
48
|
+
end
|
49
|
+
|
50
|
+
# If streaming is requested, send the prepared statement instead
|
51
|
+
# of executing it and blocking.
|
52
|
+
def _execute_prepared_statement(conn, ps_name, args, opts)
|
53
|
+
if opts[:stream]
|
54
|
+
conn.send_prepared_statement(ps_name, args)
|
55
|
+
else
|
56
|
+
super
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module AdapterMethods
|
61
|
+
# Whether the next query on this connection should use
|
62
|
+
# single_row_mode.
|
63
|
+
attr_accessor :single_row_mode
|
64
|
+
|
65
|
+
# Send the prepared statement on this connection using
|
66
|
+
# single row mode.
|
67
|
+
def send_prepared_statement(ps_name, args)
|
68
|
+
send_query_prepared(ps_name, args)
|
69
|
+
set_single_row_mode
|
70
|
+
block
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# If using single row mode, send the query instead of executing it.
|
77
|
+
def execute_query(sql, args)
|
78
|
+
if @single_row_mode
|
79
|
+
@single_row_mode = false
|
80
|
+
@db.log_yield(sql, args){args ? send_query(sql, args) : send_query(sql)}
|
81
|
+
set_single_row_mode
|
82
|
+
block
|
83
|
+
self
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Dataset methods used to implement streaming.
|
91
|
+
module DatasetMethods
|
92
|
+
# If streaming has been requested and the current dataset
|
93
|
+
# can be streamed, request the database use streaming when
|
94
|
+
# executing this query, and use yield_each_row to process
|
95
|
+
# the separate PGresult for each row in the connection.
|
96
|
+
def fetch_rows(sql)
|
97
|
+
if stream_results?
|
98
|
+
execute(sql, :stream=>true) do |conn|
|
99
|
+
yield_each_row(conn){|h| yield h}
|
100
|
+
end
|
101
|
+
else
|
102
|
+
super
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Return a clone of the dataset that will use streaming to load
|
107
|
+
# rows.
|
108
|
+
def stream
|
109
|
+
clone(:stream=>true)
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
# Only stream results if streaming has been specifically requested
|
115
|
+
# and the query is streamable.
|
116
|
+
def stream_results?
|
117
|
+
(@opts[:stream] || db.stream_all_queries) && streamable?
|
118
|
+
end
|
119
|
+
|
120
|
+
# Queries using cursors are not streamable, and queries that use
|
121
|
+
# the map/select_map/to_hash/to_hash_groups optimizations are not
|
122
|
+
# streamable, but other queries are streamable.
|
123
|
+
def streamable?
|
124
|
+
spgt = (o = @opts)[:_sequel_pg_type]
|
125
|
+
(spgt.nil? || spgt == :model) && !o[:cursor]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
Sequel::Database.register_extension(:pg_streaming, Sequel::Postgres::Streaming)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel_pg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 13
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
8
|
+
- 6
|
9
9
|
- 1
|
10
|
-
version: 1.
|
10
|
+
version: 1.6.1
|
11
11
|
platform: x86-mingw32
|
12
12
|
authors:
|
13
13
|
- Jeremy Evans
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-09-28 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: pg
|
@@ -41,12 +41,12 @@ dependencies:
|
|
41
41
|
requirements:
|
42
42
|
- - ">="
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
hash:
|
44
|
+
hash: 155
|
45
45
|
segments:
|
46
46
|
- 3
|
47
|
-
-
|
47
|
+
- 39
|
48
48
|
- 0
|
49
|
-
version: 3.
|
49
|
+
version: 3.39.0
|
50
50
|
type: :runtime
|
51
51
|
version_requirements: *id002
|
52
52
|
description: |
|
@@ -72,7 +72,7 @@ files:
|
|
72
72
|
- ext/sequel_pg/extconf.rb
|
73
73
|
- ext/sequel_pg/sequel_pg.c
|
74
74
|
- lib/sequel_pg/sequel_pg.rb
|
75
|
-
- lib/
|
75
|
+
- lib/sequel/extensions/pg_streaming.rb
|
76
76
|
- lib/1.8/sequel_pg.so
|
77
77
|
- lib/1.9/sequel_pg.so
|
78
78
|
homepage: http://github.com/jeremyevans/sequel_pg
|
data/lib/sequel_pg/streaming.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
unless Sequel::Postgres.respond_to?(:supports_streaming?)
|
2
|
-
raise LoadError, "either sequel_pg not loaded, or an old version of sequel_pg loaded"
|
3
|
-
end
|
4
|
-
unless Sequel::Postgres.supports_streaming?
|
5
|
-
raise LoadError, "streaming is not supported by the version of libpq in use"
|
6
|
-
end
|
7
|
-
|
8
|
-
# Database methods necessary to support streaming. You should extend your
|
9
|
-
# Database object with this:
|
10
|
-
#
|
11
|
-
# DB.extend Sequel::Postgres::Streaming
|
12
|
-
#
|
13
|
-
# Then you can call #stream on your datasets to use the streaming support:
|
14
|
-
#
|
15
|
-
# DB[:table].stream.each{|row| ...}
|
16
|
-
module Sequel::Postgres::Streaming
|
17
|
-
# Also extend the database's datasets to support streaming
|
18
|
-
def self.extended(db)
|
19
|
-
db.extend_datasets(DatasetMethods)
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
# If streaming is requested, set a row processor while executing
|
25
|
-
# the query.
|
26
|
-
def _execute(conn, sql, opts={})
|
27
|
-
if stream = opts[:stream]
|
28
|
-
with_row_processor(conn, *stream){super}
|
29
|
-
else
|
30
|
-
super
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# Dataset methods used to implement streaming.
|
35
|
-
module DatasetMethods
|
36
|
-
# If streaming has been requested and the current dataset
|
37
|
-
# can be streamed, request the database use streaming when
|
38
|
-
# executing this query.
|
39
|
-
def fetch_rows(sql, &block)
|
40
|
-
if stream_results?
|
41
|
-
execute(sql, :stream=>[self, block])
|
42
|
-
else
|
43
|
-
super
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Return a clone of the dataset that will use streaming to load
|
48
|
-
# rows.
|
49
|
-
def stream
|
50
|
-
clone(:stream=>true)
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
# Only stream results if streaming has been specifically requested
|
56
|
-
# and the query is streamable.
|
57
|
-
def stream_results?
|
58
|
-
@opts[:stream] && streamable?
|
59
|
-
end
|
60
|
-
|
61
|
-
# Queries using cursors are not streamable, and queries that use
|
62
|
-
# the map/select_map/to_hash/to_hash_groups optimizations are not
|
63
|
-
# streamable, but other queries are streamable.
|
64
|
-
def streamable?
|
65
|
-
spgt = (o = @opts)[:_sequel_pg_type]
|
66
|
-
(spgt.nil? || spgt == :model) && !o[:cursor]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Extend a database's datasets with this module to enable streaming
|
71
|
-
# on all streamable queries:
|
72
|
-
#
|
73
|
-
# DB.extend_datasets(Sequel::Postgres::Streaming::AllQueries)
|
74
|
-
module AllQueries
|
75
|
-
private
|
76
|
-
|
77
|
-
# Always stream results if the query is streamable.
|
78
|
-
def stream_results?
|
79
|
-
streamable?
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|