mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-3816 init-file stops getting executed if a long enough line is encountered; on a debug version, assertion `! is_set() || can_overwrite_status' fails
backport improved bootstrap error handling from 5.6 Was: revno: 3768.1.1 committer: Christopher Powers <chris.powers@oracle.com> timestamp: Wed 2012-05-02 22:16:40 -0500 message: Bug#11766342 INITIAL DB CREATION FAILS ON WINDOWS WITH AN ASSERT IN SQL_ERROR.CC Improved bootstrap error handling: - Detect and report file i/o errors - Report query size errors with nearest query text
This commit is contained in:
3
mysql-test/r/init_file_longline_3816.result
Normal file
3
mysql-test/r/init_file_longline_3816.result
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
select count(*) from t4;
|
||||||
|
count(*)
|
||||||
|
0
|
8
mysql-test/std_data/init_file_longline_3816.sql
Normal file
8
mysql-test/std_data/init_file_longline_3816.sql
Normal file
File diff suppressed because one or more lines are too long
1
mysql-test/t/init_file_longline_3816.opt
Normal file
1
mysql-test/t/init_file_longline_3816.opt
Normal file
@ -0,0 +1 @@
|
|||||||
|
--init-file=$MYSQL_TEST_DIR/std_data/init_file_longline_3816.sql
|
5
mysql-test/t/init_file_longline_3816.test
Normal file
5
mysql-test/t/init_file_longline_3816.test
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#
|
||||||
|
# MDEV-3816 init-file stops getting executed if a long enough line is encountered; on a debug version, assertion `! is_set() || can_overwrite_status' fails
|
||||||
|
#
|
||||||
|
select count(*) from t4;
|
||||||
|
|
@ -65,9 +65,12 @@ static void die(const char *fmt, ...)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *fgets_fn(char *buffer, size_t size, fgets_input_t input)
|
char *fgets_fn(char *buffer, size_t size, fgets_input_t input, int *error)
|
||||||
{
|
{
|
||||||
return fgets(buffer, size, (FILE*) input);
|
char *line= fgets(buffer, size, (FILE*) input);
|
||||||
|
if (error)
|
||||||
|
*error= (line == NULL) ? ferror((FILE*)input) : 0;
|
||||||
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_query(FILE *out, const char *query)
|
static void print_query(FILE *out, const char *query)
|
||||||
@ -116,6 +119,8 @@ int main(int argc, char *argv[])
|
|||||||
char* outfile_name= argv[3];
|
char* outfile_name= argv[3];
|
||||||
int rc;
|
int rc;
|
||||||
int query_length;
|
int query_length;
|
||||||
|
int error= 0;
|
||||||
|
char *err_ptr;
|
||||||
|
|
||||||
if (argc != 4)
|
if (argc != 4)
|
||||||
die("Usage: comp_sql <struct_name> <sql_filename> <c_filename>");
|
die("Usage: comp_sql <struct_name> <sql_filename> <c_filename>");
|
||||||
@ -136,14 +141,34 @@ int main(int argc, char *argv[])
|
|||||||
for ( ; ; )
|
for ( ; ; )
|
||||||
{
|
{
|
||||||
rc= read_bootstrap_query(query, &query_length,
|
rc= read_bootstrap_query(query, &query_length,
|
||||||
(fgets_input_t) in, fgets_fn);
|
(fgets_input_t) in, fgets_fn, &error);
|
||||||
|
|
||||||
if (rc == READ_BOOTSTRAP_ERROR)
|
|
||||||
die("Failed to read the bootstrap input file.\n");
|
|
||||||
|
|
||||||
if (rc == READ_BOOTSTRAP_EOF)
|
if (rc == READ_BOOTSTRAP_EOF)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (rc != READ_BOOTSTRAP_SUCCESS)
|
||||||
|
{
|
||||||
|
/* Get the most recent query text for reference. */
|
||||||
|
err_ptr= query + (query_length <= MAX_BOOTSTRAP_ERROR_LEN ?
|
||||||
|
0 : (query_length - MAX_BOOTSTRAP_ERROR_LEN));
|
||||||
|
switch (rc)
|
||||||
|
{
|
||||||
|
case READ_BOOTSTRAP_ERROR:
|
||||||
|
die("Failed to read the bootstrap input file. Return code (%d).\n"
|
||||||
|
"Last query: '%s'\n", error, err_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case READ_BOOTSTRAP_QUERY_SIZE:
|
||||||
|
die("Failed to read the boostrap input file. Query size exceeded %d bytes.\n"
|
||||||
|
"Last query: '%s'.\n", MAX_BOOTSTRAP_LINE_SIZE, err_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
die("Failed to read the boostrap input file. Unknown error.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
print_query(out, query);
|
print_query(out, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,24 +14,34 @@
|
|||||||
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
|
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "sql_bootstrap.h"
|
#include "sql_bootstrap.h"
|
||||||
|
|
||||||
int read_bootstrap_query(char *query, int *query_length,
|
int read_bootstrap_query(char *query, int *query_length,
|
||||||
fgets_input_t input, fgets_fn_t fgets_fn)
|
fgets_input_t input, fgets_fn_t fgets_fn, int *error)
|
||||||
{
|
{
|
||||||
char line_buffer[MAX_BOOTSTRAP_LINE_SIZE];
|
char line_buffer[MAX_BOOTSTRAP_LINE_SIZE];
|
||||||
const char *line;
|
const char *line;
|
||||||
int len;
|
int len;
|
||||||
int query_len= 0;
|
int query_len= 0;
|
||||||
|
int fgets_error= 0;
|
||||||
|
*error= 0;
|
||||||
|
|
||||||
for ( ; ; )
|
for ( ; ; )
|
||||||
{
|
{
|
||||||
line= (*fgets_fn)(line_buffer, sizeof(line_buffer), input);
|
line= (*fgets_fn)(line_buffer, sizeof(line_buffer), input, &fgets_error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
*error= fgets_error;
|
||||||
|
|
||||||
|
if (fgets_error != 0)
|
||||||
|
return READ_BOOTSTRAP_ERROR;
|
||||||
|
|
||||||
if (line == NULL)
|
if (line == NULL)
|
||||||
return (query_len ? READ_BOOTSTRAP_ERROR : READ_BOOTSTRAP_EOF);
|
return (query_len == 0) ? READ_BOOTSTRAP_EOF : READ_BOOTSTRAP_ERROR;
|
||||||
|
|
||||||
len= strlen(line);
|
len= strlen(line);
|
||||||
|
|
||||||
@ -67,10 +77,22 @@ int read_bootstrap_query(char *query, int *query_length,
|
|||||||
if (strncmp(line, "delimiter", 9) == 0)
|
if (strncmp(line, "delimiter", 9) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Append the current line to a multi line query. */
|
/* Append the current line to a multi line query. If the new line will make
|
||||||
|
the query too long, preserve the partial line to provide context for the
|
||||||
|
error message.
|
||||||
|
*/
|
||||||
if (query_len + len + 1 >= MAX_BOOTSTRAP_QUERY_SIZE)
|
if (query_len + len + 1 >= MAX_BOOTSTRAP_QUERY_SIZE)
|
||||||
return READ_BOOTSTRAP_ERROR;
|
{
|
||||||
|
int new_len= MAX_BOOTSTRAP_QUERY_SIZE - query_len - 1;
|
||||||
|
if ((new_len > 0) && (query_len < MAX_BOOTSTRAP_QUERY_SIZE))
|
||||||
|
{
|
||||||
|
memcpy(query + query_len, line, new_len);
|
||||||
|
query_len+= new_len;
|
||||||
|
}
|
||||||
|
query[query_len]= '\0';
|
||||||
|
*query_length= query_len;
|
||||||
|
return READ_BOOTSTRAP_QUERY_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
if (query_len != 0)
|
if (query_len != 0)
|
||||||
{
|
{
|
||||||
@ -78,8 +100,7 @@ int read_bootstrap_query(char *query, int *query_length,
|
|||||||
Append a \n to the current line, if any,
|
Append a \n to the current line, if any,
|
||||||
to preserve the intended presentation.
|
to preserve the intended presentation.
|
||||||
*/
|
*/
|
||||||
query[query_len]= '\n';
|
query[query_len++]= '\n';
|
||||||
query_len++;
|
|
||||||
}
|
}
|
||||||
memcpy(query + query_len, line, len);
|
memcpy(query + query_len, line, len);
|
||||||
query_len+= len;
|
query_len+= len;
|
||||||
@ -92,7 +113,7 @@ int read_bootstrap_query(char *query, int *query_length,
|
|||||||
*/
|
*/
|
||||||
query[query_len]= '\0';
|
query[query_len]= '\0';
|
||||||
*query_length= query_len;
|
*query_length= query_len;
|
||||||
return 0;
|
return READ_BOOTSTRAP_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,15 +29,18 @@
|
|||||||
Do not increase this size, use the multiline syntax instead.
|
Do not increase this size, use the multiline syntax instead.
|
||||||
*/
|
*/
|
||||||
#define MAX_BOOTSTRAP_LINE_SIZE 20000
|
#define MAX_BOOTSTRAP_LINE_SIZE 20000
|
||||||
|
#define MAX_BOOTSTRAP_ERROR_LEN 256
|
||||||
|
|
||||||
#define READ_BOOTSTRAP_EOF 1
|
#define READ_BOOTSTRAP_SUCCESS 0
|
||||||
#define READ_BOOTSTRAP_ERROR 2
|
#define READ_BOOTSTRAP_EOF 1
|
||||||
|
#define READ_BOOTSTRAP_ERROR 2
|
||||||
|
#define READ_BOOTSTRAP_QUERY_SIZE 3
|
||||||
|
|
||||||
typedef void *fgets_input_t;
|
typedef void *fgets_input_t;
|
||||||
typedef char * (*fgets_fn_t)(char *, size_t, fgets_input_t);
|
typedef char * (*fgets_fn_t)(char *, size_t, fgets_input_t, int *error);
|
||||||
|
|
||||||
int read_bootstrap_query(char *query, int *query_length,
|
int read_bootstrap_query(char *query, int *query_length,
|
||||||
fgets_input_t input, fgets_fn_t fgets_fn);
|
fgets_input_t input, fgets_fn_t fgets_fn, int *error);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -634,10 +634,13 @@ void execute_init_command(THD *thd, LEX_STRING *init_command,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static char *fgets_fn(char *buffer, size_t size, fgets_input_t input)
|
static char *fgets_fn(char *buffer, size_t size, fgets_input_t input, int *error)
|
||||||
{
|
{
|
||||||
MYSQL_FILE *in= static_cast<MYSQL_FILE*> (input);
|
MYSQL_FILE *in= static_cast<MYSQL_FILE*> (input);
|
||||||
return mysql_file_fgets(buffer, size, in);
|
char *line= mysql_file_fgets(buffer, size, in);
|
||||||
|
if (error)
|
||||||
|
*error= (line == NULL) ? ferror(in->m_file) : 0;
|
||||||
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -664,25 +667,53 @@ static void handle_bootstrap_impl(THD *thd)
|
|||||||
|
|
||||||
for ( ; ; )
|
for ( ; ; )
|
||||||
{
|
{
|
||||||
char buffer[MAX_BOOTSTRAP_QUERY_SIZE];
|
char buffer[MAX_BOOTSTRAP_QUERY_SIZE] = "";
|
||||||
int rc, length;
|
int rc, length;
|
||||||
char *query;
|
char *query;
|
||||||
|
int error= 0;
|
||||||
|
|
||||||
rc= read_bootstrap_query(buffer, &length, file, fgets_fn);
|
rc= read_bootstrap_query(buffer, &length, file, fgets_fn, &error);
|
||||||
|
|
||||||
if (rc == READ_BOOTSTRAP_ERROR)
|
if (rc == READ_BOOTSTRAP_EOF)
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
Check for bootstrap file errors. SQL syntax errors will be
|
||||||
|
caught below.
|
||||||
|
*/
|
||||||
|
if (rc != READ_BOOTSTRAP_SUCCESS)
|
||||||
{
|
{
|
||||||
thd->raise_error(ER_SYNTAX_ERROR);
|
/*
|
||||||
|
mysql_parse() may have set a successful error status for the previous
|
||||||
|
query. We must clear the error status to report the bootstrap error.
|
||||||
|
*/
|
||||||
|
thd->get_stmt_da()->reset_diagnostics_area();
|
||||||
|
|
||||||
|
/* Get the nearest query text for reference. */
|
||||||
|
char *err_ptr= buffer + (length <= MAX_BOOTSTRAP_ERROR_LEN ?
|
||||||
|
0 : (length - MAX_BOOTSTRAP_ERROR_LEN));
|
||||||
|
switch (rc)
|
||||||
|
{
|
||||||
|
case READ_BOOTSTRAP_ERROR:
|
||||||
|
my_printf_error(ER_UNKNOWN_ERROR, "Bootstrap file error, return code (%d). "
|
||||||
|
"Nearest query: '%s'", MYF(0), error, err_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case READ_BOOTSTRAP_QUERY_SIZE:
|
||||||
|
my_printf_error(ER_UNKNOWN_ERROR, "Boostrap file error. Query size "
|
||||||
|
"exceeded %d bytes near '%s'.", MYF(0),
|
||||||
|
MAX_BOOTSTRAP_LINE_SIZE, err_ptr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DBUG_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
thd->protocol->end_statement();
|
thd->protocol->end_statement();
|
||||||
bootstrap_error= 1;
|
bootstrap_error= 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == READ_BOOTSTRAP_EOF)
|
|
||||||
break;
|
|
||||||
|
|
||||||
DBUG_ASSERT(rc == 0);
|
|
||||||
|
|
||||||
query= (char *) thd->memdup_w_gap(buffer, length + 1,
|
query= (char *) thd->memdup_w_gap(buffer, length + 1,
|
||||||
thd->db_length + 1 +
|
thd->db_length + 1 +
|
||||||
QUERY_CACHE_DB_LENGTH_SIZE +
|
QUERY_CACHE_DB_LENGTH_SIZE +
|
||||||
|
Reference in New Issue
Block a user