summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorRucha Deodhar <rucha.deodhar@mariadb.com>2021-07-31 12:55:21 +0530
committerSergei Golubchik <serg@mariadb.org>2021-09-15 08:39:04 +0200
commit1be5520a3be38fd17850e4e908bc3225a145906b (patch)
treebd9bb41ceddd4383b8265bcccb8d1c380aa5fbaf /sql
parent8d08971c84036b2c4e508035ad93ad11021abdee (diff)
downloadmariadb-git-preview-10.7-MDEV-10075-insert-error-index.tar.gz
MDEV-10075: Provide index of error causing error in array INSERTpreview-10.7-MDEV-10075-insert-error-index
Extended the parser for GET DIAGNOSTICS to use ERROR_INDEX to get warning/error index. Error information is stored in Sql_condition. So it can be used to store the index of warning/error too. THD::current_insert_index keeps a track of count for each row that is processed or going to be inserted in the table (or first row in case of prepare phase). When an error occurs, first we need to fetch corrected error index (using correct_error_index()) for an error number. This is needed because in prepare phase, the error may not be because of rows/values. In such case, correct value of error_index should be 0. Once correct value if fetched, assign it to Sql_condition::error_index when the object is created during error/warning. This error_index variable is returned when ERROR_INDEX is used in GET DIAGNOSTICS.
Diffstat (limited to 'sql')
-rw-r--r--sql/lex.h1
-rw-r--r--sql/sp_rcontext.cc2
-rw-r--r--sql/sql_class.cc6
-rw-r--r--sql/sql_class.h23
-rw-r--r--sql/sql_error.cc3
-rw-r--r--sql/sql_error.h11
-rw-r--r--sql/sql_get_diagnostics.cc2
-rw-r--r--sql/sql_get_diagnostics.h3
-rw-r--r--sql/sql_insert.cc9
-rw-r--r--sql/sql_parse.cc1
-rw-r--r--sql/sql_prepare.cc4
-rw-r--r--sql/sql_signal.cc2
-rw-r--r--sql/sql_yacc.yy10
13 files changed, 69 insertions, 8 deletions
diff --git a/sql/lex.h b/sql/lex.h
index 8643197e862..57d8d807909 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -222,6 +222,7 @@ SYMBOL symbols[] = {
{ "ENUM", SYM(ENUM)},
{ "ERROR", SYM(ERROR_SYM)},
{ "ERRORS", SYM(ERRORS)},
+ { "ERROR_INDEX", SYM(ERROR_INDEX_SYM)},
{ "ESCAPE", SYM(ESCAPE_SYM)},
{ "ESCAPED", SYM(ESCAPED)},
{ "EVENT", SYM(EVENT_SYM)},
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index c4c19dd39f6..7170018c995 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -518,7 +518,7 @@ bool sp_rcontext::handle_sql_condition(THD *thd,
found_condition=
new (callers_arena->mem_root) Sql_condition(callers_arena->mem_root,
da->get_error_condition_identity(),
- da->message());
+ da->message(), 0);
}
}
else if (da->current_statement_warn_count())
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index c88bfc4c484..34d220aa27e 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -908,6 +908,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
org_charset= 0;
/* Restore THR_THD */
set_current_thd(old_THR_THD);
+ current_insert_index= 0;
}
@@ -1055,6 +1056,8 @@ Sql_condition* THD::raise_condition(uint sql_errno,
{
Diagnostics_area *da= get_stmt_da();
Sql_condition *cond= NULL;
+ ulonglong saved_error_index;
+
DBUG_ENTER("THD::raise_condition");
DBUG_ASSERT(level < Sql_condition::WARN_LEVEL_END);
@@ -1149,7 +1152,10 @@ Sql_condition* THD::raise_condition(uint sql_errno,
if (likely(!(is_fatal_error && (sql_errno == EE_OUTOFMEMORY ||
sql_errno == ER_OUTOFMEMORY))))
{
+ saved_error_index= this->current_insert_index;
+ this->current_insert_index= this->correct_error_index(sql_errno);
cond= da->push_warning(this, sql_errno, sqlstate, level, ucid, msg);
+ this->current_insert_index= saved_error_index;
}
DBUG_RETURN(cond);
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index e569fcd32d6..791e67b4f59 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5502,6 +5502,29 @@ public:
{
lex= backup_lex;
}
+
+ /*
+ Stores the the processed record during INSERT/REPLACE. Used for assigning
+ value of error_index in case of warning or error.
+ */
+ ulonglong current_insert_index;
+
+ /*
+ Error may take place in prepare phase and it might not be because of
+ rows/values we are inserting into the table, it could be because of say
+ something like wrong field name. In such case we want to return 0
+ for error index.
+ */
+ ulonglong correct_error_index(uint error_no)
+ {
+ if (error_no == ER_FIELD_SPECIFIED_TWICE ||
+ error_no == ER_BAD_FIELD_ERROR ||
+ error_no == ER_VIEW_NO_INSERT_FIELD_LIST ||
+ error_no == ER_VIEW_MULTIUPDATE)
+ return 0;
+
+ return current_insert_index;
+ }
};
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index cef9e6cec00..6961f1b258e 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -672,7 +672,8 @@ Sql_condition *Warning_info::push_warning(THD *thd,
if (m_allow_unlimited_warnings ||
m_warn_list.elements() < thd->variables.max_error_count)
{
- cond= new (& m_warn_root) Sql_condition(& m_warn_root, *value, msg);
+ cond= new (& m_warn_root) Sql_condition(& m_warn_root, *value, msg,
+ thd->current_insert_index);
if (cond)
m_warn_list.push_back(cond);
}
diff --git a/sql/sql_error.h b/sql/sql_error.h
index 6b0d4d7749c..113b51454c6 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -396,7 +396,7 @@ private:
*/
Sql_condition()
:m_mem_root(NULL)
- { }
+ { error_index= 0; }
/**
Complete the Sql_condition initialisation.
@@ -419,6 +419,7 @@ private:
:m_mem_root(mem_root)
{
DBUG_ASSERT(mem_root != NULL);
+ error_index= 0;
}
Sql_condition(MEM_ROOT *mem_root, const Sql_user_condition_identity &ucid)
@@ -426,6 +427,7 @@ private:
m_mem_root(mem_root)
{
DBUG_ASSERT(mem_root != NULL);
+ error_index= 0;
}
/**
Constructor for a fixed message text.
@@ -436,7 +438,8 @@ private:
*/
Sql_condition(MEM_ROOT *mem_root,
const Sql_condition_identity &value,
- const char *msg)
+ const char *msg,
+ ulonglong current_error_index)
:Sql_condition_identity(value),
m_mem_root(mem_root)
{
@@ -444,6 +447,7 @@ private:
DBUG_ASSERT(value.get_sql_errno() != 0);
DBUG_ASSERT(msg != NULL);
set_builtin_message_text(msg);
+ error_index= current_error_index;
}
/** Destructor. */
@@ -497,6 +501,9 @@ private:
/** Memory root to use to hold condition item values. */
MEM_ROOT *m_mem_root;
+
+ /* Index of error for INSERT/REPLACE statement. */
+ ulonglong error_index;
};
///////////////////////////////////////////////////////////////////////////
diff --git a/sql/sql_get_diagnostics.cc b/sql/sql_get_diagnostics.cc
index 197bf5e7a00..0de1cde3c49 100644
--- a/sql/sql_get_diagnostics.cc
+++ b/sql/sql_get_diagnostics.cc
@@ -338,6 +338,8 @@ Condition_information_item::get_value(THD *thd, const Sql_condition *cond)
str.set_ascii(cond->get_sqlstate(), strlen(cond->get_sqlstate()));
value= make_utf8_string_item(thd, &str);
break;
+ case ERROR_INDEX:
+ value= new (thd->mem_root) Item_uint(thd, cond->error_index);
}
DBUG_RETURN(value);
diff --git a/sql/sql_get_diagnostics.h b/sql/sql_get_diagnostics.h
index f283aa5b2c6..69432f9cf86 100644
--- a/sql/sql_get_diagnostics.h
+++ b/sql/sql_get_diagnostics.h
@@ -254,7 +254,8 @@ public:
CURSOR_NAME,
MESSAGE_TEXT,
MYSQL_ERRNO,
- RETURNED_SQLSTATE
+ RETURNED_SQLSTATE,
+ ERROR_INDEX
};
/**
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index eaafb8d7742..7b2b820752c 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -711,6 +711,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
Name_resolution_context_state ctx_state;
SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0;
unsigned char *readbuff= NULL;
+ thd->current_insert_index= 0;
#ifndef EMBEDDED_LIBRARY
char *query= thd->query();
@@ -830,7 +831,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
while ((values= its++))
{
- counter++;
+ thd->current_insert_index= ++counter;
if (values->elements != value_count)
{
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
@@ -842,6 +843,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
switch_to_nullable_trigger_fields(*values, table);
}
its.rewind ();
+ thd->current_insert_index= 0;
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
@@ -1008,6 +1010,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
while ((values= its++))
{
+ thd->current_insert_index++;
if (fields.elements || !value_count)
{
/*
@@ -1131,6 +1134,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
} while (bulk_parameters_iterations(thd));
values_loop_end:
+ thd->current_insert_index= 0;
free_underlaid_joins(thd, thd->lex->first_select_lex());
joins_freed= TRUE;
@@ -1606,6 +1610,8 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
bool res= 0;
table_map map= 0;
TABLE *table;
+ thd->current_insert_index= 1;
+
DBUG_ENTER("mysql_prepare_insert");
DBUG_PRINT("enter", ("table_list: %p view: %d",
table_list, (int) insert_into_view));
@@ -1659,6 +1665,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
if (!res)
res= setup_fields(thd, Ref_ptr_array(),
update_values, MARK_COLUMNS_READ, 0, NULL, 0);
+ thd->current_insert_index= 0;
if (!res && duplic == DUP_UPDATE)
{
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b9d3eec5a60..d853b09b354 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -7978,6 +7978,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
LEX *lex= thd->lex;
bool err= parse_sql(thd, parser_state, NULL, true);
+ thd->current_insert_index= 0;
if (likely(!err))
{
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 09ad632dd98..4d92d46f9c2 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1338,9 +1338,10 @@ static bool mysql_test_insert_common(Prepared_statement *stmt,
table_list->table_name.str));
goto error;
}
+ thd->current_insert_index= 0;
while ((values= its++))
{
- counter++;
+ thd->current_insert_index= ++counter;
if (values->elements != value_count)
{
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
@@ -1350,6 +1351,7 @@ static bool mysql_test_insert_common(Prepared_statement *stmt,
*values, COLUMNS_READ, 0, NULL, 0))
goto error;
}
+ thd->current_insert_index= 0;
}
DBUG_RETURN(FALSE);
diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc
index 8e973f9b0b3..5a085c99de7 100644
--- a/sql/sql_signal.cc
+++ b/sql/sql_signal.cc
@@ -419,7 +419,7 @@ bool Sql_cmd_resignal::execute(THD *thd)
DBUG_RETURN(result);
}
- Sql_condition signaled_err(thd->mem_root, *signaled, signaled->message);
+ Sql_condition signaled_err(thd->mem_root, *signaled, signaled->message, 0);
if (m_cond)
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 89e20165984..57201b22802 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -971,6 +971,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> MUTEX_SYM
%token <kwd> MYSQL_SYM
%token <kwd> MYSQL_ERRNO_SYM
+%token <kwd> ERROR_INDEX_SYM
%token <kwd> NAMES_SYM /* SQL-2003-N */
%token <kwd> NAME_SYM /* SQL-2003-N */
%token <kwd> NATIONAL_SYM /* SQL-2003-R */
@@ -3627,6 +3628,8 @@ condition_information_item_name:
{ $$= Condition_information_item::MYSQL_ERRNO; }
| RETURNED_SQLSTATE_SYM
{ $$= Condition_information_item::RETURNED_SQLSTATE; }
+ | ERROR_INDEX_SYM
+ { $$= Condition_information_item::ERROR_INDEX; }
;
sp_decl_ident:
@@ -12915,6 +12918,7 @@ insert_table:
//lex->field_list.empty();
lex->many_values.empty();
lex->insert_list=0;
+ thd->current_insert_index= lex->many_values.elements+1;
}
;
@@ -12924,11 +12928,14 @@ insert_field_spec:
| SET
{
LEX *lex=Lex;
+ ulonglong saved_current_insert_index= thd->current_insert_index;
if (unlikely(!(lex->insert_list= new (thd->mem_root) List_item)) ||
unlikely(lex->many_values.push_back(lex->insert_list,
thd->mem_root)))
MYSQL_YYABORT;
lex->current_select->parsing_place= NO_MATTER;
+ if (saved_current_insert_index < lex->many_values.elements)
+ thd->current_insert_index++;
}
ident_eq_list
;
@@ -13009,6 +13016,7 @@ no_braces:
if (unlikely(lex->many_values.push_back(lex->insert_list,
thd->mem_root)))
MYSQL_YYABORT;
+ thd->current_insert_index++;
}
;
@@ -13024,6 +13032,7 @@ no_braces_with_names:
if (unlikely(lex->many_values.push_back(lex->insert_list,
thd->mem_root)))
MYSQL_YYABORT;
+ thd->current_insert_index++;
}
;
@@ -15652,6 +15661,7 @@ keyword_sp_var_and_label:
| INVOKER_SYM
| IMPORT
| INDEXES
+ | ERROR_INDEX_SYM
| INITIAL_SIZE_SYM
| IO_SYM
| IPC_SYM