summaryrefslogtreecommitdiff
path: root/FS
diff options
context:
space:
mode:
authorMitch Jackson <mitch@freeside.biz>2019-03-03 16:35:25 -0500
committerMitch Jackson <mitch@freeside.biz>2019-03-03 19:53:31 -0500
commit50a717fa7328dfb36d8d3d6c30d616399cda771f (patch)
tree15cdccb2fbb44b294676626b8d8c7332246cb89a /FS
parentc06c0fb20f33de42af60208e43e41d84f3df66ea (diff)
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
Diffstat (limited to 'FS')
-rw-r--r--FS/FS/DBI.pm72
-rw-r--r--FS/FS/UID.pm20
2 files changed, 83 insertions, 9 deletions
diff --git a/FS/FS/DBI.pm b/FS/FS/DBI.pm
new file mode 100644
index 0000000..c6ff125
--- /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 d3ee8d8..3863256 100644
--- a/FS/FS/UID.pm
+++ b/FS/FS/UID.pm
@@ -9,7 +9,7 @@ use vars qw(
);
use subs qw( getsecrets );
use Carp qw( carp croak cluck confess );
-use DBI;
+use FS::DBI;
use IO::File;
use FS::CurrentUser;
@@ -172,14 +172,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";
$FS::Conf::conf_cache = undef;