Commit dc22424b authored by unknown's avatar unknown
Browse files

Merge bk-internal.mysql.com:/home/bk/mysql-5.0

into  mysql.com:/opt/local/work/mysql-5.0-11172-new


sql/sql_class.cc:
  Auto merged
sql/sql_prepare.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
parents 8ec6c354 d36c14f7
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -784,7 +784,10 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value,
  void *change_mem= alloc_root(runtime_memroot, sizeof(*change));
  if (change_mem == 0)
  {
    fatal_error();
    /*
      OOM, thd->fatal_error() is called by the error handler of the
      memroot. Just return.
    */
    return;
  }
  change= new (change_mem) Item_change_record;
+22 −8
Original line number Diff line number Diff line
@@ -2206,13 +2206,15 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
  ulong num_rows= uint4korr(packet+4);
  Prepared_statement *stmt;
  Statement stmt_backup;
  Cursor *cursor;
  DBUG_ENTER("mysql_stmt_fetch");

  statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status);
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch")))
    DBUG_VOID_RETURN;

  if (!stmt->cursor || !stmt->cursor->is_open())
  cursor= stmt->cursor;
  if (!cursor || !cursor->is_open())
  {
    my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id);
    DBUG_VOID_RETURN;
@@ -2225,22 +2227,27 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
    my_pthread_setprio(pthread_self(), QUERY_PRIOR);

  thd->protocol= &thd->protocol_prep;           // Switch to binary protocol
  stmt->cursor->fetch(num_rows);
  cursor->fetch(num_rows);
  thd->protocol= &thd->protocol_simple;         // Use normal protocol

  if (!(specialflag & SPECIAL_NO_PRIOR))
    my_pthread_setprio(pthread_self(), WAIT_PRIOR);

  thd->restore_backup_statement(stmt, &stmt_backup);
  thd->current_arena= thd;

  if (!stmt->cursor->is_open())
  if (!cursor->is_open())
  {
    /* We're done with the fetch: reset PS for next execution */
    cleanup_stmt_and_thd_after_use(stmt, thd);
    reset_stmt_params(stmt);
    /*
      Must be the last, as some momory is still needed for
      the previous calls.
    */
    free_root(cursor->mem_root, MYF(0));
  }

  thd->restore_backup_statement(stmt, &stmt_backup);
  thd->current_arena= thd;

  DBUG_VOID_RETURN;
}

@@ -2267,14 +2274,21 @@ void mysql_stmt_reset(THD *thd, char *packet)
  /* There is always space for 4 bytes in buffer */
  ulong stmt_id= uint4korr(packet);
  Prepared_statement *stmt;
  Cursor *cursor;
  DBUG_ENTER("mysql_stmt_reset");

  statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status);
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
    DBUG_VOID_RETURN;

  if (stmt->cursor && stmt->cursor->is_open())
    stmt->cursor->close();
  cursor= stmt->cursor;
  if (cursor && cursor->is_open())
  {
    thd->change_list= cursor->change_list;
    cursor->close(FALSE);
    cleanup_stmt_and_thd_after_use(stmt, thd);
    free_root(cursor->mem_root, MYF(0));
  }

  stmt->state= Query_arena::PREPARED;

+15 −11
Original line number Diff line number Diff line
@@ -1738,6 +1738,7 @@ Cursor::init_from_thd(THD *thd)
  lock=           thd->lock;
  query_id=       thd->query_id;
  free_list=	  thd->free_list;
  change_list=    thd->change_list;
  reset_thd(thd);
  /*
    XXX: thd->locked_tables is not changed.
@@ -1754,6 +1755,7 @@ Cursor::reset_thd(THD *thd)
  thd->open_tables= 0;
  thd->lock= 0;
  thd->free_list= 0;
  thd->change_list.empty();
}


@@ -1827,6 +1829,7 @@ Cursor::fetch(ulong num_rows)
  thd->open_tables= open_tables;
  thd->lock= lock;
  thd->query_id= query_id;
  thd->change_list= change_list;
  /* save references to memory, allocated during fetch */
  thd->set_n_backup_item_arena(this, &backup_arena);

@@ -1843,10 +1846,8 @@ Cursor::fetch(ulong num_rows)
#ifdef USING_TRANSACTIONS
    ha_release_temporary_latches(thd);
#endif

  /* Grab free_list here to correctly free it in close */
  thd->restore_backup_item_arena(this, &backup_arena);
  DBUG_ASSERT(thd->free_list == 0);
  reset_thd(thd);

  if (error == NESTED_LOOP_CURSOR_LIMIT)
  {
@@ -1854,10 +1855,12 @@ Cursor::fetch(ulong num_rows)
    thd->server_status|= SERVER_STATUS_CURSOR_EXISTS;
    ::send_eof(thd);
    thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS;
    change_list= thd->change_list;
    reset_thd(thd);
  }
  else
  {
    close();
    close(TRUE);
    if (error == NESTED_LOOP_OK)
    {
      thd->server_status|= SERVER_STATUS_LAST_ROW_SENT;
@@ -1872,7 +1875,7 @@ Cursor::fetch(ulong num_rows)


void
Cursor::close()
Cursor::close(bool is_active)
{
  THD *thd= join->thd;
  DBUG_ENTER("Cursor::close");
@@ -1885,6 +1888,10 @@ Cursor::close()
    (void) unit->cleanup();
  else
    (void) join->select_lex->cleanup();

  if (is_active)
    close_thread_tables(thd);
  else
  {
    /* XXX: Another hack: closing tables used in the cursor */
    DBUG_ASSERT(lock || open_tables || derived_tables);
@@ -1904,11 +1911,7 @@ Cursor::close()
  join= 0;
  unit= 0;
  free_items();
  /*
    Must be last, as some memory might be allocated for free purposes,
    like in free_tmp_table() (TODO: fix this issue)
  */
  free_root(mem_root, MYF(0));
  change_list.empty();
  DBUG_VOID_RETURN;
}

@@ -1916,7 +1919,8 @@ Cursor::close()
Cursor::~Cursor()
{
  if (is_open())
    close();
    close(FALSE);
  free_root(mem_root, MYF(0));
}

/*********************************************************************/
+3 −1
Original line number Diff line number Diff line
@@ -390,6 +390,7 @@ class Cursor: public Sql_alloc, public Query_arena
  /* List of items created during execution */
  query_id_t query_id;
public:
  Item_change_list change_list;
  select_send result;

  /* Temporary implementation as now we replace THD state by value */
@@ -402,7 +403,8 @@ class Cursor: public Sql_alloc, public Query_arena
  void fetch(ulong num_rows);
  void reset() { join= 0; }
  bool is_open() const { return join != 0; }
  void close();

  void close(bool is_active);

  void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; }
  Cursor(THD *thd);
+69 −0
Original line number Diff line number Diff line
@@ -13477,6 +13477,74 @@ static void test_bug10794()
}


/* Bug#11172: cursors, crash on a fetch from a datetime column */

static void test_bug11172()
{
  MYSQL_STMT *stmt;
  MYSQL_BIND bind_in[1], bind_out[2];
  MYSQL_TIME hired;
  int rc;
  const char *stmt_text;
  int i= 0, id;
  ulong type;

  myheader("test_bug11172");

  mysql_query(mysql, "drop table if exists t1");
  mysql_query(mysql, "create table t1 (id integer not null primary key,"
                                      "hired date not null)");
  rc= mysql_query(mysql,
                  "insert into t1 (id, hired) values (1, '1933-08-24'), "
                  "(2, '1965-01-01'), (3, '1949-08-17'), (4, '1945-07-07'), "
                  "(5, '1941-05-15'), (6, '1978-09-15'), (7, '1936-03-28')");
  myquery(rc);
  stmt= mysql_stmt_init(mysql);
  stmt_text= "SELECT id, hired FROM t1 WHERE hired=?";
  rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
  check_execute(stmt, rc);

  type= (ulong) CURSOR_TYPE_READ_ONLY;
  mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);

  bzero(bind_in, sizeof(bind_in));
  bzero(bind_out, sizeof(bind_out));
  bzero(&hired, sizeof(hired));
  hired.year= 1965;
  hired.month= 1;
  hired.day= 1;
  bind_in[0].buffer_type= MYSQL_TYPE_DATE;
  bind_in[0].buffer= (void*) &hired;
  bind_in[0].buffer_length= sizeof(hired);
  bind_out[0].buffer_type= MYSQL_TYPE_LONG;
  bind_out[0].buffer= (void*) &id;
  bind_out[1]= bind_in[0];

  for (i= 0; i < 3; i++)
  {
    rc= mysql_stmt_bind_param(stmt, bind_in);
    check_execute(stmt, rc);
    rc= mysql_stmt_bind_result(stmt, bind_out);
    check_execute(stmt, rc);
    rc= mysql_stmt_execute(stmt);
    check_execute(stmt, rc);
    while ((rc= mysql_stmt_fetch(stmt)) == 0)
    {
      if (!opt_silent)
        printf("fetched data %d:%d-%d-%d\n", id,
               hired.year, hired.month, hired.day);
    }
    DIE_UNLESS(rc == MYSQL_NO_DATA);
    mysql_stmt_free_result(stmt) || mysql_stmt_reset(stmt);
  }
  mysql_stmt_close(stmt);
  mysql_rollback(mysql);
  mysql_rollback(mysql);

  rc= mysql_query(mysql, "drop table t1");
  myquery(rc);
}

/*
  Read and parse arguments and MySQL options from my.cnf
*/
@@ -13714,6 +13782,7 @@ static struct my_tests_st my_tests[]= {
  { "test_bug9992", test_bug9992 },
  { "test_bug10736", test_bug10736 },
  { "test_bug10794", test_bug10794 },
  { "test_bug11172", test_bug11172 },
  { 0, 0 }
};