pg 1.2.3 → 1.6.1

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 (135) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +986 -0
  4. data/Gemfile +23 -0
  5. data/README-Windows.rdoc +1 -1
  6. data/README.ja.md +300 -0
  7. data/README.md +327 -0
  8. data/Rakefile +123 -144
  9. data/certs/ged.pem +24 -0
  10. data/certs/kanis@comcard.de.pem +20 -0
  11. data/certs/larskanis-2022.pem +26 -0
  12. data/certs/larskanis-2023.pem +24 -0
  13. data/certs/larskanis-2024.pem +24 -0
  14. data/ext/errorcodes.def +16 -5
  15. data/ext/errorcodes.rb +0 -0
  16. data/ext/errorcodes.txt +5 -5
  17. data/ext/extconf.rb +259 -33
  18. data/ext/gvl_wrappers.c +17 -2
  19. data/ext/gvl_wrappers.h +56 -0
  20. data/ext/pg.c +89 -63
  21. data/ext/pg.h +31 -8
  22. data/ext/pg_binary_decoder.c +232 -1
  23. data/ext/pg_binary_encoder.c +428 -1
  24. data/ext/pg_cancel_connection.c +360 -0
  25. data/ext/pg_coder.c +148 -36
  26. data/ext/pg_connection.c +1365 -817
  27. data/ext/pg_copy_coder.c +360 -38
  28. data/ext/pg_errors.c +1 -1
  29. data/ext/pg_record_coder.c +56 -25
  30. data/ext/pg_result.c +187 -76
  31. data/ext/pg_text_decoder.c +32 -11
  32. data/ext/pg_text_encoder.c +65 -33
  33. data/ext/pg_tuple.c +84 -61
  34. data/ext/pg_type_map.c +44 -10
  35. data/ext/pg_type_map_all_strings.c +17 -3
  36. data/ext/pg_type_map_by_class.c +54 -27
  37. data/ext/pg_type_map_by_column.c +74 -31
  38. data/ext/pg_type_map_by_mri_type.c +48 -19
  39. data/ext/pg_type_map_by_oid.c +61 -27
  40. data/ext/pg_type_map_in_ruby.c +55 -21
  41. data/ext/pg_util.c +2 -2
  42. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  43. data/lib/pg/basic_type_map_for_queries.rb +206 -0
  44. data/lib/pg/basic_type_map_for_results.rb +104 -0
  45. data/lib/pg/basic_type_registry.rb +311 -0
  46. data/lib/pg/binary_decoder/date.rb +9 -0
  47. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  48. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  49. data/lib/pg/cancel_connection.rb +53 -0
  50. data/lib/pg/coder.rb +18 -14
  51. data/lib/pg/connection.rb +894 -91
  52. data/lib/pg/exceptions.rb +20 -1
  53. data/lib/pg/text_decoder/date.rb +21 -0
  54. data/lib/pg/text_decoder/inet.rb +9 -0
  55. data/lib/pg/text_decoder/json.rb +17 -0
  56. data/lib/pg/text_decoder/numeric.rb +9 -0
  57. data/lib/pg/text_decoder/timestamp.rb +30 -0
  58. data/lib/pg/text_encoder/date.rb +13 -0
  59. data/lib/pg/text_encoder/inet.rb +31 -0
  60. data/lib/pg/text_encoder/json.rb +17 -0
  61. data/lib/pg/text_encoder/numeric.rb +9 -0
  62. data/lib/pg/text_encoder/timestamp.rb +24 -0
  63. data/lib/pg/version.rb +4 -0
  64. data/lib/pg.rb +109 -39
  65. data/misc/openssl-pg-segfault.rb +31 -0
  66. data/misc/postgres/History.txt +9 -0
  67. data/misc/postgres/Manifest.txt +5 -0
  68. data/misc/postgres/README.txt +21 -0
  69. data/misc/postgres/Rakefile +21 -0
  70. data/misc/postgres/lib/postgres.rb +16 -0
  71. data/misc/ruby-pg/History.txt +9 -0
  72. data/misc/ruby-pg/Manifest.txt +5 -0
  73. data/misc/ruby-pg/README.txt +21 -0
  74. data/misc/ruby-pg/Rakefile +21 -0
  75. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  76. data/misc/yugabyte/Dockerfile +9 -0
  77. data/misc/yugabyte/docker-compose.yml +28 -0
  78. data/misc/yugabyte/pg-test.rb +45 -0
  79. data/pg.gemspec +38 -0
  80. data/ports/patches/krb5/1.21.3/0001-Allow-static-linking-krb5-library.patch +30 -0
  81. data/ports/patches/openssl/3.5.1/0001-aarch64-mingw.patch +21 -0
  82. data/ports/patches/postgresql/17.5/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
  83. data/ports/patches/postgresql/17.5/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
  84. data/rakelib/pg_gem_helper.rb +64 -0
  85. data/rakelib/task_extension.rb +46 -0
  86. data/sample/array_insert.rb +20 -0
  87. data/sample/async_api.rb +102 -0
  88. data/sample/async_copyto.rb +39 -0
  89. data/sample/async_mixed.rb +56 -0
  90. data/sample/check_conn.rb +21 -0
  91. data/sample/copydata.rb +71 -0
  92. data/sample/copyfrom.rb +81 -0
  93. data/sample/copyto.rb +19 -0
  94. data/sample/cursor.rb +21 -0
  95. data/sample/disk_usage_report.rb +177 -0
  96. data/sample/issue-119.rb +94 -0
  97. data/sample/losample.rb +69 -0
  98. data/sample/minimal-testcase.rb +17 -0
  99. data/sample/notify_wait.rb +72 -0
  100. data/sample/pg_statistics.rb +285 -0
  101. data/sample/replication_monitor.rb +222 -0
  102. data/sample/test_binary_values.rb +33 -0
  103. data/sample/wal_shipper.rb +434 -0
  104. data/sample/warehouse_partitions.rb +311 -0
  105. data.tar.gz.sig +0 -0
  106. metadata +139 -213
  107. metadata.gz.sig +0 -0
  108. data/.gemtest +0 -0
  109. data/ChangeLog +0 -0
  110. data/History.rdoc +0 -578
  111. data/Manifest.txt +0 -73
  112. data/README.ja.rdoc +0 -13
  113. data/README.rdoc +0 -213
  114. data/Rakefile.cross +0 -299
  115. data/lib/pg/basic_type_mapping.rb +0 -522
  116. data/lib/pg/binary_decoder.rb +0 -23
  117. data/lib/pg/constants.rb +0 -12
  118. data/lib/pg/text_decoder.rb +0 -46
  119. data/lib/pg/text_encoder.rb +0 -59
  120. data/spec/data/expected_trace.out +0 -26
  121. data/spec/data/random_binary_data +0 -0
  122. data/spec/helpers.rb +0 -380
  123. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  124. data/spec/pg/connection_spec.rb +0 -1949
  125. data/spec/pg/connection_sync_spec.rb +0 -41
  126. data/spec/pg/result_spec.rb +0 -681
  127. data/spec/pg/tuple_spec.rb +0 -333
  128. data/spec/pg/type_map_by_class_spec.rb +0 -138
  129. data/spec/pg/type_map_by_column_spec.rb +0 -226
  130. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  131. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  132. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  133. data/spec/pg/type_map_spec.rb +0 -22
  134. data/spec/pg/type_spec.rb +0 -1123
  135. data/spec/pg_spec.rb +0 -50
data/ext/pg.c CHANGED
@@ -33,7 +33,6 @@
33
33
  *
34
34
  * - PQfreemem -- unnecessary: copied to ruby object, then freed. Ruby object's
35
35
  * memory is freed when it is garbage collected.
36
- * - PQbinaryTuples -- better to use PQfformat
37
36
  * - PQprint -- not very useful
38
37
  * - PQsetdb -- not very useful
39
38
  * - PQoidStatus -- deprecated, use PQoidValue
@@ -74,6 +73,7 @@ VALUE rb_mPGconstants;
74
73
  * The mapping from canonical encoding names in PostgreSQL to ones in Ruby.
75
74
  */
76
75
  const char * const (pg_enc_pg2ruby_mapping[][2]) = {
76
+ {"UTF8", "UTF-8" },
77
77
  {"BIG5", "Big5" },
78
78
  {"EUC_CN", "GB2312" },
79
79
  {"EUC_JP", "EUC-JP" },
@@ -105,7 +105,6 @@ const char * const (pg_enc_pg2ruby_mapping[][2]) = {
105
105
  {"SHIFT_JIS_2004","Windows-31J" },
106
106
  /* {"SQL_ASCII", NULL }, special case*/
107
107
  {"UHC", "CP949" },
108
- {"UTF8", "UTF-8" },
109
108
  {"WIN866", "IBM866" },
110
109
  {"WIN874", "Windows-874" },
111
110
  {"WIN1250", "Windows-1250"},
@@ -120,56 +119,17 @@ const char * const (pg_enc_pg2ruby_mapping[][2]) = {
120
119
  };
121
120
 
122
121
 
123
- /*
124
- * A cache of mapping from PostgreSQL's encoding indices to Ruby's rb_encoding*s.
125
- */
126
- static struct st_table *enc_pg2ruby;
127
-
128
-
129
- /*
130
- * Look up the JOHAB encoding, creating it as a dummy encoding if it's not
131
- * already defined.
132
- */
133
- static rb_encoding *
134
- pg_find_or_create_johab(void)
135
- {
136
- static const char * const aliases[] = { "JOHAB", "Windows-1361", "CP1361" };
137
- int enc_index;
138
- size_t i;
139
-
140
- for (i = 0; i < sizeof(aliases)/sizeof(aliases[0]); ++i) {
141
- enc_index = rb_enc_find_index(aliases[i]);
142
- if (enc_index > 0) return rb_enc_from_index(enc_index);
143
- }
144
-
145
- enc_index = rb_define_dummy_encoding(aliases[0]);
146
- return rb_enc_from_index(enc_index);
147
- }
148
-
149
122
  /*
150
123
  * Return the given PostgreSQL encoding ID as an rb_encoding.
151
124
  *
152
125
  * - returns NULL if the client encoding is 'SQL_ASCII'.
153
126
  * - returns ASCII-8BIT if the client encoding is unknown.
154
127
  */
155
- rb_encoding *
128
+ static rb_encoding *
156
129
  pg_get_pg_encoding_as_rb_encoding( int enc_id )
157
130
  {
158
- rb_encoding *enc;
159
-
160
- /* Use the cached value if it exists */
161
- if ( st_lookup(enc_pg2ruby, (st_data_t)enc_id, (st_data_t*)&enc) ) {
162
- return enc;
163
- }
164
- else {
165
- const char *name = pg_encoding_to_char( enc_id );
166
-
167
- enc = pg_get_pg_encname_as_rb_encoding( name );
168
- st_insert( enc_pg2ruby, (st_data_t)enc_id, (st_data_t)enc );
169
-
170
- return enc;
171
- }
172
-
131
+ const char *name = pg_encoding_to_char( enc_id );
132
+ return pg_get_pg_encname_as_rb_encoding( name );
173
133
  }
174
134
 
175
135
  /*
@@ -186,10 +146,6 @@ pg_get_pg_encname_as_rb_encoding( const char *pg_encname )
186
146
  return rb_enc_find( pg_enc_pg2ruby_mapping[i][1] );
187
147
  }
188
148
 
189
- /* JOHAB isn't a builtin encoding, so make up a dummy encoding if it's seen */
190
- if ( strncmp(pg_encname, "JOHAB", 5) == 0 )
191
- return pg_find_or_create_johab();
192
-
193
149
  /* Fallthrough to ASCII-8BIT */
194
150
  return rb_ascii8bit_encoding();
195
151
  }
@@ -376,8 +332,13 @@ pg_s_init_ssl(VALUE self, VALUE do_ssl)
376
332
  **************************************************************************/
377
333
 
378
334
  void
379
- Init_pg_ext()
335
+ Init_pg_ext(void)
380
336
  {
337
+
338
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
339
+ rb_ext_ractor_safe(PQisthreadsafe());
340
+ #endif
341
+
381
342
  if( RTEST(rb_eval_string("ENV['PG_SKIP_DEPRECATION_WARNING']")) ){
382
343
  /* Set all bits to disable all deprecation warnings. */
383
344
  pg_skip_deprecation_warning = 0xFFFF;
@@ -396,8 +357,8 @@ Init_pg_ext()
396
357
  SINGLETON_ALIAS( rb_mPG, "is_threadsafe?", "isthreadsafe" );
397
358
  SINGLETON_ALIAS( rb_mPG, "threadsafe?", "isthreadsafe" );
398
359
 
399
- rb_define_singleton_method( rb_mPG, "init_openssl", pg_s_init_openssl, 2 );
400
- rb_define_singleton_method( rb_mPG, "init_ssl", pg_s_init_ssl, 1 );
360
+ rb_define_singleton_method( rb_mPG, "init_openssl", pg_s_init_openssl, 2 );
361
+ rb_define_singleton_method( rb_mPG, "init_ssl", pg_s_init_ssl, 1 );
401
362
 
402
363
 
403
364
  /****** PG::Connection CLASS CONSTANTS: Connection Status ******/
@@ -415,14 +376,38 @@ Init_pg_ext()
415
376
  rb_define_const(rb_mPGconstants, "CONNECTION_MADE", INT2FIX(CONNECTION_MADE));
416
377
  /* Waiting for a response from the server. */
417
378
  rb_define_const(rb_mPGconstants, "CONNECTION_AWAITING_RESPONSE", INT2FIX(CONNECTION_AWAITING_RESPONSE));
418
- /* Received authentication; waiting for backend start-up to finish. */
379
+ /* Received authentication; waiting for backend startup. */
419
380
  rb_define_const(rb_mPGconstants, "CONNECTION_AUTH_OK", INT2FIX(CONNECTION_AUTH_OK));
381
+ /* This state is no longer used. */
382
+ rb_define_const(rb_mPGconstants, "CONNECTION_SETENV", INT2FIX(CONNECTION_SETENV));
420
383
  /* Negotiating SSL encryption. */
421
384
  rb_define_const(rb_mPGconstants, "CONNECTION_SSL_STARTUP", INT2FIX(CONNECTION_SSL_STARTUP));
422
- /* Negotiating environment-driven parameter settings. */
423
- rb_define_const(rb_mPGconstants, "CONNECTION_SETENV", INT2FIX(CONNECTION_SETENV));
424
385
  /* Internal state - PG.connect() needed. */
425
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. */
389
+ 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. */
393
+ rb_define_const(rb_mPGconstants, "CONNECTION_CONSUME", INT2FIX(CONNECTION_CONSUME));
394
+ #endif
395
+ #if PG_MAJORVERSION_NUM >= 12
396
+ /* Negotiating GSSAPI. Available since PostgreSQL-12. */
397
+ rb_define_const(rb_mPGconstants, "CONNECTION_GSS_STARTUP", INT2FIX(CONNECTION_GSS_STARTUP));
398
+ #endif
399
+ #if PG_MAJORVERSION_NUM >= 13
400
+ /* Checking target server properties. Available since PostgreSQL-13. */
401
+ rb_define_const(rb_mPGconstants, "CONNECTION_CHECK_TARGET", INT2FIX(CONNECTION_CHECK_TARGET));
402
+ #endif
403
+ #if PG_MAJORVERSION_NUM >= 14
404
+ /* Checking if server is in standby mode. Available since PostgreSQL-14. */
405
+ rb_define_const(rb_mPGconstants, "CONNECTION_CHECK_STANDBY", INT2FIX(CONNECTION_CHECK_STANDBY));
406
+ #endif
407
+ #if PG_MAJORVERSION_NUM >= 17
408
+ /* Waiting for connection attempt to be started. Available since PostgreSQL-17. */
409
+ rb_define_const(rb_mPGconstants, "CONNECTION_ALLOCATED", INT2FIX(CONNECTION_ALLOCATED));
410
+ #endif
426
411
 
427
412
  /****** PG::Connection CLASS CONSTANTS: Nonblocking connection polling status ******/
428
413
 
@@ -470,14 +455,12 @@ Init_pg_ext()
470
455
  rb_define_const(rb_mPGconstants, "PQERRORS_SQLSTATE", INT2FIX(PQERRORS_SQLSTATE));
471
456
  #endif
472
457
 
473
- #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
474
458
  /* See Connection#set_error_context_visibility */
475
459
  rb_define_const(rb_mPGconstants, "PQSHOW_CONTEXT_NEVER", INT2FIX(PQSHOW_CONTEXT_NEVER));
476
460
  /* See Connection#set_error_context_visibility */
477
461
  rb_define_const(rb_mPGconstants, "PQSHOW_CONTEXT_ERRORS", INT2FIX(PQSHOW_CONTEXT_ERRORS));
478
462
  /* See Connection#set_error_context_visibility */
479
463
  rb_define_const(rb_mPGconstants, "PQSHOW_CONTEXT_ALWAYS", INT2FIX(PQSHOW_CONTEXT_ALWAYS));
480
- #endif
481
464
 
482
465
  /****** PG::Connection CLASS CONSTANTS: Check Server Status ******/
483
466
 
@@ -525,6 +508,23 @@ Init_pg_ext()
525
508
  rb_define_const(rb_mPGconstants, "PGRES_COPY_BOTH", INT2FIX(PGRES_COPY_BOTH));
526
509
  /* Result#result_status constant - Single tuple from larger resultset. */
527
510
  rb_define_const(rb_mPGconstants, "PGRES_SINGLE_TUPLE", INT2FIX(PGRES_SINGLE_TUPLE));
511
+ #ifdef HAVE_PQSETCHUNKEDROWSMODE
512
+ /* Result#result_status constant - tuple chunk from larger resultset. */
513
+ rb_define_const(rb_mPGconstants, "PGRES_TUPLES_CHUNK", INT2FIX(PGRES_TUPLES_CHUNK));
514
+ #endif
515
+
516
+ #ifdef HAVE_PQENTERPIPELINEMODE
517
+ /* Result#result_status constant - The PG::Result represents a synchronization point in pipeline mode, requested by Connection#pipeline_sync.
518
+ *
519
+ * This status occurs only when pipeline mode has been selected. */
520
+ rb_define_const(rb_mPGconstants, "PGRES_PIPELINE_SYNC", INT2FIX(PGRES_PIPELINE_SYNC));
521
+
522
+ /* Result#result_status constant - The PG::Result represents a pipeline that has received an error from the server.
523
+ *
524
+ * Connection#get_result must be called repeatedly, and each time it will return this status code until the end of the current pipeline, at which point it will return PG::PGRES_PIPELINE_SYNC and normal processing can resume.
525
+ */
526
+ rb_define_const(rb_mPGconstants, "PGRES_PIPELINE_ABORTED", INT2FIX(PGRES_PIPELINE_ABORTED));
527
+ #endif
528
528
 
529
529
  /****** Result CONSTANTS: result error field codes ******/
530
530
 
@@ -536,20 +536,18 @@ Init_pg_ext()
536
536
  */
537
537
  rb_define_const(rb_mPGconstants, "PG_DIAG_SEVERITY", INT2FIX(PG_DIAG_SEVERITY));
538
538
 
539
- #ifdef PG_DIAG_SEVERITY_NONLOCALIZED
540
539
  /* Result#result_error_field argument constant
541
540
  *
542
541
  * 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).
543
542
  * This is identical to the PG_DIAG_SEVERITY field except that the contents are never localized.
544
543
  *
545
- * Available since PostgreSQL-9.6
546
544
  */
547
545
  rb_define_const(rb_mPGconstants, "PG_DIAG_SEVERITY_NONLOCALIZED", INT2FIX(PG_DIAG_SEVERITY_NONLOCALIZED));
548
- #endif
546
+
549
547
  /* Result#result_error_field argument constant
550
548
  *
551
549
  * The SQLSTATE code for the error.
552
- * The SQLSTATE code identies the type of error that has occurred; it can be used by front-end applications to perform specic operations (such as error handling) in response to a particular database error.
550
+ * The SQLSTATE code identifies the type of error that has occurred; it can be used by front-end applications to perform specific operations (such as error handling) in response to a particular database error.
553
551
  * For a list of the possible SQLSTATE codes, see Appendix A.
554
552
  * This field is not localizable, and is always present.
555
553
  */
@@ -645,15 +643,43 @@ Init_pg_ext()
645
643
  rb_define_const(rb_mPGconstants, "PG_DIAG_CONSTRAINT_NAME", INT2FIX(PG_DIAG_CONSTRAINT_NAME));
646
644
  #endif
647
645
 
646
+ #ifdef HAVE_PQENTERPIPELINEMODE
647
+ /* Connection#pipeline_status constant
648
+ *
649
+ * The libpq connection is in pipeline mode.
650
+ */
651
+ rb_define_const(rb_mPGconstants, "PQ_PIPELINE_ON", INT2FIX(PQ_PIPELINE_ON));
652
+
653
+ /* Connection#pipeline_status constant
654
+ *
655
+ * The libpq connection is not in pipeline mode.
656
+ */
657
+ rb_define_const(rb_mPGconstants, "PQ_PIPELINE_OFF", INT2FIX(PQ_PIPELINE_OFF));
658
+
659
+ /* Connection#pipeline_status constant
660
+ *
661
+ * The libpq connection is in pipeline mode and an error occurred while processing the current pipeline.
662
+ * The aborted flag is cleared when PQgetResult returns a result of type PGRES_PIPELINE_SYNC.
663
+ */
664
+ rb_define_const(rb_mPGconstants, "PQ_PIPELINE_ABORTED", INT2FIX(PQ_PIPELINE_ABORTED));
665
+ #endif
666
+
648
667
  /* Invalid OID constant */
649
668
  rb_define_const(rb_mPGconstants, "INVALID_OID", INT2FIX(InvalidOid));
650
669
  rb_define_const(rb_mPGconstants, "InvalidOid", INT2FIX(InvalidOid));
651
670
 
671
+ /* PostgreSQL compiled in default port */
672
+ rb_define_const(rb_mPGconstants, "DEF_PGPORT", INT2FIX(DEF_PGPORT));
673
+
674
+ #ifdef PG_IS_BINARY_GEM
675
+ rb_define_const(rb_mPG, "IS_BINARY_GEM", Qtrue);
676
+ #else
677
+ rb_define_const(rb_mPG, "IS_BINARY_GEM", Qfalse);
678
+ #endif
679
+
652
680
  /* Add the constants to the toplevel namespace */
653
681
  rb_include_module( rb_mPG, rb_mPGconstants );
654
682
 
655
- enc_pg2ruby = st_init_numtable();
656
-
657
683
  /* Initialize the main extension classes */
658
684
  init_pg_connection();
659
685
  init_pg_result();
@@ -673,5 +699,5 @@ Init_pg_ext()
673
699
  init_pg_copycoder();
674
700
  init_pg_recordcoder();
675
701
  init_pg_tuple();
702
+ init_pg_cancon();
676
703
  }
677
-
data/ext/pg.h CHANGED
@@ -11,6 +11,7 @@
11
11
  #include <sys/types.h>
12
12
  #if !defined(_WIN32)
13
13
  # include <sys/time.h>
14
+ # include <sys/socket.h>
14
15
  #endif
15
16
  #if defined(HAVE_UNISTD_H) && !defined(_WIN32)
16
17
  # include <unistd.h>
@@ -56,6 +57,7 @@
56
57
  #endif
57
58
 
58
59
  /* PostgreSQL headers */
60
+ #include "pg_config.h"
59
61
  #include "libpq-fe.h"
60
62
  #include "libpq/libpq-fs.h" /* large-object interface */
61
63
  #include "pg_config_manual.h"
@@ -74,10 +76,14 @@ typedef long suseconds_t;
74
76
  #define PG_MAX_COLUMNS 4000
75
77
  #endif
76
78
 
77
- #ifndef RARRAY_AREF
78
- #define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
79
- #endif
79
+ #define pg_gc_location(x) x = rb_gc_location(x)
80
80
 
81
+ /* For compatibility with ruby < 3.0 */
82
+ #ifndef RUBY_TYPED_FROZEN_SHAREABLE
83
+ #define PG_RUBY_TYPED_FROZEN_SHAREABLE 0
84
+ #else
85
+ #define PG_RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE
86
+ #endif
81
87
  #define PG_ENC_IDX_BITS 28
82
88
 
83
89
  /* The data behind each PG::Connection object */
@@ -86,6 +92,9 @@ typedef struct {
86
92
 
87
93
  /* Cached IO object for the socket descriptor */
88
94
  VALUE socket_io;
95
+ /* function pointers of the original libpq notice receivers */
96
+ PQnoticeReceiver default_notice_receiver;
97
+ PQnoticeProcessor default_notice_processor;
89
98
  /* Proc object that receives notices as PG::Result objects */
90
99
  VALUE notice_receiver;
91
100
  /* Proc object that receives notices as String objects */
@@ -104,11 +113,11 @@ typedef struct {
104
113
  int enc_idx : PG_ENC_IDX_BITS;
105
114
  /* flags controlling Symbol/String field names */
106
115
  unsigned int flags : 2;
116
+ /* enable automatic flushing of send data at the end of send_query calls */
117
+ unsigned int flush_data : 1;
107
118
 
108
- #if defined(_WIN32)
109
119
  /* File descriptor to be used for rb_w32_unwrap_io_handle() */
110
120
  int ruby_sd;
111
- #endif
112
121
  } t_pg_connection;
113
122
 
114
123
  typedef struct pg_coder t_pg_coder;
@@ -197,6 +206,7 @@ typedef struct {
197
206
  t_pg_coder comp;
198
207
  t_pg_coder *elem;
199
208
  int needs_quotation;
209
+ int dimensions;
200
210
  char delimiter;
201
211
  } t_pg_composite_coder;
202
212
 
@@ -220,6 +230,8 @@ typedef struct {
220
230
  } convs[0];
221
231
  } t_tmbc;
222
232
 
233
+ extern const rb_data_type_t pg_typemap_type;
234
+ extern const rb_data_type_t pg_coder_type;
223
235
 
224
236
  #include "gvl_wrappers.h"
225
237
 
@@ -292,6 +304,7 @@ void init_pg_text_decoder _(( void ));
292
304
  void init_pg_binary_encoder _(( void ));
293
305
  void init_pg_binary_decoder _(( void ));
294
306
  void init_pg_tuple _(( void ));
307
+ void init_pg_cancon _(( void ));
295
308
  VALUE lookup_error_class _(( const char * ));
296
309
  VALUE pg_bin_dec_bytea _(( t_pg_coder*, const char *, int, int, int, int ));
297
310
  VALUE pg_text_dec_string _(( t_pg_coder*, const char *, int, int, int, int ));
@@ -299,12 +312,12 @@ int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, c
299
312
  int pg_text_enc_identifier _(( t_pg_coder*, VALUE, char *, VALUE *, int));
300
313
  t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
301
314
  t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int ));
302
- void pg_define_coder _(( const char *, void *, VALUE, VALUE ));
315
+ VALUE pg_define_coder _(( const char *, void *, VALUE, VALUE ));
303
316
  VALUE pg_obj_to_i _(( VALUE ));
304
317
  VALUE pg_tmbc_allocate _(( void ));
305
318
  void pg_coder_init_encoder _(( VALUE ));
306
319
  void pg_coder_init_decoder _(( VALUE ));
307
- void pg_coder_mark _(( t_pg_coder * ));
320
+ void pg_coder_compact _(( void * ));
308
321
  char *pg_rb_str_ensure_capa _(( VALUE, long, char *, char ** ));
309
322
 
310
323
  #define PG_RB_STR_ENSURE_CAPA( str, expand_len, curr_ptr, end_ptr ) \
@@ -324,9 +337,20 @@ int pg_typemap_fit_to_copy_get _(( VALUE ));
324
337
  VALUE pg_typemap_result_value _(( t_typemap *, VALUE, int, int ));
325
338
  t_pg_coder *pg_typemap_typecast_query_param _(( t_typemap *, VALUE, int ));
326
339
  VALUE pg_typemap_typecast_copy_get _(( t_typemap *, VALUE, int, int, int ));
340
+ void pg_typemap_mark _(( void * ));
341
+ size_t pg_typemap_memsize _(( const void * ));
342
+ void pg_typemap_compact _(( void * ));
327
343
 
328
344
  PGconn *pg_get_pgconn _(( VALUE ));
329
345
  t_pg_connection *pg_get_connection _(( VALUE ));
346
+ VALUE pgconn_block _(( int, VALUE *, VALUE ));
347
+ #ifdef __GNUC__
348
+ __attribute__((format(printf, 3, 4)))
349
+ #endif
350
+ NORETURN(void pg_raise_conn_error _(( VALUE klass, VALUE self, const char *format, ...)));
351
+ VALUE pg_wrap_socket_io _(( int sd, VALUE self, VALUE *p_socket_io, int *p_ruby_sd ));
352
+ void pg_unwrap_socket_io _(( VALUE self, VALUE *p_socket_io, int ruby_sd ));
353
+
330
354
 
331
355
  VALUE pg_new_result _(( PGresult *, VALUE ));
332
356
  VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
@@ -345,7 +369,6 @@ pgresult_get_this( VALUE self )
345
369
  }
346
370
 
347
371
 
348
- rb_encoding * pg_get_pg_encoding_as_rb_encoding _(( int ));
349
372
  rb_encoding * pg_get_pg_encname_as_rb_encoding _(( const char * ));
350
373
  const char * pg_get_rb_encoding_as_pg_encoding _(( rb_encoding * ));
351
374
  rb_encoding *pg_conn_enc_get _(( PGconn * ));
@@ -12,6 +12,8 @@
12
12
  #endif
13
13
 
14
14
  VALUE rb_mPG_BinaryDecoder;
15
+ static VALUE s_Date;
16
+ static ID s_id_new;
15
17
 
16
18
 
17
19
  /*
@@ -131,6 +133,154 @@ pg_bin_dec_to_base64(t_pg_coder *conv, const char *val, int len, int tuple, int
131
133
  return out_value;
132
134
  }
133
135
 
136
+ /*
137
+ * Maximum number of array subscripts (arbitrary limit)
138
+ */
139
+ #define MAXDIM 6
140
+
141
+ /*
142
+ * Document-class: PG::BinaryDecoder::Array < PG::CompositeDecoder
143
+ *
144
+ * This is a decoder class for conversion of binary array types.
145
+ *
146
+ * It returns an Array with possibly an arbitrary number of sub-Arrays.
147
+ * All values are decoded according to the #elements_type accessor.
148
+ * Sub-arrays are decoded recursively.
149
+ *
150
+ * This decoder simply ignores any dimension decorations preceding the array values.
151
+ * It returns all array values as regular ruby Array with a zero based index, regardless of the index given in the dimension decoration.
152
+ *
153
+ * An array decoder which respects dimension decorations is waiting to be implemented.
154
+ *
155
+ */
156
+ static VALUE
157
+ pg_bin_dec_array(t_pg_coder *conv, const char *input_line, int len, int tuple, int field, int enc_idx)
158
+ {
159
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
160
+ t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
161
+
162
+ /* Current field */
163
+ VALUE field_str;
164
+
165
+ int32_t nitems32;
166
+ int i;
167
+ int ndim;
168
+ int nitems;
169
+ int flags;
170
+ int dim;
171
+ int dim_sizes[MAXDIM];
172
+ VALUE arrays[MAXDIM];
173
+ char *output_ptr;
174
+ const char *cur_ptr;
175
+ const char *line_end_ptr;
176
+ char *end_capa_ptr;
177
+
178
+ /* Allocate a new string with embedded capacity and realloc later with
179
+ * exponential growing size when needed. */
180
+ PG_RB_STR_NEW( field_str, output_ptr, end_capa_ptr );
181
+
182
+ /* set pointer variables for loop */
183
+ cur_ptr = input_line;
184
+ line_end_ptr = input_line + len;
185
+
186
+ /* read number of dimensions */
187
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
188
+ ndim = read_nbo32(cur_ptr);
189
+ if (ndim < 0 || ndim > MAXDIM) {
190
+ rb_raise( rb_eArgError, "unsupported number of array dimensions: %d", ndim );
191
+ }
192
+ cur_ptr += 4;
193
+
194
+ /* read flags */
195
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
196
+ flags = read_nbo32(cur_ptr);
197
+ if (flags != 0 && flags != 1) {
198
+ rb_raise( rb_eArgError, "unsupported binary array flags: %d", flags );
199
+ }
200
+ cur_ptr += 4;
201
+
202
+ /* ignore element OID */
203
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
204
+ cur_ptr += 4;
205
+
206
+ nitems32 = ndim == 0 ? 0 : 1;
207
+ for (i = 0; i < ndim; i++) {
208
+ int64_t prod;
209
+
210
+ /* read size of dimensions and ignore lower bound */
211
+ if (line_end_ptr - cur_ptr < 8 ) goto length_error;
212
+ dim_sizes[i] = read_nbo32(cur_ptr);
213
+ prod = (int64_t) nitems32 * (int64_t) dim_sizes[i];
214
+ nitems32 = (int32_t) prod;
215
+ if (dim_sizes[i] < 0 || (int64_t) nitems32 != prod) {
216
+ rb_raise( rb_eArgError, "unsupported array size: %" PRId64, prod );
217
+ }
218
+ cur_ptr += 8;
219
+ }
220
+ nitems = (int)nitems32;
221
+
222
+ dim = 0;
223
+ arrays[dim] = rb_ary_new2(ndim == 0 ? 0 : dim_sizes[dim]);
224
+ for (i = 0; i < nitems; i++) {
225
+ int input_len;
226
+
227
+ /* traverse dimensions down */
228
+ while (dim < ndim - 1) {
229
+ dim++;
230
+ arrays[dim] = rb_ary_new2(dim_sizes[dim]);
231
+ rb_ary_push(arrays[dim - 1], arrays[dim]);
232
+ }
233
+
234
+ /* read element length */
235
+ if (line_end_ptr - cur_ptr < 4 ) goto length_error;
236
+ input_len = read_nbo32(cur_ptr);
237
+ cur_ptr += 4;
238
+
239
+ /* convert and put element into array */
240
+ if (input_len < 0) {
241
+ if (input_len != -1) goto length_error;
242
+ /* NULL indicator */
243
+ rb_ary_push(arrays[dim], Qnil);
244
+ } else {
245
+ VALUE field_value;
246
+ if (line_end_ptr - cur_ptr < input_len ) goto length_error;
247
+
248
+ /* copy input data to field_str */
249
+ PG_RB_STR_ENSURE_CAPA( field_str, input_len, output_ptr, end_capa_ptr );
250
+ memcpy(output_ptr, cur_ptr, input_len);
251
+ cur_ptr += input_len;
252
+ output_ptr += input_len;
253
+ /* convert field_str through the type map */
254
+ rb_str_set_len( field_str, output_ptr - RSTRING_PTR(field_str) );
255
+ field_value = dec_func(this->elem, RSTRING_PTR(field_str), input_len, tuple, field, enc_idx);
256
+
257
+ rb_ary_push(arrays[dim], field_value);
258
+
259
+ if( field_value == field_str ){
260
+ /* Our output string will be send to the user, so we can not reuse
261
+ * it for the next field. */
262
+ PG_RB_STR_NEW( field_str, output_ptr, end_capa_ptr );
263
+ }
264
+ }
265
+
266
+ /* Reset the pointer to the start of the output/buffer string. */
267
+ output_ptr = RSTRING_PTR(field_str);
268
+
269
+ /* traverse dimensions up */
270
+ while (RARRAY_LEN(arrays[dim]) >= dim_sizes[dim] && dim > 0) {
271
+ dim--;
272
+ }
273
+ }
274
+
275
+ if (cur_ptr < line_end_ptr)
276
+ rb_raise( rb_eArgError, "trailing data after binary array data at position: %ld", (long)(cur_ptr - input_line) + 1 );
277
+
278
+ return arrays[0];
279
+
280
+ length_error:
281
+ rb_raise( rb_eArgError, "premature end of binary array data at position: %ld", (long)(cur_ptr - input_line) + 1 );
282
+ }
283
+
134
284
  #define PG_INT64_MIN (-0x7FFFFFFFFFFFFFFFL - 1)
135
285
  #define PG_INT64_MAX 0x7FFFFFFFFFFFFFFFL
136
286
 
@@ -195,6 +345,84 @@ pg_bin_dec_timestamp(t_pg_coder *conv, const char *val, int len, int tuple, int
195
345
  }
196
346
  }
197
347
 
348
+ #define PG_INT32_MIN (-0x7FFFFFFF-1)
349
+ #define PG_INT32_MAX (0x7FFFFFFF)
350
+ #define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */
351
+ #define MONTHS_PER_YEAR 12
352
+
353
+ /* taken from PostgreSQL sources at src/backend/utils/adt/datetime.c */
354
+ void
355
+ j2date(int jd, int *year, int *month, int *day)
356
+ {
357
+ unsigned int julian;
358
+ unsigned int quad;
359
+ unsigned int extra;
360
+ int y;
361
+
362
+ julian = jd;
363
+ julian += 32044;
364
+ quad = julian / 146097;
365
+ extra = (julian - quad * 146097) * 4 + 3;
366
+ julian += 60 + quad * 3 + extra / 146097;
367
+ quad = julian / 1461;
368
+ julian -= quad * 1461;
369
+ y = julian * 4 / 1461;
370
+ julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
371
+ + 123;
372
+ y += quad * 4;
373
+ *year = y - 4800;
374
+ quad = julian * 2141 / 65536;
375
+ *day = julian - 7834 * quad / 256;
376
+ *month = (quad + 10) % MONTHS_PER_YEAR + 1;
377
+ } /* j2date() */
378
+
379
+ /*
380
+ * Document-class: PG::BinaryDecoder::Date < PG::SimpleDecoder
381
+ *
382
+ * This is a decoder class for conversion of PostgreSQL binary date
383
+ * to Ruby Date objects.
384
+ *
385
+ * As soon as this class is used, it requires the ruby standard library 'date'.
386
+ */
387
+ static VALUE
388
+ pg_bin_dec_date(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
389
+ {
390
+ int year, month, day;
391
+ int date;
392
+
393
+ if (len != 4) {
394
+ rb_raise(rb_eTypeError, "unexpected date format != 4 bytes");
395
+ }
396
+
397
+ date = read_nbo32(val);
398
+ switch(date){
399
+ case PG_INT32_MAX:
400
+ return rb_str_new2("infinity");
401
+ case PG_INT32_MIN:
402
+ return rb_str_new2("-infinity");
403
+ default:
404
+ j2date(date + POSTGRES_EPOCH_JDATE, &year, &month, &day);
405
+
406
+ return rb_funcall(s_Date, s_id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
407
+ }
408
+ }
409
+
410
+ /* called per autoload when BinaryDecoder::Date is used */
411
+ static VALUE
412
+ init_pg_bin_decoder_date(VALUE rb_mPG_BinaryDecoder)
413
+ {
414
+ rb_require("date");
415
+ s_Date = rb_const_get(rb_cObject, rb_intern("Date"));
416
+ rb_gc_register_mark_object(s_Date);
417
+ s_id_new = rb_intern("new");
418
+
419
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Date", rb_cPG_SimpleDecoder ); */
420
+ pg_define_coder( "Date", pg_bin_dec_date, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
421
+
422
+ return Qnil;
423
+ }
424
+
425
+
198
426
  /*
199
427
  * Document-class: PG::BinaryDecoder::String < PG::SimpleDecoder
200
428
  *
@@ -205,10 +433,11 @@ pg_bin_dec_timestamp(t_pg_coder *conv, const char *val, int len, int tuple, int
205
433
  */
206
434
 
207
435
  void
208
- init_pg_binary_decoder()
436
+ init_pg_binary_decoder(void)
209
437
  {
210
438
  /* This module encapsulates all decoder classes with binary input format */
211
439
  rb_mPG_BinaryDecoder = rb_define_module_under( rb_mPG, "BinaryDecoder" );
440
+ rb_define_private_method(rb_singleton_class(rb_mPG_BinaryDecoder), "init_date", init_pg_bin_decoder_date, 0);
212
441
 
213
442
  /* Make RDoc aware of the decoder classes... */
214
443
  /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
@@ -224,6 +453,8 @@ init_pg_binary_decoder()
224
453
  /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
225
454
  pg_define_coder( "Timestamp", pg_bin_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
226
455
 
456
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Array", rb_cPG_CompositeDecoder ); */
457
+ pg_define_coder( "Array", pg_bin_dec_array, rb_cPG_CompositeDecoder, rb_mPG_BinaryDecoder );
227
458
  /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "ToBase64", rb_cPG_CompositeDecoder ); */
228
459
  pg_define_coder( "ToBase64", pg_bin_dec_to_base64, rb_cPG_CompositeDecoder, rb_mPG_BinaryDecoder );
229
460
  }