Commit 9bf92ed6 authored by unknown's avatar unknown
Browse files

Bug#9102 - Stored proccedures: function which returns blob causes crash

  Initialization of fields for sp return type was not complete.


mysql-test/r/sp.result:
  Bug#9102
    Test for bug
mysql-test/t/sp.test:
  Bug#9102
    Test for bug
sql/mysql_priv.h:
  Bug#9102
    new function: sp_prepare_create_field()
sql/sp_head.cc:
  Strip spaces and do charset conversion for sp function typelibs
sql/sql_table.cc:
  Bug#9102
    new function - sp_prepare_create_field()
    prepares create_field in similar way to mysql_prepare_table()
sql/sql_yacc.yy:
  Bug#9102
parent d0eecb39
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2958,4 +2958,10 @@ select @x|
set global query_cache_size = @qcs1|
delete from t1|
drop function bug9902|
drop function if exists bug9102|
create function bug9102() returns blob return 'a'|
select bug9102();
drop function bug9102|
bug9102()
a
drop table t1,t2;
+9 −0
Original line number Diff line number Diff line
@@ -3627,6 +3627,15 @@ set global query_cache_size = @qcs1|
delete from t1|
drop function bug9902|

#
# BUG#9102: New bug synopsis
#
--disable_warnings
drop function if exists bug9102|
--enable_warnings
create function bug9102() returns blob return 'a'|
select bug9102();
drop function bug9102|

#
# BUG#NNNN: New bug synopsis
+1 −0
Original line number Diff line number Diff line
@@ -647,6 +647,7 @@ 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);
void sp_prepare_create_field(THD *thd, create_field *sql_field);
int prepare_create_field(create_field *sql_field, 
			 uint *blob_columns, 
			 int *timestamps, int *timestamps_with_niladic,
+25 −1
Original line number Diff line number Diff line
@@ -370,6 +370,7 @@ TYPELIB *
sp_head::create_typelib(List<String> *src)
{
  TYPELIB *result= NULL;
  CHARSET_INFO *cs= m_returns_cs;
  DBUG_ENTER("sp_head::clone_typelib");
  if (src->elements)
  {
@@ -380,8 +381,31 @@ sp_head::create_typelib(List<String> *src)
          alloc_root(mem_root,sizeof(char *)*(result->count+1))))
      return 0;
    List_iterator<String> it(*src);
    String conv, *tmp;
    uint32 dummy;
    for (uint i=0; i<result->count; i++)
      result->type_names[i]= strdup_root(mem_root, (it++)->c_ptr());
    {
      tmp = it++;
      if (String::needs_conversion(tmp->length(), tmp->charset(),
      				   cs, &dummy))
      {
        uint cnv_errs;
        conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
        char *buf= (char*) alloc_root(mem_root,conv.length()+1);
        memcpy(buf, conv.ptr(), conv.length());
        buf[conv.length()]= '\0';
        result->type_names[i]= buf;
        result->type_lengths[i]= conv.length();
      }
      else
        result->type_names[i]= strdup_root(mem_root, tmp->c_ptr());

      // Strip trailing spaces.
      uint lengthsp= cs->cset->lengthsp(cs, result->type_names[i],
                                        result->type_lengths[i]);
      result->type_lengths[i]= lengthsp;
      ((uchar *)result->type_names[i])[lengthsp]= '\0';
    }
    result->type_names[result->count]= 0;
  }
  return result;
+71 −0
Original line number Diff line number Diff line
@@ -1351,6 +1351,77 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}


/*
  Preparation of create_field for SP function return values.
  Based on code used in the inner loop of mysql_prepare_table() above

  SYNOPSIS
    sp_prepare_create_field()
    thd			Thread object
    sql_field		Field to prepare

  DESCRIPTION
    Prepares the field structures for field creation.

*/

void sp_prepare_create_field(THD *thd, create_field *sql_field)
{
  if (sql_field->sql_type == FIELD_TYPE_SET ||
      sql_field->sql_type == FIELD_TYPE_ENUM)
  {
    uint32 field_length, dummy;
    if (sql_field->sql_type == FIELD_TYPE_SET)
    {
      calculate_interval_lengths(sql_field->charset,
                                 sql_field->interval, &dummy, 
                                 &field_length);
      sql_field->length= field_length + 
                         (sql_field->interval->count - 1);
    }
    else /* FIELD_TYPE_ENUM */
    {
      calculate_interval_lengths(sql_field->charset,
                                 sql_field->interval,
                                 &field_length, &dummy);
      sql_field->length= field_length;
    }
    set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
  }

  if (sql_field->sql_type == FIELD_TYPE_BIT)
  {
    sql_field->pack_flag= FIELDFLAG_NUMBER |
                          FIELDFLAG_TREAT_BIT_AS_CHAR;
  }
  sql_field->create_length_to_internal_length();

  if (sql_field->length > MAX_FIELD_VARCHARLENGTH &&
      !(sql_field->flags & BLOB_FLAG))
  {
    /* Convert long VARCHAR columns to TEXT or BLOB */
    char warn_buff[MYSQL_ERRMSG_SIZE];

    sql_field->sql_type= FIELD_TYPE_BLOB;
    sql_field->flags|= BLOB_FLAG;
    sprintf(warn_buff, ER(ER_AUTO_CONVERT), sql_field->field_name,
            "VARCHAR",
            (sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT");
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_AUTO_CONVERT,
                 warn_buff);
  }

  if ((sql_field->flags & BLOB_FLAG) && sql_field->length)
  {
    if (sql_field->sql_type == FIELD_TYPE_BLOB)
    {
      /* The user has given a length to the blob column */
      sql_field->sql_type= get_blob_type_from_length(sql_field->length);
      sql_field->pack_length= calc_pack_length(sql_field->sql_type, 0);
    }
    sql_field->length= 0;                     // Probably from an item
  }
}
/*
  Create a table

Loading