[freeside-commits] branch FREESIDE_3_BRANCH updated. a6483866254ab76880c010a2534268a4c24c94be

Mitch Jackson mitch at freeside.biz
Sun Mar 3 17:40:36 PST 2019


The branch, FREESIDE_3_BRANCH has been updated
       via  a6483866254ab76880c010a2534268a4c24c94be (commit)
       via  fcce61390d750f98bd82e84d4664ae9c03202be2 (commit)
       via  83eb68cd59af488d57c23b653f44a7ae9aa4a753 (commit)
      from  f036b79d6c17055ba894aed3ea5fb877c1d1bc5a (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a6483866254ab76880c010a2534268a4c24c94be
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Sun Mar 3 19:26:41 2019 -0500

    RT# 82942 Force UTF8 client_encoding for Pg in RT::Handle

diff --git a/rt/lib/RT/Handle.pm b/rt/lib/RT/Handle.pm
index 794d8b009..3b411d5e4 100644
--- a/rt/lib/RT/Handle.pm
+++ b/rt/lib/RT/Handle.pm
@@ -130,6 +130,11 @@ sub Connect {
         ($version) = $version =~ /^(\d+\.\d+)/;
         $self->dbh->{pg_server_prepare} = 0 if $version > 9.1; #and we're using a deb-7 version DBD::Pg?
         $self->dbh->do("SET bytea_output = 'escape'") if $version >= 9.0;
+
+        # Force UTF8, even when database encoding is not UTF8
+        # DBD::Pg used to do this for us prior to v3
+        $self->dbh->do('SET client_encoding TO UTF8;');
+        $self->dbh->{pg_enable_utf8} = -1;
     }
 
 

commit fcce61390d750f98bd82e84d4664ae9c03202be2
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Sun Mar 3 20:34:23 2019 -0500

    RT# 82942 Replace DBI->connect() with FS::DBI->connect()

diff --git a/FS/FS/TicketSystem/RT_External.pm b/FS/FS/TicketSystem/RT_External.pm
index 20d78c8fc..fa97b3956 100644
--- a/FS/FS/TicketSystem/RT_External.pm
+++ b/FS/FS/TicketSystem/RT_External.pm
@@ -10,6 +10,7 @@ use FS::UID qw(dbh);
 use FS::Record qw(qsearchs);
 use FS::cust_main;
 use Carp qw(cluck);
+use FS::DBI;
 
 $me = '[FS::TicketSystem::RT_External]';
 $DEBUG = 0;
@@ -36,8 +37,8 @@ FS::UID->install_callback( sub {
   $dbh = dbh;
   if ($conf->config('ticket_system') eq 'RT_External') {
     my ($datasrc, $user, $pass) = $conf->config('ticket_system-rt_external_datasrc');
-    $dbh = DBI->connect($datasrc, $user, $pass, { 'ChopBlanks' => 1 })
-      or die "RT_External DBI->connect error: $DBI::errstr\n";
+    $dbh = FS::DBI->connect($datasrc, $user, $pass, { 'ChopBlanks' => 1 })
+      or die "RT_External FS::DBI->connect error: $FS::DBI::errstr\n";
 
     $external_url = $conf->config('ticket_system-rt_external_url');
   }
diff --git a/FS/FS/Upgrade.pm b/FS/FS/Upgrade.pm
index e901a7f1d..86f51f896 100644
--- a/FS/FS/Upgrade.pm
+++ b/FS/FS/Upgrade.pm
@@ -10,6 +10,7 @@ use FS::Conf;
 use FS::Record qw(qsearchs qsearch str2time_sql);
 use FS::queue;
 use FS::upgrade_journal;
+use FS::DBI;
 
 use FS::svc_domain;
 $FS::svc_domain::whois_hack = 1;
@@ -547,11 +548,11 @@ sub upgrade_sqlradius {
     my $errmsg = 'Error adding FreesideStatus to '.
                  $part_export->option('datasrc'). ': ';
 
-    my $dbh = DBI->connect(
+    my $dbh = FS::DBI->connect(
       ( map $part_export->option($_), qw ( datasrc username password ) ),
       { PrintError => 0, PrintWarn => 0 }
     ) or do {
-      warn $errmsg.$DBI::errstr;
+      warn $errmsg.$FS::DBI::errstr;
       next;
     };
 
diff --git a/FS/FS/cdr/Import.pm b/FS/FS/cdr/Import.pm
index 7944e5b4e..dd9fc26d6 100644
--- a/FS/FS/cdr/Import.pm
+++ b/FS/FS/cdr/Import.pm
@@ -4,7 +4,7 @@ use strict;
 use Date::Format 'time2str';
 use FS::UID qw(adminsuidsetup dbh);
 use FS::cdr;
-use DBI;
+use FS::DBI;
 use Getopt::Std;
 
 use vars qw( $DEBUG );
@@ -77,8 +77,8 @@ sub dbi_import {
   my $dsn = 'dbi:'. $dbd_type . $queries->{connect_type};
   $dsn .= ";database=$database" if $database;
 
-  my $dbi = DBI->connect($dsn, $opt{U}, $opt{P}) 
-    or die $DBI::errstr;
+  my $dbi = FS::DBI->connect($dsn, $opt{U}, $opt{P})
+    or die $FS::DBI::errstr;
 
   adminsuidsetup $user;
 
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index 005931a2a..ff75eb63d 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -78,6 +78,7 @@ use FS::contact;
 use FS::Locales;
 use FS::upgrade_journal;
 use FS::reason;
+use FS::DBI;
 
 # 1 is mostly method/subroutine entry and options
 # 2 traces progress of some operations
@@ -1212,7 +1213,7 @@ sub delete {
     $ticket_dbh = $dbh;
   } elsif ($conf->config('ticket_system') eq 'RT_External') {
     my ($datasrc, $user, $pass) = $conf->config('ticket_system-rt_external_datasrc');
-    $ticket_dbh = DBI->connect($datasrc, $user, $pass, { 'ChopBlanks' => 1 });
+    $ticket_dbh = FS::DBI->connect($datasrc, $user, $pass, { 'ChopBlanks' => 1 });
       #or die "RT_External DBI->connect error: $DBI::errstr\n";
   }
 
@@ -1458,7 +1459,7 @@ sub merge {
     $ticket_dbh = $dbh;
   } elsif ($conf->config('ticket_system') eq 'RT_External') {
     my ($datasrc, $user, $pass) = $conf->config('ticket_system-rt_external_datasrc');
-    $ticket_dbh = DBI->connect($datasrc, $user, $pass, { 'ChopBlanks' => 1 });
+    $ticket_dbh = FS::DBI->connect($datasrc, $user, $pass, { 'ChopBlanks' => 1 });
       #or die "RT_External DBI->connect error: $DBI::errstr\n";
   }
 
diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm
index d4d8684ac..13390f29d 100644
--- a/FS/FS/cust_svc.pm
+++ b/FS/FS/cust_svc.pm
@@ -16,6 +16,7 @@ use FS::part_export;
 use FS::cdr;
 use FS::UI::Web;
 use FS::export_cust_svc;
+use FS::DBI;
 
 #most FS::svc_ classes are autoloaded in svc_x emthod
 use FS::svc_acct;  #this one is used in the cache stuff
@@ -743,9 +744,9 @@ sub seconds_since_sqlradacct {
     warn "$mes connecting to sqlradius database\n"
       if $DEBUG;
 
-    my $dbh = DBI->connect( map { $part_export->option($_) }
+    my $dbh = FS::DBI->connect( map { $part_export->option($_) }
                             qw(datasrc username password)    )
-      or die "can't connect to sqlradius database: ". $DBI::errstr;
+      or die "can't connect to sqlradius database: ". $FS::DBI::errstr;
 
     warn "$mes connected to sqlradius database\n"
       if $DEBUG;
@@ -888,9 +889,9 @@ sub attribute_since_sqlradacct {
     warn "$mes connecting to sqlradius database\n"
       if $DEBUG;
 
-    my $dbh = DBI->connect( map { $part_export->option($_) }
+    my $dbh = FS::DBI->connect( map { $part_export->option($_) }
                             qw(datasrc username password)    )
-      or die "can't connect to sqlradius database: ". $DBI::errstr;
+      or die "can't connect to sqlradius database: ". $FS::DBI::errstr;
 
     warn "$mes connected to sqlradius database\n"
       if $DEBUG;
@@ -959,9 +960,9 @@ sub attribute_last_sqlradacct {
     warn "$mes connecting to sqlradius database\n"
       if $DEBUG;
 
-    my $dbh = DBI->connect( map { $part_export->option($_) }
+    my $dbh = FS::DBI->connect( map { $part_export->option($_) }
                             qw(datasrc username password)    )
-      or die "can't connect to sqlradius database: ". $DBI::errstr;
+      or die "can't connect to sqlradius database: ". $FS::DBI::errstr;
 
     warn "$mes connected to sqlradius database\n"
       if $DEBUG;
diff --git a/FS/FS/part_export/a2billing.pm b/FS/FS/part_export/a2billing.pm
index 15410aebf..337e02f08 100644
--- a/FS/FS/part_export/a2billing.pm
+++ b/FS/FS/part_export/a2billing.pm
@@ -11,6 +11,7 @@ use FS::svc_phone;
 use Locale::Country qw(country_code2code);
 use Date::Format qw(time2str);
 use Carp qw( cluck );
+use FS::DBI;
 
 @ISA = qw(FS::part_export);
 
@@ -55,11 +56,11 @@ END
 
 sub dbh {
   my $self = shift;
-  $self->{dbh} ||= DBI->connect(
+  $self->{dbh} ||= FS::DBI->connect(
                       $self->option('datasrc'),
                       $self->option('username'),
                       $self->option('password')
-                      ) or die $DBI::errstr;
+                      ) or die $FS::DBI::errstr;
 
   $self->{dbh}->trace(1, '%%%FREESIDE_LOG%%%/a2b_exportlog.'.$self->exportnum)
     if $DEBUG;
diff --git a/FS/FS/part_export/acct_sql_status.pm b/FS/FS/part_export/acct_sql_status.pm
index 248105f18..0e7343151 100644
--- a/FS/FS/part_export/acct_sql_status.pm
+++ b/FS/FS/part_export/acct_sql_status.pm
@@ -5,6 +5,7 @@ use strict;
 use warnings;
 use vars qw( %info );
 use Tie::IxHash;
+use FS::DBI;
 
 tie my %options, 'Tie::IxHash', %{__PACKAGE__->sql_options};
 delete $options{$_} for qw( table schema static primary_key );
@@ -33,8 +34,8 @@ sub _export_unsuspend {}
 sub export_getstatus {
   my($self, $svc_acct, $htmlref, $hashref) = @_;
 
-  my $dbh = DBI->connect( map $self->option($_), qw(datasrc username password) )
-    or return "can't connect: ".  $DBI::errstr;
+  my $dbh = FS::DBI->connect( map $self->option($_), qw(datasrc username password) )
+    or return "can't connect: ".  $FS::DBI::errstr;
 
   ###
   #vacation settings
diff --git a/FS/FS/part_export/freeswitch_nibblebill.pm b/FS/FS/part_export/freeswitch_nibblebill.pm
index 6611f7827..921444596 100644
--- a/FS/FS/part_export/freeswitch_nibblebill.pm
+++ b/FS/FS/part_export/freeswitch_nibblebill.pm
@@ -3,7 +3,7 @@ use base qw( FS::part_export );
 
 use vars qw( %info ); # $DEBUG );
 use Tie::IxHash;
-use DBI;
+use FS::DBI;
 #use FS::Record qw( qsearch ); #qsearchs );
 #use FS::svc_phone;
 #use FS::Schema qw( dbdef );
@@ -61,7 +61,8 @@ sub _export_insert {
 
 sub nibblebill_insert {
   my($datasrc, $username, $password, $phonenum, $amount) = @_;
-  my $dbh = DBI->connect($datasrc, $username, $password) or die $DBI::errstr; 
+  my $dbh = FS::DBI->connect($datasrc, $username, $password)
+    or die $FS::DBI::errstr; 
 
   #check for existing account
   $dbh->{FetchHashKeyName} = 'NAME_lc';
@@ -119,7 +120,8 @@ sub _adjust {
 
 sub nibblebill_adjust_cash {
   my($datasrc, $username, $password, $phonenum, $amount) = @_;
-  my $dbh = DBI->connect($datasrc, $username, $password) or die $DBI::errstr; 
+  my $dbh = FS::DBI->connect($datasrc, $username, $password)
+    or die $FS::DBI::errstr; 
 
   my $sth = $dbh->prepare('UPDATE accounts SET cash = cash + ? WHERE id = ?')
     or die $dbh->errsrr;
@@ -129,8 +131,8 @@ sub nibblebill_adjust_cash {
 sub export_getstatus {                                                          
   my( $self, $svc_phone, $htmlref, $hashref ) = @_;             
 
-  my $dbh = DBI->connect( map $self->option($_), qw( datasrc username password ) )
-    or return $DBI::errstr; 
+  my $dbh = FS::DBI->connect( map $self->option($_), qw( datasrc username password ) )
+    or return $FS::DBI::errstr; 
 
   my $sth = $dbh->prepare('SELECT cash FROM accounts WHERE id = ?')
     or return $dbh->errstr;
diff --git a/FS/FS/part_export/phone_sqlopensips.pm b/FS/FS/part_export/phone_sqlopensips.pm
index 7b07ecf4a..c281787b4 100644
--- a/FS/FS/part_export/phone_sqlopensips.pm
+++ b/FS/FS/part_export/phone_sqlopensips.pm
@@ -8,6 +8,7 @@ use FS::part_export;
 use FS::svc_phone;
 use FS::export_svc;
 use LWP::UserAgent;
+use FS::DBI;
 
 @ISA = qw(FS::part_export);
 
@@ -51,8 +52,8 @@ sub _export_insert {
 
 sub opensips_connect {
     my $self = shift;
-    DBI->connect($self->option('datasrc'),$self->option('username'),
-			$self->option('password')) or die $DBI::errstr;
+    FS::DBI->connect($self->option('datasrc'),$self->option('username'),
+			$self->option('password')) or die $FS::DBI::errstr;
 }
 
 sub _export_replace {
diff --git a/FS/FS/part_export/radiator.pm b/FS/FS/part_export/radiator.pm
index f09d36abb..669e3d41c 100644
--- a/FS/FS/part_export/radiator.pm
+++ b/FS/FS/part_export/radiator.pm
@@ -3,6 +3,7 @@ package FS::part_export::radiator;
 use vars qw(@ISA %info $radusers);
 use Tie::IxHash;
 use FS::part_export::sqlradius;
+use FS::DBI;
 
 tie my %options, 'Tie::IxHash', %FS::part_export::sqlradius::options;
 
@@ -163,7 +164,7 @@ sub radiator_delete { #subroutine, not method
 sub radiator_connect {
   #my($datasrc, $username, $password) = @_;
   #DBI->connect($datasrc, $username, $password) or die $DBI::errstr;
-  DBI->connect(@_) or die $DBI::errstr;
+  FS::DBI->connect(@_) or die $FS::DBI::errstr;
 }
 
 1;
diff --git a/FS/FS/part_export/sql_Common.pm b/FS/FS/part_export/sql_Common.pm
index 6aab7ec38..d91c54751 100644
--- a/FS/FS/part_export/sql_Common.pm
+++ b/FS/FS/part_export/sql_Common.pm
@@ -3,6 +3,7 @@ use base qw( FS::part_export );
 
 use strict;
 use Tie::IxHash;
+use FS::DBI;
 
 tie my %options, 'Tie::IxHash',
   'datasrc'            => { label => 'DBI data source' },
@@ -208,7 +209,7 @@ sub sql_Common_replace { #subroutine, not method
 sub sql_Common_connect {
   #my($datasrc, $username, $password) = @_;
   #DBI->connect($datasrc, $username, $password) or die $DBI::errstr;
-  DBI->connect(@_) or die $DBI::errstr;
+  FS::DBI->connect(@_) or die $FS::DBI::errstr;
 }
 
 1;
diff --git a/FS/FS/part_export/sqlmail.pm b/FS/FS/part_export/sqlmail.pm
index 19505b488..38308b601 100644
--- a/FS/FS/part_export/sqlmail.pm
+++ b/FS/FS/part_export/sqlmail.pm
@@ -6,6 +6,7 @@ use Digest::MD5 qw(md5_hex);
 use FS::Record qw(qsearchs);
 use FS::part_export;
 use FS::svc_domain;
+use FS::DBI;
 
 @ISA = qw(FS::part_export);
 
@@ -174,7 +175,7 @@ sub sqlmail_replace {
 }
 
 sub sqlmail_connect {
-  DBI->connect(@_) or die $DBI::errstr;
+  FS::DBI->connect(@_) or die $FS::DBI::errstr;
 }
 
 sub update_values {
diff --git a/FS/FS/part_export/sqlradius.pm b/FS/FS/part_export/sqlradius.pm
index 99cd61509..dfe4c3d2d 100644
--- a/FS/FS/part_export/sqlradius.pm
+++ b/FS/FS/part_export/sqlradius.pm
@@ -11,6 +11,7 @@ use FS::export_svc;
 use Carp qw( cluck );
 use NEXT;
 use Net::OpenSSH;
+use FS::DBI;
 
 @ISA = qw(FS::part_export);
 @EXPORT_OK = qw( sqlradius_connect );
@@ -624,7 +625,7 @@ sub sqlradius_delete { #subroutine, not method
 sub sqlradius_connect {
   #my($datasrc, $username, $password) = @_;
   #DBI->connect($datasrc, $username, $password) or die $DBI::errstr;
-  DBI->connect(@_) or die $DBI::errstr;
+  FS::DBI->connect(@_) or die $FS::DBI::errstr;
 }
 
 # on success, returns '' in scalar context, ('',$jobnum) in list context
@@ -1320,10 +1321,10 @@ sub _upgrade_exporttype {
 
 sub import_attrs {
   my $self = shift;
-  my $dbh =  DBI->connect( map $self->option($_),
+  my $dbh =  FS::DBI->connect( map $self->option($_),
                                    qw( datasrc username password ) );
   unless ( $dbh ) {
-    warn "Error connecting to RADIUS server: $DBI::errstr\n";
+    warn "Error connecting to RADIUS server: $FS::DBI::errstr\n";
     return;
   }
 
diff --git a/FS/FS/part_pkg/sql_external.pm b/FS/FS/part_pkg/sql_external.pm
index 1ead113d0..1aa3cda5f 100644
--- a/FS/FS/part_pkg/sql_external.pm
+++ b/FS/FS/part_pkg/sql_external.pm
@@ -3,7 +3,7 @@ use base qw( FS::part_pkg::discount_Mixin FS::part_pkg::recur_Common );
 
 use strict;
 use vars qw( %info );
-use DBI;
+use FS::DBI;
 #use FS::Record qw(qsearch qsearchs);
 
 tie our %query_style, 'Tie::IxHash', (
@@ -75,10 +75,10 @@ sub calc_recur {
   my $price = 0;
   my $quantity; # can be overridden; if not we use the default
 
-  my $dbh = DBI->connect( map { $self->option($_) }
+  my $dbh = FS::DBI->connect( map { $self->option($_) }
                               qw( datasrc db_username db_password )
                         )
-    or die $DBI::errstr;
+    or die $FS::DBI::errstr;
 
   my $sth = $dbh->prepare( $self->option('query') )
     or die $dbh->errstr;
diff --git a/FS/FS/part_pkg/sql_generic.pm b/FS/FS/part_pkg/sql_generic.pm
index e323d8b5b..cbc2bef25 100644
--- a/FS/FS/part_pkg/sql_generic.pm
+++ b/FS/FS/part_pkg/sql_generic.pm
@@ -2,7 +2,7 @@ package FS::part_pkg::sql_generic;
 
 use strict;
 use vars qw(@ISA %info);
-use DBI;
+use FS::DBI;
 #use FS::Record qw(qsearch qsearchs);
 use FS::part_pkg::flat;
 
@@ -50,10 +50,10 @@ sub price_info {
 sub calc_recur {
   my($self, $cust_pkg ) = @_;
 
-  my $dbh = DBI->connect( map { $self->option($_) }
+  my $dbh = FS::DBI->connect( map { $self->option($_) }
                               qw( datasrc db_username db_password )
                         )
-    or die $DBI::errstr;
+    or die $FS::DBI::errstr;
 
   my $sth = $dbh->prepare( $self->option('query') )
     or die $dbh->errstr;
diff --git a/FS/bin/freeside-aradial-sftp_and_import b/FS/bin/freeside-aradial-sftp_and_import
index 668ec49ba..e7639633a 100755
--- a/FS/bin/freeside-aradial-sftp_and_import
+++ b/FS/bin/freeside-aradial-sftp_and_import
@@ -8,6 +8,7 @@ use Date::Parse;
 use Date::Format;
 use Text::CSV_XS;
 use DBI qw( :sql_types );
+use FS::DBI;
 use Net::SFTP::Foreign;
 #use FS::UID qw( adminsuidsetup datasrc );
 
@@ -81,8 +82,8 @@ mkdir $cachedir unless -d $cachedir;
 my $servername = shift or die &usage;
 
 my( $datasrc, $db_user, $db_pass ) = ( shift, shift, shift );
-my $dbh = DBI->connect( $datasrc, $db_user, $db_pass)
-  or die "can't connect: $DBI::errstr\n";
+my $dbh = FS::DBI->connect( $datasrc, $db_user, $db_pass)
+  or die "can't connect: $FS::DBI::errstr\n";
 
 my $csv = Text::CSV_XS->new;
 
diff --git a/FS/bin/freeside-cdr-asterisk_sql b/FS/bin/freeside-cdr-asterisk_sql
index 052d785b2..7638c699d 100755
--- a/FS/bin/freeside-cdr-asterisk_sql
+++ b/FS/bin/freeside-cdr-asterisk_sql
@@ -7,7 +7,7 @@ use Date::Format 'time2str';
 use FS::UID qw(adminsuidsetup dbh);
 use FS::Log;
 use FS::cdr;
-use DBI;
+use FS::DBI;
 use Getopt::Std;
 
 $DEBUG = 0;
@@ -26,7 +26,7 @@ adminsuidsetup $user;
 
 my $log = FS::Log->new( 'freeside-cdr-asterisk_sql' );
 
-my $dbi = DBI->connect($dsn, $opt{U}, $opt{P}) ;
+my $dbi = FS::DBI->connect($dsn, $opt{U}, $opt{P}) ;
 
 if ( $dbi ) {
   log_msg( info => "Established connection to CDR database at dsn($dsn)" );
@@ -34,7 +34,7 @@ if ( $dbi ) {
   log_and_die( error =>
     sprintf 'Fatal error connecting to CDR database at dsn(%s): %s',
       $dsn,
-      $DBI::errstr
+      $FS::DBI::errstr
   );
 }
 
diff --git a/FS/bin/freeside-cdr-evariste-import b/FS/bin/freeside-cdr-evariste-import
index d5e13f98c..a875d1365 100755
--- a/FS/bin/freeside-cdr-evariste-import
+++ b/FS/bin/freeside-cdr-evariste-import
@@ -2,7 +2,7 @@
 
 use strict;
 
-use DBI;
+use FS::DBI;
 use Date::Format 'time2str';
 use Date::Parse 'str2time';
 use Getopt::Long;
@@ -65,8 +65,8 @@ if ($enddate) {
 }
 $enddate ||= time2str("%Y-%m-%d %H:%M:%S",$now);
 
-my $cdbh = DBI->connect("dbi:Pg:database=$db;host=$host", $username, $password) 
-  or die $DBI::errstr;
+my $cdbh = FS::DBI->connect("dbi:Pg:database=$db;host=$host", $username, $password) 
+  or die $FS::DBI::errstr;
 
 # selecting by end_time rather than start_time 
 # so we don't lose records between batches
diff --git a/FS/bin/freeside-sqlradius-dedup-group b/FS/bin/freeside-sqlradius-dedup-group
index 441d50f62..c6497a051 100755
--- a/FS/bin/freeside-sqlradius-dedup-group
+++ b/FS/bin/freeside-sqlradius-dedup-group
@@ -3,6 +3,7 @@
 use strict;
 use vars qw( %seen @dups );
 use Getopt::Std;
+use FS::DBI;
 use FS::UID qw(adminsuidsetup);
 use FS::Record qw(qsearch qsearchs);
 use FS::part_export;
@@ -28,7 +29,7 @@ if ( !defined($export_x) ) {
   or die "No sqlradius exports specified.";
 
 foreach my $part_export ( @part_export ) {
-  my $dbh = DBI->connect( map $part_export->option($_),
+  my $dbh = FS::DBI->connect( map $part_export->option($_),
                            qw ( datasrc username password ) );
 
   my $sth = $dbh->prepare("SELECT id,username,groupname
diff --git a/FS/bin/freeside-sqlradius-reset b/FS/bin/freeside-sqlradius-reset
index b04c640d8..225de15be 100755
--- a/FS/bin/freeside-sqlradius-reset
+++ b/FS/bin/freeside-sqlradius-reset
@@ -3,6 +3,7 @@
 use strict;
 use vars qw( $opt_n );
 use Getopt::Std;
+use FS::DBI;
 use FS::UID qw(adminsuidsetup);
 use FS::Record qw(qsearch qsearchs);
 use FS::part_export;
@@ -31,9 +32,9 @@ if ( @ARGV ) {
 
 unless ( $opt_n ) {
   foreach my $export ( @exports ) {
-    my $icradius_dbh = DBI->connect(
+    my $icradius_dbh = FS::DBI->connect(
       map { $export->option($_) } qw( datasrc username password )
-    ) or die $DBI::errstr;
+    ) or die $FS::DBI::errstr;
     my $usergroup = $export->option('usergroup') || 'usergroup';
     my @attr_tables;
     @attr_tables = qw( radgroupcheck radgroupreply )
diff --git a/FS/bin/freeside-sqlradius-set-lastlog b/FS/bin/freeside-sqlradius-set-lastlog
index ad8563076..d5d8a493a 100755
--- a/FS/bin/freeside-sqlradius-set-lastlog
+++ b/FS/bin/freeside-sqlradius-set-lastlog
@@ -2,6 +2,7 @@
 
 use strict;
 use Getopt::Std;
+use FS::DBI;
 use FS::UID qw(adminsuidsetup);
 use FS::Record qw(qsearch qsearchs str2time_sql);
 use FS::Conf;
@@ -34,7 +35,7 @@ if ( !defined($export_x) ) {
 
 
 foreach my $part_export ( @part_export ) {
-  my $dbh = DBI->connect( map $part_export->option($_),
+  my $dbh = FS::DBI->connect( map $part_export->option($_),
                            qw ( datasrc username password ) );
 
   my $str2time = str2time_sql( $dbh->{Driver}->{Name} );
diff --git a/bin/aradial-sftp_and_import b/bin/aradial-sftp_and_import
index 668ec49ba..e7639633a 100755
--- a/bin/aradial-sftp_and_import
+++ b/bin/aradial-sftp_and_import
@@ -8,6 +8,7 @@ use Date::Parse;
 use Date::Format;
 use Text::CSV_XS;
 use DBI qw( :sql_types );
+use FS::DBI;
 use Net::SFTP::Foreign;
 #use FS::UID qw( adminsuidsetup datasrc );
 
@@ -81,8 +82,8 @@ mkdir $cachedir unless -d $cachedir;
 my $servername = shift or die &usage;
 
 my( $datasrc, $db_user, $db_pass ) = ( shift, shift, shift );
-my $dbh = DBI->connect( $datasrc, $db_user, $db_pass)
-  or die "can't connect: $DBI::errstr\n";
+my $dbh = FS::DBI->connect( $datasrc, $db_user, $db_pass)
+  or die "can't connect: $FS::DBI::errstr\n";
 
 my $csv = Text::CSV_XS->new;
 
diff --git a/bin/b-move-customers b/bin/b-move-customers
index 026e4cc35..e98ac62b8 100755
--- a/bin/b-move-customers
+++ b/bin/b-move-customers
@@ -5,7 +5,7 @@
 
 use strict;
 use vars qw( $sdbh );
-use DBI;
+use FS::DBI;
 use FS::UID qw( adminsuidsetup dbh );
 use FS::Schema qw( dbdef );
 use FS::Record qw( qsearchs );
@@ -72,8 +72,8 @@ my $void_paynum = 2147483646; #top of int range
 
 # source(remote) setup
 
-$sdbh = DBI->connect($source_datasrc, $source_user, $source_pw)
-  or die $DBI::errstr;
+$sdbh = FS::DBI->connect($source_datasrc, $source_user, $source_pw)
+  or die $FS::DBI::errstr;
 
 $sdbh->{ChopBlanks} = 1;
 
diff --git a/bin/freeside.import b/bin/freeside.import
index fdfcc083e..8f2b0e8a7 100755
--- a/bin/freeside.import
+++ b/bin/freeside.import
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -w
 
 use strict;
-use DBI;
+use FS::DBI;
 
 my $s_datasrc = 'DBI:mysql:host=ns1.enetonline.net;port=3307;user=ivan;dbname=freeside';
 my $s_dbuser = 'ivan';
@@ -120,8 +120,10 @@ svc_www
 type_pkgs
 );
 
-my $s_dbh = DBI->connect($s_datasrc, $s_dbuser, $s_dbpass) or die $DBI::errstr;
-my $d_dbh = DBI->connect($d_datasrc, $d_dbuser, $d_dbpass) or die $DBI::errstr;
+my $s_dbh = FS::DBI->connect($s_datasrc, $s_dbuser, $s_dbpass)
+  or die $FS::DBI::errstr;
+my $d_dbh = FS::DBI->connect($d_datasrc, $d_dbuser, $d_dbpass)
+  or die $FS::DBI::errstr;
 
 foreach my $table ( @tables ) {
   $d_dbh->do("delete from $table");
diff --git a/bin/import-optigold.pl b/bin/import-optigold.pl
index d32a2a129..a251b2322 100755
--- a/bin/import-optigold.pl
+++ b/bin/import-optigold.pl
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -Tw
 
 use strict;
-use DBI;
+use FS::DBI;
 use HTML::TableParser;
 use Date::Parse;
 use Text::CSV_XS;
@@ -60,7 +60,7 @@ my @args = (
            );
 
 
-$s_dbh = DBI->connect($s_dbname, $s_dbuser, $s_dbpass,
+$s_dbh = FS::DBI->connect($s_dbname, $s_dbuser, $s_dbpass,
                            { 'AutoCommit' => 0,
                              'ChopBlanks' => 1,
                              'ShowErrorStatement' => 1
diff --git a/bin/move-customers b/bin/move-customers
index a7ea19781..f6f556131 100755
--- a/bin/move-customers
+++ b/bin/move-customers
@@ -7,7 +7,7 @@
 
 use strict;
 use vars qw( $sdbh );
-use DBI;
+use FS::DBI;
 use FS::UID qw( adminsuidsetup dbh );
 use FS::Schema qw( dbdef );
 use FS::Record qw( qsearchs );
@@ -95,8 +95,8 @@ my $void_paynum = 2147483646; #top of int range
 
 # source(remote) setup
 
-$sdbh = DBI->connect($source_datasrc, $source_user, $source_pw)
-  or die $DBI::errstr;
+$sdbh = FS::DBI->connect($source_datasrc, $source_user, $source_pw)
+  or die $FS::DBI::errstr;
 
 $sdbh->{ChopBlanks} = 1;
 
diff --git a/bin/move-unlinked b/bin/move-unlinked
index 0d31a49f3..0661266df 100755
--- a/bin/move-unlinked
+++ b/bin/move-unlinked
@@ -5,7 +5,7 @@
 
 use strict;
 use vars qw( $sdbh );
-use DBI;
+use FS::DBI;
 use FS::UID qw( adminsuidsetup dbh );
 use FS::Schema qw( dbdef );
 use DBI;
@@ -62,8 +62,8 @@ $FS::svc_Common::noexport_hack = 1;
 
 # source(remote) setup
 
-$sdbh = DBI->connect($source_datasrc, $source_user, $source_pw)
-  or die $DBI::errstr;
+$sdbh = FS::DBI->connect($source_datasrc, $source_user, $source_pw)
+  or die $FS::DBI::errstr;
 
 $sdbh->{ChopBlanks} = 1;
 
diff --git a/bin/postfix_courierimap.import b/bin/postfix_courierimap.import
index 12c138b49..385249ba5 100755
--- a/bin/postfix_courierimap.import
+++ b/bin/postfix_courierimap.import
@@ -3,7 +3,7 @@
 use strict;
 use vars qw(%part_svc %domain_part_svc);
 #use Date::Parse;
-use DBI;
+use FS::DBI;
 use Term::Query qw(query);
 use FS::UID qw(adminsuidsetup); #datasrc
 use FS::Record qw(qsearch qsearchs);
@@ -74,8 +74,8 @@ print "\n\n";
 
 ###
 
-my $dbh = DBI->connect( $datasrc, $db_user, $db_pass )
-  or die $DBI::errstr;
+my $dbh = FS::DBI->connect( $datasrc, $db_user, $db_pass )
+  or die $FS::DBI::errstr;
 
 my $sth = $dbh->prepare('SELECT username, password, crypt, name, domain FROM mailbox')
   or die $dbh->errstr;
diff --git a/bin/sqlradius-nas.import b/bin/sqlradius-nas.import
index 0583272db..1a34c8a2b 100755
--- a/bin/sqlradius-nas.import
+++ b/bin/sqlradius-nas.import
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -w
 
 use strict;
-use DBI;
+use FS::DBI;
 use FS::UID qw(adminsuidsetup); #datasrc
 use FS::Record qw(qsearch qsearchs dbh);
 use FS::nas;
@@ -22,7 +22,7 @@ my $part_export = qsearchs('part_export', { exportnum => $exportnum })
 $part_export->isa('FS::part_export::sqlradius')
   or die "export $exportnum is not an sqlradius export.\n";
 
-my $raddbh = DBI->connect(
+my $raddbh = FS::DBI->connect(
   $part_export->option('datasrc'),
   $part_export->option('username'),
   $part_export->option('password')
diff --git a/bin/sqlradius-norealm.reimport b/bin/sqlradius-norealm.reimport
index b7d016609..7ac7465f8 100755
--- a/bin/sqlradius-norealm.reimport
+++ b/bin/sqlradius-norealm.reimport
@@ -3,7 +3,7 @@
 use strict;
 use vars qw(%part_svc);
 #use Date::Parse;
-use DBI;
+use FS::DBI;
 use Term::Query qw(query);
 use FS::UID qw(adminsuidsetup); #datasrc
 use FS::Record qw(qsearch qsearchs);
@@ -53,8 +53,8 @@ print "\n\n";
 
 ###
 
-my $dbh = DBI->connect( $datasrc, $db_user, $db_pass )
-  or die $DBI::errstr;
+my $dbh = FS::DBI->connect( $datasrc, $db_user, $db_pass )
+  or die $FS::DBI::errstr;
 
 my $sth = $dbh->prepare('SELECT DISTINCT UserName FROM radcheck')
   or die $dbh->errstr;
diff --git a/bin/sqlradius.import b/bin/sqlradius.import
index e75f65b17..69361e864 100755
--- a/bin/sqlradius.import
+++ b/bin/sqlradius.import
@@ -3,7 +3,7 @@
 use strict;
 use vars qw(%part_svc %domain_part_svc);
 #use Date::Parse;
-use DBI;
+use FS::DBI;
 use Term::Query qw(query);
 use FS::UID qw(adminsuidsetup); #datasrc
 use FS::Record qw(qsearch qsearchs);
@@ -74,8 +74,8 @@ print "\n\n";
 
 ###
 
-my $dbh = DBI->connect( $datasrc, $db_user, $db_pass )
-  or die $DBI::errstr;
+my $dbh = FS::DBI->connect( $datasrc, $db_user, $db_pass )
+  or die $FS::DBI::errstr;
 
 my $sth = $dbh->prepare('SELECT DISTINCT UserName, Realm FROM radcheck')
   or die $dbh->errstr;
diff --git a/bin/sqlradius.reimport b/bin/sqlradius.reimport
index 2218a3f13..2ae78df82 100755
--- a/bin/sqlradius.reimport
+++ b/bin/sqlradius.reimport
@@ -3,7 +3,7 @@
 use strict;
 use vars qw(%part_svc %domain_part_svc);
 #use Date::Parse;
-use DBI;
+use FS::DBI;
 use Term::Query qw(query);
 use FS::UID qw(adminsuidsetup); #datasrc
 use FS::Record qw(qsearch qsearchs);
@@ -74,8 +74,8 @@ print "\n\n";
 
 ###
 
-my $dbh = DBI->connect( $datasrc, $db_user, $db_pass )
-  or die $DBI::errstr;
+my $dbh = FS::DBI->connect( $datasrc, $db_user, $db_pass )
+  or die $FS::DBI::errstr;
 
 my $sth = $dbh->prepare('SELECT DISTINCT UserName, Realm FROM radcheck')
   or die $dbh->errstr;
diff --git a/torrus/perllib/Torrus/SQL.pm b/torrus/perllib/Torrus/SQL.pm
index de54cacee..bfd9351fb 100644
--- a/torrus/perllib/Torrus/SQL.pm
+++ b/torrus/perllib/Torrus/SQL.pm
@@ -124,16 +124,20 @@ sub dbh
 
     if( not defined( $dbh ) )
     {
-        $dbh = DBI->connect( $attrs->{'dsn'},
-                             $attrs->{'username'},
-                             $attrs->{'password'},
-                             { 'PrintError' => 0,
-                               'AutoCommit' => 0 } );
+        $dbh = FS::DBI->connect(
+            $attrs->{'dsn'},
+            $attrs->{'username'},
+            $attrs->{'password'},
+            {
+                'PrintError' => 0,
+                'AutoCommit' => 0,
+            }
+        );
 
         if( not defined( $dbh ) )
         {
             Error('Error connecting to DBI source ' . $attrs->{'dsn'} . ': ' .
-                  $DBI::errstr);
+                  $FS::DBI::errstr);
         }
         else
         {

commit 83eb68cd59af488d57c23b653f44a7ae9aa4a753
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Sun Mar 3 16:35:25 2019 -0500

    RT# 82942 Add FS::DBI, to fix database connection encoding bug
    
    - Add FS::DBI
      - Drop-in replacement for DBI
      - Ensures client_encoding is set to UTF8 for DBD::Pg
    - Implement FS::DBI in FS::UID, where nearly all freeside
      database connections are established

diff --git a/FS/FS/DBI.pm b/FS/FS/DBI.pm
new file mode 100644
index 000000000..c6ff12561
--- /dev/null
+++ b/FS/FS/DBI.pm
@@ -0,0 +1,72 @@
+package FS::DBI;
+use strict;
+use warnings;
+use base qw( DBI );
+
+=head1 NAME
+
+FS::DBI - Freeside wrapper for DBI
+
+=head1 SYNOPSIS
+
+  use FS::DBI;
+  
+  $dbh = FS::DBI->connect( @args );
+  $dbh->do(
+    'UPDATE table SET foo = ? WHERE bar = ?',
+    undef,
+    $foo, $bar
+  ) or die $dbh->errstr;
+
+See L<DBI>
+
+=head1 DESCRIPTION
+
+Allow Freeside to manage how DBI is used when necessary
+
+=head2 Legacy databases and DBD::Pg v3.0+
+
+Breaking behavior was introduced in DBD::Pg version 3.0.0
+in regards to L<DBD::Pg/pg_enable_utf8>.
+
+Some freedside databases are legacy databases with older encodings
+and locales. pg_enable_utf8 no longer sets client_encoding to utf8
+on non-utf8 databases, causing crashes and data corruption.
+
+FS::DBI->connect() enforces utf8 client_encoding on all DBD::Pg connections
+
+=head1 METHODS
+
+=head2 connect @connect_args
+
+For usage, see L<DBI/connect>
+
+Force utf8 client_encoding on DBD::Pg connections
+
+=cut
+
+sub connect {
+  my $class = shift;
+  my $dbh = $class->SUPER::connect( @_ );
+
+  if ( $_[0] =~ /^DBI::Pg/ ) {
+    $dbh->do('SET client_encoding TO UTF8;')
+      or die sprintf 'Error setting client_encoding to UTF8: %s', $dbh->errstr;
+
+    # DBD::Pg requires touching this attribute when changing the client_encoding
+    # on an already established connection, to get expected behavior.
+    $dbh->{pg_enable_utf8} = -1;
+  }
+
+  $dbh;
+}
+
+# Stub required to subclass DBI
+package FS::DBI::st;
+use base qw( DBI::st );
+
+# Stub required to subclass DBI
+package FS::DBI::db;
+use base qw( DBI::db );
+
+1;
diff --git a/FS/FS/UID.pm b/FS/FS/UID.pm
index 95924477c..eeaeff228 100644
--- a/FS/FS/UID.pm
+++ b/FS/FS/UID.pm
@@ -11,7 +11,7 @@ use subs qw(
 );
 use Exporter;
 use Carp qw(carp croak cluck confess);
-use DBI;
+use FS::DBI;
 use IO::File;
 use FS::CurrentUser;
 
@@ -230,14 +230,16 @@ sub callback_setup {
 
 
 sub myconnect {
-  my $handle = DBI->connect( getsecrets(@_), { 'AutoCommit'         => 0,
-                                               'ChopBlanks'         => 1,
-                                               'ShowErrorStatement' => 1,
-                                               'pg_enable_utf8'     => 1,
-                                               #'mysql_enable_utf8'  => 1,
-                                             }
-                           )
-    or die "DBI->connect error: $DBI::errstr\n";
+  my $handle = FS::DBI->connect(
+    getsecrets( @_ ),
+    {
+      'AutoCommit'         => 0,
+      'ChopBlanks'         => 1,
+      'ShowErrorStatement' => 1,
+      'pg_enable_utf8'     => 1,
+      # 'mysql_enable_utf8'  => 1,
+    }
+  ) or die "FS::DBI->connect error: $FS::DBI::errstr\n";
 
   if ( $schema ) {
     use DBIx::DBSchema::_util qw(_load_driver ); #quelle hack

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/DBI.pm                               | 72 ++++++++++++++++++++++++++++++
 FS/FS/TicketSystem/RT_External.pm          |  5 ++-
 FS/FS/UID.pm                               | 20 +++++----
 FS/FS/Upgrade.pm                           |  5 ++-
 FS/FS/cdr/Import.pm                        |  6 +--
 FS/FS/cust_main.pm                         |  5 ++-
 FS/FS/cust_svc.pm                          | 13 +++---
 FS/FS/part_export/a2billing.pm             |  5 ++-
 FS/FS/part_export/acct_sql_status.pm       |  5 ++-
 FS/FS/part_export/freeswitch_nibblebill.pm | 12 ++---
 FS/FS/part_export/phone_sqlopensips.pm     |  5 ++-
 FS/FS/part_export/radiator.pm              |  3 +-
 FS/FS/part_export/sql_Common.pm            |  3 +-
 FS/FS/part_export/sqlmail.pm               |  3 +-
 FS/FS/part_export/sqlradius.pm             |  7 +--
 FS/FS/part_pkg/sql_external.pm             |  6 +--
 FS/FS/part_pkg/sql_generic.pm              |  6 +--
 FS/bin/freeside-aradial-sftp_and_import    |  5 ++-
 FS/bin/freeside-cdr-asterisk_sql           |  6 +--
 FS/bin/freeside-cdr-evariste-import        |  6 +--
 FS/bin/freeside-sqlradius-dedup-group      |  3 +-
 FS/bin/freeside-sqlradius-reset            |  5 ++-
 FS/bin/freeside-sqlradius-set-lastlog      |  3 +-
 bin/aradial-sftp_and_import                |  5 ++-
 bin/b-move-customers                       |  6 +--
 bin/freeside.import                        |  8 ++--
 bin/import-optigold.pl                     |  4 +-
 bin/move-customers                         |  6 +--
 bin/move-unlinked                          |  6 +--
 bin/postfix_courierimap.import             |  6 +--
 bin/sqlradius-nas.import                   |  4 +-
 bin/sqlradius-norealm.reimport             |  6 +--
 bin/sqlradius.import                       |  6 +--
 bin/sqlradius.reimport                     |  6 +--
 rt/lib/RT/Handle.pm                        |  5 +++
 torrus/perllib/Torrus/SQL.pm               | 16 ++++---
 36 files changed, 198 insertions(+), 95 deletions(-)
 create mode 100644 FS/FS/DBI.pm




More information about the freeside-commits mailing list