List:Internals« Previous MessageNext Message »
From:antony Date:March 4 2005 9:14pm
Subject:bk commit into 5.0 tree (acurtis:1.1848) BUG#2773
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of acurtis. When acurtis does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.1848 05/03/04 21:14:35 acurtis@stripped +14 -0
  Bug#3788
    Crashes with stored procedure return non-string values
    Also fixes Bug#2773

  sql/unireg.cc
    1.51 05/03/04 21:14:18 acurtis@stripped +1 -0
    Bug#3788
      Add assertion check

  sql/sql_yacc.yy
    1.344 05/03/04 21:14:17 acurtis@stripped +25 -7
    Bug#3788
      Change how function return types are stored for SPs

  sql/sql_table.cc
    1.221 05/03/04 21:14:17 acurtis@stripped +179 -135
    Bug#3788
      Split out field preparation code into its own function

  sql/sql_parse.cc
    1.407 05/03/04 21:14:16 acurtis@stripped +39 -15
    Bug#3788
      Split out field construction into its own function

  sql/sp_head.h
    1.51 05/03/04 21:14:16 acurtis@stripped +8 -7
    Bug#3788
      Change how function return types are stored for SPs

  sql/sp_head.cc
    1.115 05/03/04 21:14:16 acurtis@stripped +39 -38
    Bug#3788
      Change how function return types are stored for SPs

  sql/sp.cc
    1.67 05/03/04 21:14:15 acurtis@stripped +22 -2
    Bug#3788
      Alter how function return type is reported

  sql/mysql_priv.h
    1.266 05/03/04 21:14:15 acurtis@stripped +11 -0
    Bug#3788
      Prototypes for new global functions

  sql/item_func.h
    1.99 05/03/04 21:14:14 acurtis@stripped +9 -0
    Bug#3788
      Alter how SP function result types are handled.

  sql/item_func.cc
    1.165 05/03/04 21:14:14 acurtis@stripped +78 -6
    Bug#3788
      Alter how SP function result types are handled.

  sql/item.cc
    1.116 05/03/04 21:14:14 acurtis@stripped +1 -1
    Fix unrelated crash in view test with --ps-protocol.

  mysql-test/t/sp.test
    1.103 05/03/04 21:14:13 acurtis@stripped +29 -0
    Bug#3788
      New tests for bug

  mysql-test/r/sp.result
    1.109 05/03/04 21:14:13 acurtis@stripped +27 -5
    Bug#3788
      Tests for Bug
      Fix results for bugfix

  mysql-test/r/information_schema.result
    1.34 05/03/04 21:14:13 acurtis@stripped +1 -1
    Bug#3788
      Fix results for bugfix

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	acurtis
# Host:	pcgem.rdg.cyberkinetica.com
# Root:	/var/db/bk/work-acurtis/bug3788.3

--- 1.115/sql/item.cc	2005-02-23 17:04:23 +00:00
+++ 1.116/sql/item.cc	2005-03-04 21:14:14 +00:00
@@ -3524,7 +3524,7 @@
   enum_parsing_place place= NO_MATTER;
   SELECT_LEX *current_sel= thd->lex->current_select;
 
-  if (!ref)
+  if (!ref || ref == not_found_item)
   {
     SELECT_LEX_UNIT *prev_unit= current_sel->master_unit();
     SELECT_LEX *outer_sel= prev_unit->outer_select();

--- 1.164/sql/item_func.cc	2005-02-23 17:04:23 +00:00
+++ 1.165/sql/item_func.cc	2005-03-04 21:14:14 +00:00
@@ -4318,13 +4318,33 @@
 Item_func_sp::Item_func_sp(sp_name *name)
   :Item_func(), m_name(name), m_sp(NULL)
 {
+  char *empty_name= (char *) "";
+  maybe_null= 1;
   m_name->init_qname(current_thd);
+  bzero(&dummy_table, sizeof(dummy_table));
+  dummy_table.share.table_cache_key = empty_name;
+  dummy_table.share.table_name = empty_name;
+  dummy_table.table.alias = empty_name;
+  dummy_table.share.table_name = empty_name;
+  dummy_table.table.maybe_null = maybe_null;
+  dummy_table.table.in_use= current_thd;
+  dummy_table.table.s = &dummy_table.share;
 }
 
 Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list)
   :Item_func(list), m_name(name), m_sp(NULL)
 {
+  char *empty_name= (char *) "";
+  maybe_null= 1;
   m_name->init_qname(current_thd);
+  bzero(&dummy_table, sizeof(dummy_table));
+  dummy_table.share.table_cache_key = empty_name;
+  dummy_table.share.table_name = empty_name;
+  dummy_table.table.alias = empty_name;
+  dummy_table.share.table_name = empty_name;
+  dummy_table.table.maybe_null = maybe_null;
+  dummy_table.table.in_use= current_thd;
+  dummy_table.table.s = &dummy_table.share;
 }
 
 const char *
@@ -4349,6 +4369,18 @@
 }
 
 
+Field *
+Item_func_sp::sp_result_field(void) const
+{
+  Field *field= 0;
+  THD *thd= current_thd;
+  DBUG_ENTER("Item_func_sp::sp_result_field");
+  if (m_sp)
+    field= m_sp->make_field(max_length, name, &dummy_table.table);
+  DBUG_RETURN(field);
+}
+
+
 int
 Item_func_sp::execute(Item **itp)
 {
@@ -4404,17 +4436,38 @@
 }
 
 
+void
+Item_func_sp::make_field(Send_field *tmp_field)
+{
+  Field *field;
+  DBUG_ENTER("Item_func_sp::make_field");
+  if (! m_sp)
+    m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
+  if ((field= sp_result_field()))
+  {
+    field->make_field(tmp_field);
+    delete field;
+    DBUG_VOID_RETURN;
+  }
+  my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+  init_make_field(tmp_field, MYSQL_TYPE_VARCHAR);  
+  DBUG_VOID_RETURN;
+}
+
+
 enum enum_field_types
 Item_func_sp::field_type() const
 {
+  Field *field= 0;
   DBUG_ENTER("Item_func_sp::field_type");
 
   if (! m_sp)
     m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
-  if (m_sp)
+  if ((field= sp_result_field()))
   {
-    DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns));
-    DBUG_RETURN(m_sp->m_returns);
+    enum_field_types result= field->type();
+    delete field;
+    DBUG_RETURN(result);
   }
   my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
   DBUG_RETURN(MYSQL_TYPE_VARCHAR);
@@ -4424,14 +4477,17 @@
 Item_result
 Item_func_sp::result_type() const
 {
+  Field *field= 0;
   DBUG_ENTER("Item_func_sp::result_type");
   DBUG_PRINT("info", ("m_sp = %p", m_sp));
 
   if (! m_sp)
     m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
-  if (m_sp)
+  if ((field= sp_result_field()))
   {
-    DBUG_RETURN(m_sp->result());
+    Item_result result= field->result_type();
+    delete field;
+    DBUG_RETURN(result);
   }
   my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
   DBUG_RETURN(STRING_RESULT);
@@ -4450,7 +4506,7 @@
   }
   else
   {
-    switch (m_sp->result()) {
+    switch (result_type()) {
     case STRING_RESULT:
       maybe_null= 1;
       max_length= MAX_BLOB_WIDTH;
@@ -4484,4 +4540,20 @@
   THD *thd= current_thd;
 
   return thd->found_rows();
+}
+
+Field *
+Item_func_sp::tmp_table_field(TABLE *t_arg)
+{
+  Field *res= 0;
+  enum_field_types ftype;
+  DBUG_ENTER("Item_func_sp::tmp_table_field");
+
+  if (m_sp)
+    res= m_sp->make_field(max_length, (const char *)name, t_arg);
+  
+  if (!res) 
+    res= Item_func::tmp_table_field(t_arg);
+
+  DBUG_RETURN(res);
 }

--- 1.98/sql/item_func.h	2005-02-22 13:46:56 +00:00
+++ 1.99/sql/item_func.h	2005-03-04 21:14:14 +00:00
@@ -1250,8 +1250,13 @@
 private:
   sp_name *m_name;
   mutable sp_head *m_sp;
+  mutable struct {
+    TABLE table;
+    TABLE_SHARE share;
+  } dummy_table;
 
   int execute(Item **itp);
+  Field *sp_result_field(void) const;
 
 public:
 
@@ -1265,6 +1270,10 @@
   const char *func_name() const;
 
   enum enum_field_types field_type() const;
+
+  Field *tmp_table_field(TABLE *t_arg);
+
+  void make_field(Send_field *tmp_field);
 
   Item_result result_type() const;
 

--- 1.265/sql/mysql_priv.h	2005-02-24 16:55:11 +00:00
+++ 1.266/sql/mysql_priv.h	2005-03-04 21:14:15 +00:00
@@ -629,6 +629,10 @@
 Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
 			Item ***copy_func, Field **from_field,
 			bool group, bool modify_item, uint convert_blob_length);
+int prepare_create_field(create_field *sql_field, 
+			 uint &blob_columns, 
+			 int &timestamps, int &timestamps_with_niladic,
+			 uint table_flags);
 int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
 		       List<create_field> &fields,
 		       List<Key> &keys, uint &db_options, 
@@ -837,6 +841,13 @@
 		       char *change, List<String> *interval_list,
 		       CHARSET_INFO *cs,
 		       uint uint_geom_type);
+create_field * new_create_field(THD *thd, char *field_name, enum_field_types type,
+				char *length, char *decimals,
+				uint type_modifier, 
+				Item *default_value, Item *on_update_value,
+				LEX_STRING *comment, char *change, 
+				List<String> *interval_list, CHARSET_INFO *cs,
+				uint uint_geom_type);
 void store_position_for_column(const char *name);
 bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc=0);
 void add_join_on(TABLE_LIST *b,Item *expr);

--- 1.406/sql/sql_parse.cc	2005-02-24 16:55:12 +00:00
+++ 1.407/sql/sql_parse.cc	2005-03-04 21:14:16 +00:00
@@ -5291,9 +5291,6 @@
 {
   register create_field *new_field;
   LEX  *lex= thd->lex;
-  uint allowed_type_modifier=0;
-  uint sign_len;
-  ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
   DBUG_ENTER("add_field_to_list");
 
   if (strlen(field_name) > NAME_LEN)
@@ -5354,9 +5351,38 @@
     my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
     DBUG_RETURN(1);
   }
-    
-  if (!(new_field=new create_field()))
+
+  if (!(new_field= new_create_field(thd, field_name, type, length, decimals,
+		type_modifier, default_value, on_update_value,
+		comment, change, interval_list, cs, uint_geom_type)))
     DBUG_RETURN(1);
+
+  lex->create_list.push_back(new_field);
+  lex->last_field=new_field;
+  DBUG_RETURN(0);
+}
+
+/*****************************************************************************
+** Create field definition for create
+** Return 0 on failure, otherwise return create_field instance
+******************************************************************************/
+  
+create_field *
+new_create_field(THD *thd, char *field_name, enum_field_types type,
+		 char *length, char *decimals,
+		 uint type_modifier, 
+		 Item *default_value, Item *on_update_value,
+		 LEX_STRING *comment,
+		 char *change, List<String> *interval_list, CHARSET_INFO *cs,
+		 uint uint_geom_type)
+{
+  register create_field *new_field;
+  uint sign_len, allowed_type_modifier=0;
+  ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
+  DBUG_ENTER("new_create_field");
+  
+  if (!(new_field=new create_field()))
+    DBUG_RETURN(NULL);
   new_field->field=0;
   new_field->field_name=field_name;
   new_field->def= default_value;
@@ -5428,7 +5454,7 @@
         new_field->length >= new_field->decimals)
       break;
     my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
-    DBUG_RETURN(1);
+    DBUG_RETURN(NULL);
   case MYSQL_TYPE_VARCHAR:
     /*
       Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
@@ -5451,7 +5477,7 @@
       {
 	my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
                  field_name); /* purecov: inspected */
-	DBUG_RETURN(1); /* purecov: inspected */
+	DBUG_RETURN(NULL);
       }
       new_field->def=0;
     }
@@ -5471,7 +5497,7 @@
       if (tmp_length > PRECISION_FOR_DOUBLE)
       {
 	my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
-	DBUG_RETURN(1);
+	DBUG_RETURN(NULL);
       }
       else if (tmp_length > PRECISION_FOR_FLOAT)
       {
@@ -5568,7 +5594,7 @@
       if (interval_list->elements > sizeof(longlong)*8)
       {
 	my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
-	DBUG_RETURN(1);				      /* purecov: inspected */
+	DBUG_RETURN(NULL);
       }
       new_field->pack_length= (interval_list->elements + 7) / 8;
       if (new_field->pack_length > 4)
@@ -5609,7 +5635,7 @@
       {
         my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name,
                  MAX_BIT_FIELD_LENGTH);
-        DBUG_RETURN(1);
+        DBUG_RETURN(NULL);
       }
       new_field->pack_length= (new_field->length + 7) / 8;
       break;
@@ -5628,17 +5654,15 @@
   {
     my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0),
              field_name, max_field_charlength); /* purecov: inspected */
-    DBUG_RETURN(1);				/* purecov: inspected */
+    DBUG_RETURN(NULL);
   }
   type_modifier&= AUTO_INCREMENT_FLAG;
   if ((~allowed_type_modifier) & type_modifier)
   {
     my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
-    DBUG_RETURN(1);
+    DBUG_RETURN(NULL);
   }
-  lex->create_list.push_back(new_field);
-  lex->last_field=new_field;
-  DBUG_RETURN(0);
+  DBUG_RETURN(new_field);
 }
 
 

--- 1.220/sql/sql_table.cc	2005-02-21 18:41:45 +00:00
+++ 1.221/sql/sql_table.cc	2005-03-04 21:14:17 +00:00
@@ -425,6 +425,173 @@
 
 
 /*
+  Prepare a create_table instance for packing
+
+  SYNOPSIS
+    prepare_create_field()
+    sql_field     field to prepare for packing
+    blob_columns  count for BLOBs
+    timestamps    count for timestamps
+    table_flags   table flags
+
+  DESCRIPTION
+    This function prepares a create_field instance.
+    Fields such as pack_flag are valid after this call.
+
+  RETURN VALUES
+   0	ok
+   1	Error
+*/
+
+int prepare_create_field(create_field *sql_field, 
+			 uint &blob_columns, 
+			 int &timestamps, int &timestamps_with_niladic,
+			 uint table_flags)
+{
+  DBUG_ENTER("prepare_field");
+  {
+    /* This code came from mysql_prepare_table.
+       Indent preserved to make patching easier */
+    DBUG_ASSERT(sql_field->charset);
+
+    switch (sql_field->sql_type) {
+    case FIELD_TYPE_BLOB:
+    case FIELD_TYPE_MEDIUM_BLOB:
+    case FIELD_TYPE_TINY_BLOB:
+    case FIELD_TYPE_LONG_BLOB:
+      sql_field->pack_flag=FIELDFLAG_BLOB |
+	pack_length_to_packflag(sql_field->pack_length -
+				portable_sizeof_char_ptr);
+      if (sql_field->charset->state & MY_CS_BINSORT)
+	sql_field->pack_flag|=FIELDFLAG_BINARY;
+      sql_field->length=8;			// Unireg field length
+      sql_field->unireg_check=Field::BLOB_FIELD;
+      blob_columns++;
+      break;
+    case FIELD_TYPE_GEOMETRY:
+#ifdef HAVE_SPATIAL
+      if (!(table_flags & HA_CAN_GEOMETRY))
+      {
+	my_printf_error(ER_CHECK_NOT_IMPLEMENTED, ER(ER_CHECK_NOT_IMPLEMENTED),
+			MYF(0), "GEOMETRY");
+	DBUG_RETURN(1);
+      }
+      sql_field->pack_flag=FIELDFLAG_GEOM |
+	pack_length_to_packflag(sql_field->pack_length -
+				portable_sizeof_char_ptr);
+      if (sql_field->charset->state & MY_CS_BINSORT)
+	sql_field->pack_flag|=FIELDFLAG_BINARY;
+      sql_field->length=8;			// Unireg field length
+      sql_field->unireg_check=Field::BLOB_FIELD;
+      blob_columns++;
+      break;
+#else
+      my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED), MYF(0),
+		      sym_group_geom.name, sym_group_geom.needed_define);
+      DBUG_RETURN(1);
+#endif /*HAVE_SPATIAL*/
+    case MYSQL_TYPE_VARCHAR:
+#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
+      if (table_flags & HA_NO_VARCHAR)
+      {
+        /* convert VARCHAR to CHAR because handler is not yet up to date */
+        sql_field->sql_type=    MYSQL_TYPE_VAR_STRING;
+        sql_field->pack_length= calc_pack_length(sql_field->sql_type,
+                                                 (uint) sql_field->length);
+        if ((sql_field->length / sql_field->charset->mbmaxlen) >
+            MAX_FIELD_CHARLENGTH)
+        {
+          my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
+                          MYF(0), sql_field->field_name, MAX_FIELD_CHARLENGTH);
+          DBUG_RETURN(1);
+        }
+      }
+#endif
+      /* fall through */
+    case FIELD_TYPE_STRING:
+      sql_field->pack_flag=0;
+      if (sql_field->charset->state & MY_CS_BINSORT)
+	sql_field->pack_flag|=FIELDFLAG_BINARY;
+      break;
+    case FIELD_TYPE_ENUM:
+      sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
+	FIELDFLAG_INTERVAL;
+      if (sql_field->charset->state & MY_CS_BINSORT)
+	sql_field->pack_flag|=FIELDFLAG_BINARY;
+      sql_field->unireg_check=Field::INTERVAL_FIELD;
+      check_duplicates_in_interval("ENUM",sql_field->field_name,
+				   sql_field->interval,
+                                   sql_field->charset);
+      break;
+    case FIELD_TYPE_SET:
+      sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
+	FIELDFLAG_BITFIELD;
+      if (sql_field->charset->state & MY_CS_BINSORT)
+	sql_field->pack_flag|=FIELDFLAG_BINARY;
+      sql_field->unireg_check=Field::BIT_FIELD;
+      check_duplicates_in_interval("SET",sql_field->field_name,
+				   sql_field->interval,
+                                   sql_field->charset);
+      break;
+    case FIELD_TYPE_DATE:			// Rest of string types
+    case FIELD_TYPE_NEWDATE:
+    case FIELD_TYPE_TIME:
+    case FIELD_TYPE_DATETIME:
+    case FIELD_TYPE_NULL:
+      sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
+      break;
+    case FIELD_TYPE_BIT:
+      if (!(table_flags & HA_CAN_BIT_FIELD))
+      {
+        my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "BIT FIELD");
+        DBUG_RETURN(1);
+      }
+      sql_field->pack_flag= FIELDFLAG_NUMBER;
+      break;
+    case FIELD_TYPE_NEWDECIMAL:
+      sql_field->pack_flag=(FIELDFLAG_NUMBER |
+                            (sql_field->flags & UNSIGNED_FLAG ? 0 :
+                             FIELDFLAG_DECIMAL) |
+                            (sql_field->flags & ZEROFILL_FLAG ?
+                             FIELDFLAG_ZEROFILL : 0) |
+                            (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
+      break;
+    case FIELD_TYPE_TIMESTAMP:
+      /* We should replace old TIMESTAMP fields with their newer analogs */
+      if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
+      {
+	if (!timestamps)
+	{
+	  sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
+	  timestamps_with_niladic++;
+	}
+	else
+	  sql_field->unireg_check= Field::NONE;
+      }
+      else if (sql_field->unireg_check != Field::NONE)
+	timestamps_with_niladic++;
+
+      timestamps++;
+      /* fall-through */
+    default:
+      sql_field->pack_flag=(FIELDFLAG_NUMBER |
+			    (sql_field->flags & UNSIGNED_FLAG ? 0 :
+			     FIELDFLAG_DECIMAL) |
+			    (sql_field->flags & ZEROFILL_FLAG ?
+			     FIELDFLAG_ZEROFILL : 0) |
+			    f_settype((uint) sql_field->sql_type) |
+			    (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
+      break;
+    }
+    if (!(sql_field->flags & NOT_NULL_FLAG))
+      sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
+    if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
+      sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
+  }
+  DBUG_RETURN(0);
+}
+
+/*
   Preparation for table creation
 
   SYNOPSIS
@@ -683,142 +850,17 @@
   {
     DBUG_ASSERT(sql_field->charset);
 
-    switch (sql_field->sql_type) {
-    case FIELD_TYPE_BLOB:
-    case FIELD_TYPE_MEDIUM_BLOB:
-    case FIELD_TYPE_TINY_BLOB:
-    case FIELD_TYPE_LONG_BLOB:
-      sql_field->pack_flag=FIELDFLAG_BLOB |
-	pack_length_to_packflag(sql_field->pack_length -
-				portable_sizeof_char_ptr);
-      if (sql_field->charset->state & MY_CS_BINSORT)
-	sql_field->pack_flag|=FIELDFLAG_BINARY;
-      sql_field->length=8;			// Unireg field length
-      sql_field->unireg_check=Field::BLOB_FIELD;
-      blob_columns++;
-      create_info->varchar= 1;
-      break;
-    case FIELD_TYPE_GEOMETRY:
-#ifdef HAVE_SPATIAL
-      if (!(file->table_flags() & HA_CAN_GEOMETRY))
-      {
-	my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY");
-	DBUG_RETURN(-1);
-      }
-      sql_field->pack_flag=FIELDFLAG_GEOM |
-	pack_length_to_packflag(sql_field->pack_length -
-				portable_sizeof_char_ptr);
-      if (sql_field->charset->state & MY_CS_BINSORT)
-	sql_field->pack_flag|=FIELDFLAG_BINARY;
-      sql_field->length=8;			// Unireg field length
-      sql_field->unireg_check=Field::BLOB_FIELD;
-      blob_columns++;
-      create_info->varchar= 1;
-      break;
-#else
-      my_error(ER_FEATURE_DISABLED, MYF(0),
-               sym_group_geom.name, sym_group_geom.needed_define);
+    if (prepare_create_field(sql_field, blob_columns, 
+			     timestamps, timestamps_with_niladic,
+			     file->table_flags()))
       DBUG_RETURN(-1);
-#endif /*HAVE_SPATIAL*/
-    case MYSQL_TYPE_VARCHAR:
-#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
-      if (file->table_flags() & HA_NO_VARCHAR)
-      {
-        /* convert VARCHAR to CHAR because handler is not yet up to date */
-        sql_field->sql_type=    MYSQL_TYPE_VAR_STRING;
-        sql_field->pack_length= calc_pack_length(sql_field->sql_type,
-                                                 (uint) sql_field->length);
-        if ((sql_field->length / sql_field->charset->mbmaxlen) >
-            MAX_FIELD_CHARLENGTH)
-        {
-          my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
-                          MYF(0), sql_field->field_name, MAX_FIELD_CHARLENGTH);
-          DBUG_RETURN(-1);
-        }
-      }
-      else
-#endif
-        create_info->varchar= 1;
-      /* fall through */
-    case MYSQL_TYPE_STRING:
-      sql_field->pack_flag=0;
-      if (sql_field->charset->state & MY_CS_BINSORT)
-	sql_field->pack_flag|= FIELDFLAG_BINARY;
-      break;
-    case FIELD_TYPE_ENUM:
-      sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
-	FIELDFLAG_INTERVAL;
-      if (sql_field->charset->state & MY_CS_BINSORT)
-	sql_field->pack_flag|=FIELDFLAG_BINARY;
-      sql_field->unireg_check=Field::INTERVAL_FIELD;
-      check_duplicates_in_interval("ENUM",sql_field->field_name,
-                                   sql_field->interval,
-                                   sql_field->charset);
-      break;
-    case FIELD_TYPE_SET:
-      sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
-	FIELDFLAG_BITFIELD;
-      if (sql_field->charset->state & MY_CS_BINSORT)
-	sql_field->pack_flag|=FIELDFLAG_BINARY;
-      sql_field->unireg_check=Field::BIT_FIELD;
-      check_duplicates_in_interval("SET",sql_field->field_name,
-                                   sql_field->interval,
-                                   sql_field->charset);
-      break;
-    case FIELD_TYPE_DATE:			// Rest of string types
-    case FIELD_TYPE_NEWDATE:
-    case FIELD_TYPE_TIME:
-    case FIELD_TYPE_DATETIME:
-    case FIELD_TYPE_NULL:
-      sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
-      break;
-    case FIELD_TYPE_BIT:
-      if (!(file->table_flags() & HA_CAN_BIT_FIELD))
-      {
-        my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "BIT FIELD");
-        DBUG_RETURN(-1);
-      }
-      sql_field->pack_flag= FIELDFLAG_NUMBER;
-      break;
-    case FIELD_TYPE_NEWDECIMAL:
-      sql_field->pack_flag=(FIELDFLAG_NUMBER |
-                            (sql_field->flags & UNSIGNED_FLAG ? 0 :
-                             FIELDFLAG_DECIMAL) |
-                            (sql_field->flags & ZEROFILL_FLAG ?
-                             FIELDFLAG_ZEROFILL : 0) |
-                            (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
-      break;
-    case FIELD_TYPE_TIMESTAMP:
-      /* We should replace old TIMESTAMP fields with their newer analogs */
-      if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
-      {
-	if (!timestamps)
-	{
-	  sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
-	  timestamps_with_niladic++;
-	}
-	else
-	  sql_field->unireg_check= Field::NONE;
-      }
-      else if (sql_field->unireg_check != Field::NONE)
-	timestamps_with_niladic++;
-
-      timestamps++;
-      /* fall-through */
-    default:
-      sql_field->pack_flag=(FIELDFLAG_NUMBER |
-			    (sql_field->flags & UNSIGNED_FLAG ? 0 :
-			     FIELDFLAG_DECIMAL) |
-			    (sql_field->flags & ZEROFILL_FLAG ?
-			     FIELDFLAG_ZEROFILL : 0) |
-			    f_settype((uint) sql_field->sql_type) |
-			    (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
-      break;
-    }
-    if (!(sql_field->flags & NOT_NULL_FLAG))
-      sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
-    if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
-      sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
+    if (sql_field->sql_type == FIELD_TYPE_BLOB ||
+        sql_field->sql_type == FIELD_TYPE_MEDIUM_BLOB ||
+        sql_field->sql_type == FIELD_TYPE_TINY_BLOB ||
+        sql_field->sql_type == FIELD_TYPE_LONG_BLOB ||
+        sql_field->sql_type == FIELD_TYPE_GEOMETRY ||
+        sql_field->sql_type == MYSQL_TYPE_VARCHAR)
+      create_info->varchar= 1;
     sql_field->offset= pos;
     if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
       auto_increment++;
@@ -1585,6 +1627,8 @@
 					   ((Item_field *)item)->field :
 					   (Field*) 0))))
       DBUG_RETURN(0);
+    if (item->maybe_null)
+      cr_field->flags &= ~NOT_NULL_FLAG;
     extra_fields->push_back(cr_field);
   }
   /*

--- 1.343/sql/sql_yacc.yy	2005-02-22 13:14:14 +00:00
+++ 1.344/sql/sql_yacc.yy	2005-03-04 21:14:17 +00:00
@@ -1370,19 +1370,37 @@
 	  RETURNS_SYM
 	  {
 	    LEX *lex= Lex;
-	    sp_head *sp= lex->sphead;
-
-	    sp->m_returns_begin= lex->tok_start;
-	    sp->m_returns_cs= lex->charset= NULL;
+	    lex->charset= NULL;
+	    lex->length= lex->dec= NULL;
+	    lex->interval_list.empty();
+	    lex->type= 0;
 	  }
 	  type
 	  {
 	    LEX *lex= Lex;
 	    sp_head *sp= lex->sphead;
+            LEX_STRING cmt = { 0, 0 };
+	    create_field *new_field;
+	    uint unused1= 0;
+	    int unused2= 0;
+
+	    if (!(new_field= new_create_field(YYTHD, "", (enum enum_field_types)$8,
+			  lex->length, lex->dec, lex->type,
+			  (Item *)0, (Item *) 0, &cmt, 0, &lex->interval_list, 
+			  (lex->charset ? lex->charset : default_charset_info),
+			  lex->uint_geom_type)))
+	      YYABORT;
+
+	    if (prepare_create_field(new_field, unused1, unused2, unused2, 0))
+	      YYABORT;
+
+	    sp->m_returns= new_field->sql_type;
+	    sp->m_returns_cs= new_field->charset;
+	    sp->m_returns_len= new_field->length;
+	    sp->m_returns_pack= new_field->pack_flag;
+	    sp->m_returns_typelib= 
+              sp->create_typelib(&new_field->interval_list);
 
-	    sp->m_returns_end= lex->tok_start;
-	    sp->m_returns= (enum enum_field_types)$8;
-	    sp->m_returns_cs= lex->charset;
 	    bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
 	  }
 	  sp_c_chistics

--- 1.50/sql/unireg.cc	2005-01-06 11:00:06 +00:00
+++ 1.51/sql/unireg.cc	2005-03-04 21:14:18 +00:00
@@ -695,6 +695,7 @@
 			       field->interval,
 			       field->field_name,
 			       &table);
+    DBUG_ASSERT(regfield);
 
     if (!(field->flags & NOT_NULL_FLAG))
       null_count++;

--- 1.33/mysql-test/r/information_schema.result	2005-02-23 12:15:15 +00:00
+++ 1.34/mysql-test/r/information_schema.result	2005-03-04 21:14:13 +00:00
@@ -202,7 +202,7 @@
 from information_schema.routines;
 parameter_style	sql_data_access	dtd_identifier
 SQL	CONTAINS SQL	NULL
-SQL	CONTAINS SQL	int
+SQL	CONTAINS SQL	int(11)
 show procedure status;
 Db	Name	Type	Definer	Modified	Created	Security_type	Comment
 test	sel2	PROCEDURE	root@localhost	#	#	DEFINER	

--- 1.108/mysql-test/r/sp.result	2005-02-24 12:56:05 +00:00
+++ 1.109/mysql-test/r/sp.result	2005-03-04 21:14:13 +00:00
@@ -951,7 +951,7 @@
   return 42|
 show create function chistics|
 Function	sql_mode	Create Function
-chistics		CREATE FUNCTION `test`.`chistics`() RETURNS int
+chistics		CREATE FUNCTION `test`.`chistics`() RETURNS int(11)
     DETERMINISTIC
     SQL SECURITY INVOKER
     COMMENT 'Characteristics procedure test'
@@ -964,7 +964,7 @@
 comment 'Characteristics function test'|
 show create function chistics|
 Function	sql_mode	Create Function
-chistics		CREATE FUNCTION `test`.`chistics`() RETURNS int
+chistics		CREATE FUNCTION `test`.`chistics`() RETURNS int(11)
     NO SQL
     DETERMINISTIC
     SQL SECURITY INVOKER
@@ -1214,7 +1214,7 @@
 end
 call bug2267_4()|
 Function	sql_mode	Create Function
-fac		CREATE FUNCTION `test`.`fac`(n int unsigned) RETURNS bigint unsigned
+fac		CREATE FUNCTION `test`.`fac`(n int unsigned) RETURNS bigint(20) unsigned
 begin
 declare f bigint unsigned default 1;
 while n > 1 do
@@ -1576,11 +1576,11 @@
 insert into "t1" values ('foo', 1)
 show create function bug2564_3|
 Function	sql_mode	Create Function
-bug2564_3		CREATE FUNCTION `test`.`bug2564_3`(x int, y int) RETURNS int
+bug2564_3		CREATE FUNCTION `test`.`bug2564_3`(x int, y int) RETURNS int(11)
 return x || y
 show create function bug2564_4|
 Function	sql_mode	Create Function
-bug2564_4	REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI	CREATE FUNCTION "test"."bug2564_4"(x int, y int) RETURNS int
+bug2564_4	REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI	CREATE FUNCTION "test"."bug2564_4"(x int, y int) RETURNS int(11)
 return x || y
 drop procedure bug2564_1|
 drop procedure bug2564_2|
@@ -1644,6 +1644,28 @@
 drop procedure bug4579_1|
 drop procedure bug4579_2|
 drop table t3|
+drop table if exists t3|
+drop procedure if exists bug2773|
+create function bug2773() returns int return null|
+create table t3 as select bug2773()|
+show create table t3|
+Table	Create Table
+t3	CREATE TABLE `t3` (
+  `bug2773()` int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t3|
+drop function bug2773|
+drop procedure if exists bug3788|
+create function bug3788() returns date return cast("2005-03-04" as date)|
+select bug3788()|
+bug3788()
+2005-03-04
+drop function bug3788|
+create function bug3788() returns binary(5) return 5|
+select bug3788()|
+bug3788()
+5
+drop function bug3788|
 drop table if exists t3|
 create table t3 (f1 int, f2 int, f3 int)|
 insert into t3 values (1,1,1)|

--- 1.102/mysql-test/t/sp.test	2005-02-24 00:59:28 +00:00
+++ 1.103/mysql-test/t/sp.test	2005-03-04 21:14:13 +00:00
@@ -2063,6 +2063,35 @@
 drop procedure bug4579_2|
 drop table t3|
 
+#
+# BUG#2773: Function's data type ignored in stored procedures
+#
+--disable_warnings
+drop table if exists t3|
+drop procedure if exists bug2773|
+--enable_warnings
+
+create function bug2773() returns int return null|
+create table t3 as select bug2773()|
+show create table t3|
+drop table t3|
+drop function bug2773|
+
+#
+# BUG#3788: Stored procedure packet error
+#
+--disable_warnings
+drop procedure if exists bug3788|
+--enable_warnings
+
+create function bug3788() returns date return cast("2005-03-04" as date)|
+select bug3788()|
+drop function bug3788|
+
+create function bug3788() returns binary(5) return 5|
+select bug3788()|
+drop function bug3788|
+ 
 
 #
 # BUG#4726

--- 1.66/sql/sp.cc	2005-02-08 19:52:40 +00:00
+++ 1.67/sql/sp.cc	2005-03-04 21:14:15 +00:00
@@ -334,6 +334,22 @@
 }
 
 
+static void
+sp_returns_type(THD *thd, String &result, sp_head *sp)
+{
+  struct {
+    TABLE table;
+    TABLE_SHARE share;
+  } dummy;
+  Field *field;
+  bzero(&dummy, sizeof(dummy));
+  dummy.table.in_use= thd;
+  dummy.table.s = &dummy.share;
+  field= sp->make_field(0, 0, &dummy.table);
+  field->sql_type(result);
+  delete field;
+}
+
 static int
 db_create_routine(THD *thd, int type, sp_head *sp)
 {
@@ -388,9 +404,13 @@
 	store((longlong)sp->m_chistics->suid);
     table->field[MYSQL_PROC_FIELD_PARAM_LIST]->
       store(sp->m_params.str, sp->m_params.length, system_charset_info);
-    if (sp->m_retstr.str)
+    if (sp->m_type == TYPE_ENUM_FUNCTION)
+    {
+      String retstr(64);
+      sp_returns_type(thd, retstr, sp);
       table->field[MYSQL_PROC_FIELD_RETURNS]->
-	store(sp->m_retstr.str, sp->m_retstr.length, system_charset_info);
+	store(retstr.ptr(), retstr.length(), system_charset_info);
+    }
     table->field[MYSQL_PROC_FIELD_BODY]->
       store(sp->m_body.str, sp->m_body.length, system_charset_info);
     table->field[MYSQL_PROC_FIELD_DEFINER]->

--- 1.114/sql/sp_head.cc	2005-02-21 17:51:02 +00:00
+++ 1.115/sql/sp_head.cc	2005-03-04 21:14:16 +00:00
@@ -300,11 +300,11 @@
   */
   lex->trg_table_fields.empty();
   my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
-  m_param_begin= m_param_end= m_returns_begin= m_returns_end= m_body_begin= 0;
-  m_qname.str= m_db.str= m_name.str= m_params.str= m_retstr.str=
+  m_param_begin= m_param_end= m_body_begin= 0;
+  m_qname.str= m_db.str= m_name.str= m_params.str= 
     m_body.str= m_defstr.str= 0;
   m_qname.length= m_db.length= m_name.length= m_params.length=
-    m_retstr.length= m_body.length= m_defstr.length= 0;
+    m_body.length= m_defstr.length= 0;
   m_returns_cs= NULL;
   DBUG_VOID_RETURN;
 }
@@ -346,41 +346,6 @@
                                (char *)m_param_begin, m_params.length);
   }
 
-  if (m_returns_begin && m_returns_end)
-  {
-    /* QQ KLUDGE: We can't seem to cut out just the type in the parser
-       (without the RETURNS), so we'll have to do it here. :-(
-       Furthermore, if there's a character type as well, it's not include
-       (beyond the m_returns_end pointer), in which case we need
-       m_returns_cs. */
-    char *p= (char *)m_returns_begin+strspn((char *)m_returns_begin,"\t\n\r ");
-    p+= strcspn(p, "\t\n\r ");
-    p+= strspn(p, "\t\n\r ");
-    if (p < (char *)m_returns_end)
-      m_returns_begin= (uchar *)p;
-    /* While we're at it, trim the end too. */
-    p= (char *)m_returns_end-1;
-    while (p > (char *)m_returns_begin &&
-	   (*p == '\t' || *p == '\n' || *p == '\r' || *p == ' '))
-      p-= 1;
-    m_returns_end= (uchar *)p+1;
-    if (m_returns_cs)
-    {
-      String s((char *)m_returns_begin, m_returns_end - m_returns_begin,
-	       system_charset_info);
-
-      s.append(' ');
-      s.append(m_returns_cs->csname);
-      m_retstr.length= s.length();
-      m_retstr.str= strmake_root(root, s.ptr(), m_retstr.length);
-    }
-    else
-    {
-      m_retstr.length= m_returns_end - m_returns_begin;
-      m_retstr.str= strmake_root(root,
-				 (char *)m_returns_begin, m_retstr.length);
-    }
-  }
   m_body.length= lex->ptr - m_body_begin;
   /* Trim nuls at the end */
   n= 0;
@@ -396,6 +361,27 @@
   DBUG_VOID_RETURN;
 }
 
+TYPELIB *
+sp_head::create_typelib(List<String> *src)
+{
+  TYPELIB *result= NULL;
+  DBUG_ENTER("sp_head::clone_typelib");
+  if (src->elements)
+  {
+    result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
+    result->count= src->elements;
+    result->name= "";
+    if (!(result->type_names=(const char **)
+          alloc_root(mem_root,sizeof(char *)*(result->count+1))))
+      return 0;
+    List_iterator<String> it(*src);
+    for (uint i=0; i<result->count; i++)
+      result->type_names[i]= strdup_root(mem_root, (it++)->c_ptr());
+    result->type_names[result->count]= 0;
+  }
+  return result;
+}
+
 int
 sp_head::create(THD *thd)
 {
@@ -462,6 +448,21 @@
   if (m_sptabs.array.buffer)
     hash_free(&m_sptabs);
   DBUG_VOID_RETURN;
+}
+
+
+Field *
+sp_head::make_field(uint max_length, const char *name, TABLE *dummy)
+{
+  Field *field;
+  DBUG_ENTER("sp_head::make_field");
+  field= ::make_field((char *)0,
+		!m_returns_len ? max_length : m_returns_len, 
+		(uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs,
+		(enum Field::geometry_type)0, Field::NONE, 
+		m_returns_typelib,
+		name ? name : (const char *)m_name.str, dummy);
+  DBUG_RETURN(field);
 }
 
 int

--- 1.50/sql/sp_head.h	2005-02-08 19:52:40 +00:00
+++ 1.51/sql/sp_head.h	2005-03-04 21:14:16 +00:00
@@ -84,6 +84,9 @@
   int m_type;			// TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
   enum enum_field_types m_returns; // For FUNCTIONs only
   CHARSET_INFO *m_returns_cs;	// For FUNCTIONs only
+  TYPELIB *m_returns_typelib;	// For FUNCTIONs only
+  uint m_returns_len;		// For FUNCTIONs only
+  uint m_returns_pack;		// For FUNCTIONs only
   my_bool m_has_return;		// For FUNCTIONs only
   my_bool m_simple_case;	// TRUE if parsing simple case, FALSE otherwise
   my_bool m_multi_results;	// TRUE if a procedure with SELECT(s)
@@ -96,7 +99,6 @@
   LEX_STRING m_db;
   LEX_STRING m_name;
   LEX_STRING m_params;
-  LEX_STRING m_retstr;		// For FUNCTIONs only
   LEX_STRING m_body;
   LEX_STRING m_defstr;
   LEX_STRING m_definer_user;
@@ -105,8 +107,7 @@
   longlong m_modified;
   HASH m_sptabs;		/* Merged table lists */
   // Pointers set during parsing
-  uchar *m_param_begin, *m_param_end, *m_returns_begin, *m_returns_end,
-    *m_body_begin;
+  uchar *m_param_begin, *m_param_end, *m_body_begin;
 
   static void *
   operator new(size_t size);
@@ -124,6 +125,9 @@
   void
   init_strings(THD *thd, LEX *lex, sp_name *name);
 
+  TYPELIB *
+  create_typelib(List<String> *src);
+
   int
   create(THD *thd);
 
@@ -197,10 +201,7 @@
 
   char *create_string(THD *thd, ulong *lenp);
 
-  inline Item_result result()
-  {
-    return sp_map_result_type(m_returns);
-  }
+  Field *make_field(uint max_length, const char *name, TABLE *dummy);
 
   void set_info(char *definer, uint definerlen,
 		longlong created, longlong modified,
Thread
bk commit into 5.0 tree (acurtis:1.1848) BUG#2773antony4 Mar