pg 1.4.4 → 1.5.9
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/Gemfile +6 -0
- data/{History.rdoc → History.md} +303 -151
- data/README.ja.md +300 -0
- data/README.md +286 -0
- data/Rakefile +16 -4
- data/Rakefile.cross +15 -14
- 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 +8 -5
- data/ext/errorcodes.txt +3 -5
- data/ext/extconf.rb +7 -0
- data/ext/pg.c +15 -30
- data/ext/pg.h +10 -6
- data/ext/pg_binary_decoder.c +81 -0
- data/ext/pg_binary_encoder.c +224 -0
- data/ext/pg_coder.c +16 -7
- data/ext/pg_connection.c +220 -82
- data/ext/pg_copy_coder.c +315 -22
- data/ext/pg_record_coder.c +11 -10
- data/ext/pg_result.c +93 -19
- data/ext/pg_text_decoder.c +31 -10
- data/ext/pg_text_encoder.c +38 -19
- data/ext/pg_tuple.c +34 -31
- data/ext/pg_type_map.c +3 -2
- data/ext/pg_type_map_all_strings.c +2 -2
- data/ext/pg_type_map_by_class.c +5 -3
- data/ext/pg_type_map_by_column.c +7 -3
- data/ext/pg_type_map_by_oid.c +7 -4
- data/ext/pg_type_map_in_ruby.c +5 -2
- 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 +44 -34
- 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 +158 -64
- data/lib/pg/exceptions.rb +13 -0
- data/lib/pg/text_decoder/date.rb +21 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +17 -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 +13 -0
- data/lib/pg/text_encoder/inet.rb +31 -0
- data/lib/pg/text_encoder/json.rb +17 -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 +65 -15
- data/pg.gemspec +7 -3
- data/rakelib/task_extension.rb +1 -1
- data.tar.gz.sig +2 -4
- metadata +104 -46
- metadata.gz.sig +0 -0
- data/.appveyor.yml +0 -36
- data/.gems +0 -6
- data/.gemtest +0 -0
- data/.github/workflows/binary-gems.yml +0 -86
- data/.github/workflows/source-gem.yml +0 -131
- data/.gitignore +0 -13
- data/.hgsigs +0 -34
- data/.hgtags +0 -41
- data/.irbrc +0 -23
- data/.pryrc +0 -23
- data/.tm_properties +0 -21
- data/.travis.yml +0 -49
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -233
- 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_connection.c
CHANGED
@@ -16,9 +16,6 @@ static ID s_id_autoclose_set;
|
|
16
16
|
static VALUE sym_type, sym_format, sym_value;
|
17
17
|
static VALUE sym_symbol, sym_string, sym_static_symbol;
|
18
18
|
|
19
|
-
static PQnoticeReceiver default_notice_receiver = NULL;
|
20
|
-
static PQnoticeProcessor default_notice_processor = NULL;
|
21
|
-
|
22
19
|
static VALUE pgconn_finish( VALUE );
|
23
20
|
static VALUE pgconn_set_default_encoding( VALUE self );
|
24
21
|
static VALUE pgconn_wait_for_flush( VALUE self );
|
@@ -36,8 +33,8 @@ static VALUE pgconn_async_flush(VALUE self);
|
|
36
33
|
#ifdef __GNUC__
|
37
34
|
__attribute__((format(printf, 3, 4)))
|
38
35
|
#endif
|
39
|
-
static void
|
40
|
-
pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...)
|
36
|
+
NORETURN( static void
|
37
|
+
pg_raise_conn_error( VALUE klass, VALUE self, const char *format, ...))
|
41
38
|
{
|
42
39
|
VALUE msg, error;
|
43
40
|
va_list ap;
|
@@ -117,7 +114,7 @@ pgconn_close_socket_io( VALUE self )
|
|
117
114
|
rb_funcall( socket_io, rb_intern("close"), 0 );
|
118
115
|
}
|
119
116
|
|
120
|
-
this->socket_io
|
117
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
121
118
|
}
|
122
119
|
|
123
120
|
|
@@ -237,7 +234,7 @@ static const rb_data_type_t pg_connection_type = {
|
|
237
234
|
},
|
238
235
|
0,
|
239
236
|
0,
|
240
|
-
|
237
|
+
RUBY_TYPED_WB_PROTECTED,
|
241
238
|
};
|
242
239
|
|
243
240
|
|
@@ -258,15 +255,16 @@ pgconn_s_allocate( VALUE klass )
|
|
258
255
|
VALUE self = TypedData_Make_Struct( klass, t_pg_connection, &pg_connection_type, this );
|
259
256
|
|
260
257
|
this->pgconn = NULL;
|
261
|
-
this->socket_io
|
262
|
-
this->notice_receiver
|
263
|
-
this->notice_processor
|
264
|
-
this->type_map_for_queries
|
265
|
-
this->type_map_for_results
|
266
|
-
this->encoder_for_put_copy_data
|
267
|
-
this->decoder_for_get_copy_data
|
268
|
-
this->trace_stream
|
258
|
+
RB_OBJ_WRITE(self, &this->socket_io, Qnil);
|
259
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, Qnil);
|
260
|
+
RB_OBJ_WRITE(self, &this->notice_processor, Qnil);
|
261
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, pg_typemap_all_strings);
|
262
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, pg_typemap_all_strings);
|
263
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, Qnil);
|
264
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, Qnil);
|
265
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
269
266
|
rb_ivar_set(self, rb_intern("@calls_to_put_copy_data"), INT2FIX(0));
|
267
|
+
rb_ivar_set(self, rb_intern("@iopts_for_reset"), Qnil);
|
270
268
|
|
271
269
|
return self;
|
272
270
|
}
|
@@ -518,9 +516,9 @@ static VALUE
|
|
518
516
|
pgconn_connect_poll(VALUE self)
|
519
517
|
{
|
520
518
|
PostgresPollingStatusType status;
|
521
|
-
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
522
519
|
|
523
520
|
pgconn_close_socket_io(self);
|
521
|
+
status = gvl_PQconnectPoll(pg_get_pgconn(self));
|
524
522
|
|
525
523
|
return INT2FIX((int)status);
|
526
524
|
}
|
@@ -566,6 +564,27 @@ pgconn_sync_reset( VALUE self )
|
|
566
564
|
return self;
|
567
565
|
}
|
568
566
|
|
567
|
+
static VALUE
|
568
|
+
pgconn_reset_start2( VALUE self, VALUE conninfo )
|
569
|
+
{
|
570
|
+
t_pg_connection *this = pg_get_connection( self );
|
571
|
+
|
572
|
+
/* Close old connection */
|
573
|
+
pgconn_close_socket_io( self );
|
574
|
+
PQfinish( this->pgconn );
|
575
|
+
|
576
|
+
/* Start new connection */
|
577
|
+
this->pgconn = gvl_PQconnectStart( StringValueCStr(conninfo) );
|
578
|
+
|
579
|
+
if( this->pgconn == NULL )
|
580
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate PGconn structure");
|
581
|
+
|
582
|
+
if ( PQstatus(this->pgconn) == CONNECTION_BAD )
|
583
|
+
pg_raise_conn_error( rb_eConnectionBad, self, "%s", PQerrorMessage(this->pgconn));
|
584
|
+
|
585
|
+
return Qnil;
|
586
|
+
}
|
587
|
+
|
569
588
|
/*
|
570
589
|
* call-seq:
|
571
590
|
* conn.reset_start() -> nil
|
@@ -597,9 +616,9 @@ static VALUE
|
|
597
616
|
pgconn_reset_poll(VALUE self)
|
598
617
|
{
|
599
618
|
PostgresPollingStatusType status;
|
600
|
-
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
601
619
|
|
602
620
|
pgconn_close_socket_io(self);
|
621
|
+
status = gvl_PQresetPoll(pg_get_pgconn(self));
|
603
622
|
|
604
623
|
return INT2FIX((int)status);
|
605
624
|
}
|
@@ -702,7 +721,10 @@ static VALUE
|
|
702
721
|
pgconn_port(VALUE self)
|
703
722
|
{
|
704
723
|
char* port = PQport(pg_get_pgconn(self));
|
705
|
-
|
724
|
+
if (!port || port[0] == '\0')
|
725
|
+
return INT2NUM(DEF_PGPORT);
|
726
|
+
else
|
727
|
+
return INT2NUM(atoi(port));
|
706
728
|
}
|
707
729
|
|
708
730
|
/*
|
@@ -763,6 +785,10 @@ pgconn_conninfo( VALUE self )
|
|
763
785
|
*
|
764
786
|
* ... and other constants of kind PG::Constants::CONNECTION_*
|
765
787
|
*
|
788
|
+
* This method returns the status of the last command from memory.
|
789
|
+
* It doesn't do any socket access hence is not suitable to test the connectivity.
|
790
|
+
* See check_socket for a way to verify the socket state.
|
791
|
+
*
|
766
792
|
* Example:
|
767
793
|
* PG.constants.grep(/CONNECTION_/).find{|c| PG.const_get(c) == conn.status} # => :CONNECTION_OK
|
768
794
|
*/
|
@@ -938,7 +964,7 @@ pgconn_socket_io(VALUE self)
|
|
938
964
|
/* Disable autoclose feature */
|
939
965
|
rb_funcall( socket_io, s_id_autoclose_set, 1, Qfalse );
|
940
966
|
|
941
|
-
this->socket_io
|
967
|
+
RB_OBJ_WRITE(self, &this->socket_io, socket_io);
|
942
968
|
}
|
943
969
|
|
944
970
|
return socket_io;
|
@@ -1155,7 +1181,7 @@ static const rb_data_type_t pg_typecast_buffer_type = {
|
|
1155
1181
|
},
|
1156
1182
|
0,
|
1157
1183
|
0,
|
1158
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
1184
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
1159
1185
|
};
|
1160
1186
|
|
1161
1187
|
static char *
|
@@ -1188,7 +1214,7 @@ static const rb_data_type_t pg_query_heap_pool_type = {
|
|
1188
1214
|
},
|
1189
1215
|
0,
|
1190
1216
|
0,
|
1191
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
1217
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
1192
1218
|
};
|
1193
1219
|
|
1194
1220
|
static int
|
@@ -1811,6 +1837,7 @@ pgconn_set_single_row_mode(VALUE self)
|
|
1811
1837
|
{
|
1812
1838
|
PGconn *conn = pg_get_pgconn(self);
|
1813
1839
|
|
1840
|
+
rb_check_frozen(self);
|
1814
1841
|
if( PQsetSingleRowMode(conn) == 0 )
|
1815
1842
|
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
1816
1843
|
|
@@ -2145,6 +2172,7 @@ pgconn_sync_setnonblocking(VALUE self, VALUE state)
|
|
2145
2172
|
{
|
2146
2173
|
int arg;
|
2147
2174
|
PGconn *conn = pg_get_pgconn(self);
|
2175
|
+
rb_check_frozen(self);
|
2148
2176
|
if(state == Qtrue)
|
2149
2177
|
arg = 1;
|
2150
2178
|
else if (state == Qfalse)
|
@@ -2239,6 +2267,17 @@ pgconn_notifies(VALUE self)
|
|
2239
2267
|
return hash;
|
2240
2268
|
}
|
2241
2269
|
|
2270
|
+
#ifndef HAVE_RB_IO_DESCRIPTOR
|
2271
|
+
static int
|
2272
|
+
rb_io_descriptor(VALUE io)
|
2273
|
+
{
|
2274
|
+
Check_Type(io, T_FILE);
|
2275
|
+
rb_io_t *fptr = RFILE(io)->fptr;
|
2276
|
+
rb_io_check_closed(fptr);
|
2277
|
+
return fptr->fd;
|
2278
|
+
}
|
2279
|
+
#endif
|
2280
|
+
|
2242
2281
|
#if defined(_WIN32)
|
2243
2282
|
|
2244
2283
|
/* We use a specialized implementation of rb_io_wait() on Windows.
|
@@ -2259,7 +2298,6 @@ int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
|
2259
2298
|
|
2260
2299
|
static VALUE
|
2261
2300
|
pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2262
|
-
rb_io_t *fptr;
|
2263
2301
|
struct timeval ptimeout;
|
2264
2302
|
|
2265
2303
|
struct timeval aborttime={0,0}, currtime, waittime;
|
@@ -2270,7 +2308,6 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2270
2308
|
long w32_events = 0;
|
2271
2309
|
DWORD wait_ret;
|
2272
2310
|
|
2273
|
-
GetOpenFile((io), fptr);
|
2274
2311
|
if( !NIL_P(timeout) ){
|
2275
2312
|
ptimeout.tv_sec = (time_t)(NUM2DBL(timeout));
|
2276
2313
|
ptimeout.tv_usec = (time_t)((NUM2DBL(timeout) - (double)ptimeout.tv_sec) * 1e6);
|
@@ -2284,7 +2321,7 @@ pg_rb_thread_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
|
2284
2321
|
if(rb_events & PG_RUBY_IO_PRIORITY) w32_events |= FD_OOB;
|
2285
2322
|
|
2286
2323
|
for(;;) {
|
2287
|
-
if ( WSAEventSelect(_get_osfhandle(
|
2324
|
+
if ( WSAEventSelect(_get_osfhandle(rb_io_descriptor(io)), hEvent, w32_events) == SOCKET_ERROR ) {
|
2288
2325
|
WSACloseEvent( hEvent );
|
2289
2326
|
rb_raise( rb_eConnectionBad, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2290
2327
|
}
|
@@ -2327,7 +2364,7 @@ static VALUE
|
|
2327
2364
|
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2328
2365
|
#if defined(HAVE_RUBY_FIBER_SCHEDULER_H)
|
2329
2366
|
/* We don't support Fiber.scheduler on Windows ruby-3.0 because there is no fast way to check whether a scheduler is active.
|
2330
|
-
*
|
2367
|
+
* Fortunately ruby-3.1 offers a C-API for it.
|
2331
2368
|
*/
|
2332
2369
|
VALUE scheduler = rb_fiber_scheduler_current();
|
2333
2370
|
|
@@ -2357,16 +2394,14 @@ typedef enum {
|
|
2357
2394
|
|
2358
2395
|
static VALUE
|
2359
2396
|
pg_rb_io_wait(VALUE io, VALUE events, VALUE timeout) {
|
2360
|
-
rb_io_t *fptr;
|
2361
2397
|
struct timeval waittime;
|
2362
2398
|
int res;
|
2363
2399
|
|
2364
|
-
GetOpenFile((io), fptr);
|
2365
2400
|
if( !NIL_P(timeout) ){
|
2366
2401
|
waittime.tv_sec = (time_t)(NUM2DBL(timeout));
|
2367
2402
|
waittime.tv_usec = (time_t)((NUM2DBL(timeout) - (double)waittime.tv_sec) * 1e6);
|
2368
2403
|
}
|
2369
|
-
res = rb_wait_for_single_fd(
|
2404
|
+
res = rb_wait_for_single_fd(rb_io_descriptor(io), NUM2UINT(events), NIL_P(timeout) ? NULL : &waittime);
|
2370
2405
|
|
2371
2406
|
return UINT2NUM(res);
|
2372
2407
|
}
|
@@ -2443,8 +2478,9 @@ pgconn_async_flush(VALUE self)
|
|
2443
2478
|
VALUE socket_io = pgconn_socket_io(self);
|
2444
2479
|
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
2445
2480
|
|
2446
|
-
if (events & PG_RUBY_IO_READABLE)
|
2481
|
+
if (events & PG_RUBY_IO_READABLE){
|
2447
2482
|
pgconn_consume_input(self);
|
2483
|
+
}
|
2448
2484
|
}
|
2449
2485
|
return Qtrue;
|
2450
2486
|
}
|
@@ -2460,6 +2496,7 @@ pgconn_wait_for_flush( VALUE self ){
|
|
2460
2496
|
static VALUE
|
2461
2497
|
pgconn_flush_data_set( VALUE self, VALUE enabled ){
|
2462
2498
|
t_pg_connection *conn = pg_get_connection(self);
|
2499
|
+
rb_check_frozen(self);
|
2463
2500
|
conn->flush_data = RTEST(enabled);
|
2464
2501
|
return enabled;
|
2465
2502
|
}
|
@@ -2714,6 +2751,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2714
2751
|
VALUE new_file;
|
2715
2752
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2716
2753
|
|
2754
|
+
rb_check_frozen(self);
|
2717
2755
|
if(!rb_respond_to(stream,rb_intern("fileno")))
|
2718
2756
|
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2719
2757
|
|
@@ -2735,7 +2773,7 @@ pgconn_trace(VALUE self, VALUE stream)
|
|
2735
2773
|
rb_raise(rb_eArgError, "stream is not writable");
|
2736
2774
|
|
2737
2775
|
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2738
|
-
this->trace_stream
|
2776
|
+
RB_OBJ_WRITE(self, &this->trace_stream, new_file);
|
2739
2777
|
|
2740
2778
|
PQtrace(this->pgconn, new_fp);
|
2741
2779
|
return Qnil;
|
@@ -2754,7 +2792,7 @@ pgconn_untrace(VALUE self)
|
|
2754
2792
|
|
2755
2793
|
PQuntrace(this->pgconn);
|
2756
2794
|
rb_funcall(this->trace_stream, rb_intern("close"), 0);
|
2757
|
-
this->trace_stream
|
2795
|
+
RB_OBJ_WRITE(self, &this->trace_stream, Qnil);
|
2758
2796
|
return Qnil;
|
2759
2797
|
}
|
2760
2798
|
|
@@ -2813,13 +2851,14 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2813
2851
|
VALUE proc, old_proc;
|
2814
2852
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2815
2853
|
|
2854
|
+
rb_check_frozen(self);
|
2816
2855
|
/* If default_notice_receiver is unset, assume that the current
|
2817
2856
|
* notice receiver is the default, and save it to a global variable.
|
2818
2857
|
* This should not be a problem because the default receiver is
|
2819
2858
|
* always the same, so won't vary among connections.
|
2820
2859
|
*/
|
2821
|
-
if(default_notice_receiver == NULL)
|
2822
|
-
default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2860
|
+
if(this->default_notice_receiver == NULL)
|
2861
|
+
this->default_notice_receiver = PQsetNoticeReceiver(this->pgconn, NULL, NULL);
|
2823
2862
|
|
2824
2863
|
old_proc = this->notice_receiver;
|
2825
2864
|
if( rb_block_given_p() ) {
|
@@ -2828,10 +2867,10 @@ pgconn_set_notice_receiver(VALUE self)
|
|
2828
2867
|
} else {
|
2829
2868
|
/* if no block is given, set back to default */
|
2830
2869
|
proc = Qnil;
|
2831
|
-
PQsetNoticeReceiver(this->pgconn, default_notice_receiver, NULL);
|
2870
|
+
PQsetNoticeReceiver(this->pgconn, this->default_notice_receiver, NULL);
|
2832
2871
|
}
|
2833
2872
|
|
2834
|
-
this->notice_receiver
|
2873
|
+
RB_OBJ_WRITE(self, &this->notice_receiver, proc);
|
2835
2874
|
return old_proc;
|
2836
2875
|
}
|
2837
2876
|
|
@@ -2846,10 +2885,10 @@ notice_processor_proxy(void *arg, const char *message)
|
|
2846
2885
|
VALUE self = (VALUE)arg;
|
2847
2886
|
t_pg_connection *this = pg_get_connection( self );
|
2848
2887
|
|
2849
|
-
if (this->
|
2888
|
+
if (this->notice_processor != Qnil) {
|
2850
2889
|
VALUE message_str = rb_str_new2(message);
|
2851
2890
|
PG_ENCODING_SET_NOCHECK( message_str, this->enc_idx );
|
2852
|
-
rb_funcall(this->
|
2891
|
+
rb_funcall(this->notice_processor, rb_intern("call"), 1, message_str);
|
2853
2892
|
}
|
2854
2893
|
return;
|
2855
2894
|
}
|
@@ -2873,25 +2912,26 @@ pgconn_set_notice_processor(VALUE self)
|
|
2873
2912
|
VALUE proc, old_proc;
|
2874
2913
|
t_pg_connection *this = pg_get_connection_safe( self );
|
2875
2914
|
|
2915
|
+
rb_check_frozen(self);
|
2876
2916
|
/* If default_notice_processor is unset, assume that the current
|
2877
2917
|
* notice processor is the default, and save it to a global variable.
|
2878
2918
|
* This should not be a problem because the default processor is
|
2879
2919
|
* always the same, so won't vary among connections.
|
2880
2920
|
*/
|
2881
|
-
if(default_notice_processor == NULL)
|
2882
|
-
default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2921
|
+
if(this->default_notice_processor == NULL)
|
2922
|
+
this->default_notice_processor = PQsetNoticeProcessor(this->pgconn, NULL, NULL);
|
2883
2923
|
|
2884
|
-
old_proc = this->
|
2924
|
+
old_proc = this->notice_processor;
|
2885
2925
|
if( rb_block_given_p() ) {
|
2886
2926
|
proc = rb_block_proc();
|
2887
2927
|
PQsetNoticeProcessor(this->pgconn, gvl_notice_processor_proxy, (void *)self);
|
2888
2928
|
} else {
|
2889
2929
|
/* if no block is given, set back to default */
|
2890
2930
|
proc = Qnil;
|
2891
|
-
PQsetNoticeProcessor(this->pgconn, default_notice_processor, NULL);
|
2931
|
+
PQsetNoticeProcessor(this->pgconn, this->default_notice_processor, NULL);
|
2892
2932
|
}
|
2893
2933
|
|
2894
|
-
this->
|
2934
|
+
RB_OBJ_WRITE(self, &this->notice_processor, proc);
|
2895
2935
|
return old_proc;
|
2896
2936
|
}
|
2897
2937
|
|
@@ -2923,6 +2963,7 @@ pgconn_sync_set_client_encoding(VALUE self, VALUE str)
|
|
2923
2963
|
{
|
2924
2964
|
PGconn *conn = pg_get_pgconn( self );
|
2925
2965
|
|
2966
|
+
rb_check_frozen(self);
|
2926
2967
|
Check_Type(str, T_STRING);
|
2927
2968
|
|
2928
2969
|
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 )
|
@@ -3091,11 +3132,13 @@ pgconn_async_get_last_result(VALUE self)
|
|
3091
3132
|
VALUE rb_pgresult = Qnil;
|
3092
3133
|
PGresult *cur, *prev;
|
3093
3134
|
|
3094
|
-
|
3135
|
+
cur = prev = NULL;
|
3095
3136
|
for(;;) {
|
3096
3137
|
int status;
|
3097
3138
|
|
3098
|
-
/*
|
3139
|
+
/* Wait for input before reading each result.
|
3140
|
+
* That way we support the ruby-3.x IO scheduler and don't block other ruby threads.
|
3141
|
+
*/
|
3099
3142
|
wait_socket_readable(self, NULL, get_result_readable);
|
3100
3143
|
|
3101
3144
|
cur = gvl_PQgetResult(conn);
|
@@ -3123,8 +3166,14 @@ pgconn_async_get_last_result(VALUE self)
|
|
3123
3166
|
* conn.discard_results()
|
3124
3167
|
*
|
3125
3168
|
* Silently discard any prior query result that application didn't eat.
|
3126
|
-
* This is
|
3127
|
-
*
|
3169
|
+
* This is internally used prior to Connection#exec and sibling methods.
|
3170
|
+
* It doesn't raise an exception on connection errors, but returns +false+ instead.
|
3171
|
+
*
|
3172
|
+
* Returns:
|
3173
|
+
* * +nil+ when the connection is already idle
|
3174
|
+
* * +true+ when some results have been discarded
|
3175
|
+
* * +false+ when a failure occurred and the connection was closed
|
3176
|
+
*
|
3128
3177
|
*/
|
3129
3178
|
static VALUE
|
3130
3179
|
pgconn_discard_results(VALUE self)
|
@@ -3132,8 +3181,12 @@ pgconn_discard_results(VALUE self)
|
|
3132
3181
|
PGconn *conn = pg_get_pgconn(self);
|
3133
3182
|
VALUE socket_io;
|
3134
3183
|
|
3135
|
-
|
3136
|
-
|
3184
|
+
switch( PQtransactionStatus(conn) ) {
|
3185
|
+
case PQTRANS_IDLE:
|
3186
|
+
case PQTRANS_INTRANS:
|
3187
|
+
case PQTRANS_INERROR:
|
3188
|
+
return Qnil;
|
3189
|
+
default:;
|
3137
3190
|
}
|
3138
3191
|
|
3139
3192
|
socket_io = pgconn_socket_io(self);
|
@@ -3146,10 +3199,21 @@ pgconn_discard_results(VALUE self)
|
|
3146
3199
|
* To avoid this call pg_rb_io_wait() and PQconsumeInput() without rb_raise().
|
3147
3200
|
*/
|
3148
3201
|
while( gvl_PQisBusy(conn) ){
|
3149
|
-
|
3150
|
-
|
3151
|
-
|
3152
|
-
|
3202
|
+
int events;
|
3203
|
+
|
3204
|
+
switch( PQflush(conn) ) {
|
3205
|
+
case 1:
|
3206
|
+
events = RB_NUM2INT(pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE | PG_RUBY_IO_WRITABLE), Qnil));
|
3207
|
+
if (events & PG_RUBY_IO_READABLE){
|
3208
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3209
|
+
}
|
3210
|
+
break;
|
3211
|
+
case 0:
|
3212
|
+
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3213
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3214
|
+
break;
|
3215
|
+
default:
|
3216
|
+
goto error;
|
3153
3217
|
}
|
3154
3218
|
}
|
3155
3219
|
|
@@ -3159,7 +3223,9 @@ pgconn_discard_results(VALUE self)
|
|
3159
3223
|
status = PQresultStatus(cur);
|
3160
3224
|
PQclear(cur);
|
3161
3225
|
if (status == PGRES_COPY_IN){
|
3162
|
-
gvl_PQputCopyEnd(conn, "COPY terminated by new
|
3226
|
+
while( gvl_PQputCopyEnd(conn, "COPY terminated by new query or discard_results") == 0 ){
|
3227
|
+
pgconn_async_flush(self);
|
3228
|
+
}
|
3163
3229
|
}
|
3164
3230
|
if (status == PGRES_COPY_OUT){
|
3165
3231
|
for(;;) {
|
@@ -3168,10 +3234,7 @@ pgconn_discard_results(VALUE self)
|
|
3168
3234
|
if( st == 0 ) {
|
3169
3235
|
/* would block -> wait for readable data */
|
3170
3236
|
pg_rb_io_wait(socket_io, RB_INT2NUM(PG_RUBY_IO_READABLE), Qnil);
|
3171
|
-
if ( PQconsumeInput(conn) == 0 )
|
3172
|
-
pgconn_close_socket_io(self);
|
3173
|
-
return Qfalse;
|
3174
|
-
}
|
3237
|
+
if ( PQconsumeInput(conn) == 0 ) goto error;
|
3175
3238
|
} else if( st > 0 ) {
|
3176
3239
|
/* some data retrieved -> discard it */
|
3177
3240
|
PQfreemem(buffer);
|
@@ -3184,6 +3247,10 @@ pgconn_discard_results(VALUE self)
|
|
3184
3247
|
}
|
3185
3248
|
|
3186
3249
|
return Qtrue;
|
3250
|
+
|
3251
|
+
error:
|
3252
|
+
pgconn_close_socket_io(self);
|
3253
|
+
return Qfalse;
|
3187
3254
|
}
|
3188
3255
|
|
3189
3256
|
/*
|
@@ -3640,6 +3707,14 @@ pgconn_send_flush_request(VALUE self)
|
|
3640
3707
|
* LARGE OBJECT SUPPORT
|
3641
3708
|
**************************************************************************/
|
3642
3709
|
|
3710
|
+
#define BLOCKING_BEGIN(conn) do { \
|
3711
|
+
int old_nonblocking = PQisnonblocking(conn); \
|
3712
|
+
PQsetnonblocking(conn, 0);
|
3713
|
+
|
3714
|
+
#define BLOCKING_END(th) \
|
3715
|
+
PQsetnonblocking(conn, old_nonblocking); \
|
3716
|
+
} while(0);
|
3717
|
+
|
3643
3718
|
/*
|
3644
3719
|
* call-seq:
|
3645
3720
|
* conn.lo_creat( [mode] ) -> Integer
|
@@ -3660,7 +3735,10 @@ pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
|
3660
3735
|
else
|
3661
3736
|
mode = NUM2INT(nmode);
|
3662
3737
|
|
3663
|
-
|
3738
|
+
BLOCKING_BEGIN(conn)
|
3739
|
+
lo_oid = lo_creat(conn, mode);
|
3740
|
+
BLOCKING_END(conn)
|
3741
|
+
|
3664
3742
|
if (lo_oid == 0)
|
3665
3743
|
pg_raise_conn_error( rb_ePGerror, self, "lo_creat failed");
|
3666
3744
|
|
@@ -3705,7 +3783,10 @@ pgconn_loimport(VALUE self, VALUE filename)
|
|
3705
3783
|
|
3706
3784
|
Check_Type(filename, T_STRING);
|
3707
3785
|
|
3708
|
-
|
3786
|
+
BLOCKING_BEGIN(conn)
|
3787
|
+
lo_oid = lo_import(conn, StringValueCStr(filename));
|
3788
|
+
BLOCKING_END(conn)
|
3789
|
+
|
3709
3790
|
if (lo_oid == 0) {
|
3710
3791
|
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3711
3792
|
}
|
@@ -3723,11 +3804,16 @@ pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
|
3723
3804
|
{
|
3724
3805
|
PGconn *conn = pg_get_pgconn(self);
|
3725
3806
|
Oid oid;
|
3807
|
+
int ret;
|
3726
3808
|
Check_Type(filename, T_STRING);
|
3727
3809
|
|
3728
3810
|
oid = NUM2UINT(lo_oid);
|
3729
3811
|
|
3730
|
-
|
3812
|
+
BLOCKING_BEGIN(conn)
|
3813
|
+
ret = lo_export(conn, oid, StringValueCStr(filename));
|
3814
|
+
BLOCKING_END(conn)
|
3815
|
+
|
3816
|
+
if (ret < 0) {
|
3731
3817
|
pg_raise_conn_error( rb_ePGerror, self, "%s", PQerrorMessage(conn));
|
3732
3818
|
}
|
3733
3819
|
return Qnil;
|
@@ -3758,7 +3844,11 @@ pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
|
3758
3844
|
else
|
3759
3845
|
mode = NUM2INT(nmode);
|
3760
3846
|
|
3761
|
-
|
3847
|
+
BLOCKING_BEGIN(conn)
|
3848
|
+
fd = lo_open(conn, lo_oid, mode);
|
3849
|
+
BLOCKING_END(conn)
|
3850
|
+
|
3851
|
+
if(fd < 0) {
|
3762
3852
|
pg_raise_conn_error( rb_ePGerror, self, "can't open large object: %s", PQerrorMessage(conn));
|
3763
3853
|
}
|
3764
3854
|
return INT2FIX(fd);
|
@@ -3783,8 +3873,12 @@ pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
|
3783
3873
|
if( RSTRING_LEN(buffer) < 0) {
|
3784
3874
|
pg_raise_conn_error( rb_ePGerror, self, "write buffer zero string");
|
3785
3875
|
}
|
3786
|
-
|
3787
|
-
|
3876
|
+
BLOCKING_BEGIN(conn)
|
3877
|
+
n = lo_write(conn, fd, StringValuePtr(buffer),
|
3878
|
+
RSTRING_LEN(buffer));
|
3879
|
+
BLOCKING_END(conn)
|
3880
|
+
|
3881
|
+
if(n < 0) {
|
3788
3882
|
pg_raise_conn_error( rb_ePGerror, self, "lo_write failed: %s", PQerrorMessage(conn));
|
3789
3883
|
}
|
3790
3884
|
|
@@ -3812,7 +3906,12 @@ pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3812
3906
|
pg_raise_conn_error( rb_ePGerror, self, "negative length %d given", len);
|
3813
3907
|
|
3814
3908
|
buffer = ALLOC_N(char, len);
|
3815
|
-
|
3909
|
+
|
3910
|
+
BLOCKING_BEGIN(conn)
|
3911
|
+
ret = lo_read(conn, lo_desc, buffer, len);
|
3912
|
+
BLOCKING_END(conn)
|
3913
|
+
|
3914
|
+
if(ret < 0)
|
3816
3915
|
pg_raise_conn_error( rb_ePGerror, self, "lo_read failed");
|
3817
3916
|
|
3818
3917
|
if(ret == 0) {
|
@@ -3842,7 +3941,11 @@ pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
|
3842
3941
|
int lo_desc = NUM2INT(in_lo_desc);
|
3843
3942
|
int ret;
|
3844
3943
|
|
3845
|
-
|
3944
|
+
BLOCKING_BEGIN(conn)
|
3945
|
+
ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence));
|
3946
|
+
BLOCKING_END(conn)
|
3947
|
+
|
3948
|
+
if(ret < 0) {
|
3846
3949
|
pg_raise_conn_error( rb_ePGerror, self, "lo_lseek failed");
|
3847
3950
|
}
|
3848
3951
|
|
@@ -3862,7 +3965,11 @@ pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
|
3862
3965
|
PGconn *conn = pg_get_pgconn(self);
|
3863
3966
|
int lo_desc = NUM2INT(in_lo_desc);
|
3864
3967
|
|
3865
|
-
|
3968
|
+
BLOCKING_BEGIN(conn)
|
3969
|
+
position = lo_tell(conn, lo_desc);
|
3970
|
+
BLOCKING_END(conn)
|
3971
|
+
|
3972
|
+
if(position < 0)
|
3866
3973
|
pg_raise_conn_error( rb_ePGerror, self, "lo_tell failed");
|
3867
3974
|
|
3868
3975
|
return INT2FIX(position);
|
@@ -3880,8 +3987,13 @@ pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
|
3880
3987
|
PGconn *conn = pg_get_pgconn(self);
|
3881
3988
|
int lo_desc = NUM2INT(in_lo_desc);
|
3882
3989
|
size_t len = NUM2INT(in_len);
|
3990
|
+
int ret;
|
3883
3991
|
|
3884
|
-
|
3992
|
+
BLOCKING_BEGIN(conn)
|
3993
|
+
ret = lo_truncate(conn,lo_desc,len);
|
3994
|
+
BLOCKING_END(conn)
|
3995
|
+
|
3996
|
+
if(ret < 0)
|
3885
3997
|
pg_raise_conn_error( rb_ePGerror, self, "lo_truncate failed");
|
3886
3998
|
|
3887
3999
|
return Qnil;
|
@@ -3898,8 +4010,13 @@ pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
|
3898
4010
|
{
|
3899
4011
|
PGconn *conn = pg_get_pgconn(self);
|
3900
4012
|
int lo_desc = NUM2INT(in_lo_desc);
|
4013
|
+
int ret;
|
3901
4014
|
|
3902
|
-
|
4015
|
+
BLOCKING_BEGIN(conn)
|
4016
|
+
ret = lo_close(conn,lo_desc);
|
4017
|
+
BLOCKING_END(conn)
|
4018
|
+
|
4019
|
+
if(ret < 0)
|
3903
4020
|
pg_raise_conn_error( rb_ePGerror, self, "lo_close failed");
|
3904
4021
|
|
3905
4022
|
return Qnil;
|
@@ -3916,8 +4033,13 @@ pgconn_lounlink(VALUE self, VALUE in_oid)
|
|
3916
4033
|
{
|
3917
4034
|
PGconn *conn = pg_get_pgconn(self);
|
3918
4035
|
Oid oid = NUM2UINT(in_oid);
|
4036
|
+
int ret;
|
3919
4037
|
|
3920
|
-
|
4038
|
+
BLOCKING_BEGIN(conn)
|
4039
|
+
ret = lo_unlink(conn,oid);
|
4040
|
+
BLOCKING_END(conn)
|
4041
|
+
|
4042
|
+
if(ret < 0)
|
3921
4043
|
pg_raise_conn_error( rb_ePGerror, self, "lo_unlink failed");
|
3922
4044
|
|
3923
4045
|
return Qnil;
|
@@ -3975,6 +4097,7 @@ static VALUE pgconn_external_encoding(VALUE self);
|
|
3975
4097
|
static VALUE
|
3976
4098
|
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3977
4099
|
{
|
4100
|
+
rb_check_frozen(self);
|
3978
4101
|
if (NIL_P(enc)) {
|
3979
4102
|
pgconn_sync_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3980
4103
|
return enc;
|
@@ -4029,6 +4152,7 @@ pgconn_async_set_client_encoding(VALUE self, VALUE encname)
|
|
4029
4152
|
{
|
4030
4153
|
VALUE query_format, query;
|
4031
4154
|
|
4155
|
+
rb_check_frozen(self);
|
4032
4156
|
Check_Type(encname, T_STRING);
|
4033
4157
|
query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
4034
4158
|
query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
@@ -4078,15 +4202,23 @@ static VALUE
|
|
4078
4202
|
pgconn_set_default_encoding( VALUE self )
|
4079
4203
|
{
|
4080
4204
|
PGconn *conn = pg_get_pgconn( self );
|
4081
|
-
rb_encoding *
|
4082
|
-
|
4083
|
-
|
4084
|
-
if ((
|
4085
|
-
|
4086
|
-
|
4087
|
-
|
4088
|
-
|
4089
|
-
|
4205
|
+
rb_encoding *rb_enc;
|
4206
|
+
|
4207
|
+
rb_check_frozen(self);
|
4208
|
+
if (( rb_enc = rb_default_internal_encoding() )) {
|
4209
|
+
rb_encoding * conn_encoding = pg_conn_enc_get( conn );
|
4210
|
+
|
4211
|
+
/* Don't set the server encoding, if it's unnecessary.
|
4212
|
+
* This is important for connection proxies, who disallow configuration settings.
|
4213
|
+
*/
|
4214
|
+
if ( conn_encoding != rb_enc ) {
|
4215
|
+
const char *encname = pg_get_rb_encoding_as_pg_encoding( rb_enc );
|
4216
|
+
if ( pgconn_set_client_encoding_async(self, rb_str_new_cstr(encname)) != 0 )
|
4217
|
+
rb_warning( "Failed to set the default_internal encoding to %s: '%s'",
|
4218
|
+
encname, PQerrorMessage(conn) );
|
4219
|
+
}
|
4220
|
+
pgconn_set_internal_encoding_index( self );
|
4221
|
+
return rb_enc_from_encoding( rb_enc );
|
4090
4222
|
} else {
|
4091
4223
|
pgconn_set_internal_encoding_index( self );
|
4092
4224
|
return Qnil;
|
@@ -4110,10 +4242,11 @@ pgconn_type_map_for_queries_set(VALUE self, VALUE typemap)
|
|
4110
4242
|
t_typemap *tm;
|
4111
4243
|
UNUSED(tm);
|
4112
4244
|
|
4245
|
+
rb_check_frozen(self);
|
4113
4246
|
/* Check type of method param */
|
4114
4247
|
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
4115
4248
|
|
4116
|
-
this->type_map_for_queries
|
4249
|
+
RB_OBJ_WRITE(self, &this->type_map_for_queries, typemap);
|
4117
4250
|
|
4118
4251
|
return typemap;
|
4119
4252
|
}
|
@@ -4150,8 +4283,9 @@ pgconn_type_map_for_results_set(VALUE self, VALUE typemap)
|
|
4150
4283
|
t_typemap *tm;
|
4151
4284
|
UNUSED(tm);
|
4152
4285
|
|
4286
|
+
rb_check_frozen(self);
|
4153
4287
|
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, tm);
|
4154
|
-
this->type_map_for_results
|
4288
|
+
RB_OBJ_WRITE(self, &this->type_map_for_results, typemap);
|
4155
4289
|
|
4156
4290
|
return typemap;
|
4157
4291
|
}
|
@@ -4189,13 +4323,14 @@ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE encoder)
|
|
4189
4323
|
{
|
4190
4324
|
t_pg_connection *this = pg_get_connection( self );
|
4191
4325
|
|
4326
|
+
rb_check_frozen(self);
|
4192
4327
|
if( encoder != Qnil ){
|
4193
4328
|
t_pg_coder *co;
|
4194
4329
|
UNUSED(co);
|
4195
4330
|
/* Check argument type */
|
4196
4331
|
TypedData_Get_Struct(encoder, t_pg_coder, &pg_coder_type, co);
|
4197
4332
|
}
|
4198
|
-
this->encoder_for_put_copy_data
|
4333
|
+
RB_OBJ_WRITE(self, &this->encoder_for_put_copy_data, encoder);
|
4199
4334
|
|
4200
4335
|
return encoder;
|
4201
4336
|
}
|
@@ -4237,13 +4372,14 @@ pgconn_decoder_for_get_copy_data_set(VALUE self, VALUE decoder)
|
|
4237
4372
|
{
|
4238
4373
|
t_pg_connection *this = pg_get_connection( self );
|
4239
4374
|
|
4375
|
+
rb_check_frozen(self);
|
4240
4376
|
if( decoder != Qnil ){
|
4241
4377
|
t_pg_coder *co;
|
4242
4378
|
UNUSED(co);
|
4243
4379
|
/* Check argument type */
|
4244
4380
|
TypedData_Get_Struct(decoder, t_pg_coder, &pg_coder_type, co);
|
4245
4381
|
}
|
4246
|
-
this->decoder_for_get_copy_data
|
4382
|
+
RB_OBJ_WRITE(self, &this->decoder_for_get_copy_data, decoder);
|
4247
4383
|
|
4248
4384
|
return decoder;
|
4249
4385
|
}
|
@@ -4289,6 +4425,7 @@ pgconn_field_name_type_set(VALUE self, VALUE sym)
|
|
4289
4425
|
{
|
4290
4426
|
t_pg_connection *this = pg_get_connection( self );
|
4291
4427
|
|
4428
|
+
rb_check_frozen(self);
|
4292
4429
|
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
4293
4430
|
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
4294
4431
|
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
@@ -4362,6 +4499,7 @@ init_pg_connection(void)
|
|
4362
4499
|
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
4363
4500
|
rb_define_method(rb_cPGconn, "sync_reset", pgconn_sync_reset, 0);
|
4364
4501
|
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
4502
|
+
rb_define_private_method(rb_cPGconn, "reset_start2", pgconn_reset_start2, 1);
|
4365
4503
|
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
4366
4504
|
rb_define_alias(rb_cPGconn, "close", "finish");
|
4367
4505
|
|