pg 1.6.3 → 1.7.0

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +52 -6
  4. data/Gemfile +1 -0
  5. data/README.ja.md +81 -30
  6. data/README.md +14 -7
  7. data/Rakefile +8 -7
  8. data/certs/larskanis-2026.pem +24 -0
  9. data/ext/extconf.rb +18 -28
  10. data/ext/gvl_wrappers.c +2 -2
  11. data/ext/gvl_wrappers.h +40 -160
  12. data/ext/pg.c +8 -12
  13. data/ext/pg.h +8 -11
  14. data/ext/pg_binary_decoder.c +6 -2
  15. data/ext/pg_binary_encoder.c +7 -0
  16. data/ext/pg_cancel_connection.c +6 -6
  17. data/ext/pg_coder.c +4 -4
  18. data/ext/pg_connection.c +196 -159
  19. data/ext/pg_copy_coder.c +34 -21
  20. data/ext/pg_record_coder.c +10 -6
  21. data/ext/pg_result.c +42 -26
  22. data/ext/pg_text_decoder.c +6 -6
  23. data/ext/pg_text_encoder.c +7 -2
  24. data/ext/pg_tuple.c +1 -1
  25. data/ext/pg_type_map.c +41 -1
  26. data/ext/pg_type_map_all_strings.c +2 -2
  27. data/ext/pg_type_map_by_class.c +1 -1
  28. data/ext/pg_type_map_by_column.c +2 -2
  29. data/ext/pg_type_map_by_oid.c +1 -1
  30. data/ext/pg_type_map_in_ruby.c +1 -1
  31. data/lib/pg/basic_type_map_based_on_result.rb +5 -0
  32. data/lib/pg/basic_type_map_for_queries.rb +9 -2
  33. data/lib/pg/basic_type_map_for_results.rb +5 -0
  34. data/lib/pg/connection.rb +166 -76
  35. data/lib/pg/text_decoder/date.rb +1 -1
  36. data/lib/pg/text_decoder/json.rb +1 -1
  37. data/lib/pg/text_encoder/date.rb +7 -1
  38. data/lib/pg/text_encoder/json.rb +1 -1
  39. data/lib/pg/version.rb +1 -1
  40. data/misc/yugabyte/docker-compose.yml +1 -1
  41. data/pg.gemspec +1 -1
  42. data/sample/async_mixed.rb +1 -1
  43. data.tar.gz.sig +0 -0
  44. metadata +18 -19
  45. metadata.gz.sig +0 -0
  46. data/ports/patches/openssl/3.5.2/0001-aarch64-mingw.patch +0 -21
  47. data/ports/patches/postgresql/18.1/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +0 -52
  48. /data/ports/patches/krb5/{1.22.1 → 1.22.2}/0001-Allow-static-linking-krb5-library.patch +0 -0
  49. /data/ports/patches/krb5/{1.22.1 → 1.22.2}/0002-unknown-command-line-option-on-clang.patch +0 -0
  50. /data/ports/patches/postgresql/{18.1 → 18.6}/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +0 -0
data/ext/gvl_wrappers.h CHANGED
@@ -15,13 +15,18 @@
15
15
  #ifndef __gvl_wrappers_h
16
16
  #define __gvl_wrappers_h
17
17
 
18
+ #include <ruby/version.h>
18
19
  #include <ruby/thread.h>
19
20
 
20
21
  #ifdef RUBY_EXTCONF_H
21
22
  # include RUBY_EXTCONF_H
22
23
  #endif
23
24
 
24
- #ifndef HAVE_PQSETCHUNKEDROWSMODE
25
+ #if RUBY_API_VERSION_MAJOR < 4
26
+ extern int ruby_thread_has_gvl_p(void);
27
+ #endif
28
+
29
+ #ifndef LIBPQ_HAS_CHUNK_MODE
25
30
  typedef struct pg_cancel_conn PGcancelConn;
26
31
  #endif
27
32
 
@@ -83,20 +88,35 @@ typedef struct pg_cancel_conn PGcancelConn;
83
88
  }
84
89
 
85
90
  #ifdef ENABLE_GVL_UNLOCK
86
- #define DEFINE_GVLCB_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \
87
- rettype gvl_##name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \
88
- struct gvl_wrapper_##name##_params params = { \
89
- {FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname}, when_non_void((rettype)0) \
90
- }; \
91
- rb_thread_call_with_gvl(gvl_##name##_skeleton, &params); \
92
- when_non_void( return params.retval; ) \
93
- }
91
+ #if RUBY_API_VERSION_MAJOR >= 4 || defined(TRUFFLERUBY)
92
+ #define DEFINE_GVLCB_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \
93
+ rettype gvl_##name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \
94
+ struct gvl_wrapper_##name##_params params = { \
95
+ {FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname}, when_non_void((rettype)0) \
96
+ }; \
97
+ rb_thread_call_with_gvl(gvl_##name##_skeleton, &params); \
98
+ when_non_void( return params.retval; ) \
99
+ }
100
+ #else
101
+ #define DEFINE_GVLCB_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \
102
+ rettype gvl_##name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \
103
+ struct gvl_wrapper_##name##_params params = { \
104
+ {FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname}, when_non_void((rettype)0) \
105
+ }; \
106
+ if (ruby_thread_has_gvl_p()) { \
107
+ gvl_##name##_skeleton(&params); \
108
+ } else { \
109
+ rb_thread_call_with_gvl(gvl_##name##_skeleton, &params); \
110
+ } \
111
+ when_non_void( return params.retval; ) \
112
+ }
113
+ #endif
94
114
  #else
95
- #define DEFINE_GVLCB_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \
96
- rettype gvl_##name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \
97
- when_non_void( return ) \
98
- name( FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname ); \
99
- }
115
+ #define DEFINE_GVLCB_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \
116
+ rettype gvl_##name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \
117
+ when_non_void( return ) \
118
+ name( FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname ); \
119
+ }
100
120
  #endif
101
121
 
102
122
  #define GVL_TYPE_VOID(string)
@@ -105,174 +125,34 @@ typedef struct pg_cancel_conn PGcancelConn;
105
125
 
106
126
  /*
107
127
  * Definitions of blocking functions and their parameters
128
+ *
129
+ * ATTENTION:
130
+ * Do not GVL-release functions that take pointers to ruby objects.
131
+ * If the ruby object is relocated by `GC.compact` from a second thread, before the pointer is used, it is no longer valid.
132
+ * That can lead to a crash or to wrong data.
133
+ * This issue has been raised in https://github.com/ged/ruby-pg/issues/738 and https://github.com/ged/ruby-pg/issues/721 .
108
134
  */
109
135
 
110
- #define FOR_EACH_PARAM_OF_PQconnectdb(param)
111
-
112
136
  #define FOR_EACH_PARAM_OF_PQconnectStart(param)
113
-
114
137
  #define FOR_EACH_PARAM_OF_PQconnectPoll(param)
115
138
 
116
- #define FOR_EACH_PARAM_OF_PQreset(param)
117
-
118
139
  #define FOR_EACH_PARAM_OF_PQresetStart(param)
119
-
120
140
  #define FOR_EACH_PARAM_OF_PQresetPoll(param)
121
141
 
122
142
  #define FOR_EACH_PARAM_OF_PQping(param)
123
143
 
124
- #define FOR_EACH_PARAM_OF_PQexec(param) \
125
- param(PGconn *, conn)
126
-
127
- #define FOR_EACH_PARAM_OF_PQexecParams(param) \
128
- param(PGconn *, conn) \
129
- param(const char *, command) \
130
- param(int, nParams) \
131
- param(const Oid *, paramTypes) \
132
- param(const char * const *, paramValues) \
133
- param(const int *, paramLengths) \
134
- param(const int *, paramFormats)
135
-
136
- #define FOR_EACH_PARAM_OF_PQexecPrepared(param) \
137
- param(PGconn *, conn) \
138
- param(const char *, stmtName) \
139
- param(int, nParams) \
140
- param(const char * const *, paramValues) \
141
- param(const int *, paramLengths) \
142
- param(const int *, paramFormats)
143
-
144
- #define FOR_EACH_PARAM_OF_PQprepare(param) \
145
- param(PGconn *, conn) \
146
- param(const char *, stmtName) \
147
- param(const char *, query) \
148
- param(int, nParams)
149
-
150
- #define FOR_EACH_PARAM_OF_PQdescribePrepared(param) \
151
- param(PGconn *, conn)
152
-
153
- #define FOR_EACH_PARAM_OF_PQdescribePortal(param) \
154
- param(PGconn *, conn)
155
-
156
- #define FOR_EACH_PARAM_OF_PQclosePrepared(param) \
157
- param(PGconn *, conn)
158
-
159
- #define FOR_EACH_PARAM_OF_PQclosePortal(param) \
160
- param(PGconn *, conn)
161
-
162
- #define FOR_EACH_PARAM_OF_PQgetResult(param)
163
-
164
- #define FOR_EACH_PARAM_OF_PQputCopyData(param) \
165
- param(PGconn *, conn) \
166
- param(const char *, buffer)
167
-
168
- #define FOR_EACH_PARAM_OF_PQputCopyEnd(param) \
169
- param(PGconn *, conn)
170
-
171
- #define FOR_EACH_PARAM_OF_PQgetCopyData(param) \
172
- param(PGconn *, conn) \
173
- param(char **, buffer)
174
-
175
- #define FOR_EACH_PARAM_OF_PQnotifies(param)
176
-
177
- #define FOR_EACH_PARAM_OF_PQsendQuery(param) \
178
- param(PGconn *, conn)
179
-
180
- #define FOR_EACH_PARAM_OF_PQsendQueryParams(param) \
181
- param(PGconn *, conn) \
182
- param(const char *, command) \
183
- param(int, nParams) \
184
- param(const Oid *, paramTypes) \
185
- param(const char *const *, paramValues) \
186
- param(const int *, paramLengths) \
187
- param(const int *, paramFormats)
188
-
189
- #define FOR_EACH_PARAM_OF_PQsendPrepare(param) \
190
- param(PGconn *, conn) \
191
- param(const char *, stmtName) \
192
- param(const char *, query) \
193
- param(int, nParams)
194
-
195
- #define FOR_EACH_PARAM_OF_PQsendQueryPrepared(param) \
196
- param(PGconn *, conn) \
197
- param(const char *, stmtName) \
198
- param(int, nParams) \
199
- param(const char *const *, paramValues) \
200
- param(const int *, paramLengths) \
201
- param(const int *, paramFormats)
202
-
203
- #define FOR_EACH_PARAM_OF_PQsendDescribePrepared(param) \
204
- param(PGconn *, conn)
205
-
206
- #define FOR_EACH_PARAM_OF_PQsendDescribePortal(param) \
207
- param(PGconn *, conn)
208
-
209
- #define FOR_EACH_PARAM_OF_PQsendClosePrepared(param) \
210
- param(PGconn *, conn)
211
-
212
- #define FOR_EACH_PARAM_OF_PQsendClosePortal(param) \
213
- param(PGconn *, conn)
214
-
215
- #define FOR_EACH_PARAM_OF_PQpipelineSync(param)
216
-
217
- #define FOR_EACH_PARAM_OF_PQsendPipelineSync(param)
218
-
219
- #define FOR_EACH_PARAM_OF_PQsetClientEncoding(param) \
220
- param(PGconn *, conn)
221
-
222
- #define FOR_EACH_PARAM_OF_PQisBusy(param)
223
-
224
- #define FOR_EACH_PARAM_OF_PQcancelBlocking(param)
225
144
  #define FOR_EACH_PARAM_OF_PQcancelStart(param)
226
145
  #define FOR_EACH_PARAM_OF_PQcancelPoll(param)
227
146
 
228
- #define FOR_EACH_PARAM_OF_PQencryptPasswordConn(param) \
229
- param(PGconn *, conn) \
230
- param(const char *, passwd) \
231
- param(const char *, user)
232
-
233
- #define FOR_EACH_PARAM_OF_PQcancel(param) \
234
- param(PGcancel *, cancel) \
235
- param(char *, errbuf)
236
-
237
147
  /* function( name, void_or_nonvoid, returntype, lastparamtype, lastparamname ) */
238
148
  #define FOR_EACH_BLOCKING_FUNCTION(function) \
239
- function(PQconnectdb, GVL_TYPE_NONVOID, PGconn *, const char *, conninfo) \
240
149
  function(PQconnectStart, GVL_TYPE_NONVOID, PGconn *, const char *, conninfo) \
241
150
  function(PQconnectPoll, GVL_TYPE_NONVOID, PostgresPollingStatusType, PGconn *, conn) \
242
- function(PQreset, GVL_TYPE_VOID, void, PGconn *, conn) \
243
151
  function(PQresetStart, GVL_TYPE_NONVOID, int, PGconn *, conn) \
244
152
  function(PQresetPoll, GVL_TYPE_NONVOID, PostgresPollingStatusType, PGconn *, conn) \
245
153
  function(PQping, GVL_TYPE_NONVOID, PGPing, const char *, conninfo) \
246
- function(PQexec, GVL_TYPE_NONVOID, PGresult *, const char *, command) \
247
- function(PQexecParams, GVL_TYPE_NONVOID, PGresult *, int, resultFormat) \
248
- function(PQexecPrepared, GVL_TYPE_NONVOID, PGresult *, int, resultFormat) \
249
- function(PQprepare, GVL_TYPE_NONVOID, PGresult *, const Oid *, paramTypes) \
250
- function(PQdescribePrepared, GVL_TYPE_NONVOID, PGresult *, const char *, stmtName) \
251
- function(PQdescribePortal, GVL_TYPE_NONVOID, PGresult *, const char *, portalName) \
252
- function(PQclosePrepared, GVL_TYPE_NONVOID, PGresult *, const char *, stmtName) \
253
- function(PQclosePortal, GVL_TYPE_NONVOID, PGresult *, const char *, portalName) \
254
- function(PQgetResult, GVL_TYPE_NONVOID, PGresult *, PGconn *, conn) \
255
- function(PQputCopyData, GVL_TYPE_NONVOID, int, int, nbytes) \
256
- function(PQputCopyEnd, GVL_TYPE_NONVOID, int, const char *, errormsg) \
257
- function(PQgetCopyData, GVL_TYPE_NONVOID, int, int, async) \
258
- function(PQnotifies, GVL_TYPE_NONVOID, PGnotify *, PGconn *, conn) \
259
- function(PQsendQuery, GVL_TYPE_NONVOID, int, const char *, query) \
260
- function(PQsendQueryParams, GVL_TYPE_NONVOID, int, int, resultFormat) \
261
- function(PQsendPrepare, GVL_TYPE_NONVOID, int, const Oid *, paramTypes) \
262
- function(PQsendQueryPrepared, GVL_TYPE_NONVOID, int, int, resultFormat) \
263
- function(PQsendDescribePrepared, GVL_TYPE_NONVOID, int, const char *, stmt) \
264
- function(PQsendDescribePortal, GVL_TYPE_NONVOID, int, const char *, portal) \
265
- function(PQsendClosePrepared, GVL_TYPE_NONVOID, int, const char *, stmt) \
266
- function(PQsendClosePortal, GVL_TYPE_NONVOID, int, const char *, portal) \
267
- function(PQpipelineSync, GVL_TYPE_NONVOID, int, PGconn *, conn) \
268
- function(PQsendPipelineSync, GVL_TYPE_NONVOID, int, PGconn *, conn) \
269
- function(PQsetClientEncoding, GVL_TYPE_NONVOID, int, const char *, encoding) \
270
- function(PQisBusy, GVL_TYPE_NONVOID, int, PGconn *, conn) \
271
- function(PQcancelBlocking, GVL_TYPE_NONVOID, int, PGcancelConn *, conn) \
272
154
  function(PQcancelStart, GVL_TYPE_NONVOID, int, PGcancelConn *, conn) \
273
155
  function(PQcancelPoll, GVL_TYPE_NONVOID, PostgresPollingStatusType, PGcancelConn *, conn) \
274
- function(PQencryptPasswordConn, GVL_TYPE_NONVOID, char *, const char *, algorithm) \
275
- function(PQcancel, GVL_TYPE_NONVOID, int, int, errbufsize);
276
156
 
277
157
  FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_STUB_DECL );
278
158
 
data/ext/pg.c CHANGED
@@ -212,10 +212,10 @@ pg_get_rb_encoding_as_pg_encoding( rb_encoding *enc )
212
212
  *
213
213
  */
214
214
  char *
215
- pg_rb_str_ensure_capa( VALUE str, long expand_len, char *curr_ptr, char **end_ptr )
215
+ pg_rb_str_ensure_capa( VALUE str, size_t expand_len, char *curr_ptr, char **end_ptr )
216
216
  {
217
- long curr_len = curr_ptr - RSTRING_PTR(str);
218
- long curr_capa = rb_str_capacity( str );
217
+ size_t curr_len = curr_ptr - RSTRING_PTR(str);
218
+ size_t curr_capa = rb_str_capacity( str );
219
219
  if( curr_capa < curr_len + expand_len ){
220
220
  rb_str_set_len( str, curr_len );
221
221
  rb_str_modify_expand( str, (curr_len + expand_len) * 2 - curr_capa );
@@ -384,14 +384,10 @@ Init_pg_ext(void)
384
384
  rb_define_const(rb_mPGconstants, "CONNECTION_SSL_STARTUP", INT2FIX(CONNECTION_SSL_STARTUP));
385
385
  /* Internal state - PG.connect() needed. */
386
386
  rb_define_const(rb_mPGconstants, "CONNECTION_NEEDED", INT2FIX(CONNECTION_NEEDED));
387
- #if PG_MAJORVERSION_NUM >= 10
388
- /* Checking if session is read-write. Available since PostgreSQL-10. */
387
+ /* Checking if session is read-write. */
389
388
  rb_define_const(rb_mPGconstants, "CONNECTION_CHECK_WRITABLE", INT2FIX(CONNECTION_CHECK_WRITABLE));
390
- #endif
391
- #if PG_MAJORVERSION_NUM >= 10
392
- /* Consuming any extra messages. Available since PostgreSQL-10. */
389
+ /* Consuming any extra messages. */
393
390
  rb_define_const(rb_mPGconstants, "CONNECTION_CONSUME", INT2FIX(CONNECTION_CONSUME));
394
- #endif
395
391
  #if PG_MAJORVERSION_NUM >= 12
396
392
  /* Negotiating GSSAPI. Available since PostgreSQL-12. */
397
393
  rb_define_const(rb_mPGconstants, "CONNECTION_GSS_STARTUP", INT2FIX(CONNECTION_GSS_STARTUP));
@@ -508,12 +504,12 @@ Init_pg_ext(void)
508
504
  rb_define_const(rb_mPGconstants, "PGRES_COPY_BOTH", INT2FIX(PGRES_COPY_BOTH));
509
505
  /* Result#result_status constant - Single tuple from larger resultset. */
510
506
  rb_define_const(rb_mPGconstants, "PGRES_SINGLE_TUPLE", INT2FIX(PGRES_SINGLE_TUPLE));
511
- #ifdef HAVE_PQSETCHUNKEDROWSMODE
507
+ #ifdef LIBPQ_HAS_CHUNK_MODE
512
508
  /* Result#result_status constant - tuple chunk from larger resultset. */
513
509
  rb_define_const(rb_mPGconstants, "PGRES_TUPLES_CHUNK", INT2FIX(PGRES_TUPLES_CHUNK));
514
510
  #endif
515
511
 
516
- #ifdef HAVE_PQENTERPIPELINEMODE
512
+ #ifdef LIBPQ_HAS_PIPELINING
517
513
  /* Result#result_status constant - The PG::Result represents a synchronization point in pipeline mode, requested by Connection#pipeline_sync.
518
514
  *
519
515
  * This status occurs only when pipeline mode has been selected. */
@@ -643,7 +639,7 @@ Init_pg_ext(void)
643
639
  rb_define_const(rb_mPGconstants, "PG_DIAG_CONSTRAINT_NAME", INT2FIX(PG_DIAG_CONSTRAINT_NAME));
644
640
  #endif
645
641
 
646
- #ifdef HAVE_PQENTERPIPELINEMODE
642
+ #ifdef LIBPQ_HAS_PIPELINING
647
643
  /* Connection#pipeline_status constant
648
644
  *
649
645
  * The libpq connection is in pipeline mode.
data/ext/pg.h CHANGED
@@ -82,12 +82,8 @@ typedef long suseconds_t;
82
82
 
83
83
  #define pg_gc_location(x) x = rb_gc_location(x)
84
84
 
85
- /* For compatibility with ruby < 3.0 */
86
- #ifndef RUBY_TYPED_FROZEN_SHAREABLE
87
- #define PG_RUBY_TYPED_FROZEN_SHAREABLE 0
88
- #else
89
- #define PG_RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE
90
- #endif
85
+ extern int ruby_native_thread_p(void);
86
+
91
87
  #define PG_ENC_IDX_BITS 28
92
88
 
93
89
  /* The data behind each PG::Connection object */
@@ -103,6 +99,8 @@ typedef struct {
103
99
  VALUE notice_receiver;
104
100
  /* Proc object that receives notices as String objects */
105
101
  VALUE notice_processor;
102
+ /* Corresponding PG::Connection ruby object. Only used for the notice_receiver */
103
+ VALUE self;
106
104
  /* Kind of PG::TypeMap object for casting query params */
107
105
  VALUE type_map_for_queries;
108
106
  /* Kind of PG::TypeMap object for casting result values */
@@ -116,7 +114,7 @@ typedef struct {
116
114
  /* Ruby encoding index of the client/internal encoding */
117
115
  int enc_idx : PG_ENC_IDX_BITS;
118
116
  /* flags controlling Symbol/String field names */
119
- unsigned int flags : 2;
117
+ unsigned int flags : 1;
120
118
  /* enable automatic flushing of send data at the end of send_query calls */
121
119
  unsigned int flush_data : 1;
122
120
 
@@ -151,7 +149,7 @@ typedef struct {
151
149
  unsigned int autoclear : 1;
152
150
 
153
151
  /* flags controlling Symbol/String field names */
154
- unsigned int flags : 2;
152
+ unsigned int flags : 1;
155
153
 
156
154
  /* Number of fields in fnames[] .
157
155
  * Set to -1 if fnames[] is not yet initialized.
@@ -181,9 +179,8 @@ typedef VALUE (* t_pg_typecast_result)(t_typemap *, VALUE, int, int);
181
179
  typedef t_pg_coder *(* t_pg_typecast_query_param)(t_typemap *, VALUE, int);
182
180
  typedef VALUE (* t_pg_typecast_copy_get)( t_typemap *, VALUE, int, int, int );
183
181
 
184
- #define PG_RESULT_FIELD_NAMES_MASK 0x03
182
+ #define PG_RESULT_FIELD_NAMES_MASK 0x01
185
183
  #define PG_RESULT_FIELD_NAMES_SYMBOL 0x01
186
- #define PG_RESULT_FIELD_NAMES_STATIC_SYMBOL 0x02
187
184
 
188
185
  #define PG_CODER_TIMESTAMP_DB_UTC 0x0
189
186
  #define PG_CODER_TIMESTAMP_DB_LOCAL 0x1
@@ -320,7 +317,7 @@ VALUE pg_tmbc_allocate _(( void ));
320
317
  void pg_coder_init_encoder _(( VALUE ));
321
318
  void pg_coder_init_decoder _(( VALUE ));
322
319
  void pg_coder_compact _(( void * ));
323
- char *pg_rb_str_ensure_capa _(( VALUE, long, char *, char ** ));
320
+ char *pg_rb_str_ensure_capa _(( VALUE, size_t, char *, char ** ));
324
321
 
325
322
  #define PG_RB_STR_ENSURE_CAPA( str, expand_len, curr_ptr, end_ptr ) \
326
323
  do { \
@@ -13,6 +13,7 @@
13
13
 
14
14
  VALUE rb_mPG_BinaryDecoder;
15
15
  static VALUE s_Date;
16
+ static VALUE s_Date_GREGORIAN; /* Date::GREGORIAN */
16
17
  static ID s_id_new;
17
18
 
18
19
 
@@ -218,6 +219,7 @@ pg_bin_dec_array(t_pg_coder *conv, const char *input_line, int len, int tuple, i
218
219
  cur_ptr += 8;
219
220
  }
220
221
  nitems = (int)nitems32;
222
+ if (nitems > (line_end_ptr - cur_ptr) / 4) goto length_error;
221
223
 
222
224
  dim = 0;
223
225
  arrays[dim] = rb_ary_new2(ndim == 0 ? 0 : dim_sizes[dim]);
@@ -403,7 +405,7 @@ pg_bin_dec_date(t_pg_coder *conv, const char *val, int len, int tuple, int field
403
405
  default:
404
406
  j2date(date + POSTGRES_EPOCH_JDATE, &year, &month, &day);
405
407
 
406
- return rb_funcall(s_Date, s_id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
408
+ return rb_funcall(s_Date, s_id_new, 4, INT2NUM(year), INT2NUM(month), INT2NUM(day), s_Date_GREGORIAN);
407
409
  }
408
410
  }
409
411
 
@@ -412,8 +414,10 @@ static VALUE
412
414
  init_pg_bin_decoder_date(VALUE rb_mPG_BinaryDecoder)
413
415
  {
414
416
  rb_require("date");
417
+ rb_gc_register_address(&s_Date);
418
+ rb_gc_register_address(&s_Date_GREGORIAN);
415
419
  s_Date = rb_const_get(rb_cObject, rb_intern("Date"));
416
- rb_gc_register_mark_object(s_Date);
420
+ s_Date_GREGORIAN = rb_const_get(s_Date, rb_intern("GREGORIAN"));
417
421
  s_id_new = rb_intern("new");
418
422
 
419
423
  /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Date", rb_cPG_SimpleDecoder ); */
@@ -11,6 +11,8 @@
11
11
  #endif
12
12
 
13
13
  VALUE rb_mPG_BinaryEncoder;
14
+ static ID s_id_gregorianP;
15
+ static ID s_id_gregorian;
14
16
  static ID s_id_year;
15
17
  static ID s_id_month;
16
18
  static ID s_id_day;
@@ -272,6 +274,9 @@ pg_bin_enc_date(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, i
272
274
  write_nbo32(PG_INT32_MIN, out);
273
275
  return 4;
274
276
  } {
277
+ /* Only create a new gregorian Date object if necessary */
278
+ if( rb_funcall(value, s_id_gregorianP, 0) != Qtrue )
279
+ value = rb_funcall(value, s_id_gregorian, 0);
275
280
  VALUE year = rb_funcall(value, s_id_year, 0);
276
281
  VALUE month = rb_funcall(value, s_id_month, 0);
277
282
  VALUE day = rb_funcall(value, s_id_day, 0);
@@ -554,6 +559,8 @@ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermed
554
559
  void
555
560
  init_pg_binary_encoder(void)
556
561
  {
562
+ s_id_gregorianP = rb_intern("gregorian?");
563
+ s_id_gregorian = rb_intern("gregorian");
557
564
  s_id_year = rb_intern("year");
558
565
  s_id_month = rb_intern("month");
559
566
  s_id_day = rb_intern("day");
@@ -6,14 +6,14 @@
6
6
  *
7
7
  * The class to represent a connection to cancel a query.
8
8
  *
9
- * On PostgreSQL-17+ client libaray this class is used to implement PG::Connection#cancel .
9
+ * On PostgreSQL-17+ client library this class is used to implement PG::Connection#cancel .
10
10
  * It works on older PostgreSQL server versions too.
11
11
  *
12
12
  * Available since PostgreSQL-17
13
13
  *
14
14
  */
15
15
 
16
- #ifdef HAVE_PQSETCHUNKEDROWSMODE
16
+ #ifdef LIBPQ_HAS_CHUNK_MODE
17
17
 
18
18
  static VALUE rb_cPG_Cancon;
19
19
  static ID s_id_autoclose_set;
@@ -75,7 +75,7 @@ static const rb_data_type_t pg_cancon_type = {
75
75
  pg_cancon_gc_compact,
76
76
  },
77
77
  0, 0,
78
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
78
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
79
79
  };
80
80
 
81
81
  /*
@@ -155,7 +155,7 @@ pg_cancon_initialize(VALUE self, VALUE rb_conn)
155
155
  *
156
156
  * Requests that the server abandons processing of the current command in a blocking manner.
157
157
  *
158
- * This method directly calls +PQcancelBlocking+ of libpq, so that it doesn't respond to ruby interrupts and doesn't trigger the +Thread.scheduler+ .
158
+ * This method directly calls +PQcancelBlocking+ of libpq, so that it doesn't allow parallel threads, doesn't respond to ruby interrupts and doesn't trigger the +Thread.scheduler+ .
159
159
  * It is threrfore recommended to call #cancel instead.
160
160
  *
161
161
  */
@@ -165,7 +165,7 @@ pg_cancon_sync_cancel(VALUE self)
165
165
  PGcancelConn *conn = pg_cancon_get_conn(self);
166
166
 
167
167
  pg_cancon_close_socket_io( self );
168
- if(gvl_PQcancelBlocking(conn) == 0)
168
+ if(PQcancelBlocking(conn) == 0)
169
169
  pg_raise_conn_error( rb_eConnectionBad, self, "PQcancelBlocking %s", PQcancelErrorMessage(conn));
170
170
  return Qnil;
171
171
  }
@@ -340,7 +340,7 @@ pg_cancon_finish(VALUE self)
340
340
  void
341
341
  init_pg_cancon(void)
342
342
  {
343
- #ifdef HAVE_PQSETCHUNKEDROWSMODE
343
+ #ifdef LIBPQ_HAS_CHUNK_MODE
344
344
  s_id_autoclose_set = rb_intern("autoclose=");
345
345
 
346
346
  rb_cPG_Cancon = rb_define_class_under( rb_mPG, "CancelConnection", rb_cObject );
data/ext/pg_coder.c CHANGED
@@ -101,7 +101,7 @@ const rb_data_type_t pg_coder_type = {
101
101
  0,
102
102
  // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
103
103
  // macro to update VALUE references, as to trigger write barriers.
104
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
104
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
105
105
  };
106
106
 
107
107
  static VALUE
@@ -123,7 +123,7 @@ static const rb_data_type_t pg_composite_coder_type = {
123
123
  },
124
124
  &pg_coder_type,
125
125
  0,
126
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
126
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
127
127
  };
128
128
 
129
129
  static VALUE
@@ -505,7 +505,7 @@ static const rb_data_type_t pg_coder_cfunc_type = {
505
505
  },
506
506
  0,
507
507
  0,
508
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
508
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
509
509
  };
510
510
 
511
511
  VALUE
@@ -631,7 +631,7 @@ init_pg_coder(void)
631
631
  /*
632
632
  * Name of the coder or the corresponding data type.
633
633
  *
634
- * This accessor is only used in PG::Coder#inspect .
634
+ * This accessor is used by PG::Coder#inspect and PG::Connection#embed_params .
635
635
  */
636
636
  rb_define_attr( rb_cPG_Coder, "name", 1, 1 );
637
637