Committed by =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <[email protected]>

Fix client_encoding detection on pre-9.1 servers

Before 9.1 the client_encoding provided in the connection parameter was
not normalised, so we need to do that ourselves.

This fixes the tests on SQL_ASCII databases, as well, so we can revert
the commits that disabled them (1f3ed13 and 53df98c).
---
 dbdimp.c           | 28 ++++++++++++++++++++++------
 t/12placeholders.t |  4 ++--
 t/30unicode.t      |  1 -
 3 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/dbdimp.c b/dbdimp.c
index 6a64487..2dee5d4 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -84,6 +84,7 @@ static int pg_st_deallocate_statement(pTHX_ SV *sth, 
imp_sth_t *imp_sth);
 static PGTransactionStatusType pg_db_txn_status (pTHX_ imp_dbh_t *imp_dbh);
 static int pg_db_start_txn (pTHX_ SV *dbh, imp_dbh_t *imp_dbh);
 static int handle_old_async(pTHX_ SV * handle, imp_dbh_t * imp_dbh, const int 
asyncflag);
+static void pg_db_detect_client_encoding_utf8(pTHX_ imp_dbh_t *imp_dbh);
 
 /* ================================================================== */
 void dbd_init (dbistate_t *dbistate)
@@ -224,9 +225,7 @@ int dbd_db_login6 (SV * dbh, imp_dbh_t * imp_dbh, char * 
dbname, char * uid, cha
                }
        }
 
-       imp_dbh->client_encoding_utf8 =
-               (0 == strncmp(PQparameterStatus(imp_dbh->conn, 
"client_encoding"), "UTF8", 4))
-               ? DBDPG_TRUE : DBDPG_FALSE;
+       pg_db_detect_client_encoding_utf8(aTHX_ imp_dbh);
 
        /* If the client_encoding is UTF8, flip the utf8 flag until convinced 
otherwise */
        imp_dbh->pg_utf8_flag = imp_dbh->client_encoding_utf8;
@@ -928,9 +927,7 @@ int dbd_db_STORE_attrib (SV * dbh, imp_dbh_t * imp_dbh, SV 
* keysv, SV * valuesv
                        }
                        /* Do The Right Thing */
                        else if (-1 == imp_dbh->pg_enable_utf8) {
-                               imp_dbh->client_encoding_utf8 =
-                                       (0 == 
strncmp(PQparameterStatus(imp_dbh->conn, "client_encoding"), "UTF8", 4))
-                                       ? DBDPG_TRUE : DBDPG_FALSE;
+                               pg_db_detect_client_encoding_utf8(aTHX_ 
imp_dbh);
                                imp_dbh->pg_enable_utf8 = -1;
                                imp_dbh->pg_utf8_flag = 
imp_dbh->client_encoding_utf8;
                        }
@@ -2952,6 +2949,25 @@ SV * pg_rightgraded_sv(pTHX_ SV *input, bool utf8) {
        return utf8 ? pg_upgraded_sv(aTHX_ input) : pg_downgraded_sv(aTHX_ 
input);
 }
 
+static void pg_db_detect_client_encoding_utf8(pTHX_ imp_dbh_t *imp_dbh) {
+       char *clean_encoding;
+       int i, j;
+       const char * const client_encoding =
+               PQparameterStatus(imp_dbh->conn, "client_encoding");
+       STRLEN len = strlen(client_encoding);
+       Newx(clean_encoding, len + 1, char);
+       for (i = 0, j = 0; i < len; i++) {
+               const char c = toLOWER(client_encoding[i]);
+               if (isALPHANUMERIC_A(c))
+                       clean_encoding[j++] = c;
+       };
+       clean_encoding[j] = '\0';
+       imp_dbh->client_encoding_utf8 =
+               (strnEQ(clean_encoding, "utf8", 4) || strnEQ(clean_encoding, 
"unicode", 8))
+               ? DBDPG_TRUE : DBDPG_FALSE;
+       Safefree(clean_encoding);
+}
+
 /* ================================================================== */
 int pg_quickexec (SV * dbh, const char * sql, const int asyncflag)
 {
diff --git a/t/12placeholders.t b/t/12placeholders.t
index a470c76..548cd19 100644
--- a/t/12placeholders.t
+++ b/t/12placeholders.t
@@ -657,8 +657,8 @@ for my $char (qw{0 9 A Z a z}) { ## six letters
 
 SKIP: {
        my $server_encoding = $dbh->selectrow_array('SHOW server_encoding');
-       skip "Cannot test non-ascii dollar quotes with 
server_encoding='$server_encoding' (need UTF8)", 3,
-               unless $server_encoding =~ /UTF8/;
+       skip "Cannot test non-ascii dollar quotes with 
server_encoding='$server_encoding' (need UTF8 or SQL_ASCII)", 3,
+               unless $server_encoding =~ /\A(?:UTF8|SQL_ASCII)\z/;
 
        for my $ident (qq{\x{5317}}, qq{abc\x{5317}}, qq{_cde\x{5317}}) { ## 
hi-bit chars
                eval {
diff --git a/t/30unicode.t b/t/30unicode.t
index 2d23c47..aa993b6 100644
--- a/t/30unicode.t
+++ b/t/30unicode.t
@@ -58,7 +58,6 @@ foreach (
 my %ranges = (
     UTF8 => qr/.*/,
     LATIN1 => qr/\A(?:ascii|latin 1 range)\z/,
-    SQL_ASCII => qr/nada/,
 );
 
 foreach (@tests) {
-- 
1.8.4

Reply via email to