Description:
Description: This happens when the C API for prepared statements is used.
A sample C source has been included.
Queries that
- GROUP on more than one column,
- AND have a aggr function (max/min/avg) on a <date> column
- AND have a DESC order on one of the group-by columns
return corrupt MYSQL_TIME values.
The following query succeeds:
select col1, col2, MIN(<date>) group by col1, col2 order by col1<n>
The following query fails:
select col1, col2, MIN(<date>) group by col1, col2 order by col1<n> DESC
How to repeat:
Table dump:
CREATE TABLE tdbtst180000 (
t_empno int(11) NOT NULL default '0',
t_projno varchar(6) collate latin1_bin NOT NULL default '',
t_emstdate date NOT NULL default '0000-00-00',
t_emendate date NOT NULL default '0000-00-00',
PRIMARY KEY (t_empno,t_projno,t_emstdate,t_emendate),
UNIQUE KEY tdbtst180000$idx2 (t_projno,t_empno,t_emstdate,t_emendate)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (10, 'AD3100', '1982-01-01', '1982-07-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (10, 'MA2100', '1982-01-01', '1982-11-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (10, 'MA2110', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (20, 'PL2100', '1982-01-01', '1982-09-15');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (30, 'IF1000', '1982-06-01', '1983-01-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (30, 'IF2000', '1982-01-01', '1983-01-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (50, 'OP1000', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (50, 'OP2010', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (70, 'AD3110', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (90, 'OP1010', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (100, 'OP2010', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (110, 'MA2100', '1982-01-01', '1982-03-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (130, 'IF1000', '1982-01-01', '1982-10-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (140, 'IF1000', '1982-10-01', '1983-01-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (140, 'IF2000', '1982-01-01', '1982-03-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (150, 'MA2112', '1982-01-01', '1982-07-15');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (160, 'MA2113', '1982-07-15', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (170, 'MA2112', '1982-01-01', '1983-06-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (170, 'MA2113', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (180, 'MA2113', '1982-04-01', '1982-06-15');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (190, 'MA2112', '1982-02-01', '1982-10-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (200, 'MA2111', '1982-01-01', '1982-06-15');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (210, 'MA2113', '1982-10-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (220, 'MA2111', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (230, 'AD3111', '1982-01-01', '1982-03-15');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (240, 'AD3111', '1982-02-15', '1982-09-15');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (250, 'AD3112', '1982-01-01', '1982-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (260, 'AD3113', '1982-06-15', '1982-07-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (270, 'AD3113', '1982-03-01', '1982-04-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (280, 'OP1010', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (290, 'OP1010', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (300, 'OP1010', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (310, 'OP1010', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (320, 'OP2011', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (330, 'OP2012', '1982-01-01', '1983-02-01');
INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (340, 'OP2013', '1982-01-01', '1983-02-01');
Reproducing C-code:
#include <stdlib.h>
#include <mysql.h>
typedef enum {
BUG_UNKNOWN = -1, /* Error occurred */
BUG_SOLVED = 0,
BUG_PRESENT = 1,
} BugStatus;
char * str_bug_stat( BugStatus bugstat )
{
if ( bugstat == BUG_PRESENT ) {
return "Bug still present";
} else if ( bugstat == BUG_SOLVED ) {
return "Bug solved";
}
return "Status UNKNOWN (or error occurred)";
}
BugStatus do_the_bug_test( MYSQL * mysql, char ** desc )
{
MYSQL_STMT * stmt;
/* Bind data */
MYSQL_BIND bind[3];
unsigned long length[2];
my_bool is_null[2];
int int_data;
MYSQL_TIME time_data;
char str_data[64];
char query[256];
int rows = 0;
*desc =
"MySQL Bug Baan-040616 \"SELECT col1, col2, fun(<date>) group by col1, col2 order by col<n> DESC\" returns corrupt <date>\n"
" ok: select col1, col2, MIN(<date>) group by col1, col2 order by col1<n>\n"
" err: select col1, col2, MIN(<date>) group by col1, col2 order by col1<n> DESC\n";
if ( !(stmt = mysql_stmt_init(mysql) ) ) {
return BUG_UNKNOWN;
}
sprintf( query, "select t_empno, t_projno, MIN( t_emstdate ) from tdbtst180000 group by 1, 2 order by 1 desc" );
if (mysql_stmt_prepare(stmt, query, strlen(query))) {
mysql_stmt_close(stmt);
return BUG_UNKNOWN;
}
if (mysql_stmt_execute(stmt)) {
mysql_stmt_close(stmt);
return BUG_UNKNOWN;
}
/* Bind the result buffers */
bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer= (char *)&int_data;
bind[0].is_null= &is_null[0];
bind[0].length= &length[0];
bind[1].buffer_type= MYSQL_TYPE_STRING;
bind[1].buffer= str_data;
bind[1].buffer_length = sizeof(str_data);
bind[1].is_null= &is_null[1];
bind[1].length= &length[1];
bind[2].buffer_type= MYSQL_TYPE_DATE;
bind[2].buffer= (char *)&time_data;
bind[2].is_null= &is_null[2];
bind[2].length= &length[2];
if (mysql_stmt_bind_result(stmt, bind)) {
mysql_stmt_close(stmt);
return BUG_UNKNOWN;
}
/* Fetch all rows */
while (!mysql_stmt_fetch(stmt))
{
MYSQL_TIME * tp = &time_data;
rows++;
if (is_null[0] || is_null[1] || is_null[2])
return BUG_UNKNOWN;
printf ( "empno %d, projno %s, date %d/%d/%d\n", int_data, str_data, tp->year, tp->month, tp->day );
if ( tp->year != 1982
|| tp->month < 1 || tp->month > 12
|| tp->day < 1 || tp->day > 31
) {
return BUG_PRESENT; }
}
/* Close the statement */
mysql_stmt_close(stmt);
if ( rows ) {
return BUG_SOLVED;
} else {
return BUG_UNKNOWN;
}
}
main()
{
MYSQL * mysql = mysql_init( NULL );
BugStatus bugstat;
char * desc;
/* Bind data */
if ( ! mysql_real_connect( mysql,
/* host */ NULL,
/* user */ User,
/* pwd */ Passwd,
/* dbase */ Dbase,
/* uint port */ 0,
/* char * socket */ NULL,
/* client_flag */ 0 ) )
{
fprintf(stderr, " mysql_real_connec() failed\n");
exit(0);
}
bugstat = do_the_bug_test( mysql, &desc );
fprintf(stdout, "%s\n%s\n\n", desc, str_bug_stat( bugstat ) );
return 0;
}
Description: Description: This happens when the C API for prepared statements is used. A sample C source has been included. Queries that - GROUP on more than one column, - AND have a aggr function (max/min/avg) on a <date> column - AND have a DESC order on one of the group-by columns return corrupt MYSQL_TIME values. The following query succeeds: select col1, col2, MIN(<date>) group by col1, col2 order by col1<n> The following query fails: select col1, col2, MIN(<date>) group by col1, col2 order by col1<n> DESC How to repeat: Table dump: CREATE TABLE tdbtst180000 ( t_empno int(11) NOT NULL default '0', t_projno varchar(6) collate latin1_bin NOT NULL default '', t_emstdate date NOT NULL default '0000-00-00', t_emendate date NOT NULL default '0000-00-00', PRIMARY KEY (t_empno,t_projno,t_emstdate,t_emendate), UNIQUE KEY tdbtst180000$idx2 (t_projno,t_empno,t_emstdate,t_emendate) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin; INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (10, 'AD3100', '1982-01-01', '1982-07-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (10, 'MA2100', '1982-01-01', '1982-11-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (10, 'MA2110', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (20, 'PL2100', '1982-01-01', '1982-09-15'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (30, 'IF1000', '1982-06-01', '1983-01-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (30, 'IF2000', '1982-01-01', '1983-01-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (50, 'OP1000', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (50, 'OP2010', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (70, 'AD3110', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (90, 'OP1010', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (100, 'OP2010', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (110, 'MA2100', '1982-01-01', '1982-03-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (130, 'IF1000', '1982-01-01', '1982-10-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (140, 'IF1000', '1982-10-01', '1983-01-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (140, 'IF2000', '1982-01-01', '1982-03-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (150, 'MA2112', '1982-01-01', '1982-07-15'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (160, 'MA2113', '1982-07-15', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (170, 'MA2112', '1982-01-01', '1983-06-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (170, 'MA2113', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (180, 'MA2113', '1982-04-01', '1982-06-15'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (190, 'MA2112', '1982-02-01', '1982-10-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (200, 'MA2111', '1982-01-01', '1982-06-15'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (210, 'MA2113', '1982-10-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (220, 'MA2111', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (230, 'AD3111', '1982-01-01', '1982-03-15'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (240, 'AD3111', '1982-02-15', '1982-09-15'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (250, 'AD3112', '1982-01-01', '1982-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (260, 'AD3113', '1982-06-15', '1982-07-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (270, 'AD3113', '1982-03-01', '1982-04-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (280, 'OP1010', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (290, 'OP1010', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (300, 'OP1010', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (310, 'OP1010', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (320, 'OP2011', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (330, 'OP2012', '1982-01-01', '1983-02-01'); INSERT INTO tdbtst180000 (t_empno, t_projno, t_emstdate, t_emendate) VALUES (340, 'OP2013', '1982-01-01', '1983-02-01'); Reproducing C-code: #include <stdlib.h> #include <mysql.h> typedef enum { BUG_UNKNOWN = -1, /* Error occurred */ BUG_SOLVED = 0, BUG_PRESENT = 1, } BugStatus; char * str_bug_stat( BugStatus bugstat ) { if ( bugstat == BUG_PRESENT ) { return "Bug still present"; } else if ( bugstat == BUG_SOLVED ) { return "Bug solved"; } return "Status UNKNOWN (or error occurred)"; } BugStatus do_the_bug_test( MYSQL * mysql, char ** desc ) { MYSQL_STMT * stmt; /* Bind data */ MYSQL_BIND bind[3]; unsigned long length[2]; my_bool is_null[2]; int int_data; MYSQL_TIME time_data; char str_data[64]; char query[256]; int rows = 0; *desc = "MySQL Bug Baan-040616 \"SELECT col1, col2, fun(<date>) group by col1, col2 order by col<n> DESC\" returns corrupt <date>\n" " ok: select col1, col2, MIN(<date>) group by col1, col2 order by col1<n>\n" " err: select col1, col2, MIN(<date>) group by col1, col2 order by col1<n> DESC\n"; if ( !(stmt = mysql_stmt_init(mysql) ) ) { return BUG_UNKNOWN; } sprintf( query, "select t_empno, t_projno, MIN( t_emstdate ) from tdbtst180000 group by 1, 2 order by 1 desc" ); if (mysql_stmt_prepare(stmt, query, strlen(query))) { mysql_stmt_close(stmt); return BUG_UNKNOWN; } if (mysql_stmt_execute(stmt)) { mysql_stmt_close(stmt); return BUG_UNKNOWN; } /* Bind the result buffers */ bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (char *)&int_data; bind[0].is_null= &is_null[0]; bind[0].length= &length[0]; bind[1].buffer_type= MYSQL_TYPE_STRING; bind[1].buffer= str_data; bind[1].buffer_length = sizeof(str_data); bind[1].is_null= &is_null[1]; bind[1].length= &length[1]; bind[2].buffer_type= MYSQL_TYPE_DATE; bind[2].buffer= (char *)&time_data; bind[2].is_null= &is_null[2]; bind[2].length= &length[2]; if (mysql_stmt_bind_result(stmt, bind)) { mysql_stmt_close(stmt); return BUG_UNKNOWN; } /* Fetch all rows */ while (!mysql_stmt_fetch(stmt)) { MYSQL_TIME * tp = &time_data; rows++; if (is_null[0] || is_null[1] || is_null[2]) return BUG_UNKNOWN; printf ( "empno %d, projno %s, date %d/%d/%d\n", int_data, str_data, tp->year, tp->month, tp->day ); if ( tp->year != 1982 || tp->month < 1 || tp->month > 12 || tp->day < 1 || tp->day > 31 ) { return BUG_PRESENT; } } /* Close the statement */ mysql_stmt_close(stmt); if ( rows ) { return BUG_SOLVED; } else { return BUG_UNKNOWN; } } main() { MYSQL * mysql = mysql_init( NULL ); BugStatus bugstat; char * desc; /* Bind data */ if ( ! mysql_real_connect( mysql, /* host */ NULL, /* user */ User, /* pwd */ Passwd, /* dbase */ Dbase, /* uint port */ 0, /* char * socket */ NULL, /* client_flag */ 0 ) ) { fprintf(stderr, " mysql_real_connec() failed\n"); exit(0); } bugstat = do_the_bug_test( mysql, &desc ); fprintf(stdout, "%s\n%s\n\n", desc, str_bug_stat( bugstat ) ); return 0; }