DBD::Informix test failure for lvarchar - bug found!

DBD::Informix test failure for lvarchar - bug found!

am 13.06.2007 08:01:46 von jonathan.leffler

------=_Part_4736_26645297.1181714506993
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Finally, after about 30 hours of hair tearing and hard work, I've isolated a
pure ESQL/C version of this bug and demonstrated that it primarily afflicts
32-bit ports of Informix ESQL/C that come with CSDK 2.90 and 2.81 . It does
not afflict most 64-bit ports (though 2.81.FC2 crashed with a core dump, as
did 2.80.UC2), and it does not affect older ports (2.80.UC1 was OK). It did
not reproduce on RHEL 4 running on Linux PPC-64 with CSDK
3.00.FC1(actually, a nightly build prior to that release). Finally,
it only affects
LVARCHAR NOT NULL, and only if the table is not a temporary table. Since I
kept the server constant (IDS 10.00.UC5 running on Solaris 10), the problem
is most likely in ESQL/C rather than IDS itself; if it is perchance in IDS,
it is in the code that recognizes different versions of ESQL/C and somehow
reacts differently.

This bug is now idsdb00139040 in the IBM/Informix CQ database.

Sadly, as yet, I do not have a workaround or fix for this -- that comes
next.

The reproduction code follows:

/*
** @(#)$Id: bug-lvcnn.ec,v 1.3 2007/06/13 05:35:27 jleffler Exp $
**
** Demonstration of bug originally reported in DBD::Informix
** as RT#13708 at http://rt.cpan.org/ and ignored for a couple of years.
** Primarily seems to afflict 32-bit ports of CSDK (ESQL/C).
** And primarily the more recent versions - 2.90 and maybe 2.81.
**
** Bug: SQL DESCRIPTOR does not handle LVARCHAR NOT NULL properly.
**
** Demonstrated on Solaris 10 with CSDK 2.90.UC4.
** No bug with 64-bit on Solaris 10 with CSDK 2.90.FC4.
** No bug with 64-bit on Linux PPC 64 with CSDK 3.00.FN125 (nightly build).
** No bug with 32-bit on Solaris 10 with CSDK 2.80.UC1
** Core dump on 64-bit on Solaris 10 with CSDK 2.81.FC2
** Core dump on 32-bit on Solaris 10 with CSDK 2.81.UC2
** In each of the above cases, the test DBMS is IDS 10.00.UC5 running on
Solaris 10.
** Also seen by customers on various platforms - primarily 32-bit.
*/

#include
#include
#include

$ static char lvc1[] = "This is row 1";
$ static char lvc2[] = "And this is in row 1 too";

static int num_bugs = 0;

static void print_descriptor(const char *p_name, int p_index)
{
$ int index = p_index;
$ const char *name = p_name;
$ long coltype;
$ long collength;
$ long colind;
$ char colname[129];
$ int nullable;

$ whenever error stop;

$ get descriptor :name VALUE :index
:coltype = TYPE, :collength = LENGTH,
:nullable = NULLABLE,
:colind = INDICATOR, :colname = NAME;
colname[byleng(colname, strlen(colname))] = '\0';
printf("%s:%02d: type = %2d, length = %4d, nulls = %2d, indicator = %2d,
name = %s\n",
name, index, coltype, collength, nullable, colind, colname);
}

static void check_data(void)
{
$ lvarchar *lv1 = 0;
$ lvarchar *lv2 = 0;
$ int row;
$ short ind;

$ prepare p from "select row_number, lvc_with_null, lvc_wout_null from
lvarchar_test order by ro
w_number";
$ declare c cursor for p;

$ allocate descriptor "d" with max 3;
$ describe p using sql descriptor "d";

/* Print allocator description */
print_descriptor("d", 1);
print_descriptor("d", 2);
print_descriptor("d", 3);

ifx_var_flag(&lv1, 1);
ifx_var_flag(&lv2, 1);

$ open c;

while (sqlca.sqlcode == 0)
{
$ fetch c using sql descriptor "d";
if (sqlca.sqlcode != 0)
break;
$ get descriptor "d" VALUE 1 :row = DATA, :ind = INDICATOR;
if (ind == 0)
printf("row_number = %d:\n", row);
else
printf("row_number IS NULL (ind = %d)\n", ind);

$ get descriptor "d" VALUE 2 :lv1 = DATA, :ind = INDICATOR;
if (ind != 0)
printf(" lvc_with_null IS NULL (ind = %d)\n", ind);
else
{
char *result = (char *)ifx_var_getdata(&lv1);
int length = ifx_var_getlen(&lv1);
if (length < 0)
{
printf("Length of lvarchar < 0\n");
length = 0;
}
if (result == 0)
{
printf("Result of lvarchar == 0x00000000\n");
}
printf(" lvc_with_null = <<%.*s>>\n", length, result);
if (strcmp(result, lvc1) != 0)
{
printf("**BUG** wanted = <<%s>>\n", lvc1);
num_bugs++;
}
}

$ get descriptor "d" VALUE 3 :lv2 = DATA, :ind = INDICATOR;
if (ind != 0)
printf(" lvc_wout_null IS NULL (ind = %d)\n", ind);
else
{
char *result = (char *)ifx_var_getdata(&lv2);
int length = ifx_var_getlen(&lv2);
if (length < 0)
{
printf("Length of lvarchar < 0\n");
length = 0;
}
if (result == 0)
{
printf("Result of lvarchar == 0x00000000\n");
}
printf(" lvc_wout_null = <<%.*s>>\n", length, result);
if (strcmp(result, lvc2) != 0)
{
printf("**BUG** wanted = <<%s>>\n", lvc2);
num_bugs++;
}
}
}

ifx_var_freevar(&lv1);
ifx_var_freevar(&lv2);

$ close c;
$ free c;
$ free p;
$ deallocate descriptor "d";
}

int main(int argc, char **argv)
{
$ char *dbname = "stores";

if (argc > 1)
dbname = argv[1];
$ database :dbname;

$ whenever error continue;
$ drop table lvarchar_test;
$ whenever error stop;

printf("\nTest 1: LVARCHAR(128) - with NOT NULL\n");
$ create table lvarchar_test
(
row_number serial not null primary key,
lvc_with_null lvarchar(128),
lvc_wout_null lvarchar(128) not null
);
$ insert into lvarchar_test values(1, :lvc1, :lvc2);
check_data();

printf("\nTest 2: LVARCHAR - with NOT NULL\n");
$ drop table lvarchar_test;
$ create table lvarchar_test
(
row_number serial not null primary key,
lvc_with_null lvarchar,
lvc_wout_null lvarchar not null
);
$ insert into lvarchar_test values(1, :lvc1, :lvc2);
check_data();

printf("\nTest 3: LVARCHAR(128) - without NOT NULL\n");
$ drop table lvarchar_test;
$ create table lvarchar_test
(
row_number serial not null primary key,
lvc_with_null lvarchar(128),
lvc_wout_null lvarchar(128)
);
$ insert into lvarchar_test values(1, :lvc1, :lvc2);
check_data();

printf("\nTest 4: LVARCHAR - without NOT NULL\n");
$ drop table lvarchar_test;
$ create table lvarchar_test
(
row_number serial not null primary key,
lvc_with_null lvarchar,
lvc_wout_null lvarchar
);
$ insert into lvarchar_test values(1, :lvc1, :lvc2);
check_data();

printf("\nTest 5: LVARCHAR(128) - with NOT NULL in TEMP TABLE\n");
$ drop table lvarchar_test;
$ create temp table lvarchar_test
(
row_number serial not null primary key,
lvc_with_null lvarchar(128),
lvc_wout_null lvarchar(128) not null
);
$ insert into lvarchar_test values(1, :lvc1, :lvc2);
check_data();

$ close database;
if (num_bugs == 0)
printf("== PASSED ==\n");
else
printf("** FAILED ** %d bugs detected\n", num_bugs);
return(num_bugs > 0); /* 0 on no bugs; 1 otherwise */
}

To say that the circumstances under which it fails are obscure is to be
excessively polite.

I tried to release an update to DBD::Informix, but the release process goes
through the test suite, and since the test t/t93lvarchar.t was failing, it
was not possible to make the release automatically, so I haven't made the
update. I may decide to cheat and make the release using a 64-bit Perl and
64-bit ESQL/C, like I did with the DBD::Informix 2007.0226 (though that was
released completely unaware of the issue - this one would be released
despite knowing the test fails). The temptation to modify the test (eg to
use a temp table instead of a permanent one) is also quite considerable.

--
Jonathan Leffler #include
Guardian of DBD::Informix - v2007.0226 - http://dbi.perl.org
"Blessed are we who can laugh at ourselves, for we shall never cease to be
amused."

------=_Part_4736_26645297.1181714506993--

Re: DBD::Informix test failure for lvarchar - bug found!

am 15.06.2007 01:29:30 von mabajian

Dear Mr. Leffler,

When I saw this Tuesday night, I thought... wow. Thanks so much for
pursuing this bug report. I will feel more confident in using
DBD::Informix, now that you have verified that this bug will not bite
us in our present configuration (no lvarchar not null columns).

I'm sure I speak for all DBD::Informix users: Thank you.
--
Mark Abajian


On Jun 12, 2007, at 11:01 PM, Jonathan Leffler wrote:

> Finally, after about 30 hours of hair tearing and hard work, I've
> isolated a
> pure ESQL/C version of this bug and demonstrated that it primarily
> afflicts
> 32-bit ports of Informix ESQL/C that come with CSDK 2.90 and
> 2.81 . It does
> not afflict most 64-bit ports (though 2.81.FC2 crashed with a core
> dump, as
> did 2.80.UC2), and it does not affect older ports (2.80.UC1 was
> OK). It did
> not reproduce on RHEL 4 running on Linux PPC-64 with CSDK
> 3.00.FC1(actually, a nightly build prior to that release). Finally,
> it only affects
> LVARCHAR NOT NULL, and only if the table is not a temporary table.
> Since I
> kept the server constant (IDS 10.00.UC5 running on Solaris 10), the
> problem
> is most likely in ESQL/C rather than IDS itself; if it is perchance
> in IDS,
> it is in the code that recognizes different versions of ESQL/C and
> somehow
> reacts differently.
>
> This bug is now idsdb00139040 in the IBM/Informix CQ database.
>
> Sadly, as yet, I do not have a workaround or fix for this -- that
> comes
> next.
>
> To say that the circumstances under which it fails are obscure is
> to be
> excessively polite.
>
> I tried to release an update to DBD::Informix, but the release
> process goes
> through the test suite, and since the test t/t93lvarchar.t was
> failing, it
> was not possible to make the release automatically, so I haven't
> made the
> update. I may decide to cheat and make the release using a 64-bit
> Perl and
> 64-bit ESQL/C, like I did with the DBD::Informix 2007.0226 (though
> that was
> released completely unaware of the issue - this one would be released
> despite knowing the test fails). The temptation to modify the test
> (eg to
> use a temp table instead of a permanent one) is also quite
> considerable.
>
> --
> Jonathan Leffler #include
> Guardian of DBD::Informix - v2007.0226 - http://dbi.perl.org
> "Blessed are we who can laugh at ourselves, for we shall never
> cease to be
> amused."