Re: [rt.cpan.org #118823] libdbd-mysql-perl: FTBFS on some architectures
On Fri, Nov 18, 2016 at 01:45:59AM +0100, gregor herrmann wrote:
> But as https://buildd.debian.org/status/package.php?p=libdbd-mysql-perl
> shows this is not only about mips but about various architectures,
> and the quick summary on IRC was "looks like a big-endian issue".
FWIW it goes away if I revert 97c8c22998e67e7c6cfe5635578e0464e9ac9513
("Add support for 64bit types when perl is compiled with 64bit support").
We're configuring Perl with -Duse64bitint on both 32-bit and 64-bit
platforms.
I think the 64-bit integer support is not quite working yet; even on
little-endian (regular x86_64), if I test for them:
--- a/t/40server_prepare.t
+++ b/t/40server_prepare.t
@@ -59,11 +59,11 @@ ok($sth2 = $dbh->prepare('INSERT INTO dbd_mysql_t40serverprepare2 VALUES (?,?,?,
ok($sth2->bind_param(1, 101, DBI::SQL_INTEGER), "binding int");
ok($sth2->bind_param(2, 102, DBI::SQL_SMALLINT), "binding smallint");
ok($sth2->bind_param(3, 103, DBI::SQL_TINYINT), "binding tinyint");
-ok($sth2->bind_param(4, 104, DBI::SQL_INTEGER), "binding bigint");
+ok($sth2->bind_param(4, (2<<32)+4, DBI::SQL_INTEGER), "binding bigint");
ok($sth2->execute(), "inserting data");
-is_deeply($dbh->selectall_arrayref('SELECT * FROM dbd_mysql_t40serverprepare2'), [[101, 102, 103, 104]]);
+is_deeply($dbh->selectall_arrayref('SELECT * FROM dbd_mysql_t40serverprepare2'), [[101, 102, 103, (2<<32)+4]]);
ok ($dbh->do(qq{DROP TABLE dbd_mysql_t40serverprepare2}), "cleaning up");
I get
not ok 20
# Failed test at t/40server_prepare.t line 66.
# Structures begin differing at:
# $got->[0][3] = '4'
# $expected->[0][3] = '8589934596'
It looks like it's coercing 64-bit integers into 32-bit ones, which mostly
works for small integers on little endian, but zeros out the result on
big endian.
I gather MYSQL_TYPE_LONG is an int (32-bit) despite the name and it
seems to be the default everywhere in dbdimp.c. Blindly sprinkling
MYSQL_TYPE_LONGLONG in the code fixes it; see the attached patch. I've
tested it on amd64 (64-bit LE), s390x (64-bit BE), armhf (32-bit LE)
and powerpc (32-bit BE).
But maybe MYSQL_TYPE_LONGLONG should be limited to just SQL_BIGINTs?
Hope this helps a bit anyway.
--
Niko Tyni ntyni@debian.org
>From 5b2c77e9e0836963d505138b7c99a959adf32538 Mon Sep 17 00:00:00 2001
From: Niko Tyni <ntyni@debian.org>
Date: Fri, 18 Nov 2016 10:53:29 +0200
Subject: [PATCH] Use MYSQL_TYPE_LONGLONG (64-bit) by default
This is possibly overkill, but it fixes test failures on
big endian platforms with 64-bit integers.
Bug-Debian: https://bugs.debian.org/844538
Bug: https://rt.cpan.org/Ticket/Display.html?id=118823
---
dbdimp.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/dbdimp.c b/dbdimp.c
index c1ef3ff..c5b4f22 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -361,7 +361,7 @@ static enum enum_field_types mysql_to_perl_type(enum enum_field_types type)
#if IVSIZE >= 8
case MYSQL_TYPE_LONGLONG:
#endif
- enum_type= MYSQL_TYPE_LONG;
+ enum_type= MYSQL_TYPE_LONGLONG;
break;
#if MYSQL_VERSION_ID > NEW_DATATYPE_VERSION
@@ -3508,7 +3508,7 @@ my_ulonglong mysql_st_internal_execute41(
{
for (i = mysql_stmt_field_count(stmt) - 1; i >=0; --i) {
enum_type = mysql_to_perl_type(stmt->fields[i].type);
- if (enum_type != MYSQL_TYPE_DOUBLE && enum_type != MYSQL_TYPE_LONG && enum_type != MYSQL_TYPE_BIT)
+ if (enum_type != MYSQL_TYPE_DOUBLE && enum_type != MYSQL_TYPE_LONG && enum_type != MYSQL_TYPE_LONGLONG && enum_type != MYSQL_TYPE_BIT)
{
/* mysql_stmt_store_result to update MYSQL_FIELD->max_length */
my_bool on = 1;
@@ -3776,6 +3776,7 @@ int dbd_describe(SV* sth, imp_sth_t* imp_sth)
break;
case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
buffer->buffer_length= sizeof(fbh->ldata);
buffer->buffer= (char*) &fbh->ldata;
buffer->is_unsigned= (fields[i].flags & UNSIGNED_FLAG) ? 1 : 0;
@@ -4016,6 +4017,7 @@ process:
break;
case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
if (DBIc_TRACE_LEVEL(imp_xxh) >= 2)
PerlIO_printf(DBIc_LOGPIO(imp_xxh), "\t\tst_fetch int data %"IVdf", unsigned? %d\n",
fbh->ldata, buffer->is_unsigned);
@@ -4178,6 +4180,7 @@ process:
break;
case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
/* Coerce to integer and set scalar as UV resp. IV */
if (fields[i].flags & UNSIGNED_FLAG)
{
@@ -4884,7 +4887,7 @@ int dbd_bind_ph(SV *sth, imp_sth_t *imp_sth, SV *param, SV *value,
case SQL_SMALLINT:
case SQL_BIGINT:
case SQL_TINYINT:
- buffer_type= MYSQL_TYPE_LONG;
+ buffer_type= MYSQL_TYPE_LONGLONG;
break;
case SQL_DOUBLE:
case SQL_DECIMAL:
@@ -4910,6 +4913,7 @@ int dbd_bind_ph(SV *sth, imp_sth_t *imp_sth, SV *param, SV *value,
if (! buffer_is_null) {
switch(buffer_type) {
case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
/* INT */
if (!SvIOK(imp_sth->params[idx].value) && DBIc_TRACE_LEVEL(imp_xxh) >= 2)
PerlIO_printf(DBIc_LOGPIO(imp_xxh), "\t\tTRY TO BIND AN INT NUMBER\n");
--
2.10.2
Reply to: