Skip to content

Commit 66c68db

Browse files
AliSQLAliSQL
authored andcommitted
[Feature] Issue#61 new built-in function to let customer manually issue an error
A new built-in function RAISE_ERROR('diagnostic-string') is needed to let mysql users fail current statement with the desired diagnostic-string error message and reserved sql error code. DB2 does in its' RAISE_ERROR() function, where the function accepts parameters of sql state and msg, and Oracle's RAISE_APPLICATION_ERROR has similar function. In our implementation, raise_error() accepts parameter of msg and optional sql state, both are strings. NULL value input is not allowed for either one, and only validate sql state is allowed. Here are samples: --error ER_SP_BAD_SQLSTATE select raise_error(NULL, 'null sql state not allowed'); --error ER_MALFORMED_MESSAGE select raise_error('70001', NULL); --error ER_SP_BAD_SQLSTATE select raise_error('00001', 'invalid sql state'); --error ER_SP_BAD_SQLSTATE select raise_error('666666', 'length of sql state exceeds 5'); --error ER_INTENTIONAL_ERROR select raise_error('70001', 'this is a sample error msg'); --error ER_INTENTIONAL_ERROR select raise_error('this is a sample error msg'); --error ER_INTENTIONAL_ERROR select raise_error('only error message applied');
1 parent e5ddf31 commit 66c68db

File tree

8 files changed

+192
-2
lines changed

8 files changed

+192
-2
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
select raise_error(NULL, 'this is a sample error msg');
2+
ERROR 42000: Bad SQLSTATE: 'NULL'
3+
select raise_error('70001', NULL);
4+
ERROR HY000: Malformed message specification 'NULL'.
5+
select raise_error('00001', 'this is a sample error msg');
6+
ERROR 42000: Bad SQLSTATE: '00001'
7+
select raise_error('666666', 'length of sql state exceeds 5');
8+
ERROR 42000: Bad SQLSTATE: '666666'
9+
select raise_error('70001', 'this is a sample error msg');
10+
ERROR 70001: this is a sample error msg
11+
select raise_error('this is a sampel error msg');
12+
ERROR HY000: this is a sampel error msg
13+
select raise_error('HY000', 'this is a sample error msg');
14+
ERROR HY000: this is a sample error msg
15+
select raise_error('08S01', 'this is a sample error msg');
16+
ERROR 08S01: this is a sample error msg
17+
select raise_error('only error message applied');
18+
ERROR HY000: only error message applied
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#sql state not allowed to be null
2+
--error ER_SP_BAD_SQLSTATE
3+
select raise_error(NULL, 'this is a sample error msg');
4+
5+
#error msg not allowed to be null
6+
--error ER_MALFORMED_MESSAGE
7+
select raise_error('70001', NULL);
8+
9+
#invalid sql state
10+
--error ER_SP_BAD_SQLSTATE
11+
select raise_error('00001', 'this is a sample error msg');
12+
--error ER_SP_BAD_SQLSTATE
13+
select raise_error('666666', 'length of sql state exceeds 5');
14+
15+
#valid input
16+
--error ER_INTENTIONAL_ERROR
17+
select raise_error('70001', 'this is a sample error msg');
18+
--error ER_INTENTIONAL_ERROR
19+
select raise_error('this is a sampel error msg');
20+
--error ER_INTENTIONAL_ERROR
21+
select raise_error('HY000', 'this is a sample error msg');
22+
--error ER_INTENTIONAL_ERROR
23+
select raise_error('08S01', 'this is a sample error msg');
24+
--error ER_INTENTIONAL_ERROR
25+
select raise_error('only error message applied');

sql/item_create.cc

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2090,7 +2090,6 @@ class Create_func_quote : public Create_func_arg1
20902090
virtual ~Create_func_quote() {}
20912091
};
20922092

2093-
20942093
class Create_func_radians : public Create_func_arg1
20952094
{
20962095
public:
@@ -2103,6 +2102,17 @@ class Create_func_radians : public Create_func_arg1
21032102
virtual ~Create_func_radians() {}
21042103
};
21052104

2105+
class Create_func_raise_error : public Create_native_func
2106+
{
2107+
public:
2108+
virtual Item *create_native(THD *thd, LEX_STRING name,
2109+
List<Item> *item_list);
2110+
2111+
static Create_func_raise_error s_singleton;
2112+
protected:
2113+
Create_func_raise_error() {}
2114+
virtual ~Create_func_raise_error() {}
2115+
};
21062116

21072117
class Create_func_rand : public Create_native_func
21082118
{
@@ -4853,6 +4863,42 @@ Create_func_radians::create(THD *thd, Item *arg1)
48534863
M_PI/180, 0.0);
48544864
}
48554865

4866+
Create_func_raise_error Create_func_raise_error::s_singleton;
4867+
4868+
Item*
4869+
Create_func_raise_error::create_native(THD *thd, LEX_STRING name,
4870+
List<Item> *item_list)
4871+
{
4872+
Item *func= NULL;
4873+
int arg_count= 0;
4874+
4875+
if (item_list != NULL)
4876+
arg_count= item_list->elements;
4877+
4878+
switch (arg_count) {
4879+
case 1:
4880+
{
4881+
Item *param_1= item_list->pop();
4882+
func= new (thd->mem_root) Item_func_raise_error(param_1);
4883+
break;
4884+
}
4885+
case 2:
4886+
{
4887+
Item *param_1= item_list->pop();
4888+
Item *param_2= item_list->pop();
4889+
func= new (thd->mem_root) Item_func_raise_error(param_1, param_2);
4890+
break;
4891+
}
4892+
default:
4893+
{
4894+
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
4895+
break;
4896+
}
4897+
}
4898+
4899+
return func;
4900+
}
4901+
48564902

48574903
Create_func_rand Create_func_rand::s_singleton;
48584904

@@ -5627,6 +5673,7 @@ static Native_func_registry func_array[] =
56275673
{ { C_STRING_WITH_LEN("POWER") }, BUILDER(Create_func_pow)},
56285674
{ { C_STRING_WITH_LEN("QUOTE") }, BUILDER(Create_func_quote)},
56295675
{ { C_STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)},
5676+
{ { C_STRING_WITH_LEN("RAISE_ERROR") }, BUILDER(Create_func_raise_error)},
56305677
{ { C_STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)},
56315678
{ { C_STRING_WITH_LEN("RANDOM_BYTES") }, BUILDER(Create_func_random_bytes) },
56325679
{ { C_STRING_WITH_LEN("RELEASE_LOCK") }, BUILDER(Create_func_release_lock) },

sql/item_func.cc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,70 @@ my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
552552
return decimal_value;
553553
}
554554

555+
/*
556+
Raise an error with specified error message and optional sql state,
557+
sql error code is ER_INTENTIONAL_ERROR.
558+
*/
559+
longlong Item_func_raise_error::val_int()
560+
{
561+
DBUG_ENTER("Item_raise_error::val_int");
562+
DBUG_ASSERT(fixed == 1);
563+
564+
THD* thd= current_thd;
565+
566+
String *sql_state= NULL;
567+
String *msg= NULL;
568+
569+
if (arg_count == 2)
570+
// both sql state and error message are specified
571+
{
572+
sql_state= args[0]->val_str(&value);
573+
// validate sql_state input
574+
if (sql_state == NULL)
575+
{
576+
my_error(ER_SP_BAD_SQLSTATE, MYF(0), "NULL");
577+
DBUG_RETURN(0);
578+
}
579+
580+
LEX_STRING lex_sql_state= sql_state->lex_string();
581+
582+
if (!is_sqlstate_valid(&lex_sql_state) || is_sqlstate_completion(sql_state->ptr()))
583+
{
584+
my_error(ER_SP_BAD_SQLSTATE, MYF(0), sql_state->ptr());
585+
DBUG_RETURN(0);
586+
}
587+
msg= args[1]->val_str(&value);
588+
// validate message input
589+
if (msg == NULL)
590+
{
591+
my_error(ER_MALFORMED_MESSAGE, MYF(0), "NULL");
592+
DBUG_RETURN(0);
593+
}
594+
595+
// raise the manual error now
596+
(void) thd->raise_error(ER_INTENTIONAL_ERROR,
597+
sql_state->ptr(),
598+
msg->ptr());
599+
600+
DBUG_RETURN(0);
601+
}
602+
else
603+
// only error message is specified
604+
{
605+
msg= args[0]->val_str(&value);
606+
// validate message input
607+
if (msg == NULL)
608+
{
609+
my_error(ER_MALFORMED_MESSAGE, MYF(0), "NULL");
610+
DBUG_RETURN(0);
611+
}
612+
// raise the manual error now
613+
(void) thd->raise_error(ER_INTENTIONAL_ERROR,
614+
NULL,
615+
msg->ptr());
616+
DBUG_RETURN(0);
617+
}
618+
}
555619

556620
String *Item_real_func::val_str(String *str)
557621
{

sql/item_func.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,22 @@ class Item_func_round :public Item_func_num1
904904
void fix_length_and_dec();
905905
};
906906

907+
/**
908+
This class is used for implementing the new raise_error function and the functions related to them.
909+
*/
910+
class Item_func_raise_error :public Item_int_func
911+
{
912+
913+
String value;
914+
public:
915+
Item_func_raise_error( Item *a) :Item_int_func(a) {}
916+
Item_func_raise_error( Item *a, Item *b)
917+
:Item_int_func(a, b)
918+
{}
919+
920+
longlong val_int();
921+
const char *func_name() const {return "raise_error";}
922+
};
907923

908924
class Item_func_rand :public Item_real_func
909925
{

sql/share/errmsg-utf8.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7142,4 +7142,7 @@ ER_SEQUENCE_NOT_DEFINED
71427142
eng "Sequence '%-.192s.%-.192s' is not yet defined in this session"
71437143
ER_NOT_SEQUENCE
71447144
eng "'%-.192s.%-.192s' is not a SEQUENCE"
7145-
7145+
ER_MALFORMED_MESSAGE
7146+
eng "Malformed message specification '%.200s'."
7147+
ER_INTENTIONAL_ERROR
7148+
eng "user issue an error intentionally."

sql/sql_class.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,16 @@ void THD::raise_error(uint sql_errno)
12341234
msg);
12351235
}
12361236

1237+
void THD::raise_error(uint sql_errno,
1238+
const char* sql_state,
1239+
const char* msg)
1240+
{
1241+
(void) raise_condition(sql_errno,
1242+
sql_state,
1243+
Sql_condition::WARN_LEVEL_ERROR,
1244+
msg);
1245+
}
1246+
12371247
void THD::raise_error_printf(uint sql_errno, ...)
12381248
{
12391249
va_list args;

sql/sql_class.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4192,6 +4192,13 @@ class THD :public MDL_context_owner,
41924192
*/
41934193
void raise_note_printf(uint code, ...);
41944194

4195+
/**
4196+
Raise an exception condition with specified msg
4197+
*/
4198+
void raise_error(uint sql_errno,
4199+
const char* sqlstate,
4200+
const char* msg);
4201+
41954202
private:
41964203
/*
41974204
Only the implementation of the SIGNAL and RESIGNAL statements

0 commit comments

Comments
 (0)