Commit ad5a8a55 authored by unknown's avatar unknown

Merge sinisa@work.mysql.com:/home/bk/mysql-4.1

into sinisa.nasamreza.org:/mnt/work/mysql-4.1

parents a2915180 b82f3bbe
...@@ -52,6 +52,14 @@ row_mysql_read_var_ref_noninline( ...@@ -52,6 +52,14 @@ row_mysql_read_var_ref_noninline(
ulint* len, /* out: variable-length field length */ ulint* len, /* out: variable-length field length */
byte* field); /* in: field */ byte* field); /* in: field */
/*********************************************************************** /***********************************************************************
Frees the blob heap in prebuilt when no longer needed. */
void
row_mysql_prebuilt_free_blob_heap(
/*==============================*/
row_prebuilt_t* prebuilt); /* in: prebuilt struct of a
ha_innobase:: table handle */
/***********************************************************************
Stores a reference to a BLOB in the MySQL format. */ Stores a reference to a BLOB in the MySQL format. */
void void
......
...@@ -115,7 +115,8 @@ row_search_for_mysql( ...@@ -115,7 +115,8 @@ row_search_for_mysql(
/*=================*/ /*=================*/
/* out: DB_SUCCESS, /* out: DB_SUCCESS,
DB_RECORD_NOT_FOUND, DB_RECORD_NOT_FOUND,
DB_END_OF_INDEX, or DB_DEADLOCK */ DB_END_OF_INDEX, DB_DEADLOCK,
or DB_TOO_BIG_RECORD */
byte* buf, /* in/out: buffer for the fetched byte* buf, /* in/out: buffer for the fetched
row in the MySQL format */ row in the MySQL format */
ulint mode, /* in: search mode PAGE_CUR_L, ... */ ulint mode, /* in: search mode PAGE_CUR_L, ... */
......
...@@ -50,6 +50,16 @@ ut_malloc( ...@@ -50,6 +50,16 @@ ut_malloc(
/* out, own: allocated memory */ /* out, own: allocated memory */
ulint n); /* in: number of bytes to allocate */ ulint n); /* in: number of bytes to allocate */
/************************************************************************** /**************************************************************************
Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
out. It cannot be used if we want to return an error message. Prints to
stderr a message if fails. */
ibool
ut_test_malloc(
/*===========*/
/* out: TRUE if succeeded */
ulint n); /* in: try to allocate this many bytes */
/**************************************************************************
Frees a memory bloock allocated with ut_malloc. */ Frees a memory bloock allocated with ut_malloc. */
void void
......
...@@ -58,6 +58,19 @@ row_mysql_read_var_ref_noninline( ...@@ -58,6 +58,19 @@ row_mysql_read_var_ref_noninline(
return(row_mysql_read_var_ref(len, field)); return(row_mysql_read_var_ref(len, field));
} }
/***********************************************************************
Frees the blob heap in prebuilt when no longer needed. */
void
row_mysql_prebuilt_free_blob_heap(
/*==============================*/
row_prebuilt_t* prebuilt) /* in: prebuilt struct of a
ha_innobase:: table handle */
{
mem_heap_free(prebuilt->blob_heap);
prebuilt->blob_heap = NULL;
}
/*********************************************************************** /***********************************************************************
Stores a reference to a BLOB in the MySQL format. */ Stores a reference to a BLOB in the MySQL format. */
......
...@@ -2039,9 +2039,12 @@ Note that the template in prebuilt may advise us to copy only a few ...@@ -2039,9 +2039,12 @@ Note that the template in prebuilt may advise us to copy only a few
columns to mysql_rec, other columns are left blank. All columns may not columns to mysql_rec, other columns are left blank. All columns may not
be needed in the query. */ be needed in the query. */
static static
void ibool
row_sel_store_mysql_rec( row_sel_store_mysql_rec(
/*====================*/ /*====================*/
/* out: TRUE if success, FALSE
if could not allocate memory for a
BLOB */
byte* mysql_rec, /* out: row in the MySQL format */ byte* mysql_rec, /* out: row in the MySQL format */
row_prebuilt_t* prebuilt, /* in: prebuilt struct */ row_prebuilt_t* prebuilt, /* in: prebuilt struct */
rec_t* rec) /* in: Innobase record in the index rec_t* rec) /* in: Innobase record in the index
...@@ -2092,7 +2095,19 @@ row_sel_store_mysql_rec( ...@@ -2092,7 +2095,19 @@ row_sel_store_mysql_rec(
if (templ->type == DATA_BLOB) { if (templ->type == DATA_BLOB) {
ut_a(prebuilt->templ_contains_blob); ut_a(prebuilt->templ_contains_blob);
/* A heuristic test that we can allocate
the memory for a big BLOB. We have a safety
margin of 1000000 bytes. Since the test
takes some CPU time, we do not use for small
BLOBs. */
if (len > 2000000
&& !ut_test_malloc(len + 1000000)) {
return(FALSE);
}
/* Copy the BLOB data to the BLOB /* Copy the BLOB data to the BLOB
heap of prebuilt */ heap of prebuilt */
...@@ -2142,6 +2157,8 @@ row_sel_store_mysql_rec( ...@@ -2142,6 +2157,8 @@ row_sel_store_mysql_rec(
} }
} }
} }
return(TRUE);
} }
/************************************************************************* /*************************************************************************
...@@ -2526,7 +2543,8 @@ row_search_for_mysql( ...@@ -2526,7 +2543,8 @@ row_search_for_mysql(
/*=================*/ /*=================*/
/* out: DB_SUCCESS, /* out: DB_SUCCESS,
DB_RECORD_NOT_FOUND, DB_RECORD_NOT_FOUND,
DB_END_OF_INDEX, or DB_DEADLOCK */ DB_END_OF_INDEX, DB_DEADLOCK,
or DB_TOO_BIG_RECORD */
byte* buf, /* in/out: buffer for the fetched byte* buf, /* in/out: buffer for the fetched
row in the MySQL format */ row in the MySQL format */
ulint mode, /* in: search mode PAGE_CUR_L, ... */ ulint mode, /* in: search mode PAGE_CUR_L, ... */
...@@ -2758,7 +2776,12 @@ row_search_for_mysql( ...@@ -2758,7 +2776,12 @@ row_search_for_mysql(
#ifdef UNIV_SEARCH_DEBUG #ifdef UNIV_SEARCH_DEBUG
ut_a(0 == cmp_dtuple_rec(search_tuple, rec)); ut_a(0 == cmp_dtuple_rec(search_tuple, rec));
#endif #endif
row_sel_store_mysql_rec(buf, prebuilt, rec); if (!row_sel_store_mysql_rec(buf, prebuilt,
rec)) {
err = DB_TOO_BIG_RECORD;
goto lock_wait_or_error;
}
mtr_commit(&mtr); mtr_commit(&mtr);
...@@ -3200,7 +3223,11 @@ rec_loop: ...@@ -3200,7 +3223,11 @@ rec_loop:
rec_get_size(rec)); rec_get_size(rec));
mach_write_to_4(buf, rec_get_extra_size(rec) + 4); mach_write_to_4(buf, rec_get_extra_size(rec) + 4);
} else { } else {
row_sel_store_mysql_rec(buf, prebuilt, rec); if (!row_sel_store_mysql_rec(buf, prebuilt, rec)) {
err = DB_TOO_BIG_RECORD;
goto lock_wait_or_error;
}
} }
if (prebuilt->clust_index_was_generated) { if (prebuilt->clust_index_was_generated) {
......
...@@ -77,8 +77,9 @@ ut_malloc_low( ...@@ -77,8 +77,9 @@ ut_malloc_low(
ret = malloc(n + sizeof(ut_mem_block_t)); ret = malloc(n + sizeof(ut_mem_block_t));
if (ret == NULL) { if (ret == NULL) {
ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
"InnoDB: Fatal error: cannot allocate %lu bytes of\n" " InnoDB: Fatal error: cannot allocate %lu bytes of\n"
"InnoDB: memory with malloc! Total allocated memory\n" "InnoDB: memory with malloc! Total allocated memory\n"
"InnoDB: by InnoDB %lu bytes. Operating system errno: %d\n" "InnoDB: by InnoDB %lu bytes. Operating system errno: %d\n"
"InnoDB: Cannot continue operation!\n" "InnoDB: Cannot continue operation!\n"
...@@ -134,6 +135,40 @@ ut_malloc( ...@@ -134,6 +135,40 @@ ut_malloc(
return(ut_malloc_low(n, TRUE)); return(ut_malloc_low(n, TRUE));
} }
/**************************************************************************
Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
out. It cannot be used if we want to return an error message. Prints to
stderr a message if fails. */
ibool
ut_test_malloc(
/*===========*/
/* out: TRUE if succeeded */
ulint n) /* in: try to allocate this many bytes */
{
void* ret;
ret = malloc(n);
if (ret == NULL) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: cannot allocate %lu bytes of memory for\n"
"InnoDB: a BLOB with malloc! Total allocated memory\n"
"InnoDB: by InnoDB %lu bytes. Operating system errno: %d\n"
"InnoDB: Check if you should increase the swap file or\n"
"InnoDB: ulimits of your operating system.\n"
"InnoDB: On FreeBSD check you have compiled the OS with\n"
"InnoDB: a big enough maximum process size.\n",
n, ut_total_allocated_memory, errno);
return(FALSE);
}
free(ret);
return(TRUE);
}
/************************************************************************** /**************************************************************************
Frees a memory block allocated with ut_malloc. */ Frees a memory block allocated with ut_malloc. */
......
...@@ -1624,6 +1624,12 @@ build_template( ...@@ -1624,6 +1624,12 @@ build_template(
} }
if (prebuilt->select_lock_type == LOCK_X) { if (prebuilt->select_lock_type == LOCK_X) {
/* In versions < 3.23.50 we always retrieved the clustered
index record if prebuilt->select_lock_type == LOCK_S,
but there is really not need for that, and in some cases
performance could be seriously degraded because the MySQL
optimizer did not know about our convention! */
/* We always retrieve the whole clustered index record if we /* We always retrieve the whole clustered index record if we
use exclusive row level locks, for example, if the read is use exclusive row level locks, for example, if the read is
done in an UPDATE statement. */ done in an UPDATE statement. */
...@@ -1632,12 +1638,6 @@ build_template( ...@@ -1632,12 +1638,6 @@ build_template(
} }
if (templ_type == ROW_MYSQL_REC_FIELDS) { if (templ_type == ROW_MYSQL_REC_FIELDS) {
/* In versions < 3.23.50 we always retrieved the clustered
index record if prebuilt->select_lock_type == LOCK_S,
but there is really not need for that, and in some cases
performance could be seriously degraded because the MySQL
optimizer did not know about our convention! */
index = prebuilt->index; index = prebuilt->index;
} else { } else {
index = clust_index; index = clust_index;
...@@ -2506,11 +2506,13 @@ ha_innobase::change_active_index( ...@@ -2506,11 +2506,13 @@ ha_innobase::change_active_index(
dict_index_copy_types(prebuilt->search_tuple, prebuilt->index, dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
prebuilt->index->n_fields); prebuilt->index->n_fields);
/* Maybe MySQL changes the active index for a handle also /* MySQL changes the active index for a handle also during some
during some queries, we do not know: then it is safest to build queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
the template such that all columns will be fetched */ and then calculates te sum. Previously we played safe and used
the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
copying. Starting from MySQL-4.1 we use a more efficient flag here. */
build_template(prebuilt, user_thd, table, ROW_MYSQL_WHOLE_ROW); build_template(prebuilt, user_thd, table, ROW_MYSQL_REC_FIELDS);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -3742,8 +3744,18 @@ ha_innobase::extra( ...@@ -3742,8 +3744,18 @@ ha_innobase::extra(
obsolete! */ obsolete! */
switch (operation) { switch (operation) {
case HA_EXTRA_FLUSH:
if (prebuilt->blob_heap) {
row_mysql_prebuilt_free_blob_heap(prebuilt);
}
break;
case HA_EXTRA_RESET: case HA_EXTRA_RESET:
case HA_EXTRA_RESET_STATE: if (prebuilt->blob_heap) {
row_mysql_prebuilt_free_blob_heap(prebuilt);
}
prebuilt->read_just_key = 0;
break;
case HA_EXTRA_RESET_STATE:
prebuilt->read_just_key = 0; prebuilt->read_just_key = 0;
break; break;
case HA_EXTRA_NO_KEYREAD: case HA_EXTRA_NO_KEYREAD:
......
...@@ -628,7 +628,7 @@ static bool parse_prepare_query(PREP_STMT *stmt, ...@@ -628,7 +628,7 @@ static bool parse_prepare_query(PREP_STMT *stmt,
Initialize parameter items in statement Initialize parameter items in statement
*/ */
static bool init_param_items( PREP_STMT *stmt) static bool init_param_items(PREP_STMT *stmt)
{ {
List<Item> &params= stmt->thd->lex.param_list; List<Item> &params= stmt->thd->lex.param_list;
Item_param **to; Item_param **to;
...@@ -642,6 +642,24 @@ static bool init_param_items( PREP_STMT *stmt) ...@@ -642,6 +642,24 @@ static bool init_param_items( PREP_STMT *stmt)
return 0; return 0;
} }
/*
Initialize stmt execution
*/
static void init_stmt_execute(PREP_STMT *stmt)
{
THD *thd= stmt->thd;
TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select_lex.table_list.first;
/*
TODO: When the new table structure is ready, then have a status bit
to indicate the table is altered, and re-do the setup_*
and open the tables back.
*/
if (tables)
tables->table=0; //safety - nasty init
}
/* /*
Parse the query and send the total number of parameters Parse the query and send the total number of parameters
and resultset metadata information back to client (if any), and resultset metadata information back to client (if any),
...@@ -722,6 +740,8 @@ void mysql_stmt_execute(THD *thd, char *packet) ...@@ -722,6 +740,8 @@ void mysql_stmt_execute(THD *thd, char *packet)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
init_stmt_execute(stmt);
if (stmt->param_count && setup_params_data(stmt)) if (stmt->param_count && setup_params_data(stmt))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment