Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
487664eb
Commit
487664eb
authored
Feb 28, 2006
by
unknown
Browse files
Options
Browse Files
Download
Plain Diff
Merge ahristov@bk-internal.mysql.com:/home/bk/mysql-5.1-new
into lmy004.:/work/mysql-5.1-bug16537
parents
04bdb1b3
995a56ef
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
378 additions
and
253 deletions
+378
-253
mysql-test/r/events.result
mysql-test/r/events.result
+48
-0
mysql-test/t/events.test
mysql-test/t/events.test
+32
-0
sql/event.cc
sql/event.cc
+122
-120
sql/event.h
sql/event.h
+3
-0
sql/event_executor.cc
sql/event_executor.cc
+66
-63
sql/event_timed.cc
sql/event_timed.cc
+92
-56
sql/sql_show.cc
sql/sql_show.cc
+12
-14
sql/sql_yacc.yy
sql/sql_yacc.yy
+3
-0
No files found.
mysql-test/r/events.result
View file @
487664eb
...
...
@@ -37,6 +37,54 @@ alter event event3 rename to event2;
drop event event2;
create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end;
drop event event2;
CREATE EVENT event_starts_test ON SCHEDULE EVERY 10 SECOND COMMENT "" DO SELECT 1;
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 10 SECOND # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
0 1
ALTER EVENT event_starts_test ON SCHEDULE AT '2020-02-02 20:00:02';
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost ONE TIME 2020-02-02 17:00:02 NULL NULL # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
1 1
ALTER EVENT event_starts_test COMMENT "non-empty comment";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost ONE TIME 2020-02-02 17:00:02 NULL NULL # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
1 1 non-empty comment
ALTER EVENT event_starts_test COMMENT "";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost ONE TIME 2020-02-02 17:00:02 NULL NULL # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
1 1
DROP EVENT event_starts_test;
CREATE EVENT event_starts_test ON SCHEDULE EVERY 20 SECOND STARTS '2020-02-02 20:00:02' ENDS '2022-02-02 20:00:02' DO SELECT 2;
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
0 0
ALTER EVENT event_starts_test COMMENT "non-empty comment";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
0 0 non-empty comment
ALTER EVENT event_starts_test COMMENT "";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLED
DROP EVENT event_starts_test;
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
alter event e_43 do alter event e_43 do set @a = 4;
...
...
mysql-test/t/events.test
View file @
487664eb
...
...
@@ -48,6 +48,38 @@ drop event event2;
create
event
event2
on
schedule
every
2
second
starts
now
()
ends
date_add
(
now
(),
interval
5
hour
)
comment
"some"
DO
begin
end
;
drop
event
event2
;
# BUG #16537 (Events: mysql.event.starts is null)
CREATE
EVENT
event_starts_test
ON
SCHEDULE
EVERY
10
SECOND
COMMENT
""
DO
SELECT
1
;
--
replace_column
8
# 9 #
SHOW
EVENTS
;
SELECT
starts
IS
NULL
,
ends
IS
NULL
,
comment
FROM
mysql
.
event
WHERE
db
=
'events_test'
AND
name
=
'event_starts_test'
;
ALTER
EVENT
event_starts_test
ON
SCHEDULE
AT
'2020-02-02 20:00:02'
;
--
replace_column
8
# 9 #
SHOW
EVENTS
;
SELECT
starts
IS
NULL
,
ends
IS
NULL
,
comment
FROM
mysql
.
event
WHERE
db
=
'events_test'
AND
name
=
'event_starts_test'
;
ALTER
EVENT
event_starts_test
COMMENT
"non-empty comment"
;
--
replace_column
8
# 9 #
SHOW
EVENTS
;
SELECT
starts
IS
NULL
,
ends
IS
NULL
,
comment
FROM
mysql
.
event
WHERE
db
=
'events_test'
AND
name
=
'event_starts_test'
;
ALTER
EVENT
event_starts_test
COMMENT
""
;
--
replace_column
8
# 9 #
SHOW
EVENTS
;
SELECT
starts
IS
NULL
,
ends
IS
NULL
,
comment
FROM
mysql
.
event
WHERE
db
=
'events_test'
AND
name
=
'event_starts_test'
;
DROP
EVENT
event_starts_test
;
CREATE
EVENT
event_starts_test
ON
SCHEDULE
EVERY
20
SECOND
STARTS
'2020-02-02 20:00:02'
ENDS
'2022-02-02 20:00:02'
DO
SELECT
2
;
--
replace_column
8
# 9 #
SHOW
EVENTS
;
SELECT
starts
IS
NULL
,
ends
IS
NULL
,
comment
FROM
mysql
.
event
WHERE
db
=
'events_test'
AND
name
=
'event_starts_test'
;
ALTER
EVENT
event_starts_test
COMMENT
"non-empty comment"
;
--
replace_column
8
# 9 #
SHOW
EVENTS
;
SELECT
starts
IS
NULL
,
ends
IS
NULL
,
comment
FROM
mysql
.
event
WHERE
db
=
'events_test'
AND
name
=
'event_starts_test'
;
ALTER
EVENT
event_starts_test
COMMENT
""
;
--
replace_column
8
# 9 #
SHOW
EVENTS
;
DROP
EVENT
event_starts_test
;
#
#
create
event
e_43
on
schedule
every
1
second
do
set
@
a
=
5
;
set
global
event_scheduler
=
1
;
--
sleep
2
...
...
sql/event.cc
View file @
487664eb
...
...
@@ -69,7 +69,7 @@ time_t mysql_event_last_create_time= 0L;
static
TABLE_FIELD_W_TYPE
event_table_fields
[
EVEX_FIELD_COUNT
]
=
{
{
{(
char
*
)
STRING_WITH_LEN
(
"db"
)},
{(
char
*
)
STRING_WITH_LEN
(
"db"
)},
{(
char
*
)
STRING_WITH_LEN
(
"char(64)"
)},
{(
char
*
)
STRING_WITH_LEN
(
"utf8"
)}
},
...
...
@@ -120,6 +120,7 @@ static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
{
{(
char
*
)
STRING_WITH_LEN
(
"last_executed"
)},
{(
char
*
)
STRING_WITH_LEN
(
"datetime"
)},
{
NULL
,
0
}
},
{
{(
char
*
)
STRING_WITH_LEN
(
"starts"
)},
...
...
@@ -162,25 +163,25 @@ static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
LEX_STRING
interval_type_to_name
[]
=
{
{(
char
*
)
STRING_WITH_LEN
(
"YEAR"
)},
{(
char
*
)
STRING_WITH_LEN
(
"QUARTER"
)},
{(
char
*
)
STRING_WITH_LEN
(
"MONTH"
)},
{(
char
*
)
STRING_WITH_LEN
(
"DAY"
)},
{(
char
*
)
STRING_WITH_LEN
(
"HOUR"
)},
{(
char
*
)
STRING_WITH_LEN
(
"MINUTE"
)},
{(
char
*
)
STRING_WITH_LEN
(
"WEEK"
)},
{(
char
*
)
STRING_WITH_LEN
(
"SECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"MICROSECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"YEAR_MONTH"
)},
{(
char
*
)
STRING_WITH_LEN
(
"DAY_HOUR"
)},
{(
char
*
)
STRING_WITH_LEN
(
"DAY_MINUTE"
)},
{(
char
*
)
STRING_WITH_LEN
(
"DAY_SECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"HOUR_MINUTE"
)},
{(
char
*
)
STRING_WITH_LEN
(
"HOUR_SECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"MINUTE_SECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"DAY_MICROSECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"HOUR_MICROSECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"MINUTE_MICROSECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"YEAR"
)},
{(
char
*
)
STRING_WITH_LEN
(
"QUARTER"
)},
{(
char
*
)
STRING_WITH_LEN
(
"MONTH"
)},
{(
char
*
)
STRING_WITH_LEN
(
"DAY"
)},
{(
char
*
)
STRING_WITH_LEN
(
"HOUR"
)},
{(
char
*
)
STRING_WITH_LEN
(
"MINUTE"
)},
{(
char
*
)
STRING_WITH_LEN
(
"WEEK"
)},
{(
char
*
)
STRING_WITH_LEN
(
"SECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"MICROSECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"YEAR_MONTH"
)},
{(
char
*
)
STRING_WITH_LEN
(
"DAY_HOUR"
)},
{(
char
*
)
STRING_WITH_LEN
(
"DAY_MINUTE"
)},
{(
char
*
)
STRING_WITH_LEN
(
"DAY_SECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"HOUR_MINUTE"
)},
{(
char
*
)
STRING_WITH_LEN
(
"HOUR_SECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"MINUTE_SECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"DAY_MICROSECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"HOUR_MICROSECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"MINUTE_MICROSECOND"
)},
{(
char
*
)
STRING_WITH_LEN
(
"SECOND_MICROSECOND"
)}
};
...
...
@@ -188,10 +189,10 @@ LEX_STRING interval_type_to_name[] = {
/*
Inits the scheduler queue - prioritized queue from mysys/queue.c
Synopsis
evex_queue_init()
queue - pointer the the memory to be initialized as queue. has to be
allocated from the caller
...
...
@@ -211,10 +212,10 @@ evex_queue_init(EVEX_QUEUE_TYPE *queue)
/*
Compares 2 LEX strings regarding case.
Synopsis
my_time_compare()
s - first LEX_STRING
t - second LEX_STRING
cs - charset
...
...
@@ -223,7 +224,7 @@ evex_queue_init(EVEX_QUEUE_TYPE *queue)
-1 - s < t
0 - s == t
1 - s > t
Notes
TIME.second_part is not considered during comparison
*/
...
...
@@ -237,18 +238,18 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
/*
Compares 2 TIME structures
Synopsis
my_time_compare()
a - first TIME
b - second time
RETURNS:
-1 - a < b
0 - a == b
1 - a > b
Notes
TIME.second_part is not considered during comparison
*/
...
...
@@ -276,18 +277,18 @@ my_time_compare(TIME *a, TIME *b)
/*
Compares the execute_at members of 2 event_timed instances
Synopsis
event_timed_compare()
a - first event_timed object
b - second event_timed object
RETURNS:
-1 - a->execute_at < b->execute_at
0 - a->execute_at == b->execute_at
1 - a->execute_at > b->execute_at
Notes
execute_at.second_part is not considered during comparison
*/
...
...
@@ -303,14 +304,14 @@ event_timed_compare(event_timed *a, event_timed *b)
Compares the execute_at members of 2 event_timed instances.
Used as callback for the prioritized queue when shifting
elements inside.
Synopsis
event_timed_compare()
vptr - not used (set it to NULL)
a - first event_timed object
b - second event_timed object
RETURNS:
-1 - a->execute_at < b->execute_at
0 - a->execute_at == b->execute_at
...
...
@@ -333,18 +334,16 @@ event_timed_compare_q(void *vptr, byte* a, byte *b)
For
YEAR_MONTH - expression is in months
DAY_MINUTE - expression is in minutes
Synopsis
event_reconstruct_interval_expression()
buf - preallocated String buffer to add the value to
interval - the interval type (for instance YEAR_MONTH)
expression - the value in the lowest entity
RETURNS
0 - OK
1 - Error
*/
int
...
...
@@ -369,7 +368,7 @@ event_reconstruct_interval_expression(String *buf,
goto
common_1_lev_code
;
case
INTERVAL_HOUR_MINUTE
:
case
INTERVAL_MINUTE_SECOND
:
multipl
=
60
;
multipl
=
60
;
common_1_lev_code:
buf
->
append
(
'\''
);
end
=
longlong10_to_str
(
expression
/
multipl
,
tmp_buff
,
10
);
...
...
@@ -473,9 +472,9 @@ event_reconstruct_interval_expression(String *buf,
table The table pointer
RETURN
1
Cannot lock table
1
Cannot lock table
2 The table is corrupted - different number of fields
0
OK
0
OK
*/
int
...
...
@@ -590,11 +589,11 @@ evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
thd THD
table the row to fill out
et Event's data
Returns
0 - ok
EVEX_GENERAL_ERROR - bad data
EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
DESCRIPTION
Used both when an event is created and when it is altered.
...
...
@@ -607,9 +606,9 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
DBUG_ENTER
(
"evex_fill_row"
);
DBUG_PRINT
(
"info"
,
(
"dbname=[%s]"
,
et
->
dbname
.
str
));
DBUG_PRINT
(
"info"
,
(
"name =[%s]"
,
et
->
name
.
str
));
DBUG_PRINT
(
"info"
,
(
"body =[%s]"
,
et
->
body
.
str
));
DBUG_PRINT
(
"info"
,
(
"dbname=[%s]"
,
et
->
dbname
.
str
));
DBUG_PRINT
(
"info"
,
(
"name =[%s]"
,
et
->
name
.
str
));
DBUG_PRINT
(
"info"
,
(
"body =[%s]"
,
et
->
body
.
str
));
if
(
table
->
field
[
field_num
=
EVEX_FIELD_DB
]
->
store
(
et
->
dbname
.
str
,
et
->
dbname
.
length
,
system_charset_info
))
...
...
@@ -619,7 +618,7 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
store
(
et
->
name
.
str
,
et
->
name
.
length
,
system_charset_info
))
goto
trunc_err
;
/
/ both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()
/
* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull() */
table
->
field
[
EVEX_FIELD_ON_COMPLETION
]
->
store
((
longlong
)
et
->
on_completion
);
table
->
field
[
EVEX_FIELD_STATUS
]
->
store
((
longlong
)
et
->
status
);
...
...
@@ -637,20 +636,6 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
goto
trunc_err
;
}
if
(
et
->
starts
.
year
)
{
table
->
field
[
EVEX_FIELD_STARTS
]
->
set_notnull
();
// set NULL flag to OFF
table
->
field
[
EVEX_FIELD_STARTS
]
->
store_time
(
&
et
->
starts
,
MYSQL_TIMESTAMP_DATETIME
);
}
if
(
et
->
ends
.
year
)
{
table
->
field
[
EVEX_FIELD_ENDS
]
->
set_notnull
();
table
->
field
[
EVEX_FIELD_ENDS
]
->
store_time
(
&
et
->
ends
,
MYSQL_TIMESTAMP_DATETIME
);
}
if
(
et
->
expression
)
{
table
->
field
[
EVEX_FIELD_INTERVAL_EXPR
]
->
set_notnull
();
...
...
@@ -664,36 +649,54 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
table
->
field
[
EVEX_FIELD_TRANSIENT_INTERVAL
]
->
store
((
longlong
)
et
->
interval
+
1
);
table
->
field
[
EVEX_FIELD_EXECUTE_AT
]
->
set_null
();
if
(
!
et
->
starts_null
)
{
table
->
field
[
EVEX_FIELD_STARTS
]
->
set_notnull
();
table
->
field
[
EVEX_FIELD_STARTS
]
->
store_time
(
&
et
->
starts
,
MYSQL_TIMESTAMP_DATETIME
);
}
if
(
!
et
->
ends_null
)
{
table
->
field
[
EVEX_FIELD_ENDS
]
->
set_notnull
();
table
->
field
[
EVEX_FIELD_ENDS
]
->
store_time
(
&
et
->
ends
,
MYSQL_TIMESTAMP_DATETIME
);
}
}
else
if
(
et
->
execute_at
.
year
)
{
// fix_fields already called in init_execute_at
table
->
field
[
EVEX_FIELD_INTERVAL_EXPR
]
->
set_null
();
table
->
field
[
EVEX_FIELD_TRANSIENT_INTERVAL
]
->
set_null
();
table
->
field
[
EVEX_FIELD_STARTS
]
->
set_null
();
table
->
field
[
EVEX_FIELD_ENDS
]
->
set_null
();
table
->
field
[
EVEX_FIELD_EXECUTE_AT
]
->
set_notnull
();
table
->
field
[
EVEX_FIELD_EXECUTE_AT
]
->
store_time
(
&
et
->
execute_at
,
MYSQL_TIMESTAMP_DATETIME
);
table
->
field
[
EVEX_FIELD_TRANSIENT_INTERVAL
]
->
set_null
();
MYSQL_TIMESTAMP_DATETIME
);
}
else
{
DBUG_ASSERT
(
is_update
);
// it is normal to be here when the action is update
// this is an error if the action is create. something is borked
/*
it is normal to be here when the action is update
this is an error if the action is create. something is borked
*/
}
((
Field_timestamp
*
)
table
->
field
[
EVEX_FIELD_MODIFIED
])
->
set_time
();
if
(
et
->
comment
.
length
)
if
(
table
->
field
[
field_num
=
EVEX_FIELD_COMMENT
]
->
store
(
et
->
comment
.
str
,
et
->
comment
.
length
,
system_charset_info
))
if
(
et
->
comment
.
str
)
{
if
(
table
->
field
[
field_num
=
EVEX_FIELD_COMMENT
]
->
store
(
et
->
comment
.
str
,
et
->
comment
.
length
,
system_charset_info
))
goto
trunc_err
;
}
DBUG_RETURN
(
0
);
trunc_err:
my_error
(
ER_EVENT_DATA_TOO_LONG
,
MYF
(
0
));
my_error
(
ER_EVENT_DATA_TOO_LONG
,
MYF
(
0
)
,
table
->
field
[
field_num
]
->
field_name
);
DBUG_RETURN
(
EVEX_GENERAL_ERROR
);
}
...
...
@@ -707,12 +710,12 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
et event_timed object containing information for the event
create_if_not - if an warning should be generated in case event exists
rows_affected - how many rows were affected
Return value
0 - OK
EVEX_GENERAL_ERROR - Failure
DESCRIPTION
Creates an event. Relies on evex_fill_row which is shared with
Creates an event. Relies on evex_fill_row which is shared with
db_update_event. The name of the event is inside "et".
*/
...
...
@@ -735,16 +738,16 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
my_error
(
ER_EVENT_OPEN_TABLE_FAILED
,
MYF
(
0
));
goto
err
;
}
DBUG_PRINT
(
"info"
,
(
"check existance of an event with the same name"
));
if
(
!
evex_db_find_event_aux
(
thd
,
et
,
table
))
{
if
(
create_if_not
)
{
push_warning_printf
(
thd
,
MYSQL_ERROR
::
WARN_LEVEL_NOTE
,
ER_EVENT_ALREADY_EXISTS
,
ER
(
ER_EVENT_ALREADY_EXISTS
),
et
->
name
.
str
);
goto
ok
;
ER_EVENT_ALREADY_EXISTS
,
ER
(
ER_EVENT_ALREADY_EXISTS
),
et
->
name
.
str
);
goto
ok
;
}
my_error
(
ER_EVENT_ALREADY_EXISTS
,
MYF
(
0
),
et
->
name
.
str
);
goto
err
;
...
...
@@ -756,8 +759,8 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
my_error
(
ER_BAD_DB_ERROR
,
MYF
(
0
));
goto
err
;
}
restore_record
(
table
,
s
->
default_values
);
// Get default values for fields
restore_record
(
table
,
s
->
default_values
);
// Get default values for fields
if
(
system_charset_info
->
cset
->
numchars
(
system_charset_info
,
et
->
dbname
.
str
,
et
->
dbname
.
str
+
et
->
dbname
.
length
)
...
...
@@ -783,7 +786,7 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
if
(
!
(
et
->
expression
)
&&
!
(
et
->
execute_at
.
year
))
{
DBUG_PRINT
(
"error"
,
(
"neither expression nor execute_at are set!"
));
my_error
(
ER_EVENT_NEITHER_M_EXPR_NOR_M_AT
,
MYF
(
0
));
my_error
(
ER_EVENT_NEITHER_M_EXPR_NOR_M_AT
,
MYF
(
0
));
goto
err
;
}
...
...
@@ -797,7 +800,10 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
((
Field_timestamp
*
)
table
->
field
[
EVEX_FIELD_CREATED
])
->
set_time
();
// evex_fill_row() calls my_error() in case of error so no need to handle it here
/*
evex_fill_row() calls my_error() in case of error so no need to
handle it here
*/
if
((
ret
=
evex_fill_row
(
thd
,
table
,
et
,
false
)))
goto
err
;
...
...
@@ -806,7 +812,8 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
my_error
(
ER_EVENT_STORE_FAILED
,
MYF
(
0
),
et
->
name
.
str
,
ret
);
goto
err
;
}
#ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED
if
(
mysql_bin_log
.
is_open
())
{
thd
->
clear_error
();
...
...
@@ -814,7 +821,8 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
thd
->
binlog_query
(
THD
::
MYSQL_QUERY_TYPE
,
thd
->
query
,
thd
->
query_length
,
FALSE
,
FALSE
);
}
#endif
*
rows_affected
=
1
;
ok:
if
(
dbchanged
)
...
...
@@ -840,7 +848,7 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
thd THD
sp_name the name of the event to alter
et event's data
NOTES
sp_name is passed since this is the name of the event to
alter in case of RENAME TO.
...
...
@@ -865,7 +873,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
goto
err
;
}
/
/ first look whether we overwrite
/
* first look whether we overwrite */
if
(
new_name
)
{
if
(
!
sortcmp_lex_string
(
et
->
name
,
new_name
->
m_name
,
system_charset_info
)
&&
...
...
@@ -891,19 +899,18 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
if
(
EVEX_KEY_NOT_FOUND
==
evex_db_find_event_aux
(
thd
,
et
,
table
))
{
my_error
(
ER_EVENT_DOES_NOT_EXIST
,
MYF
(
0
),
et
->
name
.
str
);
goto
err
;
goto
err
;
}
store_record
(
table
,
record
[
1
]);
/
/ Don't update create on row update.
/
* Don't update create on row update. */
table
->
timestamp_field_type
=
TIMESTAMP_NO_AUTO_SET
;
/
/ evex_fill_row() calls my_error() in case of error so no need to handle it here
/
* evex_fill_row() calls my_error() in case of error so no need to handle it here */
if
((
ret
=
evex_fill_row
(
thd
,
table
,
et
,
true
)))
goto
err
;
if
(
new_name
)
{
table
->
field
[
EVEX_FIELD_DB
]
->
...
...
@@ -918,7 +925,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
goto
err
;
}
/
/ close mysql.event or we crash later when loading the event from disk
/
* close mysql.event or we crash later when loading the event from disk */
close_thread_tables
(
thd
);
DBUG_RETURN
(
0
);
...
...
@@ -940,7 +947,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
definer who owns the event
ett event's data if event is found
tbl TABLE object to use when not NULL
NOTES
1) Use sp_name for look up, return in **ett if found
2) tbl is not closed at exit
...
...
@@ -995,7 +1002,7 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, event_timed **ett,
delete
et
;
et
=
0
;
}
/
/ don't close the table if we haven't opened it ourselves
/
* don't close the table if we haven't opened it ourselves */
if
(
!
tbl
&&
table
)
close_thread_tables
(
thd
);
*
ett
=
et
;
...
...
@@ -1013,11 +1020,10 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, event_timed **ett,
spn the name of the event to alter
definer who is the owner
use_lock whether to obtain a lock on LOCK_event_arrays or not
RETURN VALUE
0 - OK
< 0 - error (in this case underlying functions call my_error()).
*/
static
int
...
...
@@ -1036,7 +1042,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
thd
->
mem_root
=
&
evex_mem_root
;
thd
->
reset_n_backup_open_tables_state
(
&
backup
);
/
/ no need to use my_error() here because db_find_event() has done it
/
* no need to use my_error() here because db_find_event() has done it */
ret
=
db_find_event
(
thd
,
spn
,
&
definer
,
&
ett
,
NULL
,
NULL
);
thd
->
restore_backup_open_tables_state
(
&
backup
);
if
(
ret
)
...
...
@@ -1088,7 +1094,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
ALTER EVENT.
RETURNS
0
-
OK (always)
0 OK (always)
*/
static
int
...
...
@@ -1111,7 +1117,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
for
(
i
=
0
;
i
<
evex_queue_num_elements
(
EVEX_EQ_NAME
);
++
i
)
{
event_timed
*
et
=
evex_queue_element
(
&
EVEX_EQ_NAME
,
i
,
event_timed
*
);
DBUG_PRINT
(
"info"
,
(
"[%s.%s]==[%s.%s]?"
,
db
->
str
,
name
->
str
,
et
->
dbname
.
str
,
DBUG_PRINT
(
"info"
,
(
"[%s.%s]==[%s.%s]?"
,
db
->
str
,
name
->
str
,
et
->
dbname
.
str
,
et
->
name
.
str
));
if
(
!
sortcmp_lex_string
(
*
name
,
et
->
name
,
system_charset_info
)
&&
!
sortcmp_lex_string
(
*
db
,
et
->
dbname
,
system_charset_info
))
...
...
@@ -1131,7 +1137,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
}
DBUG_PRINT
(
"evex_remove_from_cache"
,
(
"delete from queue"
));
evex_queue_delete_element
(
&
EVEX_EQ_NAME
,
i
);
/
/ ok, we have cleaned
/
* ok, we have cleaned */
ret
=
0
;
goto
done
;
}
...
...
@@ -1155,7 +1161,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
create_options Options specified when in the query. We are
interested whether there is IF NOT EXISTS
rows_affected How many rows were affected
NOTES
- in case there is an event with the same name (db) and
IF NOT EXISTS is specified, an warning is put into the W stack.
...
...
@@ -1185,7 +1191,7 @@ evex_create_event(THD *thd, event_timed *et, uint create_options,
VOID
(
pthread_mutex_unlock
(
&
LOCK_evex_running
));
done:
/
/ No need to close the table, it will be closed in sql_parse::do_command
/
* No need to close the table, it will be closed in sql_parse::do_command */
DBUG_RETURN
(
ret
);
}
...
...
@@ -1199,7 +1205,7 @@ evex_create_event(THD *thd, event_timed *et, uint create_options,
thd THD
et event's data
new_name set in case of RENAME TO.
NOTES
et contains data about dbname and event name.
new_name is the new name of the event, if not null (this means
...
...
@@ -1259,7 +1265,6 @@ evex_update_event(THD *thd, event_timed *et, sp_name *new_name,
et event's name
drop_if_exists if set and the event not existing => warning onto the stack
rows_affected affected number of rows is returned heres
*/
int
db_drop_event
(
THD
*
thd
,
event_timed
*
et
,
bool
drop_if_exists
,
...
...
@@ -1292,8 +1297,8 @@ int db_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
if
(
drop_if_exists
)
{
push_warning_printf
(
thd
,
MYSQL_ERROR
::
WARN_LEVEL_NOTE
,
ER_SP_DOES_NOT_EXIST
,
ER
(
ER_SP_DOES_NOT_EXIST
),
"Event"
,
et
->
name
.
str
);
ER_SP_DOES_NOT_EXIST
,
ER
(
ER_SP_DOES_NOT_EXIST
),
"Event"
,
et
->
name
.
str
);
ret
=
0
;
}
else
my_error
(
ER_EVENT_DOES_NOT_EXIST
,
MYF
(
0
),
et
->
name
.
str
);
...
...
@@ -1338,7 +1343,7 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
if
(
evex_is_running
)
ret
=
evex_remove_from_cache
(
&
et
->
dbname
,
&
et
->
name
,
true
,
true
);
VOID
(
pthread_mutex_unlock
(
&
LOCK_evex_running
));
if
(
ret
==
1
)
ret
=
0
;
else
if
(
ret
==
0
)
...
...
@@ -1358,11 +1363,10 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
thd THD
spn the name of the event (db, name)
definer the definer of the event
RETURNS
0 - OK
1 - Error during writing to the wire
*/
int
...
...
@@ -1380,14 +1384,14 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
thd
->
restore_backup_open_tables_state
(
&
backup
);
if
(
!
ret
&&
et
)
{
{
Protocol
*
protocol
=
thd
->
protocol
;
char
show_str_buf
[
768
];
String
show_str
(
show_str_buf
,
sizeof
(
show_str_buf
),
system_charset_info
);
List
<
Item
>
field_list
;
byte
*
sql_mode_str
;
ulong
sql_mode_len
=
0
;
show_str
.
length
(
0
);
show_str
.
set_charset
(
system_charset_info
);
...
...
@@ -1413,19 +1417,18 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
protocol
->
store
((
char
*
)
sql_mode_str
,
sql_mode_len
,
system_charset_info
);
protocol
->
store
(
show_str
.
c_ptr
(),
show_str
.
length
(),
system_charset_info
);
ret
=
protocol
->
write
();
send_eof
(
thd
);
}
DBUG_RETURN
(
ret
);
}
/*
evex_drop_db_events - Drops all events in the selected database
thd - Thread
db - ASCIIZ the name of the database
...
...
@@ -1449,7 +1452,6 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
spawned and can_spawn() is the right method.
- event_timed::can_spawn() returns false -> being runned ATM
just set the flags so it should drop itself.
*/
int
...
...
@@ -1505,7 +1507,7 @@ evex_drop_db_events(THD *thd, char *db)
else
if
(
ret
==
EVEX_KEY_NOT_FOUND
)
{
sql_print_error
(
"Expected to find event %s.%s of %s on disk-not there."
,
et
->
dbname
.
str
,
et
->
name
.
str
,
et
->
definer
.
str
);
et
->
dbname
.
str
,
et
->
name
.
str
,
et
->
definer
.
str
);
}
et
->
free_sp
();
delete
et
;
...
...
@@ -1521,7 +1523,7 @@ evex_drop_db_events(THD *thd, char *db)
}
DBUG_PRINT
(
"info"
,(
"%d elements in the queue"
,
evex_queue_num_elements
(
EVEX_EQ_NAME
)));
evex_queue_delete_element
(
&
EVEX_EQ_NAME
,
i
);
//
1
is top
evex_queue_delete_element
(
&
EVEX_EQ_NAME
,
i
);
//
0
is top
DBUG_PRINT
(
"info"
,(
"%d elements in the queue"
,
evex_queue_num_elements
(
EVEX_EQ_NAME
)));
/*
...
...
@@ -1598,7 +1600,7 @@ evex_drop_db_events(THD *thd, char *db)
VOID
(
pthread_mutex_unlock
(
&
LOCK_event_arrays
));
end_read_record
(
&
read_record_info
);
thd
->
version
--
;
// Force close to free memory
thd
->
version
--
;
/* Force close to free memory */
close_thread_tables
(
thd
);
...
...
sql/event.h
View file @
487664eb
...
...
@@ -103,6 +103,9 @@ class event_timed
TIME
starts
;
TIME
ends
;
TIME
execute_at
;
my_bool
starts_null
;
my_bool
ends_null
;
my_bool
execute_at_null
;
longlong
expression
;
interval_type
interval
;
...
...
sql/event_executor.cc
View file @
487664eb
...
...
@@ -38,9 +38,9 @@ extern ulong thread_created;
extern
const
char
*
my_localhost
;
extern
pthread_attr_t
connection_attrib
;
pthread_mutex_t
LOCK_event_arrays
,
// mutex for when working with the queue
LOCK_workers_count
,
// mutex for when inc/dec uint workers_count
LOCK_evex_running
;
// mutes for managing bool evex_is_running
pthread_mutex_t
LOCK_event_arrays
,
// mutex for when working with the queue
LOCK_workers_count
,
// mutex for when inc/dec uint workers_count
LOCK_evex_running
;
// mutes for managing bool evex_is_running
bool
evex_is_running
=
false
;
...
...
@@ -135,7 +135,7 @@ evex_check_system_tables()
bool
not_used
;
Open_tables_state
backup
;
/
/ thd is 0x0 during boot of the server. Later it's !=0x0
/
* thd is 0x0 during boot of the server. Later it's !=0x0 */
if
(
!
thd
)
return
;
...
...
@@ -151,7 +151,7 @@ evex_check_system_tables()
else
{
table_check_intact
(
tables
.
table
,
MYSQL_DB_FIELD_COUNT
,
mysql_db_table_fields
,
&
mysql_db_table_last_check
,
ER_CANNOT_LOAD_FROM_TABLE
);
&
mysql_db_table_last_check
,
ER_CANNOT_LOAD_FROM_TABLE
);
close_thread_tables
(
thd
);
}
...
...
@@ -182,7 +182,7 @@ evex_check_system_tables()
SYNOPSIS
init_events()
NOTES
Inits the mutexes used by the scheduler. Done at server start.
*/
...
...
@@ -194,7 +194,7 @@ init_events()
DBUG_ENTER
(
"init_events"
);
DBUG_PRINT
(
"info"
,(
"Starting events main thread"
));
evex_check_system_tables
();
evex_init_mutexes
();
...
...
@@ -206,7 +206,7 @@ init_events()
if
(
event_executor_running_global_var
)
{
#ifndef DBUG_FAULTY_THR
/
/TODO Andrey: Change the error code returned!
/
* TODO Andrey: Change the error code returned! */
if
(
pthread_create
(
&
th
,
&
connection_attrib
,
event_executor_main
,(
void
*
)
NULL
))
DBUG_RETURN
(
ER_SLAVE_THREAD
);
#else
...
...
@@ -223,7 +223,7 @@ init_events()
SYNOPSIS
shutdown_events()
NOTES
Destroys the mutexes.
*/
...
...
@@ -232,10 +232,10 @@ void
shutdown_events
()
{
DBUG_ENTER
(
"shutdown_events"
);
if
(
evex_mutexes_initted
)
{
evex_mutexes_initted
=
FALSE
;
evex_mutexes_initted
=
FALSE
;
VOID
(
pthread_mutex_lock
(
&
LOCK_evex_running
));
VOID
(
pthread_mutex_unlock
(
&
LOCK_evex_running
));
...
...
@@ -253,11 +253,11 @@ shutdown_events()
SYNOPSIS
init_event_thread()
thd - the THD of the thread. Has to be allocated by the caller.
NOTES
1. The host of the thead is my_localhost
2. thd->net is initted with NULL - no communication.
Returns
0 - OK
-1 - Error
...
...
@@ -304,7 +304,7 @@ init_event_thread(THD* thd)
/*
This function waits till the time next event in the queue should be
executed.
Returns
WAIT_STATUS_READY There is an event to be executed right now
WAIT_STATUS_EMPTY_QUEUE No events or the last event was dropped.
...
...
@@ -339,14 +339,14 @@ executor_wait_till_next_event_exec(THD *thd)
if
(
et
->
dropped
)
et
->
drop
(
thd
);
delete
et
;
evex_queue_delete_element
(
&
EVEX_EQ_NAME
,
1
);
// 1 is top
evex_queue_delete_element
(
&
EVEX_EQ_NAME
,
0
);
// 0 is top, internally 1
VOID
(
pthread_mutex_unlock
(
&
LOCK_event_arrays
));
sql_print_information
(
"Event found disabled, dropping."
);
DBUG_RETURN
(
1
);
}
DBUG_PRINT
(
"evex main thread"
,(
"computing time to sleep till next exec"
));
/
/ set the internal clock of thd
/
* set the internal clock of thd */
thd
->
end_time
();
my_tz_UTC
->
gmt_sec_to_TIME
(
&
time_now
,
thd
->
query_start
());
t2sleep
=
evex_time_diff
(
&
et
->
execute_at
,
&
time_now
);
...
...
@@ -387,8 +387,8 @@ executor_wait_till_next_event_exec(THD *thd)
SYNOPSIS
event_executor_main()
arg
-
unused
arg unused
NOTES
1. The host of the thead is my_localhost
2. thd->net is initted with NULL - no communication.
...
...
@@ -404,14 +404,13 @@ event_executor_main(void *arg)
TIME
time_now
;
DBUG_ENTER
(
"event_executor_main"
);
DBUG_PRINT
(
"event_executor_main"
,
(
"EVEX thread started"
));
DBUG_PRINT
(
"event_executor_main"
,
(
"EVEX thread started"
));
/
/ init memory root
/
* init memory root */
init_alloc_root
(
&
evex_mem_root
,
MEM_ROOT_BLOCK_SIZE
,
MEM_ROOT_PREALLOC
);
/
/ needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
/
* needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff*/
my_thread_init
();
if
(
sizeof
(
my_time_t
)
!=
sizeof
(
time_t
))
...
...
@@ -422,14 +421,14 @@ event_executor_main(void *arg)
goto
err_no_thd
;
}
/
/TODO Andrey: Check for NULL
if
(
!
(
thd
=
new
THD
))
// note that contructor of THD uses DBUG_ !
/
* note that contructor of THD uses DBUG_ ! */
if
(
!
(
thd
=
new
THD
))
{
sql_print_error
(
"SCHEDULER: Cannot create THD for the main thread."
);
goto
err_no_thd
;
}
thd
->
thread_stack
=
(
char
*
)
&
thd
;
// remember where our stack is
thd
->
thread_stack
=
(
char
*
)
&
thd
;
// remember where our stack is
pthread_detach_this_thread
();
if
(
init_event_thread
(
thd
))
...
...
@@ -472,7 +471,7 @@ event_executor_main(void *arg)
{
TIME
time_now
;
event_timed
*
et
;
cnt
++
;
DBUG_PRINT
(
"info"
,
(
"EVEX External Loop %d thd->k"
,
cnt
));
...
...
@@ -488,7 +487,7 @@ event_executor_main(void *arg)
my_sleep
(
1000000
);
// sleep 1s
continue
;
}
restart_ticking:
switch
(
executor_wait_till_next_event_exec
(
thd
))
{
case
WAIT_STATUS_READY
:
// time to execute the event on top
...
...
@@ -498,7 +497,7 @@ event_executor_main(void *arg)
DBUG_PRINT
(
"evex main thread"
,(
"no more events"
));
continue
;
break
;
case
WAIT_STATUS_NEW_TOP_EVENT
:
// new event on top in the queue
case
WAIT_STATUS_NEW_TOP_EVENT
:
// new event on top in the queue
DBUG_PRINT
(
"evex main thread"
,(
"restart ticking"
));
goto
restart_ticking
;
case
WAIT_STATUS_STOP_EXECUTOR
:
...
...
@@ -523,8 +522,7 @@ event_executor_main(void *arg)
et
=
evex_queue_first_element
(
&
EVEX_EQ_NAME
,
event_timed
*
);
DBUG_PRINT
(
"evex main thread"
,(
"got event from the queue"
));
if
(
et
->
execute_at
.
year
>
1969
&&
my_time_compare
(
&
time_now
,
&
et
->
execute_at
)
==
-
1
)
if
(
!
et
->
execute_at_null
&&
my_time_compare
(
&
time_now
,
&
et
->
execute_at
)
==
-
1
)
{
DBUG_PRINT
(
"evex main thread"
,(
"still not the time for execution"
));
VOID
(
pthread_mutex_unlock
(
&
LOCK_event_arrays
));
...
...
@@ -571,8 +569,11 @@ event_executor_main(void *arg)
#else
event_executor_worker
((
void
*
)
et
);
#endif
if
((
et
->
execute_at
.
year
&&
!
et
->
expression
)
||
TIME_to_ulonglong_datetime
(
&
et
->
execute_at
)
==
0
)
/*
1. For one-time event : year is > 0 and expression is 0
2. For recurring, expression is != -=> check execute_at_null in this case
*/
if
((
et
->
execute_at
.
year
&&
!
et
->
expression
)
||
et
->
execute_at_null
)
et
->
flags
|=
EVENT_EXEC_NO_MORE
;
if
((
et
->
flags
&
EVENT_EXEC_NO_MORE
)
||
et
->
status
==
MYSQL_EVENT_DISABLED
)
...
...
@@ -582,10 +583,10 @@ event_executor_main(void *arg)
}
DBUG_PRINT
(
"evex main thread"
,(
"unlocking"
));
VOID
(
pthread_mutex_unlock
(
&
LOCK_event_arrays
));
}
/
/ while
}
/
* while */
finish:
/
/ First manifest that this thread does not work and then destroy
/
* First manifest that this thread does not work and then destroy */
VOID
(
pthread_mutex_lock
(
&
LOCK_evex_running
));
evex_is_running
=
false
;
evex_main_thread_id
=
0
;
...
...
@@ -609,7 +610,7 @@ event_executor_main(void *arg)
break
;
}
VOID
(
pthread_mutex_unlock
(
&
LOCK_workers_count
));
my_sleep
(
1000000
);
// 1s
my_sleep
(
1000000
);
// 1s
}
/*
...
...
@@ -625,9 +626,9 @@ event_executor_main(void *arg)
delete
et
;
}
VOID
(
pthread_mutex_unlock
(
&
LOCK_event_arrays
));
/
/ ... then we can thrash the whole queue at once
/
* ... then we can thrash the whole queue at once */
evex_queue_destroy
(
&
EVEX_EQ_NAME
);
thd
->
proc_info
=
"Clearing"
;
DBUG_ASSERT
(
thd
->
net
.
buff
!=
0
);
net_end
(
&
thd
->
net
);
// destructor will not free it, because we are weird
...
...
@@ -655,7 +656,7 @@ event_executor_main(void *arg)
my_thread_end
();
pthread_exit
(
0
);
#endif
DBUG_RETURN
(
0
);
// Can't return anything here
DBUG_RETURN
(
0
);
// Can't return anything here
}
...
...
@@ -665,7 +666,7 @@ event_executor_main(void *arg)
SYNOPSIS
event_executor_worker()
arg
- t
he event_timed object to be processed
arg
T
he event_timed object to be processed
*/
pthread_handler_t
...
...
@@ -682,12 +683,12 @@ event_executor_worker(void *event_void)
#ifndef DBUG_FAULTY_THR
my_thread_init
();
if
(
!
(
thd
=
new
THD
))
/
/ note that contructor of THD uses DBUG_ !
if
(
!
(
thd
=
new
THD
))
/
* note that contructor of THD uses DBUG_ ! */
{
sql_print_error
(
"SCHEDULER: Cannot create a THD structure in an worker."
);
goto
err_no_thd
;
}
thd
->
thread_stack
=
(
char
*
)
&
thd
;
// remember where our stack is
thd
->
thread_stack
=
(
char
*
)
&
thd
;
// remember where our stack is
thd
->
mem_root
=
&
worker_mem_root
;
pthread_detach_this_thread
();
...
...
@@ -697,7 +698,7 @@ event_executor_worker(void *event_void)
thd
->
init_for_queries
();
/
/ make this thread visible it has no vio -> show processlist needs this flag
/
* make this thread visible it has no vio -> show processlist needs this flag */
thd
->
system_thread
=
1
;
VOID
(
pthread_mutex_lock
(
&
LOCK_thread_count
));
...
...
@@ -747,7 +748,7 @@ event_executor_worker(void *event_void)
DBUG_ASSERT
(
thd
->
net
.
buff
!=
0
);
net_end
(
&
thd
->
net
);
// destructor will not free it, because we are weird
THD_CHECK_SENTRY
(
thd
);
VOID
(
pthread_mutex_lock
(
&
LOCK_thread_count
));
THD_CHECK_SENTRY
(
thd
);
delete
thd
;
...
...
@@ -778,9 +779,9 @@ event_executor_worker(void *event_void)
thd - Thread context. Used for memory allocation in some cases.
RETURNS
0
-
OK
!0
-
Error
0 OK
!0 Error
NOTES
Reports the error to the console
*/
...
...
@@ -793,7 +794,7 @@ evex_load_events_from_db(THD *thd)
MYSQL_LOCK
*
lock
;
int
ret
=
-
1
;
uint
count
=
0
;
DBUG_ENTER
(
"evex_load_events_from_db"
);
if
((
ret
=
evex_open_event_table
(
thd
,
TL_READ
,
&
table
)))
...
...
@@ -828,7 +829,7 @@ evex_load_events_from_db(THD *thd)
delete
et
;
continue
;
}
DBUG_PRINT
(
"evex_load_events_from_db"
,
(
"Event %s loaded from row. Time to compile"
,
et
->
name
.
str
));
...
...
@@ -844,8 +845,8 @@ evex_load_events_from_db(THD *thd)
default:
break
;
}
/
/ let's find when to be executed
/
* let's find when to be executed */
if
(
et
->
compute_next_execution_time
())
{
sql_print_error
(
"SCHEDULER: Error while computing execution time of %s.%s."
...
...
@@ -866,8 +867,9 @@ evex_load_events_from_db(THD *thd)
end:
VOID
(
pthread_mutex_unlock
(
&
LOCK_event_arrays
));
end_read_record
(
&
read_record_info
);
thd
->
version
--
;
// Force close to free memory
/* Force close to free memory */
thd
->
version
--
;
close_thread_tables
(
thd
);
if
(
!
ret
)
...
...
@@ -887,15 +889,15 @@ evex_load_events_from_db(THD *thd)
event_executor_worker()
thd - Thread context (unused)
car - the new value
Returns
0
-
OK (always)
0 OK (always)
*/
bool
sys_var_event_executor
::
update
(
THD
*
thd
,
set_var
*
var
)
{
/
/ here start the thread if not running.
/
* here start the thread if not running. */
DBUG_ENTER
(
"sys_var_event_executor::update"
);
VOID
(
pthread_mutex_lock
(
&
LOCK_evex_running
));
*
value
=
var
->
save_result
.
ulong_value
;
...
...
@@ -927,12 +929,12 @@ static sql_print_xxx_func sql_print_xxx_handlers[3] =
Prints the stack of infos, warnings, errors from thd to
the console so it can be fetched by the logs-into-tables and
checked later.
Synopsis
evex_print_warnings
thd - thread used during the execution of the event
et - the event itself
Returns
0 - OK (always)
...
...
@@ -940,19 +942,20 @@ static sql_print_xxx_func sql_print_xxx_handlers[3] =
bool
evex_print_warnings
(
THD
*
thd
,
event_timed
*
et
)
{
{
MYSQL_ERROR
*
err
;
DBUG_ENTER
(
"evex_show_warnings"
);
char
msg_buf
[
1024
];
char
prefix_buf
[
512
];
String
prefix
(
prefix_buf
,
sizeof
(
prefix_buf
),
system_charset_info
);
prefix
.
length
(
0
);
List_iterator_fast
<
MYSQL_ERROR
>
it
(
thd
->
warn_list
);
while
((
err
=
it
++
))
{
String
err_msg
(
msg_buf
,
sizeof
(
msg_buf
),
system_charset_info
);
err_msg
.
length
(
0
);
// set it to 0 or we start adding at the end
/* set it to 0 or we start adding at the end. That's the trick ;) */
err_msg
.
length
(
0
);
if
(
!
prefix
.
length
())
{
prefix
.
append
(
"SCHEDULER: ["
);
...
...
@@ -966,7 +969,7 @@ evex_print_warnings(THD *thd, event_timed *et)
append_identifier
(
thd
,
&
prefix
,
et
->
name
.
str
,
et
->
name
.
length
);
prefix
.
append
(
"] "
,
2
);
}
err_msg
.
append
(
prefix
);
err_msg
.
append
(
err
->
msg
,
strlen
(
err
->
msg
),
system_charset_info
);
err_msg
.
append
(
"]"
);
...
...
sql/event_timed.cc
View file @
487664eb
...
...
@@ -41,6 +41,7 @@ event_timed::init()
set_zero_time
(
&
ends
,
MYSQL_TIMESTAMP_DATETIME
);
set_zero_time
(
&
execute_at
,
MYSQL_TIMESTAMP_DATETIME
);
set_zero_time
(
&
last_executed
,
MYSQL_TIMESTAMP_DATETIME
);
starts_null
=
ends_null
=
execute_at_null
=
TRUE
;
definer_user
.
str
=
definer_host
.
str
=
0
;
definer_user
.
length
=
definer_host
.
length
=
0
;
...
...
@@ -115,7 +116,7 @@ event_timed::init_body(THD *thd)
body_begin
,
thd
->
lex
->
ptr
));
body
.
length
=
thd
->
lex
->
ptr
-
body_begin
;
/
/ Trim nuls at the end
/
* Trim nuls at the end */
while
(
body
.
length
&&
body_begin
[
body
.
length
-
1
]
==
'\0'
)
body
.
length
--
;
...
...
@@ -157,12 +158,16 @@ event_timed::init_execute_at(THD *thd, Item *expr)
if
(
expr
->
fix_fields
(
thd
,
&
expr
))
DBUG_RETURN
(
EVEX_PARSE_ERROR
);
/* Let's check whether time is in the past */
thd
->
variables
.
time_zone
->
gmt_sec_to_TIME
(
&
time_tmp
,
/* no starts and/or ends in case of execute_at */
DBUG_PRINT
(
"info"
,
(
"starts_null && ends_null should be 1 is %d"
,
(
starts_null
&&
ends_null
)));
DBUG_ASSERT
(
starts_null
&&
ends_null
);
/* let's check whether time is in the past */
thd
->
variables
.
time_zone
->
gmt_sec_to_TIME
(
&
time_tmp
,
(
my_time_t
)
thd
->
query_start
());
if
((
not_used
=
expr
->
get_date
(
&
ltime
,
TIME_NO_ZERO_DATE
)))
DBUG_RETURN
(
ER_WRONG_VALUE
);
...
...
@@ -177,7 +182,7 @@ event_timed::init_execute_at(THD *thd, Item *expr)
*/
my_tz_UTC
->
gmt_sec_to_TIME
(
&
ltime
,
TIME_to_timestamp
(
thd
,
&
ltime
,
&
not_used
));
execute_at_null
=
FALSE
;
execute_at
=
ltime
;
DBUG_RETURN
(
0
);
}
...
...
@@ -246,14 +251,14 @@ event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
case
INTERVAL_DAY_MINUTE
:
expression
=
(
interval
.
day
*
24
+
interval
.
hour
)
*
60
+
interval
.
minute
;
break
;
case
INTERVAL_HOUR_SECOND
:
/
/ day is anyway 0
case
INTERVAL_HOUR_SECOND
:
/
* day is anyway 0 */
case
INTERVAL_DAY_SECOND
:
/* DAY_SECOND having problems because of leap seconds? */
expression
=
((
interval
.
day
*
24
+
interval
.
hour
)
*
60
+
interval
.
minute
)
*
60
+
interval
.
second
;
break
;
case
INTERVAL_MINUTE_MICROSECOND
:
/
/ day and hour are 0
case
INTERVAL_HOUR_MICROSECOND
:
// day is anyway 0
case
INTERVAL_MINUTE_MICROSECOND
:
/
* day and hour are 0 */
case
INTERVAL_HOUR_MICROSECOND
:
/* day is anyway 0 */
case
INTERVAL_DAY_MICROSECOND
:
DBUG_RETURN
(
EVEX_MICROSECOND_UNSUP
);
expression
=
((((
interval
.
day
*
24
)
+
interval
.
hour
)
*
60
+
interval
.
minute
)
*
60
+
...
...
@@ -332,6 +337,7 @@ event_timed::init_starts(THD *thd, Item *new_starts)
my_tz_UTC
->
gmt_sec_to_TIME
(
&
ltime
,
TIME_to_timestamp
(
thd
,
&
ltime
,
&
not_used
));
starts
=
ltime
;
starts_null
=
FALSE
;
DBUG_RETURN
(
0
);
}
...
...
@@ -361,8 +367,7 @@ event_timed::init_starts(THD *thd, Item *new_starts)
int
event_timed
::
init_ends
(
THD
*
thd
,
Item
*
new_ends
)
{
TIME
ltime
;
my_time_t
my_time_tmp
;
TIME
ltime
,
ltime_now
;
my_bool
not_used
;
DBUG_ENTER
(
"event_timed::init_ends"
);
...
...
@@ -370,20 +375,34 @@ event_timed::init_ends(THD *thd, Item *new_ends)
if
(
new_ends
->
fix_fields
(
thd
,
&
new_ends
))
DBUG_RETURN
(
EVEX_PARSE_ERROR
);
/* The field was already fixed in init_ends */
DBUG_PRINT
(
"info"
,
(
"convert to TIME"
));
if
((
not_used
=
new_ends
->
get_date
(
&
ltime
,
TIME_NO_ZERO_DATE
)))
DBUG_RETURN
(
EVEX_BAD_PARAMS
);
/*
This may result in a 1970-01-01 date if ltime is > 2037-xx-xx
.
CONVERT_TZ has similar problem
.
This may result in a 1970-01-01 date if ltime is > 2037-xx-xx
?
CONVERT_TZ has similar problem
?
*/
DBUG_PRINT
(
"info"
,
(
"get the UTC time"
));
my_tz_UTC
->
gmt_sec_to_TIME
(
&
ltime
,
TIME_to_timestamp
(
thd
,
&
ltime
,
&
not_used
));
if
(
starts
.
year
&&
my_time_compare
(
&
starts
,
&
ltime
)
!=
-
1
)
/* Check whether ends is after starts */
DBUG_PRINT
(
"info"
,
(
"ENDS after STARTS?"
));
if
(
!
starts_null
&&
my_time_compare
(
&
starts
,
&
ltime
)
!=
-
1
)
DBUG_RETURN
(
EVEX_BAD_PARAMS
);
/*
The parser forces starts to be provided but one day STARTS could be
set before NOW() and in this case the following check should be done.
Check whether ENDS is not in the past.
*/
DBUG_PRINT
(
"info"
,
(
"ENDS after NOW?"
));
my_tz_UTC
->
gmt_sec_to_TIME
(
&
ltime_now
,
thd
->
query_start
());
if
(
my_time_compare
(
&
ltime_now
,
&
ltime
)
==
1
)
DBUG_RETURN
(
EVEX_BAD_PARAMS
);
ends
=
ltime
;
ends_null
=
FALSE
;
DBUG_RETURN
(
0
);
}
...
...
@@ -403,7 +422,7 @@ event_timed::init_comment(THD *thd, LEX_STRING *set_comment)
DBUG_ENTER
(
"event_timed::init_comment"
);
comment
.
str
=
strmake_root
(
thd
->
mem_root
,
set_comment
->
str
,
comment
.
length
=
set_comment
->
length
);
comment
.
length
=
set_comment
->
length
);
DBUG_VOID_RETURN
;
}
...
...
@@ -514,32 +533,41 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
et
->
definer_user
.
str
=
strmake_root
(
mem_root
,
et
->
definer
.
str
,
len
);
et
->
definer_user
.
length
=
len
;
len
=
et
->
definer
.
length
-
len
-
1
;
//1 is because of @
et
->
definer_host
.
str
=
strmake_root
(
mem_root
,
ptr
+
1
,
len
);
/
/1: because of @
len
=
et
->
definer
.
length
-
len
-
1
;
//1 is because of @
et
->
definer_host
.
str
=
strmake_root
(
mem_root
,
ptr
+
1
,
len
);
/
* 1:because of @*/
et
->
definer_host
.
length
=
len
;
et
->
starts_null
=
table
->
field
[
EVEX_FIELD_STARTS
]
->
is_null
();
res1
=
table
->
field
[
EVEX_FIELD_STARTS
]
->
get_date
(
&
et
->
starts
,
TIME_NO_ZERO_DATE
);
res1
=
table
->
field
[
EVEX_FIELD_STARTS
]
->
get_date
(
&
et
->
starts
,
TIME_NO_ZERO_DATE
);
res2
=
table
->
field
[
EVEX_FIELD_ENDS
]
->
get_date
(
&
et
->
ends
,
TIME_NO_ZERO_DATE
);
et
->
expression
=
table
->
field
[
EVEX_FIELD_INTERVAL_EXPR
]
->
val_int
();
et
->
ends_null
=
table
->
field
[
EVEX_FIELD_ENDS
]
->
is_null
();
res2
=
table
->
field
[
EVEX_FIELD_ENDS
]
->
get_date
(
&
et
->
ends
,
TIME_NO_ZERO_DATE
);
if
(
!
table
->
field
[
EVEX_FIELD_INTERVAL_EXPR
]
->
is_null
())
et
->
expression
=
table
->
field
[
EVEX_FIELD_INTERVAL_EXPR
]
->
val_int
();
else
et
->
expression
=
0
;
/*
If res1 and res2 are true then both fields are empty.
Hence if EVEX_FIELD_EXECUTE_AT is empty there is an error.
*/
if
(
res1
&&
res2
&&
!
et
->
expression
&&
table
->
field
[
EVEX_FIELD_EXECUTE_AT
]
->
get_date
(
&
et
->
execute_at
,
TIME_NO_ZERO_DATE
))
et
->
execute_at_null
=
table
->
field
[
EVEX_FIELD_EXECUTE_AT
]
->
is_null
();
DBUG_ASSERT
(
!
(
et
->
starts_null
&&
et
->
ends_null
&&
!
et
->
expression
&&
et
->
execute_at_null
));
if
(
!
et
->
expression
&&
table
->
field
[
EVEX_FIELD_EXECUTE_AT
]
->
get_date
(
&
et
->
execute_at
,
TIME_NO_ZERO_DATE
))
goto
error
;
/*
In DB the values start from 1 but enum interval_type starts
from 0
*/
et
->
interval
=
(
interval_type
)
if
(
!
table
->
field
[
EVEX_FIELD_TRANSIENT_INTERVAL
]
->
is_null
())
et
->
interval
=
(
interval_type
)
((
ulonglong
)
table
->
field
[
EVEX_FIELD_TRANSIENT_INTERVAL
]
->
val_int
()
-
1
);
else
et
->
interval
=
(
interval_type
)
0
;
et
->
modified
=
table
->
field
[
EVEX_FIELD_CREATED
]
->
val_int
();
et
->
created
=
table
->
field
[
EVEX_FIELD_MODIFIED
]
->
val_int
();
...
...
@@ -568,20 +596,20 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
#endif
last_executed_changed
=
false
;
/
/ ToDo : Andrey . Find a way not to allocate ptr on event_mem_root
/
* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if
((
ptr
=
get_field
(
mem_root
,
table
->
field
[
EVEX_FIELD_STATUS
]))
==
NullS
)
goto
error
;
DBUG_PRINT
(
"load_from_row"
,
(
"Event [%s] is [%s]"
,
et
->
name
.
str
,
ptr
));
et
->
status
=
(
ptr
[
0
]
==
'E'
?
MYSQL_EVENT_ENABLED
:
MYSQL_EVENT_DISABLED
);
/
/ ToDo : Andrey . Find a way not to allocate ptr on event_mem_root
/
* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if
((
ptr
=
get_field
(
mem_root
,
table
->
field
[
EVEX_FIELD_ON_COMPLETION
]))
==
NullS
)
goto
error
;
et
->
on_completion
=
(
ptr
[
0
]
==
'D'
?
MYSQL_EVENT_ON_COMPLETION_DROP
:
MYSQL_EVENT_ON_COMPLETION_PRESERVE
);
MYSQL_EVENT_ON_COMPLETION_PRESERVE
);
et
->
comment
.
str
=
get_field
(
mem_root
,
table
->
field
[
EVEX_FIELD_COMMENT
]);
if
(
et
->
comment
.
str
!=
NullS
)
...
...
@@ -698,14 +726,11 @@ event_timed::compute_next_execution_time()
/* Let's check whether it was executed */
if
(
last_executed
.
year
)
{
DBUG_PRINT
(
"compute_next_execution_time"
,
(
"One-time event %s was already executed"
,
name
.
str
));
if
(
on_completion
==
MYSQL_EVENT_ON_COMPLETION_DROP
)
{
DBUG_PRINT
(
"compute_next_execution_time"
,
(
"One-time event will be dropped."
));
dropped
=
true
;
}
DBUG_PRINT
(
"info"
,(
"One-time event %s.%s of was already executed"
,
dbname
.
str
,
name
.
str
,
definer
.
str
));
dropped
=
(
on_completion
==
MYSQL_EVENT_ON_COMPLETION_DROP
);
DBUG_PRINT
(
"info"
,(
"One-time event will be dropped=%d."
,
dropped
));
status
=
MYSQL_EVENT_DISABLED
;
status_changed
=
true
;
}
...
...
@@ -731,11 +756,12 @@ event_timed::compute_next_execution_time()
last_executed
.
second
);
#endif
/*
I
f time_now is after ends don't execute anymore */
if
(
ends
.
year
&&
(
tmp
=
my_time_compare
(
&
ends
,
&
time_now
))
==
-
1
)
/*
i
f time_now is after ends don't execute anymore */
if
(
!
ends_null
&&
(
tmp
=
my_time_compare
(
&
ends
,
&
time_now
))
==
-
1
)
{
/* time_now is after ends. don't execute anymore */
set_zero_time
(
&
execute_at
,
MYSQL_TIMESTAMP_DATETIME
);
execute_at_null
=
TRUE
;
if
(
on_completion
==
MYSQL_EVENT_ON_COMPLETION_DROP
)
dropped
=
true
;
status
=
MYSQL_EVENT_DISABLED
;
...
...
@@ -749,7 +775,7 @@ event_timed::compute_next_execution_time()
Let's check whether time_now is before starts.
If so schedule for starts.
*/
if
(
starts
.
year
&&
(
tmp
=
my_time_compare
(
&
time_now
,
&
starts
))
<
1
)
if
(
!
starts_null
&&
(
tmp
=
my_time_compare
(
&
time_now
,
&
starts
))
<
1
)
{
if
(
tmp
==
0
&&
my_time_compare
(
&
starts
,
&
last_executed
)
==
0
)
{
...
...
@@ -765,11 +791,12 @@ event_timed::compute_next_execution_time()
time_now before starts. Scheduling for starts
*/
execute_at
=
starts
;
execute_at_null
=
FALSE
;
goto
ret
;
}
}
if
(
starts
.
year
&&
ends
.
year
)
if
(
!
starts_null
&&
!
ends_null
)
{
/*
Both starts and m_ends are set and time_now is between them (incl.)
...
...
@@ -778,7 +805,10 @@ event_timed::compute_next_execution_time()
If not set then schedule for now.
*/
if
(
!
last_executed
.
year
)
{
execute_at
=
time_now
;
execute_at_null
=
FALSE
;
}
else
{
TIME
next_exec
;
...
...
@@ -791,15 +821,19 @@ event_timed::compute_next_execution_time()
{
/* Next execution after ends. No more executions */
set_zero_time
(
&
execute_at
,
MYSQL_TIMESTAMP_DATETIME
);
execute_at_null
=
TRUE
;
if
(
on_completion
==
MYSQL_EVENT_ON_COMPLETION_DROP
)
dropped
=
true
;
}
else
{
execute_at
=
next_exec
;
execute_at_null
=
FALSE
;
}
}
goto
ret
;
}
else
if
(
!
starts
.
year
&&
!
ends
.
year
)
else
if
(
starts_null
&&
ends_null
)
{
/*
Both starts and m_ends are not set, so we schedule for the next
...
...
@@ -815,11 +849,12 @@ event_timed::compute_next_execution_time()
/* last_executed not set. Schedule the event for now */
execute_at
=
time_now
;
}
execute_at_null
=
FALSE
;
}
else
{
/*
E
ither starts or m_ends is set */
if
(
starts
.
year
)
/*
e
ither starts or m_ends is set */
if
(
!
starts_null
)
{
/*
- starts is set.
...
...
@@ -834,6 +869,7 @@ event_timed::compute_next_execution_time()
}
else
execute_at
=
starts
;
execute_at_null
=
FALSE
;
}
else
{
...
...
@@ -856,11 +892,15 @@ event_timed::compute_next_execution_time()
if
(
my_time_compare
(
&
ends
,
&
next_exec
)
==
-
1
)
{
set_zero_time
(
&
execute_at
,
MYSQL_TIMESTAMP_DATETIME
);
execute_at_null
=
TRUE
;
if
(
on_completion
==
MYSQL_EVENT_ON_COMPLETION_DROP
)
dropped
=
true
;
}
else
{
execute_at
=
next_exec
;
execute_at_null
=
FALSE
;
}
}
}
goto
ret
;
...
...
@@ -890,7 +930,7 @@ event_timed::mark_last_executed(THD *thd)
thd
->
end_time
();
my_tz_UTC
->
gmt_sec_to_TIME
(
&
time_now
,
(
my_time_t
)
thd
->
query_start
());
last_executed
=
time_now
;
/
/ was execute_at
last_executed
=
time_now
;
/
* was execute_at */
#ifdef ANDREY_0
last_executed
=
execute_at
;
#endif
...
...
@@ -1045,7 +1085,7 @@ event_timed::get_create_event(THD *thd, String *buf)
}
else
{
char
dtime_buff
[
20
*
2
+
32
];
/
/ +32 to make my_snprintf_{8bit|ucs2} happy
char
dtime_buff
[
20
*
2
+
32
];
/
* +32 to make my_snprintf_{8bit|ucs2} happy */
buf
->
append
(
STRING_WITH_LEN
(
"AT '"
));
/*
Pass the buffer and the second param tells fills the buffer and
...
...
@@ -1324,10 +1364,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
sphead
=
lex
.
et
->
sphead
;
sphead
->
m_db
=
dbname
;
/*
Ccopy also chistics since they will vanish otherwise we get 0x0 pointer
TODO: Handle sql_mode!!
*/
sphead
->
set_definer
(
definer
.
str
,
definer
.
length
);
sphead
->
set_info
(
0
,
0
,
&
lex
.
sp_chistics
,
sql_mode
);
sphead
->
optimize
();
...
...
@@ -1389,7 +1426,7 @@ extern pthread_attr_t connection_attrib;
/*
Checks whether is possible and forks a thread. Passes self as argument.
Returns
EVENT_EXEC_STARTED - OK
EVENT_EXEC_ALREADY_EXEC - Thread not forked, already working
...
...
@@ -1460,7 +1497,6 @@ event_timed::spawn_thread_finish(THD *thd)
Returns
0 - ok
1 - not locked by this thread
*/
...
...
@@ -1486,5 +1522,5 @@ event_timed::spawn_unlock(THD *thd)
}
}
VOID
(
pthread_mutex_unlock
(
&
this
->
LOCK_running
));
return
ret
;
return
ret
;
}
sql/sql_show.cc
View file @
487664eb
...
...
@@ -3957,7 +3957,7 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
sch_table
->
field
[
3
]
->
store
(
et
.
definer
.
str
,
et
.
definer
.
length
,
scs
);
sch_table
->
field
[
4
]
->
store
(
et
.
body
.
str
,
et
.
body
.
length
,
scs
);
/
/ [9] is SQL_MODE
/
* [9] is SQL_MODE */
{
byte
*
sql_mode_str
;
ulong
sql_mode_len
=
0
;
...
...
@@ -3972,9 +3972,9 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
String
show_str
;
//type
sch_table
->
field
[
5
]
->
store
(
STRING_WITH_LEN
(
"RECURRING"
),
scs
);
/
/execute_at
/
* execute_at */
sch_table
->
field
[
6
]
->
set_null
();
/
/interval_value
/
* interval_value */
//interval_type
if
(
event_reconstruct_interval_expression
(
&
show_str
,
et
.
interval
,
et
.
expression
))
...
...
@@ -3986,26 +3986,24 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
LEX_STRING
*
ival
=
&
interval_type_to_name
[
et
.
interval
];
sch_table
->
field
[
8
]
->
set_notnull
();
sch_table
->
field
[
8
]
->
store
(
ival
->
str
,
ival
->
length
,
scs
);
//starts & ends
//starts & ends
sch_table
->
field
[
10
]
->
set_notnull
();
sch_table
->
field
[
10
]
->
store_time
(
&
et
.
starts
,
MYSQL_TIMESTAMP_DATETIME
);
sch_table
->
field
[
11
]
->
set_notnull
();
sch_table
->
field
[
11
]
->
store_time
(
&
et
.
ends
,
MYSQL_TIMESTAMP_DATETIME
);
if
(
!
et
.
ends_null
)
{
sch_table
->
field
[
11
]
->
set_notnull
();
sch_table
->
field
[
11
]
->
store_time
(
&
et
.
ends
,
MYSQL_TIMESTAMP_DATETIME
);
}
}
else
{
//type
sch_table
->
field
[
5
]
->
store
(
STRING_WITH_LEN
(
"ONE TIME"
),
scs
);
//execute_at
sch_table
->
field
[
6
]
->
set_notnull
();
sch_table
->
field
[
6
]
->
store_time
(
&
et
.
execute_at
,
MYSQL_TIMESTAMP_DATETIME
);
//interval
sch_table
->
field
[
7
]
->
set_null
();
//interval_type
sch_table
->
field
[
8
]
->
set_null
();
//starts & ends
sch_table
->
field
[
10
]
->
set_null
();
sch_table
->
field
[
11
]
->
set_null
();
}
//status
...
...
sql/sql_yacc.yy
View file @
487664eb
...
...
@@ -1476,6 +1476,9 @@ opt_ev_status: /* empty */ { $$= 0; }
;
ev_starts: /* empty */
{
Lex->et->init_starts(YYTHD, new Item_func_now_local());
}
| STARTS_SYM expr
{
LEX *lex= Lex;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment