Commit 918b25ec authored by Michael Widenius's avatar Michael Widenius

Automatic merge

parents ced63539 190ed5a2
......@@ -156,6 +156,7 @@ static my_bool ignore_errors=0,wait_flag=0,quick=0,
static my_bool debug_info_flag, debug_check_flag, batch_abort_on_error;
static my_bool column_types_flag;
static my_bool preserve_comments= 0;
static my_bool in_com_source, aborted= 0;
static ulong opt_max_allowed_packet, opt_net_buffer_length;
static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
static uint my_end_arg;
......@@ -1087,6 +1088,7 @@ int main(int argc,char *argv[])
"\\N [\\d]> ",MYF(MY_WME));
current_prompt = my_strdup(default_prompt,MYF(MY_WME));
prompt_counter=0;
aborted= 0;
outfile[0]=0; // no (default) outfile
strmov(pager, "stdout"); // the default, if --pager wasn't given
......@@ -1281,8 +1283,10 @@ sig_handler mysql_end(int sig)
/*
This function handles sigint calls
If query is in process, kill query
If 'source' is executed, abort source command
no query in process, terminate like previous behavior
*/
sig_handler handle_sigint(int sig)
{
char kill_buffer[40];
......@@ -1321,7 +1325,8 @@ sig_handler handle_sigint(int sig)
mysql_close(kill_mysql);
tee_fprintf(stdout, "Ctrl-C -- query killed. Continuing normally.\n");
interrupted_query= 0;
if (in_com_source)
aborted= 1; // Abort source command
return;
err:
......@@ -1886,7 +1891,7 @@ static int read_and_execute(bool interactive)
bool truncated= 0;
status.exit_status=1;
for (;;)
while (!aborted)
{
if (!interactive)
{
......@@ -4066,17 +4071,19 @@ static int com_source(String *buffer, char *line)
status.file_name=source_name;
glob_buffer.length(0); // Empty command buffer
ignore_errors= !batch_abort_on_error;
in_com_source= 1;
error= read_and_execute(false);
ignore_errors= save_ignore_errors;
status=old_status; // Continue as before
in_com_source= aborted= 0;
my_fclose(sql_file,MYF(0));
batch_readline_end(line_buff);
/*
If we got an error during source operation, don't abort the client
if ignore_errors is set
*/
if (error && batch_abort_on_error && ignore_errors)
error= -1;
if (error && !batch_abort_on_error && ignore_errors)
error= -1; // Ignore error
return error;
}
......
......@@ -1809,5 +1809,22 @@ SELECT MAX(t2.a) FROM t2 LEFT JOIN t1 ON t2.a = t1.a;
MAX(t2.a)
2
DROP TABLE t1, t2;
CREATE TABLE t1 (a int(11) NOT NULL);
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (
key_col int(11) NOT NULL,
KEY (key_col)
);
INSERT INTO t2 VALUES (1),(2);
select min(t2.key_col) from t1,t2 where t1.a=1;
min(t2.key_col)
1
select min(t2.key_col) from t1,t2 where t1.a > 1000;
min(t2.key_col)
NULL
select min(t2.key_col)+1 from t1,t2 where t1.a> 1000;
min(t2.key_col)+1
NULL
drop table t1,t2;
#
# End of 5.1 tests
......@@ -59,3 +59,26 @@ FROM t3 WHERE 1 = 0 GROUP BY 1;
(SELECT 1 FROM t1,t2 WHERE t2.b > t3.b)
DROP TABLE t1,t2,t3;
End of 5.0 tests.
CREATE TABLE t1 (col_int_nokey int(11) NOT NULL, col_varchar_nokey varchar(1) NOT NULL) engine=myisam;
INSERT INTO t1 VALUES (2,'s'),(0,'v'),(2,'s');
CREATE TABLE t2 (
pk int(11) NOT NULL AUTO_INCREMENT,
`col_int_key` int(11) NOT NULL,
col_varchar_key varchar(1) NOT NULL,
PRIMARY KEY (pk),
KEY `col_int_key` (`col_int_key`),
KEY `col_varchar_key` (`col_varchar_key`)
) ENGINE=MyISAM;
INSERT INTO t2 VALUES (4,10,'g'), (5,20,'v');
SELECT t1.col_int_nokey,(SELECT MIN( t2_a.col_int_key ) FROM t2 t2_a, t2 t2_b, t1 t1_a WHERE t1_a.col_varchar_nokey = t2_b.col_varchar_key and t1.col_int_nokey ) as sub FROM t1;
col_int_nokey sub
2 10
0 NULL
2 10
SELECT t1.col_int_nokey,(SELECT MIN( t2_a.col_int_key ) +1 FROM t2 t2_a, t2 t2_b, t1 t1_a WHERE t1_a.col_varchar_nokey = t2_b.col_varchar_key and t1.col_int_nokey ) as sub FROM t1;
col_int_nokey sub
2 11
0 NULL
2 11
DROP TABLE t1,t2;
End of 5.1 tests.
......@@ -1219,6 +1219,23 @@ EXPLAIN SELECT MAX(t2.a) FROM t2 LEFT JOIN t1 ON t2.a = t1.a;
SELECT MAX(t2.a) FROM t2 LEFT JOIN t1 ON t2.a = t1.a;
DROP TABLE t1, t2;
#
# min() returns wrong value when used in expression when there is no matching
# rows
#
CREATE TABLE t1 (a int(11) NOT NULL);
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (
key_col int(11) NOT NULL,
KEY (key_col)
);
INSERT INTO t2 VALUES (1),(2);
select min(t2.key_col) from t1,t2 where t1.a=1;
select min(t2.key_col) from t1,t2 where t1.a > 1000;
select min(t2.key_col)+1 from t1,t2 where t1.a> 1000;
drop table t1,t2;
--echo #
......
......@@ -62,3 +62,29 @@ FROM t3 WHERE 1 = 0 GROUP BY 1;
DROP TABLE t1,t2,t3;
--echo End of 5.0 tests.
#
# Fix for LP#612894
# Some aggregate functions (such as MIN MAX) work incorrectly in subqueries
# after getting NULL value
#
CREATE TABLE t1 (col_int_nokey int(11) NOT NULL, col_varchar_nokey varchar(1) NOT NULL) engine=myisam;
INSERT INTO t1 VALUES (2,'s'),(0,'v'),(2,'s');
CREATE TABLE t2 (
pk int(11) NOT NULL AUTO_INCREMENT,
`col_int_key` int(11) NOT NULL,
col_varchar_key varchar(1) NOT NULL,
PRIMARY KEY (pk),
KEY `col_int_key` (`col_int_key`),
KEY `col_varchar_key` (`col_varchar_key`)
) ENGINE=MyISAM;
INSERT INTO t2 VALUES (4,10,'g'), (5,20,'v');
SELECT t1.col_int_nokey,(SELECT MIN( t2_a.col_int_key ) FROM t2 t2_a, t2 t2_b, t1 t1_a WHERE t1_a.col_varchar_nokey = t2_b.col_varchar_key and t1.col_int_nokey ) as sub FROM t1;
SELECT t1.col_int_nokey,(SELECT MIN( t2_a.col_int_key ) +1 FROM t2 t2_a, t2 t2_b, t1 t1_a WHERE t1_a.col_varchar_nokey = t2_b.col_varchar_key and t1.col_int_nokey ) as sub FROM t1;
DROP TABLE t1,t2;
--echo End of 5.1 tests.
......@@ -18,7 +18,7 @@
while (<>)
{
s/^T@[0-9]+://g;
s/^T@[0-9]+\s*://g;
s/0x[0-9a-f]+(\s|\n|\))/#$1/g;
s/size: [0-9]+/size: #/g;
print $_;
......
......@@ -852,6 +852,7 @@ class Item {
set value of aggregate function in case of no rows for grouping were found
*/
virtual void no_rows_in_result() {}
virtual void restore_to_before_no_rows_in_result() {}
virtual Item *copy_or_same(THD *thd) { return this; }
virtual Item *copy_andor_structure(THD *thd) { return this; }
virtual Item *real_item() { return this; }
......@@ -908,6 +909,21 @@ class Item {
virtual bool register_field_in_read_map(uchar *arg) { return 0; }
virtual bool enumerate_field_refs_processor(uchar *arg) { return 0; }
virtual bool mark_as_eliminated_processor(uchar *arg) { return 0; }
/* To call bool function for all arguments */
struct bool_func_call_args
{
Item *original_func_item;
void (Item::*bool_function)();
};
bool call_bool_func_processor(uchar *org_item)
{
bool_func_call_args *info= (bool_func_call_args*) org_item;
/* Avoid recursion, as walk also calls for original item */
if (info->original_func_item != this)
(this->*(info->bool_function))();
return FALSE;
}
/*
Check if a partition function is allowed
SYNOPSIS
......@@ -2321,6 +2337,14 @@ class Item_ref :public Item_ident
return (*ref)->walk(processor, walk_subquery, arg) ||
(this->*processor)(arg);
}
void no_rows_in_result()
{
(*ref)->no_rows_in_result();
}
void restore_to_before_no_rows_in_result()
{
(*ref)->restore_to_before_no_rows_in_result();
}
virtual void print(String *str, enum_query_type query_type);
bool result_as_longlong()
{
......
......@@ -217,6 +217,21 @@ class Item_func :public Item_result_field
{
return functype() == *(Functype *) arg;
}
void no_rows_in_result()
{
bool_func_call_args info;
info.original_func_item= this;
info.bool_function= &Item::no_rows_in_result;
walk(&Item::call_bool_func_processor, FALSE, (uchar*) &info);
}
void restore_to_before_no_rows_in_result()
{
bool_func_call_args info;
info.original_func_item= this;
info.bool_function= &Item::restore_to_before_no_rows_in_result;
walk(&Item::call_bool_func_processor, FALSE, (uchar*) &info);
}
};
......
......@@ -1638,8 +1638,22 @@ void Item_sum_hybrid::cleanup()
void Item_sum_hybrid::no_rows_in_result()
{
was_values= FALSE;
clear();
/* We may be called here twice in case of ref field in function */
if (was_values)
{
was_values= FALSE;
was_null_value= value->null_value;
clear();
}
}
void Item_sum_hybrid::restore_to_before_no_rows_in_result()
{
if (!was_values)
{
was_values= TRUE;
null_value= value->null_value= was_null_value;
}
}
......
......@@ -496,7 +496,7 @@ class Item_sum_distinct :public Item_sum_num
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
void reset_field() {} // not used
void update_field() {} // not used
virtual void no_rows_in_result() {}
void no_rows_in_result() {}
void fix_length_and_dec();
enum Item_result result_type () const { return val.traits->type(); }
virtual void calculate_val_and_count();
......@@ -845,6 +845,7 @@ class Item_sum_hybrid :public Item_sum
enum_field_types hybrid_field_type;
int cmp_sign;
bool was_values; // Set if we have found at least one row (for max/min only)
bool was_null_value;
public:
Item_sum_hybrid(Item *item_par,int sign)
......@@ -876,6 +877,7 @@ class Item_sum_hybrid :public Item_sum
void cleanup();
bool any_value() { return was_values; }
void no_rows_in_result();
void restore_to_before_no_rows_in_result();
Field *create_tmp_field(bool group, TABLE *table,
uint convert_blob_length);
};
......
......@@ -1688,6 +1688,16 @@ JOIN::reinit()
func->clear();
}
if (no_rows_in_result_called)
{
/* Reset effect of possible no_rows_in_result() */
List_iterator_fast<Item> it(fields_list);
Item *item;
no_rows_in_result_called= 0;
while ((item= it++))
item->restore_to_before_no_rows_in_result();
}
DBUG_RETURN(0);
}
......@@ -12681,8 +12691,11 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
List_iterator_fast<Item> it(*join->fields);
Item *item;
DBUG_PRINT("info", ("no matching rows"));
/* No matching rows for group function */
join->clear();
join->no_rows_in_result_called= 1;
while ((item= it++))
item->no_rows_in_result();
......
......@@ -365,24 +365,31 @@ class JOIN :public Sql_alloc
the number of rows in it may vary from one subquery execution to another.
*/
bool no_const_tables;
/*
This flag is set if we call no_rows_in_result() as par of end_group().
This is used as a simple speed optimization to avoiding calling
restore_no_rows_in_result() in ::reinit()
*/
bool no_rows_in_result_called;
/**
Copy of this JOIN to be used with temporary tables.
tmp_join is used when the JOIN needs to be "reusable" (e.g. in a subquery
that gets re-executed several times) and we know will use temporary tables
for materialization. The materialization to a temporary table overwrites the
JOIN structure to point to the temporary table after the materialization is
done. This is where tmp_join is used : it's a copy of the JOIN before the
materialization and is used in restoring before re-execution by overwriting
the current JOIN structure with the saved copy.
Because of this we should pay extra care of not freeing up helper structures
that are referenced by the original contents of the JOIN. We can check for
this by making sure the "current" join is not the temporary copy, e.g.
!tmp_join || tmp_join != join
tmp_join is used when the JOIN needs to be "reusable" (e.g. in a
subquery that gets re-executed several times) and we know will use
temporary tables for materialization. The materialization to a
temporary table overwrites the JOIN structure to point to the
temporary table after the materialization is done. This is where
tmp_join is used : it's a copy of the JOIN before the
materialization and is used in restoring before re-execution by
overwriting the current JOIN structure with the saved copy.
Because of this we should pay extra care of not freeing up helper
structures that are referenced by the original contents of the
JOIN. We can check for this by making sure the "current" join is
not the temporary copy, e.g. !tmp_join || tmp_join != join
We should free these sub-structures at JOIN::destroy() if the "current" join
has a copy is not that copy.
We should free these sub-structures at JOIN::destroy() if the
"current" join has a copy is not that copy.
*/
JOIN *tmp_join;
ROLLUP rollup; ///< Used with rollup
......@@ -512,6 +519,7 @@ class JOIN :public Sql_alloc
optimized= 0;
cond_equal= 0;
group_optimized_away= 0;
no_rows_in_result_called= 0;
all_fields= fields_arg;
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
......
......@@ -1814,7 +1814,7 @@ int ha_maria::enable_indexes(uint mode)
"retrying",
my_errno, param.db_name, param.table_name);
/* This should never fail normally */
DBUG_ASSERT(0);
DBUG_ASSERT(thd->killed != 0);
/* Repairing by sort failed. Now try standard repair method. */
param.testflag &= ~T_REP_BY_SORT;
error= (repair(thd, &param, 0) != HA_ADMIN_OK);
......
......@@ -2063,6 +2063,13 @@ my_bool _ma_bitmap_set_full_page_bits(MARIA_HA *info,
safe_mutex_assert_owner(&info->s->bitmap.bitmap_lock);
bitmap_page= page - page % bitmap->pages_covered;
if (page == bitmap_page ||
page + page_count >= bitmap_page + bitmap->pages_covered)
{
DBUG_ASSERT(0); /* Wrong in data */
DBUG_RETURN(1);
}
if (bitmap_page != bitmap->page &&
_ma_change_bitmap_page(info, bitmap, bitmap_page))
DBUG_RETURN(1);
......
This diff is collapsed.
......@@ -64,8 +64,9 @@ void _ma_unpin_all_pages(MARIA_HA *info, LSN undo_lsn)
builds.
*/
#ifdef EXTRA_DEBUG
DBUG_ASSERT(!pinned_page->changed ||
undo_lsn != LSN_IMPOSSIBLE || !info->s->now_transactional);
DBUG_ASSERT((!pinned_page->changed ||
undo_lsn != LSN_IMPOSSIBLE || !info->s->now_transactional) ||
(info->s->state.changed & STATE_CRASHED));
#endif
pagecache_unlock_by_link(info->s->pagecache, pinned_page->link,
pinned_page->unlock, PAGECACHE_UNPIN,
......
......@@ -2397,6 +2397,7 @@ static int run_redo_phase(LSN lsn, LSN lsn_end, enum maria_apply_log_way apply)
struct st_translog_scanner_data scanner;
int len;
uint i;
DBUG_ENTER("run_redo_phase");
/* install hooks for execution */
#define install_redo_exec_hook(R) \
......@@ -2461,7 +2462,7 @@ static int run_redo_phase(LSN lsn, LSN lsn_end, enum maria_apply_log_way apply)
{
tprint(tracef, "checkpoint address refers to the log end log or "
"log is empty, nothing to do.\n");
return 0;
DBUG_RETURN(0);
}
len= translog_read_record_header(lsn, &rec);
......@@ -2469,12 +2470,12 @@ static int run_redo_phase(LSN lsn, LSN lsn_end, enum maria_apply_log_way apply)
if (len == RECHEADER_READ_ERROR)
{
eprint(tracef, "Failed to read header of the first record.");
return 1;
DBUG_RETURN(1);
}
if (translog_scanner_init(lsn, 1, &scanner, 1))
{
tprint(tracef, "Scanner init failed\n");
return 1;
DBUG_RETURN(1);
}
for (i= 1;;i++)
{
......@@ -2527,7 +2528,7 @@ static int run_redo_phase(LSN lsn, LSN lsn_end, enum maria_apply_log_way apply)
LSN_IN_PARTS(rec2.lsn));
translog_destroy_scanner(&scanner);
translog_free_record_header(&rec);
return(0);
DBUG_RETURN(0);
}
if (translog_scanner_init(rec2.lsn, 1, &scanner2, 1))
......@@ -2625,12 +2626,12 @@ static int run_redo_phase(LSN lsn, LSN lsn_end, enum maria_apply_log_way apply)
fflush(stderr);
procent_printed= 1;
}
return 0;
DBUG_RETURN(0);
err:
translog_destroy_scanner(&scanner);
translog_free_record_header(&rec);
return 1;
DBUG_RETURN(1);
}
......
......@@ -459,8 +459,9 @@ typedef struct st_maria_row
uint *null_field_lengths; /* All null field lengths */
ulong *blob_lengths; /* Length for each blob */
ulong min_length, normal_length, char_length, varchar_length;
ulong blob_length, head_length, total_length;
ulong blob_length, total_length;
size_t extents_buffer_length; /* Size of 'extents' buffer */
uint head_length, header_length;
uint field_lengths_length; /* Length of data in field_lengths */
uint extents_count; /* number of extents in 'extents' */
uint full_page_count, tail_count; /* For maria_chk */
......
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