do_postgres 0.9.12-x86-mswin32-60 → 0.10.0-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,8 +1,12 @@
1
- == 0.9.11 2009-01-19
1
+ ## 0.9.12 2009-05-17
2
+ * Improvements
3
+ * Windows support
4
+
5
+ ## 0.9.11 2009-01-19
2
6
  * Improvements
3
7
  * Ruby 1.9 support
4
8
  * Fixes
5
9
  * Fix build issue on certain platforms introduces with 0.9.10
6
10
 
7
- == 0.9.9 2008-11-27
11
+ ## 0.9.9 2008-11-27
8
12
  * No changes since 0.9.8
data/Manifest.txt CHANGED
@@ -1,8 +1,8 @@
1
1
  .gitignore
2
- History.txt
2
+ HISTORY.markdown
3
3
  LICENSE
4
4
  Manifest.txt
5
- README.txt
5
+ README.markdown
6
6
  Rakefile
7
7
  autobuild.rb
8
8
  buildfile
@@ -1,3 +1,4 @@
1
- = do_postgres
1
+ do_postgres
2
+ ===========
2
3
 
3
4
  A PostgreSQL driver for DataObjects
data/Rakefile CHANGED
@@ -8,9 +8,9 @@ require 'lib/do_postgres/version'
8
8
  ROOT = Pathname(__FILE__).dirname.expand_path
9
9
  JRUBY = RUBY_PLATFORM =~ /java/
10
10
  WINDOWS = Gem.win_platform?
11
- SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
11
+ SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
12
12
  BINARY_VERSION = '5.0.77'
13
13
 
14
- Dir['tasks/*.rake'].each { |f| import f }
14
+ Dir['tasks/*.rake'].sort.each { |f| import f }
15
15
 
16
16
  CLEAN.include(%w[ {tmp,pkg}/ **/*.{o,so,bundle,jar,log,a,gem,dSYM,obj,pdb,exp,DS_Store,rbc,db} ext/do_postgres_ext/Makefile ext-java/target ])
@@ -2,6 +2,7 @@
2
2
  #include <postgres.h>
3
3
  #include <mb/pg_wchar.h>
4
4
  #include <catalog/pg_type.h>
5
+ #include <utils/errcodes.h>
5
6
 
6
7
  /* Undefine constants Postgres also defines */
7
8
  #undef PACKAGE_BUGREPORT
@@ -30,14 +31,13 @@
30
31
  #include <math.h>
31
32
  #include <ctype.h>
32
33
  #include <time.h>
34
+ #include "error.h"
33
35
 
34
36
  #define ID_CONST_GET rb_intern("const_get")
35
37
  #define ID_PATH rb_intern("path")
36
38
  #define ID_NEW rb_intern("new")
37
39
  #define ID_ESCAPE rb_intern("escape_sql")
38
40
 
39
- #define RUBY_STRING(char_ptr) rb_str_new2(char_ptr)
40
- #define TAINTED_STRING(name, length) rb_tainted_str_new(name, length)
41
41
  #define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
42
42
  #define POSTGRES_CLASS(klass, parent) (rb_define_class_under(mPostgres, klass, parent))
43
43
  #define DEBUG(value) data_objects_debug(value)
@@ -55,6 +55,36 @@
55
55
  #define RARRAY_LEN(a) RARRAY(a)->len
56
56
  #endif
57
57
 
58
+ #ifdef HAVE_RUBY_ENCODING_H
59
+ #include <ruby/encoding.h>
60
+
61
+ #define DO_STR_NEW2(str, encoding) \
62
+ ({ \
63
+ VALUE _string = rb_str_new2((const char *)str); \
64
+ if(encoding != -1) { \
65
+ rb_enc_associate_index(_string, encoding); \
66
+ } \
67
+ _string; \
68
+ })
69
+
70
+ #define DO_STR_NEW(str, len, encoding) \
71
+ ({ \
72
+ VALUE _string = rb_str_new((const char *)str, (long)len); \
73
+ if(encoding != -1) { \
74
+ rb_enc_associate_index(_string, encoding); \
75
+ } \
76
+ _string; \
77
+ })
78
+
79
+ #else
80
+
81
+ #define DO_STR_NEW2(str, doc) \
82
+ rb_str_new2((const char *)str)
83
+
84
+ #define DO_STR_NEW(str, len, doc) \
85
+ rb_str_new((const char *)str, (long)len)
86
+ #endif
87
+
58
88
 
59
89
  // To store rb_intern values
60
90
  static ID ID_NEW_DATE;
@@ -66,6 +96,7 @@ static ID ID_RATIONAL;
66
96
 
67
97
  static VALUE mExtlib;
68
98
  static VALUE mDO;
99
+ static VALUE mEncoding;
69
100
  static VALUE cDO_Quoting;
70
101
  static VALUE cDO_Connection;
71
102
  static VALUE cDO_Command;
@@ -84,7 +115,8 @@ static VALUE cResult;
84
115
  static VALUE cReader;
85
116
 
86
117
  static VALUE eArgumentError;
87
- static VALUE ePostgresError;
118
+ static VALUE eConnectionError;
119
+ static VALUE eDataError;
88
120
 
89
121
  static void data_objects_debug(VALUE string, struct timeval* start) {
90
122
  struct timeval stop;
@@ -116,7 +148,7 @@ static char * get_uri_option(VALUE query_hash, char * key) {
116
148
 
117
149
  if(!rb_obj_is_kind_of(query_hash, rb_cHash)) { return NULL; }
118
150
 
119
- query_value = rb_hash_aref(query_hash, RUBY_STRING(key));
151
+ query_value = rb_hash_aref(query_hash, rb_str_new2(key));
120
152
 
121
153
  if (Qnil != query_value) {
122
154
  value = StringValuePtr(query_value);
@@ -219,7 +251,7 @@ static VALUE parse_date_time(const char *date) {
219
251
  hour_offset = 0;
220
252
  minute_offset = 0;
221
253
  sec = 0;
222
- }
254
+ }
223
255
  // We read the Date and Time, default to the current locale's offset
224
256
 
225
257
  // Get localtime
@@ -241,7 +273,7 @@ static VALUE parse_date_time(const char *date) {
241
273
 
242
274
  } else {
243
275
  // Something went terribly wrong
244
- rb_raise(ePostgresError, "Couldn't parse date: %s", date);
276
+ rb_raise(eDataError, "Couldn't parse date: %s", date);
245
277
  }
246
278
 
247
279
  jd = jd_from_date(year, month, day);
@@ -327,16 +359,16 @@ static VALUE infer_ruby_type(Oid type) {
327
359
  }
328
360
  }
329
361
 
330
- static VALUE typecast(const char *value, long length, const VALUE type) {
362
+ static VALUE typecast(const char *value, long length, const VALUE type, int encoding) {
331
363
 
332
364
  if (type == rb_cInteger) {
333
365
  return rb_cstr2inum(value, 10);
334
366
  } else if (type == rb_cString) {
335
- return TAINTED_STRING(value, length);
367
+ return DO_STR_NEW(value, length, encoding);
336
368
  } else if (type == rb_cFloat) {
337
369
  return rb_float_new(rb_cstr_to_dbl(value, Qfalse));
338
370
  } else if (type == rb_cBigDecimal) {
339
- return rb_funcall(rb_cBigDecimal, ID_NEW, 1, TAINTED_STRING(value, length));
371
+ return rb_funcall(rb_cBigDecimal, ID_NEW, 1, rb_str_new(value, length));
340
372
  } else if (type == rb_cDate) {
341
373
  return parse_date(value);
342
374
  } else if (type == rb_cDateTime) {
@@ -348,21 +380,55 @@ static VALUE typecast(const char *value, long length, const VALUE type) {
348
380
  } else if (type == rb_cByteArray) {
349
381
  size_t new_length = 0;
350
382
  char* unescaped = (char *)PQunescapeBytea((unsigned char*)value, &new_length);
351
- VALUE byte_array = rb_funcall(rb_cByteArray, ID_NEW, 1, TAINTED_STRING(unescaped, new_length));
383
+ VALUE byte_array = rb_funcall(rb_cByteArray, ID_NEW, 1, rb_str_new(unescaped, new_length));
352
384
  PQfreemem(unescaped);
353
385
  return byte_array;
354
386
  } else if (type == rb_cClass) {
355
- return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1, TAINTED_STRING(value, length));
387
+ return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1, rb_str_new(value, length));
356
388
  } else if (type == rb_cObject) {
357
- return rb_marshal_load(rb_str_new2(value));
389
+ return rb_marshal_load(rb_str_new(value, length));
358
390
  } else if (type == rb_cNilClass) {
359
391
  return Qnil;
360
392
  } else {
361
- return TAINTED_STRING(value, length);
393
+ return DO_STR_NEW(value, length, encoding);
362
394
  }
363
395
 
364
396
  }
365
397
 
398
+ static void raise_error(VALUE self, PGresult *result, VALUE query) {
399
+ VALUE exception;
400
+ char *message;
401
+ char *sqlstate;
402
+ int postgres_errno;
403
+
404
+ message = PQresultErrorMessage(result);
405
+ sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
406
+ postgres_errno = MAKE_SQLSTATE(sqlstate[0], sqlstate[1], sqlstate[2], sqlstate[3], sqlstate[4]);
407
+ PQclear(result);
408
+
409
+ const char *exception_type = "SQLError";
410
+
411
+ struct errcodes *errs;
412
+
413
+ for (errs = errors; errs->error_name; errs++) {
414
+ if(errs->error_no == postgres_errno) {
415
+ exception_type = errs->exception;
416
+ break;
417
+ }
418
+ }
419
+
420
+ VALUE uri = rb_funcall(rb_iv_get(self, "@connection"), rb_intern("to_s"), 0);
421
+
422
+ exception = rb_funcall(CONST_GET(mDO, exception_type), ID_NEW, 5,
423
+ rb_str_new2(message),
424
+ INT2NUM(postgres_errno),
425
+ rb_str_new2(sqlstate),
426
+ query,
427
+ uri);
428
+ rb_exc_raise(exception);
429
+ }
430
+
431
+
366
432
  /* ====== Public API ======= */
367
433
  static VALUE cConnection_dispose(VALUE self) {
368
434
  VALUE connection_container = rb_iv_get(self, "@connection");
@@ -449,7 +515,8 @@ static VALUE cConnection_quote_string(VALUE self, VALUE string) {
449
515
  // Wrap the escaped string in single-quotes, this is DO's convention
450
516
  escaped[quoted_length + 1] = escaped[0] = '\'';
451
517
 
452
- result = rb_str_new(escaped, quoted_length + 2);
518
+ result = DO_STR_NEW(escaped, quoted_length + 2, FIX2INT(rb_iv_get(self, "@encoding_id")));
519
+
453
520
  free(escaped);
454
521
  return result;
455
522
  }
@@ -474,14 +541,16 @@ static VALUE cConnection_quote_byte_array(VALUE self, VALUE string) {
474
541
  // Wrap the escaped string in single-quotes, this is DO's convention (replace trailing \0)
475
542
  escaped_quotes[quoted_length] = escaped_quotes[0] = '\'';
476
543
 
477
- result = TAINTED_STRING((char*)escaped_quotes, quoted_length + 1);
544
+ result = rb_str_new((const char *)escaped_quotes, quoted_length + 1);
478
545
  PQfreemem(escaped);
479
546
  free(escaped_quotes);
480
547
  return result;
481
548
  }
482
549
 
550
+ static void full_connect(VALUE self, PGconn *db);
551
+
483
552
  #ifdef _WIN32
484
- static PGresult* cCommand_execute_sync(PGconn *db, VALUE query) {
553
+ static PGresult* cCommand_execute_sync(VALUE self, PGconn *db, VALUE query) {
485
554
  PGresult *response;
486
555
  struct timeval start;
487
556
  char* str = StringValuePtr(query);
@@ -499,11 +568,15 @@ static PGresult* cCommand_execute_sync(PGconn *db, VALUE query) {
499
568
  PQreset(db);
500
569
  if (PQstatus(db) == CONNECTION_OK) {
501
570
  response = PQexec(db, str);
571
+ } else {
572
+ VALUE connection = rb_iv_get(self, "@connection");
573
+ full_connect(connection, db);
574
+ response = PQexec(db, str);
502
575
  }
503
576
  }
504
577
 
505
578
  if(response == NULL) {
506
- rb_raise(ePostgresError, PQerrorMessage(db));
579
+ rb_raise(eConnectionError, PQerrorMessage(db));
507
580
  }
508
581
  }
509
582
 
@@ -511,7 +584,7 @@ static PGresult* cCommand_execute_sync(PGconn *db, VALUE query) {
511
584
  return response;
512
585
  }
513
586
  #else
514
- static PGresult* cCommand_execute_async(PGconn *db, VALUE query) {
587
+ static PGresult* cCommand_execute_async(VALUE self, PGconn *db, VALUE query) {
515
588
  int socket_fd;
516
589
  int retval;
517
590
  fd_set rset;
@@ -530,11 +603,15 @@ static PGresult* cCommand_execute_async(PGconn *db, VALUE query) {
530
603
  PQreset(db);
531
604
  if (PQstatus(db) == CONNECTION_OK) {
532
605
  retval = PQsendQuery(db, str);
606
+ } else {
607
+ VALUE connection = rb_iv_get(self, "@connection");
608
+ full_connect(connection, db);
609
+ retval = PQsendQuery(db, str);
533
610
  }
534
611
  }
535
612
 
536
613
  if(!retval) {
537
- rb_raise(ePostgresError, PQerrorMessage(db));
614
+ rb_raise(eConnectionError, PQerrorMessage(db));
538
615
  }
539
616
  }
540
617
 
@@ -554,7 +631,7 @@ static PGresult* cCommand_execute_async(PGconn *db, VALUE query) {
554
631
  }
555
632
 
556
633
  if (PQconsumeInput(db) == 0) {
557
- rb_raise(ePostgresError, PQerrorMessage(db));
634
+ rb_raise(eConnectionError, PQerrorMessage(db));
558
635
  }
559
636
 
560
637
  if (PQisBusy(db) == 0) {
@@ -568,52 +645,94 @@ static PGresult* cCommand_execute_async(PGconn *db, VALUE query) {
568
645
  #endif
569
646
 
570
647
  static VALUE cConnection_initialize(VALUE self, VALUE uri) {
571
- PGresult *result = NULL;
572
- VALUE r_host, r_user, r_password, r_path, r_port, r_query, r_options;
573
- char *host = NULL, *user = NULL, *password = NULL, *path;
574
- char *database = "", *port = "5432";
575
- char *encoding = NULL;
576
- char *search_path = NULL;
577
- char *search_path_query = NULL;
578
- char *backslash_off = "SET backslash_quote = off";
579
- char *standard_strings_on = "SET standard_conforming_strings = on";
580
- char *warning_messages = "SET client_min_messages = warning";
648
+ VALUE r_host, r_user, r_password, r_path, r_query, r_port;
581
649
 
582
- PGconn *db;
650
+ PGconn *db = NULL;
651
+
652
+ rb_iv_set(self, "@using_socket", Qfalse);
583
653
 
584
654
  r_host = rb_funcall(uri, rb_intern("host"), 0);
585
- if ( Qnil != r_host ) {
586
- host = StringValuePtr(r_host);
655
+ if (Qnil != r_host) {
656
+ rb_iv_set(self, "@host", r_host);
587
657
  }
588
658
 
589
659
  r_user = rb_funcall(uri, rb_intern("user"), 0);
590
660
  if (Qnil != r_user) {
591
- user = StringValuePtr(r_user);
661
+ rb_iv_set(self, "@user", r_user);
592
662
  }
593
663
 
594
664
  r_password = rb_funcall(uri, rb_intern("password"), 0);
595
665
  if (Qnil != r_password) {
596
- password = StringValuePtr(r_password);
666
+ rb_iv_set(self, "@password", r_password);
597
667
  }
598
668
 
599
669
  r_path = rb_funcall(uri, rb_intern("path"), 0);
600
- path = StringValuePtr(r_path);
601
670
  if (Qnil != r_path) {
602
- database = strtok(path, "/");
603
- }
604
-
605
- if (NULL == database || 0 == strlen(database)) {
606
- rb_raise(ePostgresError, "Database must be specified");
671
+ rb_iv_set(self, "@path", r_path);
607
672
  }
608
673
 
609
674
  r_port = rb_funcall(uri, rb_intern("port"), 0);
610
675
  if (Qnil != r_port) {
611
676
  r_port = rb_funcall(r_port, rb_intern("to_s"), 0);
612
- port = StringValuePtr(r_port);
677
+ rb_iv_set(self, "@port", r_port);
613
678
  }
614
679
 
615
680
  // Pull the querystring off the URI
616
681
  r_query = rb_funcall(uri, rb_intern("query"), 0);
682
+ rb_iv_set(self, "@query", r_query);
683
+
684
+ const char* encoding = get_uri_option(r_query, "encoding");
685
+ if (!encoding) { encoding = get_uri_option(r_query, "charset"); }
686
+ if (!encoding) { encoding = "UTF-8"; }
687
+
688
+ rb_iv_set(self, "@encoding", rb_str_new2(encoding));
689
+
690
+ full_connect(self, db);
691
+
692
+ rb_iv_set(self, "@uri", uri);
693
+
694
+ return Qtrue;
695
+ }
696
+
697
+ static void full_connect(VALUE self, PGconn *db) {
698
+
699
+ PGresult *result = NULL;
700
+ VALUE r_host, r_user, r_password, r_path, r_port, r_query, r_options;
701
+ char *host = NULL, *user = NULL, *password = NULL, *path;
702
+ char *database = "", *port = "5432";
703
+ VALUE encoding = Qnil;
704
+ char *search_path = NULL;
705
+ char *search_path_query = NULL;
706
+ char *backslash_off = "SET backslash_quote = off";
707
+ char *standard_strings_on = "SET standard_conforming_strings = on";
708
+ char *warning_messages = "SET client_min_messages = warning";
709
+
710
+ if((r_host = rb_iv_get(self, "@host")) != Qnil) {
711
+ host = StringValuePtr(r_host);
712
+ }
713
+
714
+ if((r_user = rb_iv_get(self, "@user")) != Qnil) {
715
+ user = StringValuePtr(r_user);
716
+ }
717
+
718
+ if((r_password = rb_iv_get(self, "@password")) != Qnil) {
719
+ password = StringValuePtr(r_password);
720
+ }
721
+
722
+ if((r_port = rb_iv_get(self, "@port")) != Qnil) {
723
+ port = StringValuePtr(r_port);
724
+ }
725
+
726
+ if((r_path = rb_iv_get(self, "@path")) != Qnil) {
727
+ path = StringValuePtr(r_path);
728
+ database = strtok(path, "/");
729
+ }
730
+
731
+ if (NULL == database || 0 == strlen(database)) {
732
+ rb_raise(eConnectionError, "Database must be specified");
733
+ }
734
+
735
+ r_query = rb_iv_get(self, "@query");
617
736
 
618
737
  search_path = get_uri_option(r_query, "search_path");
619
738
 
@@ -628,81 +747,78 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
628
747
  );
629
748
 
630
749
  if ( PQstatus(db) == CONNECTION_BAD ) {
631
- rb_raise(ePostgresError, PQerrorMessage(db));
750
+ rb_raise(eConnectionError, PQerrorMessage(db));
632
751
  }
633
752
 
634
753
  if (search_path != NULL) {
635
754
  search_path_query = (char *)calloc(256, sizeof(char));
636
755
  snprintf(search_path_query, 256, "set search_path to %s;", search_path);
637
756
  r_query = rb_str_new2(search_path_query);
638
- result = cCommand_execute(db, r_query);
757
+ result = cCommand_execute(self, db, r_query);
639
758
 
640
759
  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
641
760
  free(search_path_query);
642
- rb_raise(ePostgresError, PQresultErrorMessage(result));
761
+ raise_error(self, result, r_query);
643
762
  }
644
763
 
645
764
  free(search_path_query);
646
765
  }
647
766
 
648
767
  r_options = rb_str_new2(backslash_off);
649
- result = cCommand_execute(db, r_options);
768
+ result = cCommand_execute(self, db, r_options);
650
769
 
651
770
  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
652
771
  rb_warn(PQresultErrorMessage(result));
653
772
  }
654
773
 
655
774
  r_options = rb_str_new2(standard_strings_on);
656
- result = cCommand_execute(db, r_options);
775
+ result = cCommand_execute(self, db, r_options);
657
776
 
658
777
  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
659
778
  rb_warn(PQresultErrorMessage(result));
660
779
  }
661
780
 
662
781
  r_options = rb_str_new2(warning_messages);
663
- result = cCommand_execute(db, r_options);
782
+ result = cCommand_execute(self, db, r_options);
664
783
 
665
784
  if (PQresultStatus(result) != PGRES_COMMAND_OK) {
666
785
  rb_warn(PQresultErrorMessage(result));
667
786
  }
668
787
 
669
- encoding = get_uri_option(r_query, "encoding");
670
- if (!encoding) { encoding = get_uri_option(r_query, "charset"); }
671
- if (!encoding) { encoding = "utf8"; }
788
+ encoding = rb_iv_get(self, "@encoding");
672
789
 
673
790
  #ifdef HAVE_PQSETCLIENTENCODING
674
- if(PQsetClientEncoding(db, encoding)) {
675
- rb_raise(ePostgresError, "Couldn't set encoding: %s", encoding);
791
+ VALUE pg_encoding = rb_hash_aref(CONST_GET(mEncoding, "MAP"), encoding);
792
+ if(pg_encoding != Qnil) {
793
+ if(PQsetClientEncoding(db, RSTRING_PTR(pg_encoding))) {
794
+ rb_raise(eConnectionError, "Couldn't set encoding: %s", RSTRING_PTR(encoding));
795
+ } else {
796
+ #ifdef HAVE_RUBY_ENCODING_H
797
+ rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index(RSTRING_PTR(encoding))));
798
+ #endif
799
+ rb_iv_set(self, "@pg_encoding", pg_encoding);
800
+ }
801
+ } else {
802
+ rb_warn("Encoding %s is not a known Ruby encoding for PostgreSQL\n", RSTRING_PTR(encoding));
803
+ rb_iv_set(self, "@encoding", rb_str_new2("UTF-8"));
804
+ #ifdef HAVE_RUBY_ENCODING_H
805
+ rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index("UTF-8")));
806
+ #endif
807
+ rb_iv_set(self, "@pg_encoding", rb_str_new2("UTF8"));
676
808
  }
677
809
  #endif
678
-
679
- rb_iv_set(self, "@uri", uri);
680
810
  rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
681
-
682
- return Qtrue;
683
811
  }
684
812
 
685
813
  static VALUE cConnection_character_set(VALUE self) {
686
- VALUE connection_container = rb_iv_get(self, "@connection");
687
- PGconn *db;
688
-
689
- const char *encoding;
690
-
691
- if (Qnil == connection_container)
692
- return Qfalse;
693
-
694
- db = DATA_PTR(connection_container);
695
-
696
- encoding = pg_encoding_to_char(PQclientEncoding(db));
697
-
698
- return rb_funcall(RUBY_STRING(encoding), rb_intern("downcase"), 0);
814
+ return rb_iv_get(self, "@encoding");
699
815
  }
700
816
 
701
817
  static VALUE cCommand_execute_non_query(int argc, VALUE *argv[], VALUE self) {
702
818
  VALUE connection = rb_iv_get(self, "@connection");
703
819
  VALUE postgres_connection = rb_iv_get(connection, "@connection");
704
820
  if (Qnil == postgres_connection) {
705
- rb_raise(ePostgresError, "This connection has already been closed.");
821
+ rb_raise(eConnectionError, "This connection has already been closed.");
706
822
  }
707
823
 
708
824
  PGconn *db = DATA_PTR(postgres_connection);
@@ -714,7 +830,7 @@ static VALUE cCommand_execute_non_query(int argc, VALUE *argv[], VALUE self) {
714
830
 
715
831
  VALUE query = build_query_from_args(self, argc, argv);
716
832
 
717
- response = cCommand_execute(db, query);
833
+ response = cCommand_execute(self, db, query);
718
834
 
719
835
  status = PQresultStatus(response);
720
836
 
@@ -727,10 +843,7 @@ static VALUE cCommand_execute_non_query(int argc, VALUE *argv[], VALUE self) {
727
843
  affected_rows = INT2NUM(atoi(PQcmdTuples(response)));
728
844
  }
729
845
  else {
730
- char *message = PQresultErrorMessage(response);
731
- char *sqlstate = PQresultErrorField(response, PG_DIAG_SQLSTATE);
732
- PQclear(response);
733
- rb_raise(ePostgresError, "(sql_state=%s) %sQuery: %s\n", sqlstate, message, StringValuePtr(query));
846
+ raise_error(self, response, query);
734
847
  }
735
848
 
736
849
  PQclear(response);
@@ -749,7 +862,7 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv[], VALUE self) {
749
862
  VALUE connection = rb_iv_get(self, "@connection");
750
863
  VALUE postgres_connection = rb_iv_get(connection, "@connection");
751
864
  if (Qnil == postgres_connection) {
752
- rb_raise(ePostgresError, "This connection has already been closed.");
865
+ rb_raise(eConnectionError, "This connection has already been closed.");
753
866
  }
754
867
 
755
868
  PGconn *db = DATA_PTR(postgres_connection);
@@ -757,17 +870,16 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv[], VALUE self) {
757
870
 
758
871
  query = build_query_from_args(self, argc, argv);
759
872
 
760
- response = cCommand_execute(db, query);
873
+ response = cCommand_execute(self, db, query);
761
874
 
762
875
  if ( PQresultStatus(response) != PGRES_TUPLES_OK ) {
763
- char *message = PQresultErrorMessage(response);
764
- PQclear(response);
765
- rb_raise(ePostgresError, "%sQuery: %s\n", message, StringValuePtr(query));
876
+ raise_error(self, response, query);
766
877
  }
767
878
 
768
879
  field_count = PQnfields(response);
769
880
 
770
881
  reader = rb_funcall(cReader, ID_NEW, 0);
882
+ rb_iv_set(reader, "@connection", connection);
771
883
  rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, response));
772
884
  rb_iv_set(reader, "@field_count", INT2NUM(field_count));
773
885
  rb_iv_set(reader, "@row_count", INT2NUM(PQntuples(response)));
@@ -834,17 +946,25 @@ static VALUE cReader_next(VALUE self) {
834
946
  field_types = rb_iv_get(self, "@field_types");
835
947
  position = NUM2INT(rb_iv_get(self, "@position"));
836
948
 
837
- if ( position > (row_count-1) ) {
949
+ if ( position > (row_count - 1) ) {
838
950
  rb_iv_set(self, "@values", Qnil);
839
951
  return Qfalse;
840
952
  }
841
953
 
954
+ int enc = -1;
955
+ #ifdef HAVE_RUBY_ENCODING_H
956
+ VALUE encoding_id = rb_iv_get(rb_iv_get(self, "@connection"), "@encoding_id");
957
+ if (encoding_id != Qnil) {
958
+ enc = FIX2INT(encoding_id);
959
+ }
960
+ #endif
961
+
842
962
  for ( i = 0; i < field_count; i++ ) {
843
963
  field_type = rb_ary_entry(field_types, i);
844
964
 
845
965
  // Always return nil if the value returned from Postgres is null
846
966
  if (!PQgetisnull(reader, position, i)) {
847
- value = typecast(PQgetvalue(reader, position, i), PQgetlength(reader, position, i), field_type);
967
+ value = typecast(PQgetvalue(reader, position, i), PQgetlength(reader, position, i), field_type, enc);
848
968
  } else {
849
969
  value = Qnil;
850
970
  }
@@ -862,7 +982,7 @@ static VALUE cReader_values(VALUE self) {
862
982
 
863
983
  VALUE values = rb_iv_get(self, "@values");
864
984
  if(values == Qnil) {
865
- rb_raise(ePostgresError, "Reader not initialized");
985
+ rb_raise(eDataError, "Reader not initialized");
866
986
  return Qnil;
867
987
  } else {
868
988
  return values;
@@ -913,7 +1033,9 @@ void Init_do_postgres_ext() {
913
1033
 
914
1034
  eArgumentError = CONST_GET(rb_mKernel, "ArgumentError");
915
1035
  mPostgres = rb_define_module_under(mDO, "Postgres");
916
- ePostgresError = rb_define_class("PostgresError", rb_eStandardError);
1036
+ eConnectionError = CONST_GET(mDO, "ConnectionError");
1037
+ eDataError = CONST_GET(mDO, "DataError");
1038
+ mEncoding = rb_define_module_under(mPostgres, "Encoding");
917
1039
 
918
1040
  cConnection = POSTGRES_CLASS("Connection", cDO_Connection);
919
1041
  rb_define_method(cConnection, "initialize", cConnection_initialize, 1);
@@ -936,4 +1058,10 @@ void Init_do_postgres_ext() {
936
1058
  rb_define_method(cReader, "fields", cReader_fields, 0);
937
1059
  rb_define_method(cReader, "field_count", cReader_field_count, 0);
938
1060
 
1061
+ struct errcodes *errs;
1062
+
1063
+ for (errs = errors; errs->error_name; errs++) {
1064
+ rb_const_set(mPostgres, rb_intern(errs->error_name), INT2NUM(errs->error_no));
1065
+ }
1066
+
939
1067
  }