pg 0.18.0.pre20141017160319 → 0.18.0.pre20141117110243

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.
@@ -10,6 +10,9 @@ VALUE rb_ePGerror;
10
10
  VALUE rb_eServerError;
11
11
  VALUE rb_eUnableToSend;
12
12
  VALUE rb_eConnectionBad;
13
+ VALUE rb_eInvalidResultStatus;
14
+ VALUE rb_eNoResultError;
15
+ VALUE rb_eInvalidChangeOfResultFields;
13
16
 
14
17
  static VALUE
15
18
  define_error_class(const char *name, const char *baseclass_code)
@@ -84,6 +87,9 @@ init_pg_errors()
84
87
  rb_eServerError = rb_define_class_under( rb_mPG, "ServerError", rb_ePGerror );
85
88
  rb_eUnableToSend = rb_define_class_under( rb_mPG, "UnableToSend", rb_ePGerror );
86
89
  rb_eConnectionBad = rb_define_class_under( rb_mPG, "ConnectionBad", rb_ePGerror );
90
+ rb_eInvalidResultStatus = rb_define_class_under( rb_mPG, "InvalidResultStatus", rb_ePGerror );
91
+ rb_eNoResultError = rb_define_class_under( rb_mPG, "NoResultError", rb_ePGerror );
92
+ rb_eInvalidChangeOfResultFields = rb_define_class_under( rb_mPG, "InvalidChangeOfResultFields", rb_ePGerror );
87
93
 
88
94
  #include "errorcodes.def"
89
95
  }
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_result.c - PG::Result class extension
3
- * $Id: pg_result.c,v f0b7f99b1dd5 2014/10/06 08:31:02 kanis $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
@@ -27,28 +27,32 @@ static t_pg_result *pgresult_get_this_safe( VALUE );
27
27
  VALUE
28
28
  pg_new_result(PGresult *result, VALUE rb_pgconn)
29
29
  {
30
+ int nfields = result ? PQnfields(result) : 0;
30
31
  VALUE self = pgresult_s_allocate( rb_cPGresult );
31
- t_pg_result *this = pgresult_get_this(self);
32
- t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
32
+ t_pg_result *this;
33
33
 
34
- PG_ENCODING_SET_NOCHECK(self, ENCODING_GET(rb_pgconn));
34
+ this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
35
+ DATA_PTR(self) = this;
35
36
 
36
37
  this->pgresult = result;
37
38
  this->connection = rb_pgconn;
38
- if( result ){
39
- VALUE typemap = p_conn->type_map_for_results;
39
+ this->typemap = pg_typemap_all_strings;
40
+ this->p_typemap = DATA_PTR( this->typemap );
41
+ this->autoclear = 0;
42
+ this->nfields = -1;
43
+ this->tuple_hash = Qnil;
40
44
 
41
- if( !NIL_P(typemap) ){
42
- t_typemap *p_typemap;
45
+ PG_ENCODING_SET_NOCHECK(self, ENCODING_GET(rb_pgconn));
43
46
 
44
- /* Type check is done when assigned to PG::Connection. */
45
- p_typemap = DATA_PTR(typemap);
47
+ if( result ){
48
+ t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
49
+ VALUE typemap = p_conn->type_map_for_results;
46
50
 
47
- typemap = p_typemap->fit_to_result( typemap, self );
48
- this->p_typemap = DATA_PTR( typemap );
49
- }
51
+ /* Type check is done when assigned to PG::Connection. */
52
+ t_typemap *p_typemap = DATA_PTR(typemap);
50
53
 
51
- this->typemap = typemap;
54
+ this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
55
+ this->p_typemap = DATA_PTR( this->typemap );
52
56
  }
53
57
 
54
58
  return self;
@@ -74,11 +78,11 @@ pg_result_check( VALUE self )
74
78
  {
75
79
  t_pg_result *this = pgresult_get_this(self);
76
80
  VALUE error, exception, klass;
77
- PGconn *conn = pg_get_pgconn(this->connection);
78
81
  char * sqlstate;
79
82
 
80
83
  if(this->pgresult == NULL)
81
84
  {
85
+ PGconn *conn = pg_get_pgconn(this->connection);
82
86
  error = rb_str_new2( PQerrorMessage(conn) );
83
87
  }
84
88
  else
@@ -162,7 +166,7 @@ pgresult_cleared_p( VALUE self )
162
166
 
163
167
  /*
164
168
  * call-seq:
165
- * res.autoclose? -> boolean
169
+ * res.autoclear? -> boolean
166
170
  *
167
171
  * Returns +true+ if the underlying C struct will be cleared automatically by libpq.
168
172
  * Elsewise the result is cleared by PG::Result#clear or by the GC when it's no longer in use.
@@ -185,8 +189,16 @@ pgresult_autoclear_p( VALUE self )
185
189
  static void
186
190
  pgresult_gc_mark( t_pg_result *this )
187
191
  {
192
+ int i;
193
+
194
+ if( !this ) return;
188
195
  rb_gc_mark( this->connection );
189
196
  rb_gc_mark( this->typemap );
197
+ rb_gc_mark( this->tuple_hash );
198
+
199
+ for( i=0; i < this->nfields; i++ ){
200
+ rb_gc_mark( this->fnames[i] );
201
+ }
190
202
  }
191
203
 
192
204
  /*
@@ -195,6 +207,7 @@ pgresult_gc_mark( t_pg_result *this )
195
207
  static void
196
208
  pgresult_gc_free( t_pg_result *this )
197
209
  {
210
+ if( !this ) return;
198
211
  if(this->pgresult != NULL && !this->autoclear)
199
212
  PQclear(this->pgresult);
200
213
 
@@ -216,6 +229,10 @@ pgresult_get_this_safe( VALUE self )
216
229
 
217
230
  /*
218
231
  * Fetch the PGresult pointer for the result object and check validity
232
+ *
233
+ * Note: This function is used externally by the sequel_pg gem,
234
+ * so do changes carefully.
235
+ *
219
236
  */
220
237
  PGresult*
221
238
  pgresult_get(VALUE self)
@@ -235,18 +252,30 @@ pgresult_get(VALUE self)
235
252
  static VALUE
236
253
  pgresult_s_allocate( VALUE klass )
237
254
  {
238
- t_pg_result *this;
239
- VALUE self = Data_Make_Struct( klass, t_pg_result, pgresult_gc_mark, pgresult_gc_free, this );
240
-
241
- this->pgresult = NULL;
242
- this->connection = Qnil;
243
- this->typemap = Qnil;
244
- this->p_typemap = DATA_PTR( pg_default_typemap );
245
- this->autoclear = 0;
255
+ VALUE self = Data_Wrap_Struct( klass, pgresult_gc_mark, pgresult_gc_free, NULL );
246
256
 
247
257
  return self;
248
258
  }
249
259
 
260
+ static void pgresult_init_fnames(VALUE self)
261
+ {
262
+ t_pg_result *this = pgresult_get_this_safe(self);
263
+
264
+ if( this->nfields == -1 ){
265
+ int i;
266
+ int nfields = PQnfields(this->pgresult);
267
+
268
+ for( i=0; i<nfields; i++ ){
269
+ VALUE fname = rb_tainted_str_new2(PQfname(this->pgresult, i));
270
+ PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
271
+ this->fnames[i] = rb_obj_freeze(fname);
272
+ this->nfields = i + 1;
273
+
274
+ RB_GC_GUARD(fname);
275
+ }
276
+ this->nfields = nfields;
277
+ }
278
+ }
250
279
 
251
280
  /********************************************************************
252
281
  *
@@ -395,6 +424,12 @@ pgresult_ntuples(VALUE self)
395
424
  return INT2FIX(PQntuples(pgresult_get(self)));
396
425
  }
397
426
 
427
+ static VALUE
428
+ pgresult_ntuples_for_enum(VALUE self, VALUE args, VALUE eobj)
429
+ {
430
+ return pgresult_ntuples(self);
431
+ }
432
+
398
433
  /*
399
434
  * call-seq:
400
435
  * res.nfields() -> Integer
@@ -417,16 +452,16 @@ static VALUE
417
452
  pgresult_fname(VALUE self, VALUE index)
418
453
  {
419
454
  VALUE fname;
420
- PGresult *result;
455
+ PGresult *result = pgresult_get(self);
421
456
  int i = NUM2INT(index);
422
457
 
423
- result = pgresult_get(self);
424
458
  if (i < 0 || i >= PQnfields(result)) {
425
459
  rb_raise(rb_eArgError,"invalid field number %d", i);
426
460
  }
461
+
427
462
  fname = rb_tainted_str_new2(PQfname(result, i));
428
463
  PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
429
- return fname;
464
+ return rb_obj_freeze(fname);
430
465
  }
431
466
 
432
467
  /*
@@ -633,7 +668,7 @@ pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num)
633
668
  if(j < 0 || j >= PQnfields(this->pgresult)) {
634
669
  rb_raise(rb_eArgError,"invalid field number %d", j);
635
670
  }
636
- return this->p_typemap->typecast_result_value(self, i, j);
671
+ return this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, i, j);
637
672
  }
638
673
 
639
674
  /*
@@ -783,18 +818,26 @@ pgresult_aref(VALUE self, VALUE index)
783
818
  t_pg_result *this = pgresult_get_this_safe(self);
784
819
  int tuple_num = NUM2INT(index);
785
820
  int field_num;
786
- VALUE fname;
821
+ int num_tuples = PQntuples(this->pgresult);
787
822
  VALUE tuple;
788
823
 
789
- if ( tuple_num < 0 || tuple_num >= PQntuples(this->pgresult) )
824
+ if( this->nfields == -1 )
825
+ pgresult_init_fnames( self );
826
+
827
+ if ( tuple_num < 0 || tuple_num >= num_tuples )
790
828
  rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
791
829
 
792
- tuple = rb_hash_new();
793
- for ( field_num = 0; field_num < PQnfields(this->pgresult); field_num++ ) {
794
- fname = rb_tainted_str_new2( PQfname(this->pgresult,field_num) );
795
- PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
796
- rb_hash_aset( tuple, fname, this->p_typemap->typecast_result_value(self, tuple_num, field_num) );
830
+ /* We reuse the Hash of the previous output for larger row counts.
831
+ * This is somewhat faster than populating an empty Hash object. */
832
+ tuple = NIL_P(this->tuple_hash) ? rb_hash_new() : this->tuple_hash;
833
+ for ( field_num = 0; field_num < this->nfields; field_num++ ) {
834
+ VALUE val = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, tuple_num, field_num);
835
+ rb_hash_aset( tuple, this->fnames[field_num], val );
797
836
  }
837
+ /* Store a copy of the filled hash for use at the next row. */
838
+ if( num_tuples > 10 )
839
+ this->tuple_hash = rb_hash_dup(tuple);
840
+
798
841
  return tuple;
799
842
  }
800
843
 
@@ -807,20 +850,26 @@ pgresult_aref(VALUE self, VALUE index)
807
850
  static VALUE
808
851
  pgresult_each_row(VALUE self)
809
852
  {
810
- t_pg_result *this = pgresult_get_this_safe(self);
853
+ t_pg_result *this;
811
854
  int row;
812
855
  int field;
813
- int num_rows = PQntuples(this->pgresult);
814
- int num_fields = PQnfields(this->pgresult);
856
+ int num_rows;
857
+ int num_fields;
858
+
859
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pgresult_ntuples_for_enum);
860
+
861
+ this = pgresult_get_this_safe(self);
862
+ num_rows = PQntuples(this->pgresult);
863
+ num_fields = PQnfields(this->pgresult);
815
864
 
816
865
  for ( row = 0; row < num_rows; row++ ) {
817
- VALUE new_row = rb_ary_new2(num_fields);
866
+ VALUE row_values[num_fields];
818
867
 
819
868
  /* populate the row */
820
869
  for ( field = 0; field < num_fields; field++ ) {
821
- rb_ary_store( new_row, field, this->p_typemap->typecast_result_value(self, row, field) );
870
+ row_values[field] = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, row, field);
822
871
  }
823
- rb_yield( new_row );
872
+ rb_yield( rb_ary_new4( num_fields, row_values ));
824
873
  }
825
874
 
826
875
  return Qnil;
@@ -843,13 +892,13 @@ pgresult_values(VALUE self)
843
892
  VALUE results = rb_ary_new2( num_rows );
844
893
 
845
894
  for ( row = 0; row < num_rows; row++ ) {
846
- VALUE new_row = rb_ary_new2(num_fields);
895
+ VALUE row_values[num_fields];
847
896
 
848
897
  /* populate the row */
849
898
  for ( field = 0; field < num_fields; field++ ) {
850
- rb_ary_store( new_row, field, this->p_typemap->typecast_result_value(self, row, field) );
899
+ row_values[field] = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, row, field);
851
900
  }
852
- rb_ary_store( results, row, new_row );
901
+ rb_ary_store( results, row, rb_ary_new4( num_fields, row_values ) );
853
902
  }
854
903
 
855
904
  return results;
@@ -871,7 +920,7 @@ make_column_result_array( VALUE self, int col )
871
920
  rb_raise( rb_eIndexError, "no column %d in result", col );
872
921
 
873
922
  for ( i=0; i < rows; i++ ) {
874
- VALUE val = this->p_typemap->typecast_result_value(self, i, col);
923
+ VALUE val = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, i, col);
875
924
  rb_ary_store( results, i, val );
876
925
  }
877
926
 
@@ -925,9 +974,13 @@ pgresult_field_values( VALUE self, VALUE field )
925
974
  static VALUE
926
975
  pgresult_each(VALUE self)
927
976
  {
928
- PGresult *result = pgresult_get(self);
977
+ PGresult *result;
929
978
  int tuple_num;
930
979
 
980
+ RETURN_SIZED_ENUMERATOR(self, 0, NULL, pgresult_ntuples_for_enum);
981
+
982
+ result = pgresult_get(self);
983
+
931
984
  for(tuple_num = 0; tuple_num < PQntuples(result); tuple_num++) {
932
985
  rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
933
986
  }
@@ -943,18 +996,12 @@ pgresult_each(VALUE self)
943
996
  static VALUE
944
997
  pgresult_fields(VALUE self)
945
998
  {
946
- PGresult *result = pgresult_get( self );
947
- int n = PQnfields( result );
948
- VALUE fields = rb_ary_new2( n );
949
- int i;
999
+ t_pg_result *this = pgresult_get_this_safe(self);
950
1000
 
951
- for ( i = 0; i < n; i++ ) {
952
- VALUE val = rb_tainted_str_new2(PQfname(result, i));
953
- PG_ENCODING_SET_NOCHECK(val, ENCODING_GET(self));
954
- rb_ary_store( fields, i, val );
955
- }
1001
+ if( this->nfields == -1 )
1002
+ pgresult_init_fnames( self );
956
1003
 
957
- return fields;
1004
+ return rb_ary_new4( this->nfields, this->fnames );
958
1005
  }
959
1006
 
960
1007
  /*
@@ -967,32 +1014,23 @@ pgresult_fields(VALUE self)
967
1014
  * type casts from PostgreSQL's wire format to Ruby objects on the fly,
968
1015
  * according to the rules and decoders defined in the given typemap.
969
1016
  *
970
- * +typemap+ can be:
971
- * * a kind of PG::TypeMap
972
- * * +nil+ - to type cast all result values to String.
1017
+ * +typemap+ must be a kind of PG::TypeMap .
973
1018
  *
974
1019
  */
975
1020
  static VALUE
976
1021
  pgresult_type_map_set(VALUE self, VALUE typemap)
977
1022
  {
978
1023
  t_pg_result *this = pgresult_get_this(self);
1024
+ t_typemap *p_typemap;
979
1025
 
980
- if( NIL_P(typemap) ){
981
- this->p_typemap = DATA_PTR( pg_default_typemap );
982
- } else {
983
- t_typemap *p_typemap;
984
-
985
- if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
986
- rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
987
- rb_obj_classname( typemap ) );
988
- }
989
- Data_Get_Struct(typemap, t_typemap, p_typemap);
990
-
991
- typemap = p_typemap->fit_to_result( typemap, self );
992
- this->p_typemap = DATA_PTR( typemap );
1026
+ if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
1027
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
1028
+ rb_obj_classname( typemap ) );
993
1029
  }
1030
+ Data_Get_Struct(typemap, t_typemap, p_typemap);
994
1031
 
995
- this->typemap = typemap;
1032
+ this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
1033
+ this->p_typemap = DATA_PTR( this->typemap );
996
1034
 
997
1035
  return typemap;
998
1036
  }
@@ -1003,10 +1041,6 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
1003
1041
  *
1004
1042
  * Returns the TypeMap that is currently set for type casts of result values to ruby objects.
1005
1043
  *
1006
- * Returns either:
1007
- * * a kind of PG::TypeMap or
1008
- * * +nil+ - when no type map is set.
1009
- *
1010
1044
  */
1011
1045
  static VALUE
1012
1046
  pgresult_type_map_get(VALUE self)
@@ -1016,6 +1050,162 @@ pgresult_type_map_get(VALUE self)
1016
1050
  return this->typemap;
1017
1051
  }
1018
1052
 
1053
+ #ifdef HAVE_PQSETSINGLEROWMODE
1054
+ /*
1055
+ * call-seq:
1056
+ * res.stream_each{ |tuple| ... }
1057
+ *
1058
+ * Invokes block for each tuple in the result set in single row mode.
1059
+ *
1060
+ * This is a convenience method for retrieving all result tuples
1061
+ * as they are transferred. It is an alternative to repeated calls of
1062
+ * PG::Connection#get_result , but given that it avoids the overhead of
1063
+ * wrapping each row into a dedicated result object, it delivers data in nearly
1064
+ * the same speed as with ordinary results.
1065
+ *
1066
+ * The result must be in status PGRES_SINGLE_TUPLE.
1067
+ * It iterates over all tuples until the status changes to PGRES_TUPLES_OK.
1068
+ * A PG::Error is raised for any errors from the server.
1069
+ *
1070
+ * Row description data does not change while the iteration. All value retrieval
1071
+ * methods refer to only the current row. Result#ntuples returns +1+ while
1072
+ * the iteration and +0+ after all tuples were yielded.
1073
+ *
1074
+ * Example:
1075
+ * conn.send_query( "first SQL query; second SQL query" )
1076
+ * conn.set_single_row_mode
1077
+ * conn.get_result.stream_each do |row|
1078
+ * # do something with the received row of the first query
1079
+ * end
1080
+ * conn.get_result.stream_each do |row|
1081
+ * # do something with the received row of the second query
1082
+ * end
1083
+ * conn.get_result # => nil (no more results)
1084
+ */
1085
+ static VALUE
1086
+ pgresult_stream_each(VALUE self)
1087
+ {
1088
+ t_pg_result *this;
1089
+ int nfields;
1090
+ PGconn *pgconn;
1091
+ PGresult *pgresult;
1092
+
1093
+ RETURN_ENUMERATOR(self, 0, NULL);
1094
+
1095
+ this = pgresult_get_this_safe(self);
1096
+ pgconn = pg_get_pgconn(this->connection);
1097
+ pgresult = this->pgresult;
1098
+ nfields = PQnfields(pgresult);
1099
+
1100
+ for(;;){
1101
+ int tuple_num;
1102
+ int ntuples = PQntuples(pgresult);
1103
+
1104
+ switch( PQresultStatus(pgresult) ){
1105
+ case PGRES_TUPLES_OK:
1106
+ if( ntuples == 0 )
1107
+ return self;
1108
+ rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
1109
+ case PGRES_SINGLE_TUPLE:
1110
+ break;
1111
+ default:
1112
+ pg_result_check( self );
1113
+ }
1114
+
1115
+ for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1116
+ rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
1117
+ }
1118
+
1119
+ if( !this->autoclear ){
1120
+ PQclear( pgresult );
1121
+ this->pgresult = NULL;
1122
+ }
1123
+
1124
+ pgresult = gvl_PQgetResult(pgconn);
1125
+ if( pgresult == NULL )
1126
+ rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another result retrieval");
1127
+
1128
+ if( nfields != PQnfields(pgresult) )
1129
+ rb_raise( rb_eInvalidChangeOfResultFields, "number of fields must not change in single row mode");
1130
+
1131
+ this->pgresult = pgresult;
1132
+ }
1133
+
1134
+ /* never reached */
1135
+ return self;
1136
+ }
1137
+
1138
+ /*
1139
+ * call-seq:
1140
+ * res.stream_each_row { |row| ... }
1141
+ *
1142
+ * Yields each row of the result set in single row mode.
1143
+ * The row is a list of column values.
1144
+ *
1145
+ * This method works equally to #stream_each , but yields an Array of
1146
+ * values.
1147
+ */
1148
+ static VALUE
1149
+ pgresult_stream_each_row(VALUE self)
1150
+ {
1151
+ t_pg_result *this;
1152
+ int row;
1153
+ int nfields;
1154
+ PGconn *pgconn;
1155
+ PGresult *pgresult;
1156
+
1157
+ RETURN_ENUMERATOR(self, 0, NULL);
1158
+
1159
+ this = pgresult_get_this_safe(self);
1160
+ pgconn = pg_get_pgconn(this->connection);
1161
+ pgresult = this->pgresult;
1162
+ nfields = PQnfields(pgresult);
1163
+
1164
+ for(;;){
1165
+ int ntuples = PQntuples(pgresult);
1166
+
1167
+ switch( PQresultStatus(pgresult) ){
1168
+ case PGRES_TUPLES_OK:
1169
+ if( ntuples == 0 )
1170
+ return self;
1171
+ rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
1172
+ case PGRES_SINGLE_TUPLE:
1173
+ break;
1174
+ default:
1175
+ pg_result_check( self );
1176
+ }
1177
+
1178
+ for ( row = 0; row < ntuples; row++ ) {
1179
+ VALUE row_values[nfields];
1180
+ int field;
1181
+
1182
+ /* populate the row */
1183
+ for ( field = 0; field < nfields; field++ ) {
1184
+ row_values[field] = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, row, field);
1185
+ }
1186
+ rb_yield( rb_ary_new4( nfields, row_values ));
1187
+ }
1188
+
1189
+ if( !this->autoclear ){
1190
+ PQclear( pgresult );
1191
+ this->pgresult = NULL;
1192
+ }
1193
+
1194
+ pgresult = gvl_PQgetResult(pgconn);
1195
+ if( pgresult == NULL )
1196
+ rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another result retrieval");
1197
+
1198
+ if( nfields != PQnfields(pgresult) )
1199
+ rb_raise( rb_eInvalidChangeOfResultFields, "number of fields must not change in single row mode");
1200
+
1201
+ this->pgresult = pgresult;
1202
+ }
1203
+
1204
+ /* never reached */
1205
+ return self;
1206
+ }
1207
+ #endif
1208
+
1019
1209
 
1020
1210
  void
1021
1211
  init_pg_result()
@@ -1070,6 +1260,12 @@ init_pg_result()
1070
1260
 
1071
1261
  rb_define_method(rb_cPGresult, "type_map=", pgresult_type_map_set, 1);
1072
1262
  rb_define_method(rb_cPGresult, "type_map", pgresult_type_map_get, 0);
1263
+
1264
+ #ifdef HAVE_PQSETSINGLEROWMODE
1265
+ /****** PG::Result INSTANCE METHODS: streaming ******/
1266
+ rb_define_method(rb_cPGresult, "stream_each", pgresult_stream_each, 0);
1267
+ rb_define_method(rb_cPGresult, "stream_each_row", pgresult_stream_each_row, 0);
1268
+ #endif
1073
1269
  }
1074
1270
 
1075
1271