Bug #4231 Wrong result with MYSQL_TIME parameters
Submitted: 21 Jun 2004 13:55 Modified: 2 Sep 2004 18:17
Reporter: Anthon Ouwendijk Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S2 (Serious)
Version:4.1.2 OS:Any (all)
Assigned to: Konstantin Osipov CPU Architecture:Any

[21 Jun 2004 13:55] Anthon Ouwendijk
Description:
This happens when the C API for prepared statements is used.
A sample C source using the standard mysql.helptopic table has been included.

Query: select * from T where ? = ?
Both parameters are of the type MYSQL_TIME.

When the actual values of the parameters are set to a different date, the
where clause should evaluate to FALSE, and an empty result set should be returned.
This works fine, as long as no '0000-00-00' date is used. In that case the where clause evalueate to TRUE, causing the complete table to be fetched.

where ? /* 1999-01-01 */ = ? /* 2000-01-01 */ ----> FALSE
where ? /* 1999-01-01 */ = ? /* 0000-00-00 */ ----> TRUE

How to repeat:
#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;
	char *		query;

	MYSQL_BIND      ParamBind[2];
        unsigned long   ParamLength;
        my_bool         ParamIsNull;
	MYSQL_TIME	left_date = { 0 };
	MYSQL_TIME	right_date = { 0 };

	MYSQL_BIND      ResultBind[1];
        unsigned long   ResultLength;
        my_bool         ResultIsNull;
        char            ResultStrData[ 128 ];

	*desc = 
	"MySQL-#.... Baan-040621	wrong result with MYSQL_TIME binding \n"
	"			ok:	empty result set on WHERE <date> ? = <date> ? \n"
	"					with date 'xxxx-xx-xx' and 'yyyy-yy-yy' \n"
	"			err:	NON empty result set on WHERE <date> ? = <date> ? \n"
	"					with date 'xxxx-xx-xx' and '0000-00-00' \n"
	;

	if ( !(stmt = mysql_stmt_init(mysql) ) ) {
		return BUG_UNKNOWN;
	}

	query = "select name from mysql.help_topic where ? = ? order by help_topic_id ";

	if (mysql_stmt_prepare(stmt, query, strlen(query))) {
		printf( "Prepare ERR: %s\n", query );
		mysql_stmt_close(stmt);
		return BUG_UNKNOWN;
	}

	/* Bind the param buffers */
	ParamBind[0].buffer_type= MYSQL_TYPE_DATE;
	ParamBind[0].buffer_length = sizeof ( MYSQL_TIME );
	ParamBind[0].buffer = (char *) &left_date;
	ParamBind[0].is_null= &ParamIsNull;
	ParamBind[0].length = 0;

	ParamBind[1].buffer_type= MYSQL_TYPE_DATE;
	ParamBind[1].buffer_length = sizeof ( MYSQL_TIME );
	ParamBind[1].buffer = (char *) &right_date;
	ParamBind[1].is_null= &ParamIsNull;
	ParamBind[1].length = 0;

	if (mysql_stmt_bind_param(stmt, ParamBind)) {
		mysql_stmt_close(stmt);
		return BUG_UNKNOWN;
	}

	/* Bind the result buffers */
	ResultBind[0].buffer_type= MYSQL_TYPE_STRING;
	ResultBind[0].buffer= ResultStrData;
	ResultBind[0].is_null= &ResultIsNull;
	ResultBind[0].length= &ResultLength;

	if (mysql_stmt_bind_result(stmt, ResultBind)) {
		mysql_stmt_close(stmt);
		return BUG_UNKNOWN;
	}

/*
	Test with 'normal' dates. As the dates are unequal, no rows should be fetched.
	This works fine. The test is added to be sure everything is OK
*/

	/* Set actual parameter values */
	left_date.time_type = MYSQL_TIMESTAMP_DATE;
	right_date.time_type = MYSQL_TIMESTAMP_DATE;

	left_date.year = 2000;
	left_date.month = 1;
	left_date.day = 1;

	right_date.year = left_date.year - 1;	/* note left_date != right_date */
	right_date.month = left_date.month;
	right_date.day = left_date.day;

	/* Execute */
	if (mysql_stmt_execute(stmt)) {
		mysql_stmt_close(stmt);
		return BUG_UNKNOWN;
	}

	/* Fetch all rows */
	while (!mysql_stmt_fetch(stmt))
	{
		/* As binds are unequal, no row should be returned */
		return BUG_UNKNOWN;
	}

/*
	Now do the REAL test. Change one bind to '0000-00-00'
*/

	/* Set actual Param value */
	right_date.year = 0;
	right_date.month = 0;
	right_date.day = 0;

	if (mysql_stmt_execute(stmt)) {
		mysql_stmt_close(stmt);
		return BUG_UNKNOWN;
	}

	while (!mysql_stmt_fetch(stmt))
	{
		if (ResultIsNull)
			return BUG_UNKNOWN;
			
		printf ( "fetched name = %s\n", ResultStrData );

		return BUG_PRESENT;
	}

	/* Close the statement */
	mysql_stmt_close(stmt);

	return BUG_SOLVED;
}

main()
{
	MYSQL *		mysql = mysql_init( NULL );
	BugStatus	bugstat;
	char *		desc;

	/* Bind data */

	if ( ! mysql_real_connect( mysql,
					/* host */ NULL,
					/* user */ User,
					/* pwd */ Pwd,
					/* 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;
}
[20 Jul 2004 5:40] Konstantin Osipov
Could you please check if the bug is still present?
See also my comment for Bug#4183, "mysql_stmt_fetch() fetches numbers in wrong byte order"
at http://bugs.mysql.com/bug.php?id=4183
[22 Jul 2004 18:34] Joerg Rueschenschmidt
Hi,

i am working in the same company as Anthon. He is currently in vacation and will be back next monday.

However, i looked to the problem to give you a quick response.

We can not test the bug on version 4.1.3, because there is no binary distribution for HP-UX 11.00 available on your webserver. I tried to compile the source, but this was failing.

I tested it on window 2000 with version 4.1.3 now. The problem is still there !

Regards ...

Joerg Rueschenschmidt
[1 Sep 2004 17:01] Konstantin Osipov
This is not HP-UX specific: I was able to reproduce this behaviour onon Linux.
[2 Sep 2004 15:43] Konstantin Osipov
bk commit - 4.1 tree (konstantin:1.2035) BUG#4231
[2 Sep 2004 18:17] Konstantin Osipov
Fixed in 4.1.5