pg 0.17.1 → 0.18.4

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 (53) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/ChangeLog +2407 -2
  4. data/History.rdoc +68 -0
  5. data/Manifest.txt +29 -1
  6. data/README-Windows.rdoc +15 -26
  7. data/README.rdoc +52 -2
  8. data/Rakefile +56 -18
  9. data/Rakefile.cross +77 -49
  10. data/ext/extconf.rb +33 -26
  11. data/ext/pg.c +142 -21
  12. data/ext/pg.h +242 -6
  13. data/ext/pg_binary_decoder.c +162 -0
  14. data/ext/pg_binary_encoder.c +162 -0
  15. data/ext/pg_coder.c +479 -0
  16. data/ext/pg_connection.c +858 -553
  17. data/ext/pg_copy_coder.c +561 -0
  18. data/ext/pg_errors.c +6 -0
  19. data/ext/pg_result.c +479 -128
  20. data/ext/pg_text_decoder.c +421 -0
  21. data/ext/pg_text_encoder.c +663 -0
  22. data/ext/pg_type_map.c +159 -0
  23. data/ext/pg_type_map_all_strings.c +116 -0
  24. data/ext/pg_type_map_by_class.c +239 -0
  25. data/ext/pg_type_map_by_column.c +312 -0
  26. data/ext/pg_type_map_by_mri_type.c +284 -0
  27. data/ext/pg_type_map_by_oid.c +355 -0
  28. data/ext/pg_type_map_in_ruby.c +299 -0
  29. data/ext/util.c +149 -0
  30. data/ext/util.h +65 -0
  31. data/lib/pg/basic_type_mapping.rb +399 -0
  32. data/lib/pg/coder.rb +83 -0
  33. data/lib/pg/connection.rb +81 -29
  34. data/lib/pg/result.rb +13 -3
  35. data/lib/pg/text_decoder.rb +44 -0
  36. data/lib/pg/text_encoder.rb +27 -0
  37. data/lib/pg/type_map_by_column.rb +15 -0
  38. data/lib/pg.rb +12 -2
  39. data/spec/{lib/helpers.rb → helpers.rb} +101 -39
  40. data/spec/pg/basic_type_mapping_spec.rb +251 -0
  41. data/spec/pg/connection_spec.rb +516 -218
  42. data/spec/pg/result_spec.rb +216 -112
  43. data/spec/pg/type_map_by_class_spec.rb +138 -0
  44. data/spec/pg/type_map_by_column_spec.rb +222 -0
  45. data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  46. data/spec/pg/type_map_by_oid_spec.rb +149 -0
  47. data/spec/pg/type_map_in_ruby_spec.rb +164 -0
  48. data/spec/pg/type_map_spec.rb +22 -0
  49. data/spec/pg/type_spec.rb +697 -0
  50. data/spec/pg_spec.rb +24 -18
  51. data.tar.gz.sig +0 -0
  52. metadata +111 -45
  53. metadata.gz.sig +0 -0
data/ext/extconf.rb CHANGED
@@ -15,36 +15,35 @@ if pgdir = with_config( 'pg' )
15
15
  ENV['PATH'] = "#{pgdir}/bin" + File::PATH_SEPARATOR + ENV['PATH']
16
16
  end
17
17
 
18
- if ENV['CROSS_COMPILING']
19
- $LDFLAGS << " -L#{CONFIG['libdir']}"
20
-
21
- # Link against all required libraries for static build, if they are available
22
- have_library( 'crypt32', 'CertOpenStore' ) && append_library( $libs, 'crypt32' )
23
- have_library( 'gdi32', 'CreateDC' ) && append_library( $libs, 'gdi32' )
24
- have_library( 'secur32' ) && append_library( $libs, 'secur32' )
25
- have_library( 'ws2_32', 'WSASocket') && append_library( $libs, 'ws2_32' )
26
- have_library( 'crypto', 'BIO_new' ) && append_library( $libs, 'crypto' )
27
- have_library( 'ssl', 'SSL_new' ) && append_library( $libs, 'ssl' )
28
- end
18
+ if enable_config("windows-cross")
19
+ # Avoid dependency to external libgcc.dll on x86-mingw32
20
+ $LDFLAGS << " -static-libgcc"
21
+ # Don't use pg_config for cross build, but --with-pg-* path options
22
+ dir_config 'pg'
29
23
 
30
- if pgconfig = ( with_config('pg-config') || with_config('pg_config') || find_executable('pg_config') )
31
- $stderr.puts "Using config values from %s" % [ pgconfig ]
32
- incdir = `"#{pgconfig}" --includedir`.chomp
33
- libdir = `"#{pgconfig}" --libdir`.chomp
34
- dir_config 'pg', incdir, libdir
35
-
36
- # Try to use runtime path linker option, even if RbConfig doesn't know about it.
37
- # The rpath option is usually set implicit by dir_config(), but so far not
38
- # on MacOS-X.
39
- if RbConfig::CONFIG["RPATHFLAG"].to_s.empty? && try_link('int main() {return 0;}', " -Wl,-rpath,#{libdir}")
40
- $LDFLAGS << " -Wl,-rpath,#{libdir}"
41
- end
42
24
  else
43
- $stderr.puts "No pg_config... trying anyway. If building fails, please try again with",
44
- " --with-pg-config=/path/to/pg_config"
45
- dir_config 'pg'
25
+ # Native build
26
+
27
+ if pgconfig = ( with_config('pg-config') || with_config('pg_config') || find_executable('pg_config') )
28
+ $stderr.puts "Using config values from %s" % [ pgconfig ]
29
+ incdir = `"#{pgconfig}" --includedir`.chomp
30
+ libdir = `"#{pgconfig}" --libdir`.chomp
31
+ dir_config 'pg', incdir, libdir
32
+
33
+ # Try to use runtime path linker option, even if RbConfig doesn't know about it.
34
+ # The rpath option is usually set implicit by dir_config(), but so far not
35
+ # on MacOS-X.
36
+ if RbConfig::CONFIG["RPATHFLAG"].to_s.empty? && try_link('int main() {return 0;}', " -Wl,-rpath,#{libdir}")
37
+ $LDFLAGS << " -Wl,-rpath,#{libdir}"
38
+ end
39
+ else
40
+ $stderr.puts "No pg_config... trying anyway. If building fails, please try again with",
41
+ " --with-pg-config=/path/to/pg_config"
42
+ dir_config 'pg'
43
+ end
46
44
  end
47
45
 
46
+
48
47
  find_header( 'libpq-fe.h' ) or abort "Can't find the 'libpq-fe.h header"
49
48
  find_header( 'libpq/libpq-fs.h' ) or abort "Can't find the 'libpq/libpq-fs.h header"
50
49
  find_header( 'pg_config_manual.h' ) or abort "Can't find the 'pg_config_manual.h' header"
@@ -73,6 +72,7 @@ have_func 'PQsetClientEncoding'
73
72
  have_func 'PQlibVersion'
74
73
  have_func 'PQping'
75
74
  have_func 'PQsetSingleRowMode'
75
+ have_func 'PQconninfo'
76
76
 
77
77
  have_func 'rb_encdb_alias'
78
78
  have_func 'rb_enc_alias'
@@ -80,6 +80,8 @@ have_func 'rb_thread_call_without_gvl'
80
80
  have_func 'rb_thread_call_with_gvl'
81
81
  have_func 'rb_thread_fd_select'
82
82
  have_func 'rb_w32_wrap_io_handle'
83
+ have_func 'rb_str_modify_expand'
84
+ have_func 'rb_hash_dup'
83
85
 
84
86
  have_const 'PGRES_COPY_BOTH', 'libpq-fe.h'
85
87
  have_const 'PGRES_SINGLE_TUPLE', 'libpq-fe.h'
@@ -90,8 +92,13 @@ $defs.push( "-DHAVE_ST_NOTIFY_EXTRA" ) if
90
92
 
91
93
  # unistd.h confilicts with ruby/win32.h when cross compiling for win32 and ruby 1.9.1
92
94
  have_header 'unistd.h'
95
+ have_header 'inttypes.h'
93
96
  have_header 'ruby/st.h' or have_header 'st.h' or abort "pg currently requires the ruby/st.h header"
94
97
 
98
+ checking_for "C99 variable length arrays" do
99
+ $defs.push( "-DHAVE_VARIABLE_LENGTH_ARRAYS" ) if try_compile('void test_vla(int l){ int vla[l]; }')
100
+ end
101
+
95
102
  create_header()
96
103
  create_makefile( "pg_ext" )
97
104
 
data/ext/pg.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg.c - Toplevel extension
3
- * $Id: pg.c,v 74aa9514a381 2013/05/18 17:29:19 lars $
3
+ * $Id: pg.c,v b60c89ee93c8 2015/02/11 20:59:36 lars $
4
4
  *
5
5
  * Author/s:
6
6
  *
@@ -15,7 +15,7 @@
15
15
  * See Contributors.rdoc for the many additional fine people that have contributed
16
16
  * to this library over the years.
17
17
  *
18
- * Copyright (c) 1997-2012 by the authors.
18
+ * Copyright (c) 1997-2015 by the authors.
19
19
  *
20
20
  * You may redistribute this software under the same terms as Ruby itself; see
21
21
  * http://www.ruby-lang.org/en/LICENSE.txt or the LICENSE file in the source
@@ -123,24 +123,6 @@ const char * const (pg_enc_pg2ruby_mapping[][2]) = {
123
123
  * A cache of mapping from PostgreSQL's encoding indices to Ruby's rb_encoding*s.
124
124
  */
125
125
  static struct st_table *enc_pg2ruby;
126
- static ID s_id_index;
127
-
128
-
129
- /*
130
- * Get the index of encoding +val+.
131
- * :FIXME: Look into replacing this with rb_enc_get_index() since 1.9.1 isn't really
132
- * used anymore.
133
- */
134
- int
135
- pg_enc_get_index(VALUE val)
136
- {
137
- int i = ENCODING_GET_INLINED(val);
138
- if (i == ENCODING_INLINE_MAX) {
139
- VALUE iv = rb_ivar_get(val, s_id_index);
140
- i = NUM2INT(iv);
141
- }
142
- return i;
143
- }
144
126
 
145
127
 
146
128
  /*
@@ -249,6 +231,68 @@ pg_get_rb_encoding_as_pg_encoding( rb_encoding *enc )
249
231
  #endif /* M17N_SUPPORTED */
250
232
 
251
233
 
234
+ /*
235
+ * Ensures that the given string has enough capacity to take expand_len
236
+ * more data bytes. The new data part of the String is not initialized.
237
+ *
238
+ * current_out must be a pointer within the data part of the String object.
239
+ * This pointer is returned and possibly adjusted, because the location of the data
240
+ * part of the String can change through this function.
241
+ *
242
+ * PG_RB_STR_ENSURE_CAPA can be used to do fast inline checks of the remaining capacity.
243
+ * end_capa it is then set to the first byte after the currently reserved memory,
244
+ * if not NULL.
245
+ *
246
+ * Before the String can be used with other string functions or returned to Ruby space,
247
+ * the string length has to be set with rb_str_set_len().
248
+ *
249
+ * Usage example:
250
+ *
251
+ * VALUE string;
252
+ * char *current_out, *end_capa;
253
+ * PG_RB_STR_NEW( string, current_out, end_capa );
254
+ * while( data_is_going_to_be_processed ){
255
+ * PG_RB_STR_ENSURE_CAPA( string, 2, current_out, end_capa );
256
+ * *current_out++ = databyte1;
257
+ * *current_out++ = databyte2;
258
+ * }
259
+ * rb_str_set_len( string, current_out - RSTRING_PTR(string) );
260
+ *
261
+ */
262
+ #ifdef HAVE_RB_STR_MODIFY_EXPAND
263
+ /* Use somewhat faster version with access to string capacity on MRI */
264
+ char *
265
+ pg_rb_str_ensure_capa( VALUE str, long expand_len, char *curr_ptr, char **end_ptr )
266
+ {
267
+ long curr_len = curr_ptr - RSTRING_PTR(str);
268
+ long curr_capa = rb_str_capacity( str );
269
+ if( curr_capa < curr_len + expand_len ){
270
+ rb_str_set_len( str, curr_len );
271
+ rb_str_modify_expand( str, (curr_len + expand_len) * 2 - curr_capa );
272
+ curr_ptr = RSTRING_PTR(str) + curr_len;
273
+ }
274
+ if( end_ptr )
275
+ *end_ptr = RSTRING_PTR(str) + rb_str_capacity( str );
276
+ return curr_ptr;
277
+ }
278
+ #else
279
+ /* Use the more portable version */
280
+ char *
281
+ pg_rb_str_ensure_capa( VALUE str, long expand_len, char *curr_ptr, char **end_ptr )
282
+ {
283
+ long curr_len = curr_ptr - RSTRING_PTR(str);
284
+ long curr_capa = RSTRING_LEN( str );
285
+ if( curr_capa < curr_len + expand_len ){
286
+ rb_str_resize( str, (curr_len + expand_len) * 2 - curr_capa );
287
+ curr_ptr = RSTRING_PTR(str) + curr_len;
288
+ }
289
+ if( end_ptr )
290
+ *end_ptr = RSTRING_PTR(str) + RSTRING_LEN(str);
291
+ return curr_ptr;
292
+ }
293
+ #endif
294
+
295
+
252
296
  /**************************************************************************
253
297
  * Module Methods
254
298
  **************************************************************************/
@@ -289,6 +333,67 @@ pg_s_threadsafe_p(VALUE self)
289
333
  return PQisthreadsafe() ? Qtrue : Qfalse;
290
334
  }
291
335
 
336
+ static int
337
+ pg_to_bool_int(VALUE value)
338
+ {
339
+ switch( TYPE(value) ){
340
+ case T_FALSE:
341
+ return 0;
342
+ case T_TRUE:
343
+ return 1;
344
+ default:
345
+ return NUM2INT(value);
346
+ }
347
+ }
348
+
349
+ /*
350
+ * call-seq:
351
+ * PG.init_openssl(do_ssl, do_crypto) -> nil
352
+ *
353
+ * Allows applications to select which security libraries to initialize.
354
+ *
355
+ * If your application initializes libssl and/or libcrypto libraries and libpq is
356
+ * built with SSL support, you should call PG.init_openssl() to tell libpq that the
357
+ * libssl and/or libcrypto libraries have been initialized by your application,
358
+ * so that libpq will not also initialize those libraries. See
359
+ * http://h71000.www7.hp.com/doc/83final/BA554_90007/ch04.html for details on the SSL API.
360
+ *
361
+ * When do_ssl is +true+, libpq will initialize the OpenSSL library before first
362
+ * opening a database connection. When do_crypto is +true+, the libcrypto library
363
+ * will be initialized. By default (if PG.init_openssl() is not called), both libraries
364
+ * are initialized. When SSL support is not compiled in, this function is present but does nothing.
365
+ *
366
+ * If your application uses and initializes either OpenSSL or its underlying libcrypto library,
367
+ * you must call this function with +false+ for the appropriate parameter(s) before first opening
368
+ * a database connection. Also be sure that you have done that initialization before opening a
369
+ * database connection.
370
+ *
371
+ */
372
+ static VALUE
373
+ pg_s_init_openssl(VALUE self, VALUE do_ssl, VALUE do_crypto)
374
+ {
375
+ UNUSED( self );
376
+ PQinitOpenSSL(pg_to_bool_int(do_ssl), pg_to_bool_int(do_crypto));
377
+ return Qnil;
378
+ }
379
+
380
+
381
+ /*
382
+ * call-seq:
383
+ * PG.init_ssl(do_ssl) -> nil
384
+ *
385
+ * Allows applications to select which security libraries to initialize.
386
+ *
387
+ * This function is equivalent to <tt>PG.init_openssl(do_ssl, do_ssl)</tt> . It is sufficient for
388
+ * applications that initialize both or neither of OpenSSL and libcrypto.
389
+ */
390
+ static VALUE
391
+ pg_s_init_ssl(VALUE self, VALUE do_ssl)
392
+ {
393
+ UNUSED( self );
394
+ PQinitSSL(pg_to_bool_int(do_ssl));
395
+ return Qnil;
396
+ }
292
397
 
293
398
 
294
399
  /**************************************************************************
@@ -311,6 +416,10 @@ Init_pg_ext()
311
416
  SINGLETON_ALIAS( rb_mPG, "is_threadsafe?", "isthreadsafe" );
312
417
  SINGLETON_ALIAS( rb_mPG, "threadsafe?", "isthreadsafe" );
313
418
 
419
+ rb_define_singleton_method( rb_mPG, "init_openssl", pg_s_init_openssl, 2 );
420
+ rb_define_singleton_method( rb_mPG, "init_ssl", pg_s_init_ssl, 1 );
421
+
422
+
314
423
  /****** PG::Connection CLASS CONSTANTS: Connection Status ******/
315
424
 
316
425
  /* Connection succeeded */
@@ -534,12 +643,24 @@ Init_pg_ext()
534
643
 
535
644
  #ifdef M17N_SUPPORTED
536
645
  enc_pg2ruby = st_init_numtable();
537
- s_id_index = rb_intern("@encoding");
538
646
  #endif
539
647
 
540
648
  /* Initialize the main extension classes */
541
649
  init_pg_connection();
542
650
  init_pg_result();
543
651
  init_pg_errors();
652
+ init_pg_type_map();
653
+ init_pg_type_map_all_strings();
654
+ init_pg_type_map_by_class();
655
+ init_pg_type_map_by_column();
656
+ init_pg_type_map_by_mri_type();
657
+ init_pg_type_map_by_oid();
658
+ init_pg_type_map_in_ruby();
659
+ init_pg_coder();
660
+ init_pg_text_encoder();
661
+ init_pg_text_decoder();
662
+ init_pg_binary_encoder();
663
+ init_pg_binary_decoder();
664
+ init_pg_copycoder();
544
665
  }
545
666
 
data/ext/pg.h CHANGED
@@ -24,7 +24,6 @@
24
24
  #if defined(HAVE_RUBY_ENCODING_H) && HAVE_RUBY_ENCODING_H
25
25
  # include "ruby/encoding.h"
26
26
  # define M17N_SUPPORTED
27
- # define ASSOCIATE_INDEX( obj, index_holder ) rb_enc_associate_index((obj), pg_enc_get_index((index_holder)))
28
27
  # ifdef HAVE_RB_ENCDB_ALIAS
29
28
  extern int rb_encdb_alias(const char *, const char *);
30
29
  # define ENC_ALIAS(name, orig) rb_encdb_alias((name), (orig))
@@ -35,8 +34,28 @@
35
34
  extern int rb_enc_alias(const char *alias, const char *orig); /* declaration missing in Ruby 1.9.1 */
36
35
  # define ENC_ALIAS(name, orig) rb_enc_alias((name), (orig))
37
36
  # endif
37
+
38
+
39
+ # if !defined(ENCODING_SET_INLINED)
40
+ /* Rubinius doesn't define ENCODING_SET_INLINED, so we fall back to the more
41
+ * portable version.
42
+ */
43
+ # define PG_ENCODING_SET_NOCHECK(obj,i) \
44
+ do { \
45
+ rb_enc_set_index((obj), (i)); \
46
+ } while(0)
47
+ # else
48
+ # define PG_ENCODING_SET_NOCHECK(obj,i) \
49
+ do { \
50
+ if ((i) < ENCODING_INLINE_MAX) \
51
+ ENCODING_SET_INLINED((obj), (i)); \
52
+ else \
53
+ rb_enc_set_index((obj), (i)); \
54
+ } while(0)
55
+ # endif
56
+
38
57
  #else
39
- # define ASSOCIATE_INDEX( obj, index_holder ) /* nothing */
58
+ # define PG_ENCODING_SET_NOCHECK(obj,i) /* nothing */
40
59
  #endif
41
60
 
42
61
  #if RUBY_VM != 1
@@ -66,6 +85,20 @@
66
85
  # include "ruby/io.h"
67
86
  #endif
68
87
 
88
+ #ifdef RUBINIUS
89
+ /* Workaround for wrong FIXNUM_MAX definition */
90
+ typedef intptr_t native_int;
91
+ #endif
92
+
93
+ #ifndef RETURN_SIZED_ENUMERATOR
94
+ #define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn) RETURN_ENUMERATOR((obj), (argc), (argv))
95
+ #endif
96
+
97
+ #ifndef HAVE_RB_HASH_DUP
98
+ /* Rubinius doesn't define rb_hash_dup() */
99
+ #define rb_hash_dup(tuple) rb_funcall((tuple), rb_intern("dup"), 0)
100
+ #endif
101
+
69
102
  #ifndef timeradd
70
103
  #define timeradd(a, b, result) \
71
104
  do { \
@@ -97,10 +130,126 @@
97
130
 
98
131
  #if defined(_WIN32)
99
132
  # include <fcntl.h>
100
- __declspec(dllexport)
101
133
  typedef long suseconds_t;
102
134
  #endif
103
135
 
136
+ #if defined(HAVE_VARIABLE_LENGTH_ARRAYS)
137
+ #define PG_VARIABLE_LENGTH_ARRAY(type, name, len, maxlen) type name[(len)];
138
+ #else
139
+ #define PG_VARIABLE_LENGTH_ARRAY(type, name, len, maxlen) \
140
+ type name[(maxlen)] = {(len)>(maxlen) ? (rb_raise(rb_eArgError, "Number of " #name " (%d) exceeds allowed maximum of " #maxlen, (len) ), (type)1) : (type)0};
141
+
142
+ #define PG_MAX_COLUMNS 4000
143
+ #endif
144
+
145
+ /* The data behind each PG::Connection object */
146
+ typedef struct {
147
+ PGconn *pgconn;
148
+
149
+ /* Cached IO object for the socket descriptor */
150
+ VALUE socket_io;
151
+ /* Proc object that receives notices as PG::Result objects */
152
+ VALUE notice_receiver;
153
+ /* Proc object that receives notices as String objects */
154
+ VALUE notice_processor;
155
+ /* Kind of PG::TypeMap object for casting query params */
156
+ VALUE type_map_for_queries;
157
+ /* Kind of PG::TypeMap object for casting result values */
158
+ VALUE type_map_for_results;
159
+ /* IO object internally used for the trace stream */
160
+ VALUE trace_stream;
161
+ /* Cached Encoding object */
162
+ VALUE external_encoding;
163
+ /* Kind of PG::Coder object for casting ruby values to COPY rows */
164
+ VALUE encoder_for_put_copy_data;
165
+ /* Kind of PG::Coder object for casting COPY rows to ruby values */
166
+ VALUE decoder_for_get_copy_data;
167
+
168
+ } t_pg_connection;
169
+
170
+ typedef struct pg_coder t_pg_coder;
171
+ typedef struct pg_typemap t_typemap;
172
+
173
+ /* The data behind each PG::Result object */
174
+ typedef struct {
175
+ PGresult *pgresult;
176
+
177
+ /* The connection object used to build this result */
178
+ VALUE connection;
179
+
180
+ /* The TypeMap used to type cast result values */
181
+ VALUE typemap;
182
+
183
+ /* Pointer to the typemap object data. This is assumed to be
184
+ * always valid.
185
+ */
186
+ t_typemap *p_typemap;
187
+
188
+ /* 0 = PGresult is cleared by PG::Result#clear or by the GC
189
+ * 1 = PGresult is cleared internally by libpq
190
+ */
191
+ int autoclear;
192
+
193
+ /* Number of fields in fnames[] .
194
+ * Set to -1 if fnames[] is not yet initialized.
195
+ */
196
+ int nfields;
197
+
198
+ /* Prefilled tuple Hash with fnames[] as keys. */
199
+ VALUE tuple_hash;
200
+
201
+ /* List of field names as frozen String objects.
202
+ * Only valid if nfields != -1
203
+ */
204
+ VALUE fnames[0];
205
+ } t_pg_result;
206
+
207
+
208
+ typedef int (* t_pg_coder_enc_func)(t_pg_coder *, VALUE, char *, VALUE *);
209
+ typedef VALUE (* t_pg_coder_dec_func)(t_pg_coder *, char *, int, int, int, int);
210
+ typedef VALUE (* t_pg_fit_to_result)(VALUE, VALUE);
211
+ typedef VALUE (* t_pg_fit_to_query)(VALUE, VALUE);
212
+ typedef int (* t_pg_fit_to_copy_get)(VALUE);
213
+ typedef VALUE (* t_pg_typecast_result)(t_typemap *, VALUE, int, int);
214
+ typedef t_pg_coder *(* t_pg_typecast_query_param)(t_typemap *, VALUE, int);
215
+ typedef VALUE (* t_pg_typecast_copy_get)( t_typemap *, VALUE, int, int, int );
216
+
217
+ struct pg_coder {
218
+ t_pg_coder_enc_func enc_func;
219
+ t_pg_coder_dec_func dec_func;
220
+ VALUE coder_obj;
221
+ Oid oid;
222
+ int format;
223
+ };
224
+
225
+ typedef struct {
226
+ t_pg_coder comp;
227
+ t_pg_coder *elem;
228
+ int needs_quotation;
229
+ char delimiter;
230
+ } t_pg_composite_coder;
231
+
232
+ struct pg_typemap {
233
+ struct pg_typemap_funcs {
234
+ t_pg_fit_to_result fit_to_result;
235
+ t_pg_fit_to_query fit_to_query;
236
+ t_pg_fit_to_copy_get fit_to_copy_get;
237
+ t_pg_typecast_result typecast_result_value;
238
+ t_pg_typecast_query_param typecast_query_param;
239
+ t_pg_typecast_copy_get typecast_copy_get;
240
+ } funcs;
241
+ VALUE default_typemap;
242
+ };
243
+
244
+ typedef struct {
245
+ t_typemap typemap;
246
+ int nfields;
247
+ struct pg_tmbc_converter {
248
+ t_pg_coder *cconv;
249
+ } convs[0];
250
+ } t_tmbc;
251
+
252
+
104
253
  #include "gvl_wrappers.h"
105
254
 
106
255
  /***************************************************************************
@@ -112,11 +261,33 @@ extern VALUE rb_ePGerror;
112
261
  extern VALUE rb_eServerError;
113
262
  extern VALUE rb_eUnableToSend;
114
263
  extern VALUE rb_eConnectionBad;
264
+ extern VALUE rb_eInvalidResultStatus;
265
+ extern VALUE rb_eNoResultError;
266
+ extern VALUE rb_eInvalidChangeOfResultFields;
115
267
  extern VALUE rb_mPGconstants;
116
268
  extern VALUE rb_cPGconn;
117
269
  extern VALUE rb_cPGresult;
118
270
  extern VALUE rb_hErrors;
271
+ extern VALUE rb_cTypeMap;
272
+ extern VALUE rb_cTypeMapAllStrings;
273
+ extern VALUE rb_mDefaultTypeMappable;
274
+ extern VALUE rb_cPG_Coder;
275
+ extern VALUE rb_cPG_SimpleEncoder;
276
+ extern VALUE rb_cPG_SimpleDecoder;
277
+ extern VALUE rb_cPG_CompositeEncoder;
278
+ extern VALUE rb_cPG_CompositeDecoder;
279
+ extern VALUE rb_cPG_CopyCoder;
280
+ extern VALUE rb_cPG_CopyEncoder;
281
+ extern VALUE rb_cPG_CopyDecoder;
282
+ extern VALUE rb_mPG_TextEncoder;
283
+ extern VALUE rb_mPG_TextDecoder;
284
+ extern VALUE rb_mPG_BinaryEncoder;
285
+ extern VALUE rb_mPG_BinaryDecoder;
286
+ extern VALUE rb_mPG_BinaryFormatting;
287
+ extern const struct pg_typemap_funcs pg_tmbc_funcs;
288
+ extern const struct pg_typemap_funcs pg_typemap_funcs;
119
289
 
290
+ extern VALUE pg_typemap_all_strings;
120
291
 
121
292
  /***************************************************************************
122
293
  * MACROS
@@ -134,19 +305,84 @@ void Init_pg_ext _(( void ));
134
305
  void init_pg_connection _(( void ));
135
306
  void init_pg_result _(( void ));
136
307
  void init_pg_errors _(( void ));
137
- VALUE lookup_error_class _(( const char *sqlstate ));
308
+ void init_pg_type_map _(( void ));
309
+ void init_pg_type_map_all_strings _(( void ));
310
+ void init_pg_type_map_by_class _(( void ));
311
+ void init_pg_type_map_by_column _(( void ));
312
+ void init_pg_type_map_by_mri_type _(( void ));
313
+ void init_pg_type_map_by_oid _(( void ));
314
+ void init_pg_type_map_in_ruby _(( void ));
315
+ void init_pg_coder _(( void ));
316
+ void init_pg_copycoder _(( void ));
317
+ void init_pg_text_encoder _(( void ));
318
+ void init_pg_text_decoder _(( void ));
319
+ void init_pg_binary_encoder _(( void ));
320
+ void init_pg_binary_decoder _(( void ));
321
+ VALUE lookup_error_class _(( const char * ));
322
+ VALUE pg_bin_dec_bytea _(( t_pg_coder*, char *, int, int, int, int ));
323
+ VALUE pg_text_dec_string _(( t_pg_coder*, char *, int, int, int, int ));
324
+ int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, char *, VALUE *));
325
+ int pg_text_enc_identifier _(( t_pg_coder*, VALUE, char *, VALUE *));
326
+ t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
327
+ t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int ));
328
+ void pg_define_coder _(( const char *, void *, VALUE, VALUE ));
329
+ VALUE pg_obj_to_i _(( VALUE ));
330
+ VALUE pg_tmbc_allocate _(( void ));
331
+ void pg_coder_init_encoder _(( VALUE ));
332
+ void pg_coder_init_decoder _(( VALUE ));
333
+ char *pg_rb_str_ensure_capa _(( VALUE, long, char *, char ** ));
334
+
335
+ #define PG_RB_STR_ENSURE_CAPA( str, expand_len, curr_ptr, end_ptr ) \
336
+ do { \
337
+ if( (curr_ptr) + (expand_len) >= (end_ptr) ) \
338
+ (curr_ptr) = pg_rb_str_ensure_capa( (str), (expand_len), (curr_ptr), &(end_ptr) ); \
339
+ } while(0);
340
+
341
+ #define PG_RB_STR_NEW( str, curr_ptr, end_ptr ) ( \
342
+ (str) = rb_str_new( NULL, 0 ), \
343
+ (curr_ptr) = (end_ptr) = RSTRING_PTR(str) \
344
+ )
345
+
346
+ #define PG_RB_TAINTED_STR_NEW( str, curr_ptr, end_ptr ) ( \
347
+ (str) = rb_tainted_str_new( NULL, 0 ), \
348
+ (curr_ptr) = (end_ptr) = RSTRING_PTR(str) \
349
+ )
138
350
 
139
- PGconn *pg_get_pgconn _(( VALUE ));
351
+ VALUE pg_typemap_fit_to_result _(( VALUE, VALUE ));
352
+ VALUE pg_typemap_fit_to_query _(( VALUE, VALUE ));
353
+ int pg_typemap_fit_to_copy_get _(( VALUE ));
354
+ VALUE pg_typemap_result_value _(( t_typemap *, VALUE, int, int ));
355
+ t_pg_coder *pg_typemap_typecast_query_param _(( t_typemap *, VALUE, int ));
356
+ VALUE pg_typemap_typecast_copy_get _(( t_typemap *, VALUE, int, int, int ));
357
+
358
+ PGconn *pg_get_pgconn _(( VALUE ));
359
+ t_pg_connection *pg_get_connection _(( VALUE ));
140
360
 
141
361
  VALUE pg_new_result _(( PGresult *, VALUE ));
362
+ VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
363
+ PGresult* pgresult_get _(( VALUE ));
142
364
  VALUE pg_result_check _(( VALUE ));
143
365
  VALUE pg_result_clear _(( VALUE ));
144
366
 
367
+ /*
368
+ * Fetch the data pointer for the result object
369
+ */
370
+ static inline t_pg_result *
371
+ pgresult_get_this( VALUE self )
372
+ {
373
+ t_pg_result *this = DATA_PTR(self);
374
+
375
+ if( this == NULL )
376
+ rb_raise(rb_ePGerror, "result has been cleared");
377
+
378
+ return this;
379
+ }
380
+
381
+
145
382
  #ifdef M17N_SUPPORTED
146
383
  rb_encoding * pg_get_pg_encoding_as_rb_encoding _(( int ));
147
384
  rb_encoding * pg_get_pg_encname_as_rb_encoding _(( const char * ));
148
385
  const char * pg_get_rb_encoding_as_pg_encoding _(( rb_encoding * ));
149
- int pg_enc_get_index _(( VALUE ));
150
386
  rb_encoding *pg_conn_enc_get _(( PGconn * ));
151
387
  #endif /* M17N_SUPPORTED */
152
388