Bug #5615 type of aggregate function column wrong when using group by
Submitted: 16 Sep 2004 19:37 Modified: 2 Mar 2005 21:18
Reporter: Jim Nusbaum Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S1 (Critical)
Version:4.1.3 OS:Any (any)
Assigned to: Ramil Kalimullin CPU Architecture:Any

[16 Sep 2004 19:37] Jim Nusbaum
Description:
When using the C API the type of a returned column is wrong in certain circumstances.  In particular the type of a MAX(datetime) column is sometimes returned as datetime and sometimes returned as varchar, depending on whether a group by is used or not.

How to repeat:
Consider the following code run against a MySQL server 4.1.3 running under Solaris 8 on a multiprocessor SPARC machine:

#include <mysql.h> /* Headers for MySQL usage */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>

static MYSQL test_db;

int main(int argc, 
         char **argv)
{
   MYSQL test_db;
   MYSQL_RES* res = 0;
   MYSQL_FIELD* fmt = 0;
   int x;

   if (!mysql_init(&test_db))
   {
      printf("Error initing mysql lib\n");
      exit(1);
   }
   
   mysql_options(&test_db, MYSQL_READ_DEFAULT_GROUP, "client");

   if (!mysql_real_connect(&test_db, "server", 
                                     "operator", "pwd", "test", 0, 0, 0))
   { 
      printf("Error connecting to database: %s\n", mysql_error(&test_db));
      exit(1);
   }

   /* create tables */
   char tcreate[] = 
   "CREATE TABLE test (product VARCHAR(32), stamp DATETIME) TYPE = MEMORY";

   if (mysql_real_query(&test_db, tcreate, strlen(tcreate)))
   { /* Make query */
      printf("error creating test: %s\n", mysql_error(&test_db));
      exit(1);
   }

   for (x = 0; x < 100; ++x)
   {
      char insert[1024];
      const char* products[] = {
         "A", "B", "C", "D", "E"
      };
      int i = x % 5;

      sprintf(insert, 
              "INSERT INTO test(product, stamp) VALUES('%s', '2004-09-15 13:45:05')",
              products[i]);
      if (mysql_real_query(&test_db, insert, strlen(insert)))
      { /* Make query */
         printf("%s\n", mysql_error(&test_db));
         exit(1);
      }
   }

   const char* select1 = "SELECT MAX(stamp) FROM test";
   if (mysql_real_query(&test_db, select1, strlen(select1)))
   { /* Make query */
      printf("%s\n", mysql_error(&test_db));
      exit(1);
   }

   res = mysql_store_result(&test_db); /* Download result from server */

   // print out types of result columns
   fmt = mysql_fetch_field_direct(res, 0);
   printf("field[0] (MAX(datetime)) type is %d\n", fmt->type);

   mysql_free_result(res); /* Release memory used to store results. */

   const char* select2 = "SELECT product, MAX(stamp) FROM test GROUP BY product";
   if (mysql_real_query(&test_db, select2, strlen(select2)))
   { /* Make query */
      printf("%s\n", mysql_error(&test_db));
      exit(1);
   }

   res = mysql_store_result(&test_db); /* Download result from server */

   // print out types of result columns
   fmt = mysql_fetch_field_direct(res, 0);
   printf("field[0] (varchar) type is %d\n", fmt->type);
   fmt = mysql_fetch_field_direct(res, 1);
   printf("field[1] (MAX(datetime)) type is %d\n", fmt->type);
   
   mysql_free_result(res); /* Release memory used to store results. */

   char drop[] = "DROP TABLE test";
   if (mysql_real_query(&test_db, drop, strlen(drop)))
   { /* Make query */
      printf("error dropping test: %s\n", mysql_error(&test_db));
      exit(1);
   }

   mysql_close(&test_db);

   return 0;
}

When run this code produces:

field[0] (MAX(datetime)) type is 12
field[0] (varchar) type is 253
field[1] (MAX(datetime)) type is 253

Notice that the first query produces a correct type (12 = datetime).  The second query however incorrectly identifies the MAX(datetime) field as being of varchar type (253 = varchar).  This is clearly incorrect.  The data is correct but the type is wrong.

I have verified this only on MEMORY type tables and only on 4.1.3.

Suggested fix:
Fix the client lib or server to return the correct type.
[16 Sep 2004 19:39] Jim Nusbaum
I have verified that the same bug occurs for all table types and in 4.1.4.
[6 Oct 2004 10:58] Hartmut Holzgraefe
the following PHP script was used to reproduce the problem:

<?php
	mysql_connect("localhost", "root", "") or die(mysql_error());
	mysql_select_db("test") or die(mysql_error());

	mysql_query("CREATE TEMPORARY TABLE test (product VARCHAR(32), stamp DATETIME)");

	for ($i = 0; $i < 100; $i++) {
		$t = chr(65 + $i % 5);
		mysql_query("INSERT INTO test(product, stamp) VALUES('$t', '2004-09-15 13:45:05')");
	}

	$res = mysql_query("SELECT MAX(stamp) FROM test");
	echo mysql_field_type($res, 0) . "\n";

	$res = mysql_query("SELECT MAX(stamp) FROM test GROUP BY product");
	echo mysql_field_type($res, 0) . "\n";
?>
[11 Oct 2004 13:03] Ramil Kalimullin
An easier way to check it is something like:

drop table if exists t1, t2;
create table t1(a int, b datetime);
insert into t1 values (1, NOW()), (2, NOW());
create table t2 select MAX(b) from t1 order by a;
show create table t2;
[11 Oct 2004 13:17] Ramil Kalimullin
Sorry, 
create table t2 select MAX(b) from t1 order by a;   --->
create table t2 select MAX(b) from t1 group by a;
[1 Mar 2005 10:17] Ramil Kalimullin
fixed in 4.1.11
[2 Mar 2005 21:18] Paul DuBois
Noted in 4.1.11 changelog.