Commit 15a42a0a authored by Marko Mäkelä's avatar Marko Mäkelä

Merge 10.6 into 10.9

parents ecd23f62 2855bc53
......@@ -299,6 +299,7 @@ ENDIF()
# MDEV-24629, we need it outside of ELSIFs
IF(RPM MATCHES "fedora")
ALTERNATIVE_NAME("common" "mariadb-connector-c-config" ${MARIADB_CONNECTOR_C_VERSION}-1)
ALTERNATIVE_NAME("shared" "mariadb-connector-c" ${MARIADB_CONNECTOR_C_VERSION}-1)
ENDIF()
SET(PYTHON_SHEBANG "/usr/bin/python3" CACHE STRING "python shebang")
......
#
# MDEV-30680 Warning: Memory not freed: 280 on mangled query, LeakSanitizer: detected memory leaks
#
BEGIN NOT ATOMIC
IF SCALAR() expected_THEN_here;
END
$$
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'expected_THEN_here;
END' at line 2
BEGIN NOT ATOMIC
WHILE SCALAR() expected_DO_here;
END
$$
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'expected_DO_here;
END' at line 2
BEGIN NOT ATOMIC
REPEAT SELECT 1; UNTIL SCALAR() expected_END_here;
END
$$
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'expected_END_here;
END' at line 2
#
# MDEV-31578 DECLARE CURSOR: "Memory not freed: 280 bytes lost" on syntax error
#
BEGIN NOT ATOMIC
DECLARE cur CURSOR (a INT) FOR SELECT a+1;
OPEN cur(sp_followed_by_syntax_error();
CLOSE cur;
END;
$$
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ';
CLOSE cur;
END' at line 3
BEGIN NOT ATOMIC
DECLARE cur CURSOR (a INT) FOR SELECT a+1;
OPEN cur(1,sp_followed_by_syntax_error();
CLOSE cur;
END;
$$
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ';
CLOSE cur;
END' at line 3
--echo #
--echo # MDEV-30680 Warning: Memory not freed: 280 on mangled query, LeakSanitizer: detected memory leaks
--echo #
DELIMITER $$;
--error ER_PARSE_ERROR
BEGIN NOT ATOMIC
IF SCALAR() expected_THEN_here;
END
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_PARSE_ERROR
BEGIN NOT ATOMIC
WHILE SCALAR() expected_DO_here;
END
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_PARSE_ERROR
BEGIN NOT ATOMIC
REPEAT SELECT 1; UNTIL SCALAR() expected_END_here;
END
$$
DELIMITER ;$$
--echo #
--echo # MDEV-31578 DECLARE CURSOR: "Memory not freed: 280 bytes lost" on syntax error
--echo #
DELIMITER $$;
--error ER_PARSE_ERROR
BEGIN NOT ATOMIC
DECLARE cur CURSOR (a INT) FOR SELECT a+1;
OPEN cur(sp_followed_by_syntax_error();
CLOSE cur;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_PARSE_ERROR
BEGIN NOT ATOMIC
DECLARE cur CURSOR (a INT) FOR SELECT a+1;
OPEN cur(1,sp_followed_by_syntax_error();
CLOSE cur;
END;
$$
DELIMITER ;$$
......@@ -620,20 +620,24 @@ class sp_head :private Query_arena,
restore_lex(THD *thd)
{
DBUG_ENTER("sp_head::restore_lex");
/*
There is no a need to free the current thd->lex here.
- In the majority of the cases restore_lex() is called
on success and thd->lex does not need to be deleted.
- In cases when restore_lex() is called on error,
e.g. from sp_create_assignment_instr(), thd->lex is
already linked to some sp_instr_xxx (using sp_lex_keeper).
Note, we don't get to here in case of a syntax error
when the current thd->lex is not yet completely
initialized and linked. It gets automatically deleted
by the Bison %destructor in sql_yacc.yy.
*/
LEX *oldlex= (LEX *) m_lex.pop();
if (!oldlex)
DBUG_RETURN(false); // Nothing to restore
LEX *sublex= thd->lex;
// This restores thd->lex and thd->stmt_lex
if (thd->restore_from_local_lex_to_old_lex(oldlex))
DBUG_RETURN(true);
if (!sublex->sp_lex_in_use)
{
sublex->sphead= NULL;
lex_end(sublex);
delete sublex;
}
DBUG_RETURN(false);
DBUG_RETURN(thd->restore_from_local_lex_to_old_lex(oldlex));
}
/**
......
......@@ -486,11 +486,15 @@ bool sp_create_assignment_instr(THD *thd, bool no_lookahead,
be deleted by the destructor ~sp_instr_xxx().
So we should remove "lex" from the stack sp_head::m_lex,
to avoid double free.
Note, in case "lex" is not owned by any sp_instr_xxx,
it's also safe to remove it from the stack right now.
So we can remove it unconditionally, without testing lex->sp_lex_in_use.
*/
lex->sphead->restore_lex(thd);
/*
No needs for "delete lex" here: "lex" is already linked
to the sp_instr_stmt (using sp_lex_keeper) instance created by
the call for new_sp_instr_stmt() above. It will be freed
by ~sp_head/~sp_instr/~sp_lex_keeper during THD::end_statement().
*/
DBUG_ASSERT(lex->sp_lex_in_use); // used by sp_instr_stmt
return true;
}
enum_var_type inner_option_type= lex->option_type;
......@@ -6831,7 +6835,6 @@ bool LEX::sp_for_loop_implicit_cursor_statement(THD *thd,
if (unlikely(!(bounds->m_index=
new (thd->mem_root) sp_assignment_lex(thd, this))))
return true;
bounds->m_index->sp_lex_in_use= true;
sphead->reset_lex(thd, bounds->m_index);
DBUG_ASSERT(thd->lex != this);
/*
......
......@@ -3471,6 +3471,12 @@ struct LEX: public Query_tables_list
sp_head *sphead;
sp_name *spname;
void delete_if_not_sp_lex_in_use()
{
if (!sp_lex_in_use)
delete this;
}
sp_pcontext *spcont;
st_sp_chistics sp_chistics;
......
......@@ -10406,6 +10406,15 @@ bool parse_sql(THD *thd, Parser_state *parser_state,
bool mysql_parse_status= thd->variables.sql_mode & MODE_ORACLE
? ORAparse(thd) : MYSQLparse(thd);
if (mysql_parse_status)
/*
Restore the original LEX if it was replaced when parsing
a stored procedure. We must ensure that a parsing error
does not leave any side effects in the THD.
*/
LEX::cleanup_lex_after_parse_error(thd);
DBUG_ASSERT(opt_bootstrap || mysql_parse_status ||
thd->lex->select_stack_top == 0);
thd->lex->current_select= thd->lex->first_select_lex();
......
......@@ -99,7 +99,6 @@ int yylex(void *yylval, void *yythd);
#define MYSQL_YYABORT \
do \
{ \
LEX::cleanup_lex_after_parse_error(thd); \
YYABORT; \
} while (0)
......@@ -150,13 +149,6 @@ static Item* escape(THD *thd)
static void yyerror(THD *thd, const char *s)
{
/*
Restore the original LEX if it was replaced when parsing
a stored procedure. We must ensure that a parsing error
does not leave any side effects in the THD.
*/
LEX::cleanup_lex_after_parse_error(thd);
/* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
s= ER_THD(thd, ER_SYNTAX_ERROR);
......@@ -1554,6 +1546,19 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <expr_lex>
expr_lex
%destructor
{
/*
In case of a syntax/oom error let's free the sp_expr_lex
instance, but only if it has not been linked to any structures
such as sp_instr_jump_if_not::m_lex_keeper yet, e.g.:
IF f1() THEN1
i.e. THEN1 came instead of the expected THEN causing a syntax error.
*/
if (!$$->sp_lex_in_use)
delete $$;
} <expr_lex>
%type <assignment_lex>
assignment_source_lex
assignment_source_expr
......@@ -1563,6 +1568,21 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
cursor_actual_parameters
opt_parenthesized_cursor_actual_parameters
%destructor
{
if ($$)
{
sp_assignment_lex *elem;
List_iterator<sp_assignment_lex> li(*$$);
while ((elem= li++))
{
if (!elem->sp_lex_in_use)
delete elem;
}
}
} <sp_assignment_lex_list>
%type <var_type>
option_type opt_var_type opt_var_ident_type
......@@ -3857,7 +3877,6 @@ expr_lex:
expr
{
$$= $<expr_lex>1;
$$->sp_lex_in_use= true;
$$->set_item($2);
Lex->pop_select(); //min select
if (Lex->check_cte_dependencies_and_resolve_references())
......@@ -3889,7 +3908,6 @@ assignment_source_expr:
{
DBUG_ASSERT($1 == thd->lex);
$$= $1;
$$->sp_lex_in_use= true;
$$->set_item_and_free_list($3, thd->free_list);
thd->free_list= NULL;
Lex->pop_select(); //min select
......@@ -3910,7 +3928,6 @@ for_loop_bound_expr:
{
DBUG_ASSERT($1 == thd->lex);
$$= $1;
$$->sp_lex_in_use= true;
$$->set_item_and_free_list($3, NULL);
Lex->pop_select(); //main select
if (unlikely($$->sphead->restore_lex(thd)))
......
......@@ -362,8 +362,20 @@ static bool fil_node_open_file_low(fil_node_t *node)
: OS_FILE_OPEN | OS_FILE_ON_ERROR_NO_EXIT,
OS_FILE_AIO, type,
srv_read_only_mode, &success);
if (success)
if (node->is_open())
{
ut_ad(success);
#ifndef _WIN32
if (!node->space->id && !srv_read_only_mode && my_disable_locking &&
os_file_lock(node->handle, node->name))
{
os_file_close(node->handle);
node->handle= OS_FILE_CLOSED;
return false;
}
#endif
break;
}
/* The following call prints an error message */
if (os_file_get_last_error(true) == EMFILE + 100 &&
......
......@@ -243,21 +243,11 @@ mysql_mutex_t ibuf_mutex,
ibuf_pessimistic_insert_mutex;
/** The area in pages from which contract looks for page numbers for merge */
const ulint IBUF_MERGE_AREA = 8;
constexpr ulint IBUF_MERGE_AREA = 8;
/** Inside the merge area, pages which have at most 1 per this number less
buffered entries compared to maximum volume that can buffered for a single
page are merged along with the page whose buffer became full */
const ulint IBUF_MERGE_THRESHOLD = 4;
/** In ibuf_contract at most this number of pages is read to memory in one
batch, in order to merge the entries for them in the insert buffer */
const ulint IBUF_MAX_N_PAGES_MERGED = IBUF_MERGE_AREA;
/** If the combined size of the ibuf trees exceeds ibuf.max_size by
this many pages, we start to contract it synchronous contract, but do
not insert */
const ulint IBUF_CONTRACT_DO_NOT_INSERT = 10;
/** In ibuf_contract() at most this number of pages is read to memory in one
batch, in order to merge the entries for them in the change buffer */
constexpr ulint IBUF_MAX_N_PAGES_MERGED = IBUF_MERGE_AREA;
/* TODO: how to cope with drop table if there are records in the insert
buffer for the indexes of the table? Is there actually any problem,
......@@ -2005,11 +1995,11 @@ ibuf_free_excess_pages(void)
}
#ifdef UNIV_DEBUG
# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,pages,n_stored) \
ibuf_get_merge_page_nos_func(contract,rec,mtr,ids,pages,n_stored)
# define ibuf_get_merge_page_nos(rec,mtr,ids,pages,n_stored) \
ibuf_get_merge_page_nos_func(rec,mtr,ids,pages,n_stored)
#else /* UNIV_DEBUG */
# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,pages,n_stored) \
ibuf_get_merge_page_nos_func(contract,rec,ids,pages,n_stored)
# define ibuf_get_merge_page_nos(rec,mtr,ids,pages,n_stored) \
ibuf_get_merge_page_nos_func(rec,ids,pages,n_stored)
#endif /* UNIV_DEBUG */
/*********************************************************************//**
......@@ -2020,10 +2010,6 @@ static
ulint
ibuf_get_merge_page_nos_func(
/*=========================*/
ibool contract,/*!< in: TRUE if this function is called to
contract the tree, FALSE if this is called
when a single page becomes full and we look
if it pays to read also nearby pages */
const rec_t* rec, /*!< in: insert buffer record */
#ifdef UNIV_DEBUG
mtr_t* mtr, /*!< in: mini-transaction holding rec */
......@@ -2154,22 +2140,10 @@ ibuf_get_merge_page_nos_func(
|| rec_page_no != prev_page_no)
&& (prev_space_id != 0 || prev_page_no != 0)) {
if (contract
|| (prev_page_no == first_page_no
&& prev_space_id == first_space_id)
|| (volume_for_page
> ((IBUF_MERGE_THRESHOLD - 1)
* 4U << srv_page_size_shift
/ IBUF_PAGE_SIZE_PER_FREE_SPACE)
/ IBUF_MERGE_THRESHOLD)) {
space_ids[*n_stored] = prev_space_id;
page_nos[*n_stored] = prev_page_no;
(*n_stored)++;
sum_volumes += volume_for_page;
}
space_ids[*n_stored] = prev_space_id;
page_nos[*n_stored] = prev_page_no;
(*n_stored)++;
sum_volumes += volume_for_page;
if (rec_space_id != first_space_id
|| rec_page_no / IBUF_MERGE_AREA
......@@ -2429,7 +2403,7 @@ static void ibuf_read_merge_pages(const uint32_t* space_ids,
@return a lower limit for the combined size in bytes of entries which
will be merged from ibuf trees to the pages read
@retval 0 if ibuf.empty */
ulint ibuf_contract()
ATTRIBUTE_COLD ulint ibuf_contract()
{
if (UNIV_UNLIKELY(!ibuf.index)) return 0;
mtr_t mtr;
......@@ -2461,10 +2435,8 @@ ulint ibuf_contract()
}
ulint n_pages = 0;
sum_sizes = ibuf_get_merge_page_nos(TRUE,
btr_cur_get_rec(&cur), &mtr,
space_ids,
page_nos, &n_pages);
sum_sizes = ibuf_get_merge_page_nos(btr_cur_get_rec(&cur), &mtr,
space_ids, page_nos, &n_pages);
ibuf_mtr_commit(&mtr);
ibuf_read_merge_pages(space_ids, page_nos, n_pages);
......@@ -2554,30 +2526,6 @@ ibuf_merge_space(
return(n_pages);
}
/*********************************************************************//**
Contract insert buffer trees after insert if they are too big. */
UNIV_INLINE
void
ibuf_contract_after_insert(
/*=======================*/
ulint entry_size) /*!< in: size of a record which was inserted
into an ibuf tree */
{
/* dirty comparison, to avoid contention on ibuf_mutex */
if (ibuf.size < ibuf.max_size) {
return;
}
/* Contract at least entry_size many bytes */
ulint sum_sizes = 0;
ulint size;
do {
size = ibuf_contract();
sum_sizes += size;
} while (size > 0 && sum_sizes < entry_size);
}
/** Determine if a change buffer record has been encountered already.
@param rec change buffer record in the MySQL 5.5 format
@param hash hash table of encountered records
......@@ -3176,10 +3124,6 @@ ibuf_insert_low(
buf_block_t* block = NULL;
page_t* root;
dberr_t err;
ibool do_merge;
uint32_t space_ids[IBUF_MAX_N_PAGES_MERGED];
uint32_t page_nos[IBUF_MAX_N_PAGES_MERGED];
ulint n_stored;
mtr_t mtr;
mtr_t bitmap_mtr;
......@@ -3190,28 +3134,9 @@ ibuf_insert_low(
ut_ad(page_id.space() == index->table->space_id);
ut_a(op < IBUF_OP_COUNT);
do_merge = FALSE;
/* Perform dirty comparison of ibuf.max_size and ibuf.size to
reduce ibuf_mutex contention. This should be OK; at worst we
are doing some excessive ibuf_contract() or occasionally
skipping an ibuf_contract(). */
const ulint max_size = ibuf.max_size;
if (max_size == 0) {
return(DB_STRONG_FAIL);
}
if (ibuf.size >= max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
/* Insert buffer is now too big, contract it but do not try
to insert */
#ifdef UNIV_IBUF_DEBUG
fputs("Ibuf too big\n", stderr);
#endif
ibuf_contract();
reduce ibuf_mutex contention. */
if (ibuf.size >= ibuf.max_size) {
return(DB_STRONG_FAIL);
}
......@@ -3263,17 +3188,6 @@ ibuf_insert_low(
ibuf_mtr_commit(&mtr);
ut_free(pcur.old_rec_buf);
mem_heap_free(heap);
if (err == DB_SUCCESS && mode == BTR_INSERT_TREE) {
ibuf_contract_after_insert(entry_size);
}
if (do_merge) {
#ifdef UNIV_IBUF_DEBUG
ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED);
#endif
ibuf_read_merge_pages(space_ids, page_nos, n_stored);
}
return err;
}
......@@ -3363,15 +3277,6 @@ ibuf_insert_low(
bits)) {
/* Release the bitmap page latch early. */
ibuf_mtr_commit(&bitmap_mtr);
/* It may not fit */
do_merge = TRUE;
ibuf_get_merge_page_nos(FALSE,
btr_pcur_get_rec(&pcur), &mtr,
space_ids,
page_nos, &n_stored);
goto fail_exit;
}
}
......
......@@ -242,9 +242,11 @@ enum rec_leaf_format {
REC_LEAF_INSTANT
};
#if defined __GNUC__ && !defined __clang__ && __GNUC__ < 12
#if defined __GNUC__ && !defined __clang__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wconversion" /* GCC 5 to 11 need this */
# if __GNUC__ < 12 || defined WITH_UBSAN
# pragma GCC diagnostic ignored "-Wconversion"
# endif
#endif
/** Determine the offset to each field in a leaf-page record
in ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED.
......@@ -1707,7 +1709,7 @@ rec_convert_dtuple_to_rec_new(
REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
return buf;
}
#if defined __GNUC__ && !defined __clang__ && __GNUC__ < 11
#if defined __GNUC__ && !defined __clang__
# pragma GCC diagnostic pop /* ignored "-Wconversion" */
#endif
......
......@@ -4,11 +4,11 @@ for child3
MDEV-6268 SPIDER table with no COMMENT clause causes queries to wait forever
CREATE SERVER srv FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root');
CREATE SERVER $srv FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root');
create table t2 (c int);
create table t1 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t2"';
create table t0 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t1"';
alter table t2 ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t0"';
create table t1 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv_self_reference_multi",TABLE "t2"';
create table t0 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv_self_reference_multi",TABLE "t1"';
alter table t2 ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv_self_reference_multi",TABLE "t0"';
select * from t0;
ERROR HY000: An infinite loop is detected when opening table test.t0
select * from t1;
......
......@@ -8,12 +8,12 @@
--echo MDEV-6268 SPIDER table with no COMMENT clause causes queries to wait forever
--echo
--replace_regex /SOCKET ".*"/SOCKET "$MASTER_1_MYSOCK"/
eval CREATE SERVER srv FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root');
--let $srv=srv_self_reference_multi
evalp CREATE SERVER $srv FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root');
create table t2 (c int);
create table t1 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t2"';
create table t0 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t1"';
alter table t2 ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t0"';
eval create table t1 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "$srv",TABLE "t2"';
eval create table t0 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "$srv",TABLE "t1"';
eval alter table t2 ENGINE=Spider COMMENT='WRAPPER "mysql", srv "$srv",TABLE "t0"';
--error 12719
select * from t0;
--error 12719
......
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