pg 1.5.9 → 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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/{History.md → CHANGELOG.md} +126 -0
- data/Gemfile +11 -7
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +83 -32
- data/README.md +79 -29
- data/Rakefile +84 -19
- data/certs/larskanis-2026.pem +24 -0
- data/ext/errorcodes.def +9 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +8 -1
- data/ext/extconf.rb +194 -30
- data/ext/gvl_wrappers.c +13 -2
- data/ext/gvl_wrappers.h +47 -134
- data/ext/pg.c +23 -16
- data/ext/pg.h +23 -24
- data/ext/pg_binary_decoder.c +157 -3
- data/ext/pg_binary_encoder.c +219 -9
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +58 -9
- data/ext/pg_connection.c +558 -291
- data/ext/pg_copy_coder.c +36 -23
- data/ext/pg_record_coder.c +11 -7
- data/ext/pg_result.c +144 -76
- data/ext/pg_text_decoder.c +7 -7
- data/ext/pg_text_encoder.c +29 -11
- data/ext/pg_tuple.c +9 -9
- data/ext/pg_type_map.c +45 -3
- data/ext/pg_type_map_all_strings.c +3 -3
- data/ext/pg_type_map_by_class.c +2 -2
- data/ext/pg_type_map_by_column.c +4 -3
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +4 -2
- data/ext/pg_type_map_in_ruby.c +2 -2
- data/ext/pg_util.c +2 -2
- data/ext/pg_util.h +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +5 -0
- data/lib/pg/basic_type_map_for_queries.rb +16 -5
- data/lib/pg/basic_type_map_for_results.rb +5 -0
- data/lib/pg/basic_type_registry.rb +2 -2
- data/lib/pg/cancel_connection.rb +53 -0
- data/lib/pg/coder.rb +4 -2
- data/lib/pg/connection.rb +393 -180
- data/lib/pg/text_decoder/date.rb +1 -1
- data/lib/pg/text_decoder/json.rb +1 -1
- data/lib/pg/text_encoder/date.rb +7 -1
- data/lib/pg/text_encoder/json.rb +1 -1
- data/lib/pg/version.rb +2 -1
- data/lib/pg.rb +156 -130
- data/misc/glibc/Dockerfile +20 -0
- data/misc/glibc/docker-compose.yml +9 -0
- data/misc/glibc/glibc_spec.rb +5 -0
- data/misc/yugabyte/Dockerfile +9 -0
- data/misc/yugabyte/docker-compose.yml +28 -0
- data/misc/yugabyte/pg-test.rb +45 -0
- data/pg.gemspec +5 -3
- data/ports/patches/krb5/1.22.2/0001-Allow-static-linking-krb5-library.patch +30 -0
- data/ports/patches/krb5/1.22.2/0002-unknown-command-line-option-on-clang.patch +12 -0
- data/ports/patches/postgresql/18.6/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
- data/rakelib/pg_gem_helper.rb +64 -0
- data/sample/async_mixed.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +36 -22
- metadata.gz.sig +0 -0
- data/Manifest.txt +0 -72
- data/Rakefile.cross +0 -303
data/ext/gvl_wrappers.h
CHANGED
|
@@ -15,12 +15,21 @@
|
|
|
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
|
|
|
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
|
|
30
|
+
typedef struct pg_cancel_conn PGcancelConn;
|
|
31
|
+
#endif
|
|
32
|
+
|
|
24
33
|
#define DEFINE_PARAM_LIST1(type, name) \
|
|
25
34
|
name,
|
|
26
35
|
|
|
@@ -79,20 +88,35 @@
|
|
|
79
88
|
}
|
|
80
89
|
|
|
81
90
|
#ifdef ENABLE_GVL_UNLOCK
|
|
82
|
-
#
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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, ¶ms); \
|
|
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(¶ms); \
|
|
108
|
+
} else { \
|
|
109
|
+
rb_thread_call_with_gvl(gvl_##name##_skeleton, ¶ms); \
|
|
110
|
+
} \
|
|
111
|
+
when_non_void( return params.retval; ) \
|
|
112
|
+
}
|
|
113
|
+
#endif
|
|
90
114
|
#else
|
|
91
|
-
#define DEFINE_GVLCB_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
+
}
|
|
96
120
|
#endif
|
|
97
121
|
|
|
98
122
|
#define GVL_TYPE_VOID(string)
|
|
@@ -101,145 +125,34 @@
|
|
|
101
125
|
|
|
102
126
|
/*
|
|
103
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 .
|
|
104
134
|
*/
|
|
105
135
|
|
|
106
|
-
#define FOR_EACH_PARAM_OF_PQconnectdb(param)
|
|
107
|
-
|
|
108
136
|
#define FOR_EACH_PARAM_OF_PQconnectStart(param)
|
|
109
|
-
|
|
110
137
|
#define FOR_EACH_PARAM_OF_PQconnectPoll(param)
|
|
111
138
|
|
|
112
|
-
#define FOR_EACH_PARAM_OF_PQreset(param)
|
|
113
|
-
|
|
114
139
|
#define FOR_EACH_PARAM_OF_PQresetStart(param)
|
|
115
|
-
|
|
116
140
|
#define FOR_EACH_PARAM_OF_PQresetPoll(param)
|
|
117
141
|
|
|
118
142
|
#define FOR_EACH_PARAM_OF_PQping(param)
|
|
119
143
|
|
|
120
|
-
#define
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
#define FOR_EACH_PARAM_OF_PQexecParams(param) \
|
|
124
|
-
param(PGconn *, conn) \
|
|
125
|
-
param(const char *, command) \
|
|
126
|
-
param(int, nParams) \
|
|
127
|
-
param(const Oid *, paramTypes) \
|
|
128
|
-
param(const char * const *, paramValues) \
|
|
129
|
-
param(const int *, paramLengths) \
|
|
130
|
-
param(const int *, paramFormats)
|
|
131
|
-
|
|
132
|
-
#define FOR_EACH_PARAM_OF_PQexecPrepared(param) \
|
|
133
|
-
param(PGconn *, conn) \
|
|
134
|
-
param(const char *, stmtName) \
|
|
135
|
-
param(int, nParams) \
|
|
136
|
-
param(const char * const *, paramValues) \
|
|
137
|
-
param(const int *, paramLengths) \
|
|
138
|
-
param(const int *, paramFormats)
|
|
139
|
-
|
|
140
|
-
#define FOR_EACH_PARAM_OF_PQprepare(param) \
|
|
141
|
-
param(PGconn *, conn) \
|
|
142
|
-
param(const char *, stmtName) \
|
|
143
|
-
param(const char *, query) \
|
|
144
|
-
param(int, nParams)
|
|
145
|
-
|
|
146
|
-
#define FOR_EACH_PARAM_OF_PQdescribePrepared(param) \
|
|
147
|
-
param(PGconn *, conn)
|
|
148
|
-
|
|
149
|
-
#define FOR_EACH_PARAM_OF_PQdescribePortal(param) \
|
|
150
|
-
param(PGconn *, conn)
|
|
151
|
-
|
|
152
|
-
#define FOR_EACH_PARAM_OF_PQgetResult(param)
|
|
153
|
-
|
|
154
|
-
#define FOR_EACH_PARAM_OF_PQputCopyData(param) \
|
|
155
|
-
param(PGconn *, conn) \
|
|
156
|
-
param(const char *, buffer)
|
|
157
|
-
|
|
158
|
-
#define FOR_EACH_PARAM_OF_PQputCopyEnd(param) \
|
|
159
|
-
param(PGconn *, conn)
|
|
160
|
-
|
|
161
|
-
#define FOR_EACH_PARAM_OF_PQgetCopyData(param) \
|
|
162
|
-
param(PGconn *, conn) \
|
|
163
|
-
param(char **, buffer)
|
|
164
|
-
|
|
165
|
-
#define FOR_EACH_PARAM_OF_PQnotifies(param)
|
|
166
|
-
|
|
167
|
-
#define FOR_EACH_PARAM_OF_PQsendQuery(param) \
|
|
168
|
-
param(PGconn *, conn)
|
|
169
|
-
|
|
170
|
-
#define FOR_EACH_PARAM_OF_PQsendQueryParams(param) \
|
|
171
|
-
param(PGconn *, conn) \
|
|
172
|
-
param(const char *, command) \
|
|
173
|
-
param(int, nParams) \
|
|
174
|
-
param(const Oid *, paramTypes) \
|
|
175
|
-
param(const char *const *, paramValues) \
|
|
176
|
-
param(const int *, paramLengths) \
|
|
177
|
-
param(const int *, paramFormats)
|
|
178
|
-
|
|
179
|
-
#define FOR_EACH_PARAM_OF_PQsendPrepare(param) \
|
|
180
|
-
param(PGconn *, conn) \
|
|
181
|
-
param(const char *, stmtName) \
|
|
182
|
-
param(const char *, query) \
|
|
183
|
-
param(int, nParams)
|
|
184
|
-
|
|
185
|
-
#define FOR_EACH_PARAM_OF_PQsendQueryPrepared(param) \
|
|
186
|
-
param(PGconn *, conn) \
|
|
187
|
-
param(const char *, stmtName) \
|
|
188
|
-
param(int, nParams) \
|
|
189
|
-
param(const char *const *, paramValues) \
|
|
190
|
-
param(const int *, paramLengths) \
|
|
191
|
-
param(const int *, paramFormats)
|
|
192
|
-
|
|
193
|
-
#define FOR_EACH_PARAM_OF_PQsendDescribePrepared(param) \
|
|
194
|
-
param(PGconn *, conn)
|
|
195
|
-
|
|
196
|
-
#define FOR_EACH_PARAM_OF_PQsendDescribePortal(param) \
|
|
197
|
-
param(PGconn *, conn)
|
|
198
|
-
|
|
199
|
-
#define FOR_EACH_PARAM_OF_PQsetClientEncoding(param) \
|
|
200
|
-
param(PGconn *, conn)
|
|
201
|
-
|
|
202
|
-
#define FOR_EACH_PARAM_OF_PQisBusy(param)
|
|
203
|
-
|
|
204
|
-
#define FOR_EACH_PARAM_OF_PQencryptPasswordConn(param) \
|
|
205
|
-
param(PGconn *, conn) \
|
|
206
|
-
param(const char *, passwd) \
|
|
207
|
-
param(const char *, user)
|
|
208
|
-
|
|
209
|
-
#define FOR_EACH_PARAM_OF_PQcancel(param) \
|
|
210
|
-
param(PGcancel *, cancel) \
|
|
211
|
-
param(char *, errbuf)
|
|
144
|
+
#define FOR_EACH_PARAM_OF_PQcancelStart(param)
|
|
145
|
+
#define FOR_EACH_PARAM_OF_PQcancelPoll(param)
|
|
212
146
|
|
|
213
147
|
/* function( name, void_or_nonvoid, returntype, lastparamtype, lastparamname ) */
|
|
214
148
|
#define FOR_EACH_BLOCKING_FUNCTION(function) \
|
|
215
|
-
function(PQconnectdb, GVL_TYPE_NONVOID, PGconn *, const char *, conninfo) \
|
|
216
149
|
function(PQconnectStart, GVL_TYPE_NONVOID, PGconn *, const char *, conninfo) \
|
|
217
150
|
function(PQconnectPoll, GVL_TYPE_NONVOID, PostgresPollingStatusType, PGconn *, conn) \
|
|
218
|
-
function(PQreset, GVL_TYPE_VOID, void, PGconn *, conn) \
|
|
219
151
|
function(PQresetStart, GVL_TYPE_NONVOID, int, PGconn *, conn) \
|
|
220
152
|
function(PQresetPoll, GVL_TYPE_NONVOID, PostgresPollingStatusType, PGconn *, conn) \
|
|
221
153
|
function(PQping, GVL_TYPE_NONVOID, PGPing, const char *, conninfo) \
|
|
222
|
-
function(
|
|
223
|
-
function(
|
|
224
|
-
function(PQexecPrepared, GVL_TYPE_NONVOID, PGresult *, int, resultFormat) \
|
|
225
|
-
function(PQprepare, GVL_TYPE_NONVOID, PGresult *, const Oid *, paramTypes) \
|
|
226
|
-
function(PQdescribePrepared, GVL_TYPE_NONVOID, PGresult *, const char *, stmtName) \
|
|
227
|
-
function(PQdescribePortal, GVL_TYPE_NONVOID, PGresult *, const char *, portalName) \
|
|
228
|
-
function(PQgetResult, GVL_TYPE_NONVOID, PGresult *, PGconn *, conn) \
|
|
229
|
-
function(PQputCopyData, GVL_TYPE_NONVOID, int, int, nbytes) \
|
|
230
|
-
function(PQputCopyEnd, GVL_TYPE_NONVOID, int, const char *, errormsg) \
|
|
231
|
-
function(PQgetCopyData, GVL_TYPE_NONVOID, int, int, async) \
|
|
232
|
-
function(PQnotifies, GVL_TYPE_NONVOID, PGnotify *, PGconn *, conn) \
|
|
233
|
-
function(PQsendQuery, GVL_TYPE_NONVOID, int, const char *, query) \
|
|
234
|
-
function(PQsendQueryParams, GVL_TYPE_NONVOID, int, int, resultFormat) \
|
|
235
|
-
function(PQsendPrepare, GVL_TYPE_NONVOID, int, const Oid *, paramTypes) \
|
|
236
|
-
function(PQsendQueryPrepared, GVL_TYPE_NONVOID, int, int, resultFormat) \
|
|
237
|
-
function(PQsendDescribePrepared, GVL_TYPE_NONVOID, int, const char *, stmt) \
|
|
238
|
-
function(PQsendDescribePortal, GVL_TYPE_NONVOID, int, const char *, portal) \
|
|
239
|
-
function(PQsetClientEncoding, GVL_TYPE_NONVOID, int, const char *, encoding) \
|
|
240
|
-
function(PQisBusy, GVL_TYPE_NONVOID, int, PGconn *, conn) \
|
|
241
|
-
function(PQencryptPasswordConn, GVL_TYPE_NONVOID, char *, const char *, algorithm) \
|
|
242
|
-
function(PQcancel, GVL_TYPE_NONVOID, int, int, errbufsize);
|
|
154
|
+
function(PQcancelStart, GVL_TYPE_NONVOID, int, PGcancelConn *, conn) \
|
|
155
|
+
function(PQcancelPoll, GVL_TYPE_NONVOID, PostgresPollingStatusType, PGcancelConn *, conn) \
|
|
243
156
|
|
|
244
157
|
FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_STUB_DECL );
|
|
245
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,
|
|
215
|
+
pg_rb_str_ensure_capa( VALUE str, size_t expand_len, char *curr_ptr, char **end_ptr )
|
|
216
216
|
{
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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));
|
|
@@ -404,6 +400,10 @@ Init_pg_ext(void)
|
|
|
404
400
|
/* Checking if server is in standby mode. Available since PostgreSQL-14. */
|
|
405
401
|
rb_define_const(rb_mPGconstants, "CONNECTION_CHECK_STANDBY", INT2FIX(CONNECTION_CHECK_STANDBY));
|
|
406
402
|
#endif
|
|
403
|
+
#if PG_MAJORVERSION_NUM >= 17
|
|
404
|
+
/* Waiting for connection attempt to be started. Available since PostgreSQL-17. */
|
|
405
|
+
rb_define_const(rb_mPGconstants, "CONNECTION_ALLOCATED", INT2FIX(CONNECTION_ALLOCATED));
|
|
406
|
+
#endif
|
|
407
407
|
|
|
408
408
|
/****** PG::Connection CLASS CONSTANTS: Nonblocking connection polling status ******/
|
|
409
409
|
|
|
@@ -451,14 +451,12 @@ Init_pg_ext(void)
|
|
|
451
451
|
rb_define_const(rb_mPGconstants, "PQERRORS_SQLSTATE", INT2FIX(PQERRORS_SQLSTATE));
|
|
452
452
|
#endif
|
|
453
453
|
|
|
454
|
-
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
|
455
454
|
/* See Connection#set_error_context_visibility */
|
|
456
455
|
rb_define_const(rb_mPGconstants, "PQSHOW_CONTEXT_NEVER", INT2FIX(PQSHOW_CONTEXT_NEVER));
|
|
457
456
|
/* See Connection#set_error_context_visibility */
|
|
458
457
|
rb_define_const(rb_mPGconstants, "PQSHOW_CONTEXT_ERRORS", INT2FIX(PQSHOW_CONTEXT_ERRORS));
|
|
459
458
|
/* See Connection#set_error_context_visibility */
|
|
460
459
|
rb_define_const(rb_mPGconstants, "PQSHOW_CONTEXT_ALWAYS", INT2FIX(PQSHOW_CONTEXT_ALWAYS));
|
|
461
|
-
#endif
|
|
462
460
|
|
|
463
461
|
/****** PG::Connection CLASS CONSTANTS: Check Server Status ******/
|
|
464
462
|
|
|
@@ -506,8 +504,12 @@ Init_pg_ext(void)
|
|
|
506
504
|
rb_define_const(rb_mPGconstants, "PGRES_COPY_BOTH", INT2FIX(PGRES_COPY_BOTH));
|
|
507
505
|
/* Result#result_status constant - Single tuple from larger resultset. */
|
|
508
506
|
rb_define_const(rb_mPGconstants, "PGRES_SINGLE_TUPLE", INT2FIX(PGRES_SINGLE_TUPLE));
|
|
507
|
+
#ifdef LIBPQ_HAS_CHUNK_MODE
|
|
508
|
+
/* Result#result_status constant - tuple chunk from larger resultset. */
|
|
509
|
+
rb_define_const(rb_mPGconstants, "PGRES_TUPLES_CHUNK", INT2FIX(PGRES_TUPLES_CHUNK));
|
|
510
|
+
#endif
|
|
509
511
|
|
|
510
|
-
#ifdef
|
|
512
|
+
#ifdef LIBPQ_HAS_PIPELINING
|
|
511
513
|
/* Result#result_status constant - The PG::Result represents a synchronization point in pipeline mode, requested by Connection#pipeline_sync.
|
|
512
514
|
*
|
|
513
515
|
* This status occurs only when pipeline mode has been selected. */
|
|
@@ -530,16 +532,14 @@ Init_pg_ext(void)
|
|
|
530
532
|
*/
|
|
531
533
|
rb_define_const(rb_mPGconstants, "PG_DIAG_SEVERITY", INT2FIX(PG_DIAG_SEVERITY));
|
|
532
534
|
|
|
533
|
-
#ifdef PG_DIAG_SEVERITY_NONLOCALIZED
|
|
534
535
|
/* Result#result_error_field argument constant
|
|
535
536
|
*
|
|
536
537
|
* The severity; the field contents are ERROR, FATAL, or PANIC (in an error message), or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message).
|
|
537
538
|
* This is identical to the PG_DIAG_SEVERITY field except that the contents are never localized.
|
|
538
539
|
*
|
|
539
|
-
* Available since PostgreSQL-9.6
|
|
540
540
|
*/
|
|
541
541
|
rb_define_const(rb_mPGconstants, "PG_DIAG_SEVERITY_NONLOCALIZED", INT2FIX(PG_DIAG_SEVERITY_NONLOCALIZED));
|
|
542
|
-
|
|
542
|
+
|
|
543
543
|
/* Result#result_error_field argument constant
|
|
544
544
|
*
|
|
545
545
|
* The SQLSTATE code for the error.
|
|
@@ -639,7 +639,7 @@ Init_pg_ext(void)
|
|
|
639
639
|
rb_define_const(rb_mPGconstants, "PG_DIAG_CONSTRAINT_NAME", INT2FIX(PG_DIAG_CONSTRAINT_NAME));
|
|
640
640
|
#endif
|
|
641
641
|
|
|
642
|
-
#ifdef
|
|
642
|
+
#ifdef LIBPQ_HAS_PIPELINING
|
|
643
643
|
/* Connection#pipeline_status constant
|
|
644
644
|
*
|
|
645
645
|
* The libpq connection is in pipeline mode.
|
|
@@ -667,6 +667,12 @@ Init_pg_ext(void)
|
|
|
667
667
|
/* PostgreSQL compiled in default port */
|
|
668
668
|
rb_define_const(rb_mPGconstants, "DEF_PGPORT", INT2FIX(DEF_PGPORT));
|
|
669
669
|
|
|
670
|
+
#ifdef PG_IS_BINARY_GEM
|
|
671
|
+
rb_define_const(rb_mPG, "IS_BINARY_GEM", Qtrue);
|
|
672
|
+
#else
|
|
673
|
+
rb_define_const(rb_mPG, "IS_BINARY_GEM", Qfalse);
|
|
674
|
+
#endif
|
|
675
|
+
|
|
670
676
|
/* Add the constants to the toplevel namespace */
|
|
671
677
|
rb_include_module( rb_mPG, rb_mPGconstants );
|
|
672
678
|
|
|
@@ -689,4 +695,5 @@ Init_pg_ext(void)
|
|
|
689
695
|
init_pg_copycoder();
|
|
690
696
|
init_pg_recordcoder();
|
|
691
697
|
init_pg_tuple();
|
|
698
|
+
init_pg_cancon();
|
|
692
699
|
}
|
data/ext/pg.h
CHANGED
|
@@ -76,21 +76,14 @@ typedef long suseconds_t;
|
|
|
76
76
|
#define PG_MAX_COLUMNS 4000
|
|
77
77
|
#endif
|
|
78
78
|
|
|
79
|
-
#
|
|
80
|
-
#define
|
|
81
|
-
#define pg_gc_location(x) x = rb_gc_location(x)
|
|
82
|
-
#else
|
|
83
|
-
#define rb_gc_mark_movable(x) rb_gc_mark(x)
|
|
84
|
-
#define pg_compact_callback(x) {(x)}
|
|
85
|
-
#define pg_gc_location(x) UNUSED(x)
|
|
79
|
+
#ifndef HAVE_RB_HASH_NEW_CAPA
|
|
80
|
+
#define rb_hash_new_capa(x) rb_hash_new()
|
|
86
81
|
#endif
|
|
87
82
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
#define PG_RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE
|
|
93
|
-
#endif
|
|
83
|
+
#define pg_gc_location(x) x = rb_gc_location(x)
|
|
84
|
+
|
|
85
|
+
extern int ruby_native_thread_p(void);
|
|
86
|
+
|
|
94
87
|
#define PG_ENC_IDX_BITS 28
|
|
95
88
|
|
|
96
89
|
/* The data behind each PG::Connection object */
|
|
@@ -106,6 +99,8 @@ typedef struct {
|
|
|
106
99
|
VALUE notice_receiver;
|
|
107
100
|
/* Proc object that receives notices as String objects */
|
|
108
101
|
VALUE notice_processor;
|
|
102
|
+
/* Corresponding PG::Connection ruby object. Only used for the notice_receiver */
|
|
103
|
+
VALUE self;
|
|
109
104
|
/* Kind of PG::TypeMap object for casting query params */
|
|
110
105
|
VALUE type_map_for_queries;
|
|
111
106
|
/* Kind of PG::TypeMap object for casting result values */
|
|
@@ -119,14 +114,12 @@ typedef struct {
|
|
|
119
114
|
/* Ruby encoding index of the client/internal encoding */
|
|
120
115
|
int enc_idx : PG_ENC_IDX_BITS;
|
|
121
116
|
/* flags controlling Symbol/String field names */
|
|
122
|
-
unsigned int flags :
|
|
117
|
+
unsigned int flags : 1;
|
|
123
118
|
/* enable automatic flushing of send data at the end of send_query calls */
|
|
124
119
|
unsigned int flush_data : 1;
|
|
125
120
|
|
|
126
|
-
#if defined(_WIN32)
|
|
127
121
|
/* File descriptor to be used for rb_w32_unwrap_io_handle() */
|
|
128
122
|
int ruby_sd;
|
|
129
|
-
#endif
|
|
130
123
|
} t_pg_connection;
|
|
131
124
|
|
|
132
125
|
typedef struct pg_coder t_pg_coder;
|
|
@@ -156,7 +149,7 @@ typedef struct {
|
|
|
156
149
|
unsigned int autoclear : 1;
|
|
157
150
|
|
|
158
151
|
/* flags controlling Symbol/String field names */
|
|
159
|
-
unsigned int flags :
|
|
152
|
+
unsigned int flags : 1;
|
|
160
153
|
|
|
161
154
|
/* Number of fields in fnames[] .
|
|
162
155
|
* Set to -1 if fnames[] is not yet initialized.
|
|
@@ -166,10 +159,8 @@ typedef struct {
|
|
|
166
159
|
/* Size of PGresult as published to ruby memory management. */
|
|
167
160
|
ssize_t result_size;
|
|
168
161
|
|
|
169
|
-
/*
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
/* Hash with fnames[] to field number mapping. */
|
|
162
|
+
/* Hash with fnames[] to field number mapping.
|
|
163
|
+
* Init on-demand to create PG::Tuple objects, otherwise Qnil. */
|
|
173
164
|
VALUE field_map;
|
|
174
165
|
|
|
175
166
|
/* List of field names as frozen String or Symbol objects.
|
|
@@ -188,9 +179,8 @@ typedef VALUE (* t_pg_typecast_result)(t_typemap *, VALUE, int, int);
|
|
|
188
179
|
typedef t_pg_coder *(* t_pg_typecast_query_param)(t_typemap *, VALUE, int);
|
|
189
180
|
typedef VALUE (* t_pg_typecast_copy_get)( t_typemap *, VALUE, int, int, int );
|
|
190
181
|
|
|
191
|
-
#define PG_RESULT_FIELD_NAMES_MASK
|
|
182
|
+
#define PG_RESULT_FIELD_NAMES_MASK 0x01
|
|
192
183
|
#define PG_RESULT_FIELD_NAMES_SYMBOL 0x01
|
|
193
|
-
#define PG_RESULT_FIELD_NAMES_STATIC_SYMBOL 0x02
|
|
194
184
|
|
|
195
185
|
#define PG_CODER_TIMESTAMP_DB_UTC 0x0
|
|
196
186
|
#define PG_CODER_TIMESTAMP_DB_LOCAL 0x1
|
|
@@ -215,6 +205,7 @@ typedef struct {
|
|
|
215
205
|
t_pg_coder comp;
|
|
216
206
|
t_pg_coder *elem;
|
|
217
207
|
int needs_quotation;
|
|
208
|
+
int dimensions;
|
|
218
209
|
char delimiter;
|
|
219
210
|
} t_pg_composite_coder;
|
|
220
211
|
|
|
@@ -312,6 +303,7 @@ void init_pg_text_decoder _(( void ));
|
|
|
312
303
|
void init_pg_binary_encoder _(( void ));
|
|
313
304
|
void init_pg_binary_decoder _(( void ));
|
|
314
305
|
void init_pg_tuple _(( void ));
|
|
306
|
+
void init_pg_cancon _(( void ));
|
|
315
307
|
VALUE lookup_error_class _(( const char * ));
|
|
316
308
|
VALUE pg_bin_dec_bytea _(( t_pg_coder*, const char *, int, int, int, int ));
|
|
317
309
|
VALUE pg_text_dec_string _(( t_pg_coder*, const char *, int, int, int, int ));
|
|
@@ -325,7 +317,7 @@ VALUE pg_tmbc_allocate _(( void ));
|
|
|
325
317
|
void pg_coder_init_encoder _(( VALUE ));
|
|
326
318
|
void pg_coder_init_decoder _(( VALUE ));
|
|
327
319
|
void pg_coder_compact _(( void * ));
|
|
328
|
-
char *pg_rb_str_ensure_capa _(( VALUE,
|
|
320
|
+
char *pg_rb_str_ensure_capa _(( VALUE, size_t, char *, char ** ));
|
|
329
321
|
|
|
330
322
|
#define PG_RB_STR_ENSURE_CAPA( str, expand_len, curr_ptr, end_ptr ) \
|
|
331
323
|
do { \
|
|
@@ -351,6 +343,13 @@ void pg_typemap_compact _(( void * ));
|
|
|
351
343
|
PGconn *pg_get_pgconn _(( VALUE ));
|
|
352
344
|
t_pg_connection *pg_get_connection _(( VALUE ));
|
|
353
345
|
VALUE pgconn_block _(( int, VALUE *, VALUE ));
|
|
346
|
+
#ifdef __GNUC__
|
|
347
|
+
__attribute__((format(printf, 3, 4)))
|
|
348
|
+
#endif
|
|
349
|
+
NORETURN(void pg_raise_conn_error _(( VALUE klass, VALUE self, const char *format, ...)));
|
|
350
|
+
VALUE pg_wrap_socket_io _(( int sd, VALUE self, VALUE *p_socket_io, int *p_ruby_sd ));
|
|
351
|
+
void pg_unwrap_socket_io _(( VALUE self, VALUE *p_socket_io, int ruby_sd ));
|
|
352
|
+
|
|
354
353
|
|
|
355
354
|
VALUE pg_new_result _(( PGresult *, VALUE ));
|
|
356
355
|
VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
|
data/ext/pg_binary_decoder.c
CHANGED
|
@@ -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
|
|
|
@@ -117,7 +118,7 @@ pg_bin_dec_to_base64(t_pg_coder *conv, const char *val, int len, int tuple, int
|
|
|
117
118
|
/* create a buffer of the encoded length */
|
|
118
119
|
VALUE out_value = rb_str_new(NULL, encoded_len);
|
|
119
120
|
|
|
120
|
-
|
|
121
|
+
rbpg_base64_encode( RSTRING_PTR(out_value), val, len );
|
|
121
122
|
|
|
122
123
|
/* Is it a pure String conversion? Then we can directly send out_value to the user. */
|
|
123
124
|
if( this->comp.format == 0 && dec_func == pg_text_dec_string ){
|
|
@@ -133,6 +134,155 @@ pg_bin_dec_to_base64(t_pg_coder *conv, const char *val, int len, int tuple, int
|
|
|
133
134
|
return out_value;
|
|
134
135
|
}
|
|
135
136
|
|
|
137
|
+
/*
|
|
138
|
+
* Maximum number of array subscripts (arbitrary limit)
|
|
139
|
+
*/
|
|
140
|
+
#define MAXDIM 6
|
|
141
|
+
|
|
142
|
+
/*
|
|
143
|
+
* Document-class: PG::BinaryDecoder::Array < PG::CompositeDecoder
|
|
144
|
+
*
|
|
145
|
+
* This is a decoder class for conversion of binary array types.
|
|
146
|
+
*
|
|
147
|
+
* It returns an Array with possibly an arbitrary number of sub-Arrays.
|
|
148
|
+
* All values are decoded according to the #elements_type accessor.
|
|
149
|
+
* Sub-arrays are decoded recursively.
|
|
150
|
+
*
|
|
151
|
+
* This decoder simply ignores any dimension decorations preceding the array values.
|
|
152
|
+
* It returns all array values as regular ruby Array with a zero based index, regardless of the index given in the dimension decoration.
|
|
153
|
+
*
|
|
154
|
+
* An array decoder which respects dimension decorations is waiting to be implemented.
|
|
155
|
+
*
|
|
156
|
+
*/
|
|
157
|
+
static VALUE
|
|
158
|
+
pg_bin_dec_array(t_pg_coder *conv, const char *input_line, int len, int tuple, int field, int enc_idx)
|
|
159
|
+
{
|
|
160
|
+
t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
|
|
161
|
+
t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
|
|
162
|
+
|
|
163
|
+
/* Current field */
|
|
164
|
+
VALUE field_str;
|
|
165
|
+
|
|
166
|
+
int32_t nitems32;
|
|
167
|
+
int i;
|
|
168
|
+
int ndim;
|
|
169
|
+
int nitems;
|
|
170
|
+
int flags;
|
|
171
|
+
int dim;
|
|
172
|
+
int dim_sizes[MAXDIM];
|
|
173
|
+
VALUE arrays[MAXDIM];
|
|
174
|
+
char *output_ptr;
|
|
175
|
+
const char *cur_ptr;
|
|
176
|
+
const char *line_end_ptr;
|
|
177
|
+
char *end_capa_ptr;
|
|
178
|
+
|
|
179
|
+
/* Allocate a new string with embedded capacity and realloc later with
|
|
180
|
+
* exponential growing size when needed. */
|
|
181
|
+
PG_RB_STR_NEW( field_str, output_ptr, end_capa_ptr );
|
|
182
|
+
|
|
183
|
+
/* set pointer variables for loop */
|
|
184
|
+
cur_ptr = input_line;
|
|
185
|
+
line_end_ptr = input_line + len;
|
|
186
|
+
|
|
187
|
+
/* read number of dimensions */
|
|
188
|
+
if (line_end_ptr - cur_ptr < 4 ) goto length_error;
|
|
189
|
+
ndim = read_nbo32(cur_ptr);
|
|
190
|
+
if (ndim < 0 || ndim > MAXDIM) {
|
|
191
|
+
rb_raise( rb_eArgError, "unsupported number of array dimensions: %d", ndim );
|
|
192
|
+
}
|
|
193
|
+
cur_ptr += 4;
|
|
194
|
+
|
|
195
|
+
/* read flags */
|
|
196
|
+
if (line_end_ptr - cur_ptr < 4 ) goto length_error;
|
|
197
|
+
flags = read_nbo32(cur_ptr);
|
|
198
|
+
if (flags != 0 && flags != 1) {
|
|
199
|
+
rb_raise( rb_eArgError, "unsupported binary array flags: %d", flags );
|
|
200
|
+
}
|
|
201
|
+
cur_ptr += 4;
|
|
202
|
+
|
|
203
|
+
/* ignore element OID */
|
|
204
|
+
if (line_end_ptr - cur_ptr < 4 ) goto length_error;
|
|
205
|
+
cur_ptr += 4;
|
|
206
|
+
|
|
207
|
+
nitems32 = ndim == 0 ? 0 : 1;
|
|
208
|
+
for (i = 0; i < ndim; i++) {
|
|
209
|
+
int64_t prod;
|
|
210
|
+
|
|
211
|
+
/* read size of dimensions and ignore lower bound */
|
|
212
|
+
if (line_end_ptr - cur_ptr < 8 ) goto length_error;
|
|
213
|
+
dim_sizes[i] = read_nbo32(cur_ptr);
|
|
214
|
+
prod = (int64_t) nitems32 * (int64_t) dim_sizes[i];
|
|
215
|
+
nitems32 = (int32_t) prod;
|
|
216
|
+
if (dim_sizes[i] < 0 || (int64_t) nitems32 != prod) {
|
|
217
|
+
rb_raise( rb_eArgError, "unsupported array size: %" PRId64, prod );
|
|
218
|
+
}
|
|
219
|
+
cur_ptr += 8;
|
|
220
|
+
}
|
|
221
|
+
nitems = (int)nitems32;
|
|
222
|
+
if (nitems > (line_end_ptr - cur_ptr) / 4) goto length_error;
|
|
223
|
+
|
|
224
|
+
dim = 0;
|
|
225
|
+
arrays[dim] = rb_ary_new2(ndim == 0 ? 0 : dim_sizes[dim]);
|
|
226
|
+
for (i = 0; i < nitems; i++) {
|
|
227
|
+
int input_len;
|
|
228
|
+
|
|
229
|
+
/* traverse dimensions down */
|
|
230
|
+
while (dim < ndim - 1) {
|
|
231
|
+
dim++;
|
|
232
|
+
arrays[dim] = rb_ary_new2(dim_sizes[dim]);
|
|
233
|
+
rb_ary_push(arrays[dim - 1], arrays[dim]);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* read element length */
|
|
237
|
+
if (line_end_ptr - cur_ptr < 4 ) goto length_error;
|
|
238
|
+
input_len = read_nbo32(cur_ptr);
|
|
239
|
+
cur_ptr += 4;
|
|
240
|
+
|
|
241
|
+
/* convert and put element into array */
|
|
242
|
+
if (input_len < 0) {
|
|
243
|
+
if (input_len != -1) goto length_error;
|
|
244
|
+
/* NULL indicator */
|
|
245
|
+
rb_ary_push(arrays[dim], Qnil);
|
|
246
|
+
} else {
|
|
247
|
+
VALUE field_value;
|
|
248
|
+
if (line_end_ptr - cur_ptr < input_len ) goto length_error;
|
|
249
|
+
|
|
250
|
+
/* copy input data to field_str */
|
|
251
|
+
PG_RB_STR_ENSURE_CAPA( field_str, input_len, output_ptr, end_capa_ptr );
|
|
252
|
+
memcpy(output_ptr, cur_ptr, input_len);
|
|
253
|
+
cur_ptr += input_len;
|
|
254
|
+
output_ptr += input_len;
|
|
255
|
+
/* convert field_str through the type map */
|
|
256
|
+
rb_str_set_len( field_str, output_ptr - RSTRING_PTR(field_str) );
|
|
257
|
+
field_value = dec_func(this->elem, RSTRING_PTR(field_str), input_len, tuple, field, enc_idx);
|
|
258
|
+
|
|
259
|
+
rb_ary_push(arrays[dim], field_value);
|
|
260
|
+
|
|
261
|
+
if( field_value == field_str ){
|
|
262
|
+
/* Our output string will be send to the user, so we can not reuse
|
|
263
|
+
* it for the next field. */
|
|
264
|
+
PG_RB_STR_NEW( field_str, output_ptr, end_capa_ptr );
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* Reset the pointer to the start of the output/buffer string. */
|
|
269
|
+
output_ptr = RSTRING_PTR(field_str);
|
|
270
|
+
|
|
271
|
+
/* traverse dimensions up */
|
|
272
|
+
while (RARRAY_LEN(arrays[dim]) >= dim_sizes[dim] && dim > 0) {
|
|
273
|
+
dim--;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (cur_ptr < line_end_ptr)
|
|
278
|
+
rb_raise( rb_eArgError, "trailing data after binary array data at position: %ld", (long)(cur_ptr - input_line) + 1 );
|
|
279
|
+
|
|
280
|
+
return arrays[0];
|
|
281
|
+
|
|
282
|
+
length_error:
|
|
283
|
+
rb_raise( rb_eArgError, "premature end of binary array data at position: %ld", (long)(cur_ptr - input_line) + 1 );
|
|
284
|
+
}
|
|
285
|
+
|
|
136
286
|
#define PG_INT64_MIN (-0x7FFFFFFFFFFFFFFFL - 1)
|
|
137
287
|
#define PG_INT64_MAX 0x7FFFFFFFFFFFFFFFL
|
|
138
288
|
|
|
@@ -255,7 +405,7 @@ pg_bin_dec_date(t_pg_coder *conv, const char *val, int len, int tuple, int field
|
|
|
255
405
|
default:
|
|
256
406
|
j2date(date + POSTGRES_EPOCH_JDATE, &year, &month, &day);
|
|
257
407
|
|
|
258
|
-
return rb_funcall(s_Date, s_id_new,
|
|
408
|
+
return rb_funcall(s_Date, s_id_new, 4, INT2NUM(year), INT2NUM(month), INT2NUM(day), s_Date_GREGORIAN);
|
|
259
409
|
}
|
|
260
410
|
}
|
|
261
411
|
|
|
@@ -264,8 +414,10 @@ static VALUE
|
|
|
264
414
|
init_pg_bin_decoder_date(VALUE rb_mPG_BinaryDecoder)
|
|
265
415
|
{
|
|
266
416
|
rb_require("date");
|
|
417
|
+
rb_gc_register_address(&s_Date);
|
|
418
|
+
rb_gc_register_address(&s_Date_GREGORIAN);
|
|
267
419
|
s_Date = rb_const_get(rb_cObject, rb_intern("Date"));
|
|
268
|
-
|
|
420
|
+
s_Date_GREGORIAN = rb_const_get(s_Date, rb_intern("GREGORIAN"));
|
|
269
421
|
s_id_new = rb_intern("new");
|
|
270
422
|
|
|
271
423
|
/* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Date", rb_cPG_SimpleDecoder ); */
|
|
@@ -305,6 +457,8 @@ init_pg_binary_decoder(void)
|
|
|
305
457
|
/* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
|
|
306
458
|
pg_define_coder( "Timestamp", pg_bin_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
|
|
307
459
|
|
|
460
|
+
/* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Array", rb_cPG_CompositeDecoder ); */
|
|
461
|
+
pg_define_coder( "Array", pg_bin_dec_array, rb_cPG_CompositeDecoder, rb_mPG_BinaryDecoder );
|
|
308
462
|
/* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "ToBase64", rb_cPG_CompositeDecoder ); */
|
|
309
463
|
pg_define_coder( "ToBase64", pg_bin_dec_to_base64, rb_cPG_CompositeDecoder, rb_mPG_BinaryDecoder );
|
|
310
464
|
}
|