developers
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
March 2010
- 23 participants
- 366 discussions
[Maria-developers] Rev 2758: Atomic operation removed because we do not need it. in file:///home/bell/maria/bzr/work-maria-5.2-sync/
by sanja@askmonty.org 29 Mar '10
by sanja@askmonty.org 29 Mar '10
29 Mar '10
At file:///home/bell/maria/bzr/work-maria-5.2-sync/
------------------------------------------------------------
revno: 2758
revision-id: sanja(a)askmonty.org-20100329185318-s8s6lsuvm12oi8yb
parent: sergii(a)pisem.net-20100329151428-zkvrkidiyqmb19pn
committer: sanja(a)askmonty.org
branch nick: work-maria-5.2-sync
timestamp: Mon 2010-03-29 21:53:18 +0300
message:
Atomic operation removed because we do not need it.
=== modified file 'storage/maria/ma_loghandler.c'
--- a/storage/maria/ma_loghandler.c 2010-03-15 11:51:23 +0000
+++ b/storage/maria/ma_loghandler.c 2010-03-29 18:53:18 +0000
@@ -8060,18 +8060,14 @@
/* keep values for soft sync() and forced sync() actual */
{
uint32 fileno= LSN_FILE_NO(lsn);
- my_atomic_rwlock_wrlock(&soft_sync_rwl);
- my_atomic_store32(&soft_sync_min, fileno);
- my_atomic_store32(&soft_sync_max, fileno);
- my_atomic_rwlock_wrunlock(&soft_sync_rwl);
+ soft_sync_min= fileno;
+ soft_sync_max= fileno;
}
}
else
{
- my_atomic_rwlock_wrlock(&soft_sync_rwl);
- my_atomic_store32(&soft_sync_max, LSN_FILE_NO(lsn));
- my_atomic_store32(&soft_need_sync, 1);
- my_atomic_rwlock_wrunlock(&soft_sync_rwl);
+ soft_sync_max= lsn;
+ soft_need_sync= 1;
}
DBUG_ASSERT(flush_horizon <= log_descriptor.horizon);
@@ -8464,9 +8460,7 @@
translog_status == TRANSLOG_READONLY);
soft= soft_sync;
- my_atomic_rwlock_wrlock(&soft_sync_rwl);
- min_unsync= my_atomic_load32(&soft_sync_min);
- my_atomic_rwlock_wrunlock(&soft_sync_rwl);
+ min_unsync= soft_sync_min;
DBUG_PRINT("info", ("min_unsync: %lu", (ulong) min_unsync));
if (soft && min_unsync < last_need_file)
{
@@ -8748,9 +8742,7 @@
uint32 min;
DBUG_ENTER("ma_translog_sync");
- my_atomic_rwlock_rdlock(&soft_sync_rwl);
- min= my_atomic_load32(&soft_sync_min);
- my_atomic_rwlock_rdunlock(&soft_sync_rwl);
+ min= soft_sync_min;
if (!min)
min= max;
@@ -8796,13 +8788,11 @@
ulonglong prev_loop= my_micro_time();
ulonglong time, sleep;
uint32 min, max, sync_request;
- my_atomic_rwlock_rdlock(&soft_sync_rwl);
- min= my_atomic_load32(&soft_sync_min);
- max= my_atomic_load32(&soft_sync_max);
- sync_request= my_atomic_load32(&soft_need_sync);
- my_atomic_store32(&soft_sync_min, max);
- my_atomic_store32(&soft_need_sync, 0);
- my_atomic_rwlock_rdunlock(&soft_sync_rwl);
+ min= soft_sync_min;
+ max= soft_sync_max;
+ sync_request= soft_need_sync;
+ soft_sync_min= max;
+ soft_need_sync= 0;
sleep= group_commit_wait;
if (sync_request)
@@ -8834,15 +8824,13 @@
DBUG_ENTER("translog_soft_sync_start");
/* check and init variables */
- my_atomic_rwlock_rdlock(&soft_sync_rwl);
- min= my_atomic_load32(&soft_sync_min);
- max= my_atomic_load32(&soft_sync_max);
+ min= soft_sync_min;
+ max= soft_sync_max;
if (!max)
- my_atomic_store32(&soft_sync_max, (max= get_current_logfile()->number));
+ soft_sync_max= max= get_current_logfile()->number;
if (!min)
- my_atomic_store32(&soft_sync_min, max);
- my_atomic_store32(&soft_need_sync, 1);
- my_atomic_rwlock_rdunlock(&soft_sync_rwl);
+ soft_sync_min= max;
+ soft_need_sync= 1;
if (!(res= ma_service_thread_control_init(&soft_sync_control)))
if (!(res= pthread_create(&th, NULL, ma_soft_sync_background, NULL)))
1
0
[Maria-developers] Updated (by Knielsen): Merge OQGraph into MariaDB (112)
by worklog-noreply@askmonty.org 29 Mar '10
by worklog-noreply@askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Merge OQGraph into MariaDB
CREATION DATE..: Mon, 29 Mar 2010, 18:00
SUPERVISOR.....: Knielsen
IMPLEMENTOR....: Knielsen
COPIES TO......:
CATEGORY.......: Server-Sprint
TASK ID........: 112 (http://askmonty.org/worklog/?tid=112)
VERSION........: Server-5.2
STATUS.........: Assigned
PRIORITY.......: 60
WORKED HOURS...: 0
ESTIMATE.......: 15 (hours remain)
ORIG. ESTIMATE.: 15
PROGRESS NOTES:
-=-=(Knielsen - Mon, 29 Mar 2010, 18:09)=-=-
High-Level Specification modified.
--- /tmp/wklog.112.old.23061 2010-03-29 18:09:27.000000000 +0000
+++ /tmp/wklog.112.new.23061 2010-03-29 18:09:27.000000000 +0000
@@ -1 +1,28 @@
+Tasks:
+
+Find the latest version of OQGraph to base this on (there should be a
+Launchpad branch somewhere, match it up with what is in the OQGraph patch for
+MySQL 5.0 in the ourdelta stuff).
+
+Extract the correct version of Boost from the MySQL 5.0 ourdelta patch. This
+is a patched version of Boost fixing a bug that is supposedly fatal for
+OQGraph (details are not known at the time of writing).
+
+Document in OQGraph README the need for boost of a specific version, and point
+to where it can be obtained. Also include the patch for boost if the correct
+base version of boost to do this against can be determined.
+
+Install the patched boost in /usr/local/ on the build machines (release builds
+and selected Buildbot slaves).
+
+Fix OQGraph plug.in to detect correct version of OQGraph that makes the build
+not break. Check which version in Ubuntu starts working (I think it was
+Jaunty), and require at least that version.
+
+Setup some repository or source tarball of the patched boost
+somewhere. Preferably a Launchpad branch or similar (if upstream project can
+be found).
+
+Setup in plug.in or /configure.in appropriate --with-boost=xxx. Or in a pinch,
+we can make do with CFLAGS=-Ixxx, or even default look in /usr/local/.
DESCRIPTION:
Get the OQGraph storage engine merged into MariaDB, fixing the remaining
problems blocking the merge.
HIGH-LEVEL SPECIFICATION:
Tasks:
Find the latest version of OQGraph to base this on (there should be a
Launchpad branch somewhere, match it up with what is in the OQGraph patch for
MySQL 5.0 in the ourdelta stuff).
Extract the correct version of Boost from the MySQL 5.0 ourdelta patch. This
is a patched version of Boost fixing a bug that is supposedly fatal for
OQGraph (details are not known at the time of writing).
Document in OQGraph README the need for boost of a specific version, and point
to where it can be obtained. Also include the patch for boost if the correct
base version of boost to do this against can be determined.
Install the patched boost in /usr/local/ on the build machines (release builds
and selected Buildbot slaves).
Fix OQGraph plug.in to detect correct version of OQGraph that makes the build
not break. Check which version in Ubuntu starts working (I think it was
Jaunty), and require at least that version.
Setup some repository or source tarball of the patched boost
somewhere. Preferably a Launchpad branch or similar (if upstream project can
be found).
Setup in plug.in or /configure.in appropriate --with-boost=xxx. Or in a pinch,
we can make do with CFLAGS=-Ixxx, or even default look in /usr/local/.
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0
[Maria-developers] New (by Knielsen): Merge OQGraph into MariaDB (112)
by worklog-noreply@askmonty.org 29 Mar '10
by worklog-noreply@askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Merge OQGraph into MariaDB
CREATION DATE..: Mon, 29 Mar 2010, 18:00
SUPERVISOR.....: Knielsen
IMPLEMENTOR....: Knielsen
COPIES TO......:
CATEGORY.......: Server-Sprint
TASK ID........: 112 (http://askmonty.org/worklog/?tid=112)
VERSION........: Server-5.2
STATUS.........: Assigned
PRIORITY.......: 60
WORKED HOURS...: 0
ESTIMATE.......: 15 (hours remain)
ORIG. ESTIMATE.: 15
PROGRESS NOTES:
DESCRIPTION:
Get the OQGraph storage engine merged into MariaDB, fixing the remaining
problems blocking the merge.
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0
[Maria-developers] Updated (by Guest): Make EXPLAIN always show materialization separately (110)
by worklog-noreply@askmonty.org 29 Mar '10
by worklog-noreply@askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Make EXPLAIN always show materialization separately
CREATION DATE..: Mon, 29 Mar 2010, 06:45
SUPERVISOR.....: Igor
IMPLEMENTOR....: Psergey
COPIES TO......:
CATEGORY.......: Server-RawIdeaBin
TASK ID........: 110 (http://askmonty.org/worklog/?tid=110)
VERSION........: Server-5.3
STATUS.........: Complete
PRIORITY.......: 60
WORKED HOURS...: 0
ESTIMATE.......: 0 (hours remain)
ORIG. ESTIMATE.: 0
PROGRESS NOTES:
-=-=(Guest - Mon, 29 Mar 2010, 14:09)=-=-
Status updated.
--- /tmp/wklog.110.old.11193 2010-03-29 14:09:27.000000000 +0000
+++ /tmp/wklog.110.new.11193 2010-03-29 14:09:27.000000000 +0000
@@ -1 +1 @@
-Un-Assigned
+Complete
-=-=(Psergey - Mon, 29 Mar 2010, 06:46)=-=-
Low Level Design modified.
--- /tmp/wklog.110.old.11745 2010-03-29 06:46:30.000000000 +0000
+++ /tmp/wklog.110.new.11745 2010-03-29 06:46:30.000000000 +0000
@@ -1 +1,8 @@
+For now, all changes will be in select_describe():
+- In the for-each-join-table loop, when we've reached a line where we would
+ have printed "[Start ]Materialize;" in Extra column, remember the table
+ number, and emit a materialized table access line instead
+- After the loop, do another loop over remembered materialization nests and
+ print them (a possible difficulty: do we remember what select# they are
+ from?)
-=-=(Psergey - Mon, 29 Mar 2010, 06:46)=-=-
High-Level Specification modified.
--- /tmp/wklog.110.old.11654 2010-03-29 06:46:19.000000000 +0000
+++ /tmp/wklog.110.new.11654 2010-03-29 06:46:19.000000000 +0000
@@ -1 +1,15 @@
+Materialized table access line will look as follows:
+Table name
+----------
+* Table name will be "SUBQUERY#%d" where %d will refer to the id of first
+ select in the subquery (when the subquery is a UNION it would be better
+ to refe to the union-operation line but it has id=NULL so it's not easy
+ to refer to it)
+
+Access method
+-------------
+* SJ-Materialization-lookup will have eq_ref on 'distinct_key'
+* SJ-Materialization-scan will have access method ALL, with #rows being
+ expected number of records in the temp table (i.e. after duplicates are
+ removed)
-=-=(Psergey - Mon, 29 Mar 2010, 06:46)=-=-
Category updated.
--- /tmp/wklog.110.old.11639 2010-03-29 06:46:02.000000000 +0000
+++ /tmp/wklog.110.new.11639 2010-03-29 06:46:02.000000000 +0000
@@ -1 +1 @@
-Client-BackLog
+Server-RawIdeaBin
-=-=(Psergey - Mon, 29 Mar 2010, 06:46)=-=-
Version updated.
--- /tmp/wklog.110.old.11639 2010-03-29 06:46:02.000000000 +0000
+++ /tmp/wklog.110.new.11639 2010-03-29 06:46:02.000000000 +0000
@@ -1 +1 @@
-Benchmarks-3.0
+9.x
-=-=(Psergey - Mon, 29 Mar 2010, 06:46)=-=-
Version updated.
--- /tmp/wklog.110.old.11639 2010-03-29 06:46:02.000000000 +0000
+++ /tmp/wklog.110.new.11639 2010-03-29 06:46:02.000000000 +0000
@@ -1 +1 @@
-9.x
+Server-5.3
DESCRIPTION:
At the moment, SJM-Materialization is shown in EXPLAIN output in this way:
MariaDB [j45]> explain select * from ot where a in (select b from it1);
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows
| Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | ot | ALL | NULL | NULL | NULL | NULL | 10
| |
| 1 | PRIMARY | it1 | ALL | NULL | NULL | NULL | NULL | 10
| Materialize |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
MariaDB [j45]> explain select * from ot where a in (select it1.b from it1, it2);
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows
| Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------------+
| 1 | PRIMARY | ot | ALL | NULL | NULL | NULL | NULL | 10
| |
| 1 | PRIMARY | it1 | ALL | NULL | NULL | NULL | NULL | 10
| Start materialize |
| 1 | PRIMARY | it2 | ALL | NULL | NULL | NULL | NULL | 10
| End materialize; Using join buffer |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------------+
This WL task is to change the output format so it will look as follows:
- Tables inside the SJM-nest are displayed as a separate select
- within the master select, there is a line that denotes SJM-lookup or
SJM-Scan.
The above examples will look as follows:
MariaDB [j45]> explain select * from ot where a in (select b from it1);
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------+
| id | select_type | table | type | possible_keys | key |
key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------+
| 1 | PRIMARY | ot | ALL | NULL | NULL | NULL
| NULL | 10 | |
| 1 | PRIMARY | SUBQUERY#2 | eq_ref | distinct_key | distinct_key | 5
| j45.ot.a | 1 | |
| 2 | SUBQUERY | it1 | ALL | NULL | NULL | NULL
| NULL | 10 | |
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------+
MariaDB [j45]> explain select * from ot where a in (select it1.b from it1, it2);
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------------------+
| id | select_type | table | type | possible_keys | key |
key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------------------+
| 1 | PRIMARY | ot | ALL | NULL | NULL | NULL
| NULL | 10 | |
| 1 | PRIMARY | SUBQUERY#2 | eq_ref | distinct_key | distinct_key | 5
| j45.ot.a | 1 | |
| 2 | SUBQUERY | it1 | ALL | NULL | NULL | NULL
| NULL | 10 | |
| 2 | SUBQUERY | it2 | ALL | NULL | NULL | NULL
| NULL | 10 | Using join buffer |
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------------------+
The rationale behind the change is:
- Unification of EXPLAIN output with MWL#90
- The new format is more natural representation of what is going on,
conceptually-wise (and may be soon be code-wise)
- The new format allows to display E(#records-in-temp-table) for the
SJM-Scan case (and for SJM-lookup that number doesn't matter that much)
- The new format doesn't put anything into "Extra" column and that's good
because that column is already overloaded and horizontal screen space is
precious (while vertical is not so much).
HIGH-LEVEL SPECIFICATION:
Materialized table access line will look as follows:
Table name
----------
* Table name will be "SUBQUERY#%d" where %d will refer to the id of first
select in the subquery (when the subquery is a UNION it would be better
to refe to the union-operation line but it has id=NULL so it's not easy
to refer to it)
Access method
-------------
* SJ-Materialization-lookup will have eq_ref on 'distinct_key'
* SJ-Materialization-scan will have access method ALL, with #rows being
expected number of records in the temp table (i.e. after duplicates are
removed)
LOW-LEVEL DESIGN:
For now, all changes will be in select_describe():
- In the for-each-join-table loop, when we've reached a line where we would
have printed "[Start ]Materialize;" in Extra column, remember the table
number, and emit a materialized table access line instead
- After the loop, do another loop over remembered materialization nests and
print them (a possible difficulty: do we remember what select# they are
from?)
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0
[Maria-developers] Updated (by Guest): Make EXPLAIN always show materialization separately (110)
by worklog-noreply@askmonty.org 29 Mar '10
by worklog-noreply@askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Make EXPLAIN always show materialization separately
CREATION DATE..: Mon, 29 Mar 2010, 06:45
SUPERVISOR.....: Igor
IMPLEMENTOR....: Psergey
COPIES TO......:
CATEGORY.......: Server-RawIdeaBin
TASK ID........: 110 (http://askmonty.org/worklog/?tid=110)
VERSION........: Server-5.3
STATUS.........: Complete
PRIORITY.......: 60
WORKED HOURS...: 0
ESTIMATE.......: 0 (hours remain)
ORIG. ESTIMATE.: 0
PROGRESS NOTES:
-=-=(Guest - Mon, 29 Mar 2010, 14:09)=-=-
Status updated.
--- /tmp/wklog.110.old.11193 2010-03-29 14:09:27.000000000 +0000
+++ /tmp/wklog.110.new.11193 2010-03-29 14:09:27.000000000 +0000
@@ -1 +1 @@
-Un-Assigned
+Complete
-=-=(Psergey - Mon, 29 Mar 2010, 06:46)=-=-
Low Level Design modified.
--- /tmp/wklog.110.old.11745 2010-03-29 06:46:30.000000000 +0000
+++ /tmp/wklog.110.new.11745 2010-03-29 06:46:30.000000000 +0000
@@ -1 +1,8 @@
+For now, all changes will be in select_describe():
+- In the for-each-join-table loop, when we've reached a line where we would
+ have printed "[Start ]Materialize;" in Extra column, remember the table
+ number, and emit a materialized table access line instead
+- After the loop, do another loop over remembered materialization nests and
+ print them (a possible difficulty: do we remember what select# they are
+ from?)
-=-=(Psergey - Mon, 29 Mar 2010, 06:46)=-=-
High-Level Specification modified.
--- /tmp/wklog.110.old.11654 2010-03-29 06:46:19.000000000 +0000
+++ /tmp/wklog.110.new.11654 2010-03-29 06:46:19.000000000 +0000
@@ -1 +1,15 @@
+Materialized table access line will look as follows:
+Table name
+----------
+* Table name will be "SUBQUERY#%d" where %d will refer to the id of first
+ select in the subquery (when the subquery is a UNION it would be better
+ to refe to the union-operation line but it has id=NULL so it's not easy
+ to refer to it)
+
+Access method
+-------------
+* SJ-Materialization-lookup will have eq_ref on 'distinct_key'
+* SJ-Materialization-scan will have access method ALL, with #rows being
+ expected number of records in the temp table (i.e. after duplicates are
+ removed)
-=-=(Psergey - Mon, 29 Mar 2010, 06:46)=-=-
Category updated.
--- /tmp/wklog.110.old.11639 2010-03-29 06:46:02.000000000 +0000
+++ /tmp/wklog.110.new.11639 2010-03-29 06:46:02.000000000 +0000
@@ -1 +1 @@
-Client-BackLog
+Server-RawIdeaBin
-=-=(Psergey - Mon, 29 Mar 2010, 06:46)=-=-
Version updated.
--- /tmp/wklog.110.old.11639 2010-03-29 06:46:02.000000000 +0000
+++ /tmp/wklog.110.new.11639 2010-03-29 06:46:02.000000000 +0000
@@ -1 +1 @@
-Benchmarks-3.0
+9.x
-=-=(Psergey - Mon, 29 Mar 2010, 06:46)=-=-
Version updated.
--- /tmp/wklog.110.old.11639 2010-03-29 06:46:02.000000000 +0000
+++ /tmp/wklog.110.new.11639 2010-03-29 06:46:02.000000000 +0000
@@ -1 +1 @@
-9.x
+Server-5.3
DESCRIPTION:
At the moment, SJM-Materialization is shown in EXPLAIN output in this way:
MariaDB [j45]> explain select * from ot where a in (select b from it1);
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows
| Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | ot | ALL | NULL | NULL | NULL | NULL | 10
| |
| 1 | PRIMARY | it1 | ALL | NULL | NULL | NULL | NULL | 10
| Materialize |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
MariaDB [j45]> explain select * from ot where a in (select it1.b from it1, it2);
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows
| Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------------+
| 1 | PRIMARY | ot | ALL | NULL | NULL | NULL | NULL | 10
| |
| 1 | PRIMARY | it1 | ALL | NULL | NULL | NULL | NULL | 10
| Start materialize |
| 1 | PRIMARY | it2 | ALL | NULL | NULL | NULL | NULL | 10
| End materialize; Using join buffer |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------------+
This WL task is to change the output format so it will look as follows:
- Tables inside the SJM-nest are displayed as a separate select
- within the master select, there is a line that denotes SJM-lookup or
SJM-Scan.
The above examples will look as follows:
MariaDB [j45]> explain select * from ot where a in (select b from it1);
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------+
| id | select_type | table | type | possible_keys | key |
key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------+
| 1 | PRIMARY | ot | ALL | NULL | NULL | NULL
| NULL | 10 | |
| 1 | PRIMARY | SUBQUERY#2 | eq_ref | distinct_key | distinct_key | 5
| j45.ot.a | 1 | |
| 2 | SUBQUERY | it1 | ALL | NULL | NULL | NULL
| NULL | 10 | |
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------+
MariaDB [j45]> explain select * from ot where a in (select it1.b from it1, it2);
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------------------+
| id | select_type | table | type | possible_keys | key |
key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------------------+
| 1 | PRIMARY | ot | ALL | NULL | NULL | NULL
| NULL | 10 | |
| 1 | PRIMARY | SUBQUERY#2 | eq_ref | distinct_key | distinct_key | 5
| j45.ot.a | 1 | |
| 2 | SUBQUERY | it1 | ALL | NULL | NULL | NULL
| NULL | 10 | |
| 2 | SUBQUERY | it2 | ALL | NULL | NULL | NULL
| NULL | 10 | Using join buffer |
+----+-------------+------------+--------+---------------+--------------+---------+----------+------+-------------------+
The rationale behind the change is:
- Unification of EXPLAIN output with MWL#90
- The new format is more natural representation of what is going on,
conceptually-wise (and may be soon be code-wise)
- The new format allows to display E(#records-in-temp-table) for the
SJM-Scan case (and for SJM-lookup that number doesn't matter that much)
- The new format doesn't put anything into "Extra" column and that's good
because that column is already overloaded and horizontal screen space is
precious (while vertical is not so much).
HIGH-LEVEL SPECIFICATION:
Materialized table access line will look as follows:
Table name
----------
* Table name will be "SUBQUERY#%d" where %d will refer to the id of first
select in the subquery (when the subquery is a UNION it would be better
to refe to the union-operation line but it has id=NULL so it's not easy
to refer to it)
Access method
-------------
* SJ-Materialization-lookup will have eq_ref on 'distinct_key'
* SJ-Materialization-scan will have access method ALL, with #rows being
expected number of records in the temp table (i.e. after duplicates are
removed)
LOW-LEVEL DESIGN:
For now, all changes will be in select_describe():
- In the for-each-join-table loop, when we've reached a line where we would
have printed "[Start ]Materialize;" in Extra column, remember the table
number, and emit a materialized table access line instead
- After the loop, do another loop over remembered materialization nests and
print them (a possible difficulty: do we remember what select# they are
from?)
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0
[Maria-developers] Rev 2786: MWL#110: Make EXPLAIN always show materialization separately in file:///home/psergey/dev/maria-5.3-subqueries-r10/
by Sergey Petrunya 29 Mar '10
by Sergey Petrunya 29 Mar '10
29 Mar '10
At file:///home/psergey/dev/maria-5.3-subqueries-r10/
------------------------------------------------------------
revno: 2786
revision-id: psergey(a)askmonty.org-20100329140435-bb21mofh3i85tt4q
parent: psergey(a)askmonty.org-20100323145750-sr9oucry979i3p60
committer: Sergey Petrunya <psergey(a)askmonty.org>
branch nick: maria-5.3-subqueries-r10
timestamp: Mon 2010-03-29 18:04:35 +0400
message:
MWL#110: Make EXPLAIN always show materialization separately
- Add Item_in_subselect::get_identifier() that returns subquery's id
- Change select_describe() to produce output in new format
- Update test results (checked)
=== modified file 'mysql-test/r/subselect3.result'
--- a/mysql-test/r/subselect3.result 2010-03-20 12:01:47 +0000
+++ b/mysql-test/r/subselect3.result 2010-03-29 14:04:35 +0000
@@ -1017,10 +1017,11 @@
explain select t21.* from t21,t22 where t21.a = t22.a and
t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t11 ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort; Start materialize; Scan
-1 PRIMARY t12 ALL NULL NULL NULL NULL 8 Using where; End materialize; Using join buffer
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 8 Using temporary; Using filesort
1 PRIMARY t21 ALL NULL NULL NULL NULL 26 Using where; Using join buffer
1 PRIMARY t22 ALL NULL NULL NULL NULL 26 Using where; Using join buffer
+2 SUBQUERY t11 ALL NULL NULL NULL NULL 8 Using where
+2 SUBQUERY t12 ALL NULL NULL NULL NULL 8 Using where; Using join buffer
select t21.* from t21,t22 where t21.a = t22.a and
t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
a b c
@@ -1034,7 +1035,8 @@
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY X ALL NULL NULL NULL NULL 2
2 DEPENDENT SUBQUERY Y ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY Z ALL NULL NULL NULL NULL 2 Materialize
+2 DEPENDENT SUBQUERY subselect3 eq_ref unique_key unique_key 5 func 1
+3 SUBQUERY Z ALL NULL NULL NULL NULL 2
select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X;
subq
NULL
@@ -1156,8 +1158,9 @@
insert into t3 select A.a + 10*B.a, 'filler' from t0 A, t0 B;
explain select * from t3 where a in (select a from t2) and (a > 5 or a < 10);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 2
1 PRIMARY t3 ref a a 5 test.t2.a 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where
select * from t3 where a in (select a from t2);
a filler
1 filler
@@ -1204,8 +1207,9 @@
explain select * from t1, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30) and t1.a =3;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where
-1 PRIMARY t2 ALL NULL NULL NULL NULL 10 Using where; Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 10
1 PRIMARY t3 ref a a 5 test.t2.a 10
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 10 Using where
explain select straight_join * from t1 A, t1 B where A.a in (select a from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY A ALL NULL NULL NULL NULL 10 Using where
@@ -1233,14 +1237,16 @@
explain select * from t0, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 system NULL NULL NULL NULL 1
-1 PRIMARY t2 ALL NULL NULL NULL NULL 10 Using where; Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 10
1 PRIMARY t3 ref a a 5 test.t2.a 10
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 10 Using where
create table t4 as select a as x, a as y from t1;
explain select * from t0, t3 where (t3.a, t3.b) in (select x,y from t4) and (t3.a < 10 or t3.a >30);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 system NULL NULL NULL NULL 1
-1 PRIMARY t4 ALL NULL NULL NULL NULL 10 Using where; Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 10
1 PRIMARY t3 ref a a 5 test.t4.x 10 Using where
+2 SUBQUERY t4 ALL NULL NULL NULL NULL 10 Using where
drop table t0,t1,t2,t3,t4;
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
@@ -1264,13 +1270,15 @@
explain select * from t1 where (a,b) in (select a,b from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 10
-1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 10 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 100
set @save_optimizer_search_depth=@@optimizer_search_depth;
set @@optimizer_search_depth=63;
explain select * from t1 where (a,b) in (select a,b from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 10
-1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 10 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 100
set @@optimizer_search_depth=@save_optimizer_search_depth;
set @@optimizer_switch=default;
drop table t0, t1, t2;
@@ -1308,9 +1316,10 @@
explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
-1 PRIMARY X ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 PRIMARY Y ALL NULL NULL NULL NULL 6 Using join buffer
-1 PRIMARY Z ALL NULL NULL NULL NULL 6 End materialize; Using join buffer
+1 PRIMARY subselect2 eq_ref unique_key unique_key 15 func 1
+2 SUBQUERY X ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY Y ALL NULL NULL NULL NULL 6 Using join buffer
+2 SUBQUERY Z ALL NULL NULL NULL NULL 6 Using join buffer
drop table t0,t1,t2;
BUG#37842: Assertion in DsMrr_impl::dsmrr_init, at handler.cc:4307
@@ -1380,9 +1389,10 @@
WHERE cona.postalStripped='T2H3B2'
);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY cona ALL NULL NULL NULL NULL 2 100.00 Using where; Start materialize; Scan
-1 PRIMARY c eq_ref PRIMARY PRIMARY 4 test.cona.idContact 1 100.00 End materialize
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 2 1.00
1 PRIMARY a index PRIMARY PRIMARY 4 NULL 2 100.00 Using where; Using index; Using join buffer
+2 SUBQUERY cona ALL NULL NULL NULL NULL 2 100.00 Using where
+2 SUBQUERY c eq_ref PRIMARY PRIMARY 4 test.cona.idContact 1 100.00
Warnings:
Note 1003 select `test`.`a`.`idIndividual` AS `idIndividual` from `test`.`t1` `a` semi join (`test`.`t3` `cona` join `test`.`t2` `c`) where ((`test`.`c`.`idContact` = `test`.`cona`.`idContact`) and (`test`.`a`.`idIndividual` = `test`.`c`.`idObj`) and (`test`.`cona`.`postalStripped` = 'T2H3B2'))
drop table t1,t2,t3;
=== modified file 'mysql-test/r/subselect3_jcl6.result'
--- a/mysql-test/r/subselect3_jcl6.result 2010-03-11 21:43:31 +0000
+++ b/mysql-test/r/subselect3_jcl6.result 2010-03-29 14:04:35 +0000
@@ -1021,10 +1021,11 @@
explain select t21.* from t21,t22 where t21.a = t22.a and
t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t11 ALL NULL NULL NULL NULL 8 Using where; Using temporary; Using filesort; Start materialize; Scan
-1 PRIMARY t12 ALL NULL NULL NULL NULL 8 Using where; End materialize; Using join buffer
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 8 Using temporary; Using filesort
1 PRIMARY t21 ALL NULL NULL NULL NULL 26 Using where; Using join buffer
1 PRIMARY t22 ALL NULL NULL NULL NULL 26 Using where; Using join buffer
+2 SUBQUERY t11 ALL NULL NULL NULL NULL 8 Using where
+2 SUBQUERY t12 ALL NULL NULL NULL NULL 8 Using where; Using join buffer
select t21.* from t21,t22 where t21.a = t22.a and
t22.a in (select t12.a from t11, t12 where t11.a in(255,256) and t11.a = t12.a and t11.c is null) and t22.c is null order by t21.a;
a b c
@@ -1039,7 +1040,8 @@
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY X ALL NULL NULL NULL NULL 2
2 DEPENDENT SUBQUERY Y ALL NULL NULL NULL NULL 2 Using where
-2 DEPENDENT SUBQUERY Z ALL NULL NULL NULL NULL 2 Materialize
+2 DEPENDENT SUBQUERY subselect3 eq_ref unique_key unique_key 5 func 1
+3 SUBQUERY Z ALL NULL NULL NULL NULL 2
select (select max(Y.a) from t1 Y where a in (select a from t1 Z) and a < X.a) as subq from t1 X;
subq
NULL
@@ -1161,8 +1163,9 @@
insert into t3 select A.a + 10*B.a, 'filler' from t0 A, t0 B;
explain select * from t3 where a in (select a from t2) and (a > 5 or a < 10);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where; Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 2
1 PRIMARY t3 ref a a 5 test.t2.a 1 Using join buffer
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where
select * from t3 where a in (select a from t2);
a filler
1 filler
@@ -1209,8 +1212,9 @@
explain select * from t1, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30) and t1.a =3;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using where
-1 PRIMARY t2 ALL NULL NULL NULL NULL 10 Using where; Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 10
1 PRIMARY t3 ref a a 5 test.t2.a 10 Using join buffer
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 10 Using where
explain select straight_join * from t1 A, t1 B where A.a in (select a from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY A ALL NULL NULL NULL NULL 10 Using where
@@ -1238,14 +1242,16 @@
explain select * from t0, t3 where t3.a in (select a from t2) and (t3.a < 10 or t3.a >30);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 system NULL NULL NULL NULL 1
-1 PRIMARY t2 ALL NULL NULL NULL NULL 10 Using where; Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 10
1 PRIMARY t3 ref a a 5 test.t2.a 10 Using join buffer
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 10 Using where
create table t4 as select a as x, a as y from t1;
explain select * from t0, t3 where (t3.a, t3.b) in (select x,y from t4) and (t3.a < 10 or t3.a >30);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t0 system NULL NULL NULL NULL 1
-1 PRIMARY t4 ALL NULL NULL NULL NULL 10 Using where; Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 10
1 PRIMARY t3 ref a a 5 test.t4.x 10 Using where; Using join buffer
+2 SUBQUERY t4 ALL NULL NULL NULL NULL 10 Using where
drop table t0,t1,t2,t3,t4;
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
@@ -1269,13 +1275,15 @@
explain select * from t1 where (a,b) in (select a,b from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 10
-1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 10 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 100
set @save_optimizer_search_depth=@@optimizer_search_depth;
set @@optimizer_search_depth=63;
explain select * from t1 where (a,b) in (select a,b from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 10
-1 PRIMARY t2 ALL NULL NULL NULL NULL 100 Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 10 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 100
set @@optimizer_search_depth=@save_optimizer_search_depth;
set @@optimizer_switch=default;
drop table t0, t1, t2;
@@ -1313,9 +1321,10 @@
explain select * from t1 where (a,b,c) in (select X.a, Y.a, Z.a from t2 X, t2 Y, t2 Z where X.b=33);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
-1 PRIMARY X ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 PRIMARY Y ALL NULL NULL NULL NULL 6 Using join buffer
-1 PRIMARY Z ALL NULL NULL NULL NULL 6 End materialize; Using join buffer
+1 PRIMARY subselect2 eq_ref unique_key unique_key 15 func 1
+2 SUBQUERY X ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY Y ALL NULL NULL NULL NULL 6 Using join buffer
+2 SUBQUERY Z ALL NULL NULL NULL NULL 6 Using join buffer
drop table t0,t1,t2;
BUG#37842: Assertion in DsMrr_impl::dsmrr_init, at handler.cc:4307
@@ -1385,9 +1394,10 @@
WHERE cona.postalStripped='T2H3B2'
);
id select_type table type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY cona ALL NULL NULL NULL NULL 2 100.00 Using where; Start materialize; Scan
-1 PRIMARY c eq_ref PRIMARY PRIMARY 4 test.cona.idContact 1 100.00 End materialize; Using join buffer
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 2 1.00
1 PRIMARY a index PRIMARY PRIMARY 4 NULL 2 100.00 Using where; Using index; Using join buffer
+2 SUBQUERY cona ALL NULL NULL NULL NULL 2 100.00 Using where
+2 SUBQUERY c eq_ref PRIMARY PRIMARY 4 test.cona.idContact 1 100.00 Using join buffer
Warnings:
Note 1003 select `test`.`a`.`idIndividual` AS `idIndividual` from `test`.`t1` `a` semi join (`test`.`t3` `cona` join `test`.`t2` `c`) where ((`test`.`c`.`idContact` = `test`.`cona`.`idContact`) and (`test`.`a`.`idIndividual` = `test`.`c`.`idObj`) and (`test`.`cona`.`postalStripped` = 'T2H3B2'))
drop table t1,t2,t3;
=== modified file 'mysql-test/r/subselect4.result'
--- a/mysql-test/r/subselect4.result 2010-03-20 12:01:47 +0000
+++ b/mysql-test/r/subselect4.result 2010-03-29 14:04:35 +0000
@@ -216,8 +216,9 @@
WHERE PTYPE = 'Design'));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5
-1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 PRIMARY t3 ALL NULL NULL NULL NULL 12 Using where; End materialize; Using join buffer
+1 PRIMARY subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer
PREPARE stmt FROM "EXPLAIN SELECT EMPNAME
FROM t1
WHERE EMPNUM IN
@@ -230,13 +231,15 @@
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5
-1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 PRIMARY t3 ALL NULL NULL NULL NULL 12 Using where; End materialize; Using join buffer
+1 PRIMARY subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL t1_IDX NULL NULL NULL 5
-1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 SIMPLE t3 ALL NULL NULL NULL NULL 12 Using where; End materialize; Using join buffer
+1 SIMPLE subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer
DEALLOCATE PREPARE stmt;
DROP INDEX t1_IDX ON t1;
CREATE INDEX t1_IDX ON t1(EMPNUM);
@@ -251,8 +254,9 @@
WHERE PTYPE = 'Design'));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5
-1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 PRIMARY t3 ALL NULL NULL NULL NULL 12 Using where; End materialize; Using join buffer
+1 PRIMARY subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer
PREPARE stmt FROM "EXPLAIN SELECT EMPNAME
FROM t1
WHERE EMPNUM IN
@@ -265,13 +269,15 @@
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL t1_IDX NULL NULL NULL 5
-1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 PRIMARY t3 ALL NULL NULL NULL NULL 12 Using where; End materialize; Using join buffer
+1 PRIMARY subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL t1_IDX NULL NULL NULL 5
-1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 SIMPLE t3 ALL NULL NULL NULL NULL 12 Using where; End materialize; Using join buffer
+1 SIMPLE subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer
DEALLOCATE PREPARE stmt;
DROP INDEX t1_IDX ON t1;
EXPLAIN SELECT EMPNAME
@@ -285,8 +291,9 @@
WHERE PTYPE = 'Design'));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 5
-1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 PRIMARY t3 ALL NULL NULL NULL NULL 12 Using where; End materialize; Using join buffer
+1 PRIMARY subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer
PREPARE stmt FROM "EXPLAIN SELECT EMPNAME
FROM t1
WHERE EMPNUM IN
@@ -299,13 +306,15 @@
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 5
-1 PRIMARY t2 ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 PRIMARY t3 ALL NULL NULL NULL NULL 12 Using where; End materialize; Using join buffer
+1 PRIMARY subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 5
-1 SIMPLE t2 ALL NULL NULL NULL NULL 6 Using where; Start materialize
-1 SIMPLE t3 ALL NULL NULL NULL NULL 12 Using where; End materialize; Using join buffer
+1 SIMPLE subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 6 Using where
+2 SUBQUERY t3 ALL NULL NULL NULL NULL 12 Using where; Using join buffer
DEALLOCATE PREPARE stmt;
SET SESSION optimizer_switch = @old_optimizer_switch;
SET SESSION join_cache_level = @old_join_cache_level;
=== modified file 'mysql-test/r/subselect_mat.result'
--- a/mysql-test/r/subselect_mat.result 2010-03-13 21:11:06 +0000
+++ b/mysql-test/r/subselect_mat.result 2010-03-29 14:04:35 +0000
@@ -1190,8 +1190,9 @@
SET @@optimizer_switch='default,semijoin=on,materialization=on';
EXPLAIN SELECT COUNT(*) FROM t1 WHERE (f1,f2) IN (SELECT f1,f2 FROM t2);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 2
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer
+2 SUBQUERY t2 ALL NULL NULL NULL NULL 2
SELECT COUNT(*) FROM t1 WHERE (f1,f2) IN (SELECT f1,f2 FROM t2);
COUNT(*)
2
@@ -1211,7 +1212,8 @@
EXPLAIN SELECT pk FROM t1 WHERE (a) IN (SELECT a FROM t2 WHERE pk > 0);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2
-1 PRIMARY t2 range PRIMARY PRIMARY 4 NULL 2 Using index condition; Using MRR; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 5 func 1
+2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 2 Using index condition; Using MRR
SELECT pk FROM t1 WHERE (a) IN (SELECT a FROM t2 WHERE pk > 0);
pk
2
=== modified file 'mysql-test/r/subselect_sj.result'
--- a/mysql-test/r/subselect_sj.result 2010-03-15 19:52:58 +0000
+++ b/mysql-test/r/subselect_sj.result 2010-03-29 14:04:35 +0000
@@ -848,7 +848,8 @@
EXPLAIN EXTENDED SELECT pk FROM t1 WHERE (a, b) IN (SELECT a, b FROM t2 WHERE pk > 0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
-1 PRIMARY t2 range PRIMARY PRIMARY 4 NULL 2 100.00 Using index condition; Using MRR; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 13 func 1 1.00
+2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 2 100.00 Using index condition; Using MRR
Warnings:
Note 1003 select `test`.`t1`.`pk` AS `pk` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`pk` > 0))
SELECT pk FROM t1 WHERE (a, b) IN (SELECT a, b FROM t2 WHERE pk > 0);
@@ -1016,7 +1017,8 @@
WHERE `varchar_nokey` < 'n' XOR `pk` ) ;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00
-1 PRIMARY t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 8 func 1 1.00
+2 SUBQUERY t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where
Warnings:
Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key`) and ((`test`.`t1`.`varchar_nokey` < 'n') xor `test`.`t1`.`pk`))
SELECT varchar_nokey
=== modified file 'mysql-test/r/subselect_sj2.result'
--- a/mysql-test/r/subselect_sj2.result 2010-03-07 15:41:45 +0000
+++ b/mysql-test/r/subselect_sj2.result 2010-03-29 14:04:35 +0000
@@ -32,8 +32,9 @@
9 5
explain select * from t2 where b in (select a from t1);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 3
1 PRIMARY t2 ref b b 5 test.t1.a 2
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3
select * from t2 where b in (select a from t1);
a b
1 1
@@ -73,8 +74,9 @@
from t0 A, t0 B where B.a <5;
explain select * from t3 where b in (select a from t0);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t0 ALL NULL NULL NULL NULL 10 Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 10
1 PRIMARY t3 ref b b 5 test.t0.a 1
+2 SUBQUERY t0 ALL NULL NULL NULL NULL 10
set @save_ecp= @@engine_condition_pushdown;
set engine_condition_pushdown=0;
select * from t3 where b in (select A.a+B.a from t0 A, t0 B where B.a<5);
@@ -99,7 +101,8 @@
explain select * from t1 where a in (select b from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
-1 PRIMARY t2 index b b 5 NULL 10 Using index; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 5 func 1
+2 SUBQUERY t2 index b b 5 NULL 10 Using index
select * from t1;
a b
1 1
@@ -126,8 +129,9 @@
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY it ALL NULL NULL NULL NULL 22 Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 22
1 PRIMARY ot ALL NULL NULL NULL NULL 32 Using where; Using join buffer
+2 SUBQUERY it ALL NULL NULL NULL NULL 22
select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
@@ -159,7 +163,8 @@
from t2 ot where a in (select a from t1 it);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY ot ALL NULL NULL NULL NULL 22
-1 PRIMARY it ALL NULL NULL NULL NULL 32 Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 5 func 1
+2 SUBQUERY it ALL NULL NULL NULL NULL 32
select
a, mid(filler1, 1,10), length(filler1)=length(filler2)
from t2 ot where a in (select a from t1 it);
@@ -192,8 +197,9 @@
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY it ALL NULL NULL NULL NULL 22 Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 22
1 PRIMARY ot ALL NULL NULL NULL NULL 52 Using where; Using join buffer
+2 SUBQUERY it ALL NULL NULL NULL NULL 22
select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
@@ -225,7 +231,8 @@
from t2 ot where a in (select a from t1 it);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY ot ALL NULL NULL NULL NULL 22
-1 PRIMARY it ALL NULL NULL NULL NULL 52 Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 5 func 1
+2 SUBQUERY it ALL NULL NULL NULL NULL 52
select
a, mid(filler1, 1,10), length(filler1)=length(filler2)
from t2 ot where a in (select a from t1 it);
@@ -341,7 +348,8 @@
SELECT t2.CountryCode FROM t2 WHERE Population > 5000000);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 31
-1 PRIMARY t2 ALL CountryCode NULL NULL NULL 545 Using where; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL CountryCode NULL NULL NULL 545 Using where
SELECT Name FROM t1
WHERE t1.Code IN (
SELECT t2.CountryCode FROM t2 WHERE Population > 5000000);
@@ -684,7 +692,8 @@
explain select count(a) from t2 where a in ( SELECT a FROM t3);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index a a 5 NULL 1000 Using index
-1 PRIMARY t3 index a a 5 NULL 30000 Using index; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 5 func 1
+2 SUBQUERY t3 index a a 5 NULL 30000 Using index
select count(a) from t2 where a in ( SELECT a FROM t3);
count(a)
1000
=== modified file 'mysql-test/r/subselect_sj2_jcl6.result'
--- a/mysql-test/r/subselect_sj2_jcl6.result 2010-03-07 15:41:45 +0000
+++ b/mysql-test/r/subselect_sj2_jcl6.result 2010-03-29 14:04:35 +0000
@@ -36,8 +36,9 @@
9 5
explain select * from t2 where b in (select a from t1);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 3
1 PRIMARY t2 ref b b 5 test.t1.a 2 Using join buffer
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3
select * from t2 where b in (select a from t1);
a b
1 1
@@ -77,8 +78,9 @@
from t0 A, t0 B where B.a <5;
explain select * from t3 where b in (select a from t0);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t0 ALL NULL NULL NULL NULL 10 Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 10
1 PRIMARY t3 ref b b 5 test.t0.a 1 Using join buffer
+2 SUBQUERY t0 ALL NULL NULL NULL NULL 10
set @save_ecp= @@engine_condition_pushdown;
set engine_condition_pushdown=0;
select * from t3 where b in (select A.a+B.a from t0 A, t0 B where B.a<5);
@@ -103,7 +105,8 @@
explain select * from t1 where a in (select b from t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
-1 PRIMARY t2 index b b 5 NULL 10 Using index; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 5 func 1
+2 SUBQUERY t2 index b b 5 NULL 10 Using index
select * from t1;
a b
1 1
@@ -130,8 +133,9 @@
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY it ALL NULL NULL NULL NULL 22 Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 22
1 PRIMARY ot ALL NULL NULL NULL NULL 32 Using where; Using join buffer
+2 SUBQUERY it ALL NULL NULL NULL NULL 22
select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
@@ -163,7 +167,8 @@
from t2 ot where a in (select a from t1 it);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY ot ALL NULL NULL NULL NULL 22
-1 PRIMARY it ALL NULL NULL NULL NULL 32 Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 5 func 1
+2 SUBQUERY it ALL NULL NULL NULL NULL 32
select
a, mid(filler1, 1,10), length(filler1)=length(filler2)
from t2 ot where a in (select a from t1 it);
@@ -196,8 +201,9 @@
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY it ALL NULL NULL NULL NULL 22 Materialize; Scan
+1 PRIMARY subselect2 ALL unique_key NULL NULL NULL 22
1 PRIMARY ot ALL NULL NULL NULL NULL 52 Using where; Using join buffer
+2 SUBQUERY it ALL NULL NULL NULL NULL 22
select
a, mid(filler1, 1,10), length(filler1)=length(filler2) as Z
from t1 ot where a in (select a from t2 it);
@@ -229,7 +235,8 @@
from t2 ot where a in (select a from t1 it);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY ot ALL NULL NULL NULL NULL 22
-1 PRIMARY it ALL NULL NULL NULL NULL 52 Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 5 func 1
+2 SUBQUERY it ALL NULL NULL NULL NULL 52
select
a, mid(filler1, 1,10), length(filler1)=length(filler2)
from t2 ot where a in (select a from t1 it);
@@ -345,7 +352,8 @@
SELECT t2.CountryCode FROM t2 WHERE Population > 5000000);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL PRIMARY NULL NULL NULL 31
-1 PRIMARY t2 ALL CountryCode NULL NULL NULL 545 Using where; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 3 func 1
+2 SUBQUERY t2 ALL CountryCode NULL NULL NULL 545 Using where
SELECT Name FROM t1
WHERE t1.Code IN (
SELECT t2.CountryCode FROM t2 WHERE Population > 5000000);
@@ -690,7 +698,8 @@
explain select count(a) from t2 where a in ( SELECT a FROM t3);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index a a 5 NULL 1000 Using index
-1 PRIMARY t3 index a a 5 NULL 30000 Using index; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 5 func 1
+2 SUBQUERY t3 index a a 5 NULL 30000 Using index
select count(a) from t2 where a in ( SELECT a FROM t3);
count(a)
1000
=== modified file 'mysql-test/r/subselect_sj_jcl6.result'
--- a/mysql-test/r/subselect_sj_jcl6.result 2010-03-15 19:52:58 +0000
+++ b/mysql-test/r/subselect_sj_jcl6.result 2010-03-29 14:04:35 +0000
@@ -852,7 +852,8 @@
EXPLAIN EXTENDED SELECT pk FROM t1 WHERE (a, b) IN (SELECT a, b FROM t2 WHERE pk > 0);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00
-1 PRIMARY t2 range PRIMARY PRIMARY 4 NULL 2 100.00 Using index condition; Using MRR; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 13 func 1 1.00
+2 SUBQUERY t2 range PRIMARY PRIMARY 4 NULL 2 100.00 Using index condition; Using MRR
Warnings:
Note 1003 select `test`.`t1`.`pk` AS `pk` from `test`.`t1` semi join (`test`.`t2`) where ((`test`.`t2`.`pk` > 0))
SELECT pk FROM t1 WHERE (a, b) IN (SELECT a, b FROM t2 WHERE pk > 0);
@@ -1020,7 +1021,8 @@
WHERE `varchar_nokey` < 'n' XOR `pk` ) ;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 18 100.00
-1 PRIMARY t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where; Materialize
+1 PRIMARY subselect2 eq_ref unique_key unique_key 8 func 1 1.00
+2 SUBQUERY t1 ALL varchar_key NULL NULL NULL 15 100.00 Using where
Warnings:
Note 1003 select `test`.`t2`.`varchar_nokey` AS `varchar_nokey` from `test`.`t2` semi join (`test`.`t1`) where ((`test`.`t1`.`varchar_nokey` = `test`.`t1`.`varchar_key`) and ((`test`.`t1`.`varchar_nokey` < 'n') xor `test`.`t1`.`pk`))
SELECT varchar_nokey
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2010-03-20 12:01:47 +0000
+++ b/sql/item_subselect.cc 2010-03-29 14:04:35 +0000
@@ -926,6 +926,11 @@
DBUG_VOID_RETURN;
}
+int Item_in_subselect::get_identifier()
+{
+ return engine->get_identifier();
+}
+
Item_allany_subselect::Item_allany_subselect(Item * left_exp,
chooser_compare_func_creator fc,
st_select_lex *select_lex,
@@ -2271,6 +2276,10 @@
select_lex->master_unit()->item= item_arg;
}
+int subselect_single_select_engine::get_identifier()
+{
+ return select_lex->select_number;
+}
void subselect_single_select_engine::cleanup()
{
=== modified file 'sql/item_subselect.h'
--- a/sql/item_subselect.h 2010-03-20 12:01:47 +0000
+++ b/sql/item_subselect.h 2010-03-29 14:04:35 +0000
@@ -433,7 +433,12 @@
/* Inform 'this' that it was computed, and contains a valid result. */
void set_first_execution() { if (first_execution) first_execution= FALSE; }
bool is_expensive_processor(uchar *arg);
-
+
+ /*
+ Return the identifier that we could use to identify the subquery for the
+ user.
+ */
+ int get_identifier();
friend class Item_ref_null_helper;
friend class Item_is_not_null_test;
friend class Item_in_optimizer;
@@ -534,7 +539,7 @@
/* Check if subquery produced any rows during last query execution */
virtual bool no_rows() = 0;
virtual enum_engine_type engine_type() { return ABSTRACT_ENGINE; }
-
+ virtual int get_identifier() { DBUG_ASSERT(0); return 0; }
protected:
void set_row(List<Item> &item_list, Item_cache **row);
};
@@ -566,6 +571,7 @@
bool is_executed() const { return executed; }
bool no_rows();
virtual enum_engine_type engine_type() { return SINGLE_SELECT_ENGINE; }
+ int get_identifier();
friend class subselect_hash_sj_engine;
friend class Item_in_subselect;
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2010-03-20 16:59:30 +0000
+++ b/sql/sql_select.cc 2010-03-29 14:04:35 +0000
@@ -17889,8 +17889,15 @@
else
{
table_map used_tables=0;
- uint last_sjm_table= MAX_TABLES;
- for (uint i=0 ; i < join->tables ; i++)
+
+ uchar sjm_nests[MAX_TABLES];
+ uint sjm_nests_cur=0;
+ uint sjm_nests_end= 0;
+ uint end_table= join->tables;
+ bool printing_materialize_nest= FALSE;
+ uint select_id= join->select_lex->select_number;
+
+ for (uint i=0 ; i < end_table ; i++)
{
JOIN_TAB *tab=join->join_tab+i;
TABLE *table=tab->table;
@@ -17898,6 +17905,7 @@
char buff[512];
char buff1[512], buff2[512], buff3[512];
char keylen_str_buf[64];
+ my_bool key_read;
String extra(buff, sizeof(buff),cs);
char table_name_buffer[NAME_LEN];
String tmp1(buff1,sizeof(buff1),cs);
@@ -17907,7 +17915,6 @@
tmp1.length(0);
tmp2.length(0);
tmp3.length(0);
-
quick_type= -1;
/* Don't show eliminated tables */
@@ -17919,12 +17926,89 @@
item_list.empty();
/* id */
- item_list.push_back(new Item_uint((uint32)
- join->select_lex->select_number));
+ item_list.push_back(new Item_uint((uint32)select_id));
/* select_type */
- item_list.push_back(new Item_string(join->select_lex->type,
- strlen(join->select_lex->type),
- cs));
+ const char* stype= printing_materialize_nest? "SUBQUERY" :
+ join->select_lex->type;
+ item_list.push_back(new Item_string(stype, strlen(stype), cs));
+
+ /*
+ Special processing for SJ-Materialization nests: print the fake table
+ and delay printing of the SJM nest contents until later.
+ */
+ uint sj_strategy= join->best_positions[i].sj_strategy;
+ if (sj_is_materialize_strategy(sj_strategy) &&
+ !printing_materialize_nest)
+ {
+ /* table */
+ int len= my_snprintf(table_name_buffer,
+ sizeof(table_name_buffer)-1,
+ "subselect%d",
+ tab->emb_sj_nest->sj_subq_pred->get_identifier());
+ item_list.push_back(new Item_string(table_name_buffer, len, cs));
+ /* partitions */
+ if (join->thd->lex->describe & DESCRIBE_PARTITIONS)
+ item_list.push_back(item_null);
+ /* type */
+ uint type= (sj_strategy == SJ_OPT_MATERIALIZE_SCAN)? JT_ALL : JT_EQ_REF;
+ item_list.push_back(new Item_string(join_type_str[type],
+ strlen(join_type_str[type]),
+ cs));
+ /* possible_keys */
+ item_list.push_back(new Item_string("unique_key",
+ strlen("unique_key"), cs));
+ if (sj_strategy == SJ_OPT_MATERIALIZE_SCAN)
+ {
+ item_list.push_back(item_null); /* key */
+ item_list.push_back(item_null); /* key_len */
+ item_list.push_back(item_null); /* ref */
+ }
+ else
+ {
+ /* key */
+ item_list.push_back(new Item_string("unique_key", strlen("unique_key"), cs));
+ /* key_len */
+ uint klen= tab->emb_sj_nest->sj_mat_info->table->key_info[0].key_length;
+ uint buflen= longlong2str(klen, keylen_str_buf, 10) - keylen_str_buf;
+ item_list.push_back(new Item_string(keylen_str_buf, buflen, cs));
+ /* ref */
+ item_list.push_back(new Item_string("func", strlen("func"), cs));
+ }
+ /* rows */
+ ha_rows rows= (sj_strategy == SJ_OPT_MATERIALIZE_SCAN)?
+ tab->emb_sj_nest->sj_mat_info->rows : 1;
+ item_list.push_back(new Item_int(rows));
+ /* filtered */
+ if (join->thd->lex->describe & DESCRIBE_EXTENDED)
+ item_list.push_back(new Item_float(1.0, 2));
+
+ /* Extra */
+ if (need_tmp_table)
+ {
+ need_tmp_table=0;
+ extra.append(STRING_WITH_LEN("; Using temporary"));
+ }
+ if (need_order)
+ {
+ need_order=0;
+ extra.append(STRING_WITH_LEN("; Using filesort"));
+ }
+ /* Skip initial "; "*/
+ const char *str= extra.ptr();
+ uint32 extra_len= extra.length();
+ if (extra_len)
+ {
+ str += 2;
+ extra_len -= 2;
+ }
+ item_list.push_back(new Item_string(str, extra_len, cs));
+
+ /* Register the nest for further processing: */
+ sjm_nests[sjm_nests_end++]= i;
+ i += join->best_positions[i].n_sj_tables-1;
+ goto loop_end;
+ }
+
if (tab->type == JT_ALL && tab->select && tab->select->quick)
{
quick_type= tab->select->quick->get_type();
@@ -17935,6 +18019,7 @@
else
tab->type = JT_RANGE;
}
+
/* table */
if (table->derived_select_number)
{
@@ -18113,7 +18198,7 @@
}
/* Build "Extra" field and add it to item_list. */
- my_bool key_read=table->key_read;
+ key_read=table->key_read;
if ((tab->type == JT_NEXT || tab->type == JT_CONST) &&
table->covering_keys.is_set(tab->index))
key_read=1;
@@ -18269,7 +18354,8 @@
extra.append(STRING_WITH_LEN(")"));
}
}
- uint sj_strategy= join->best_positions[i].sj_strategy;
+
+ /*
if (sj_is_materialize_strategy(sj_strategy))
{
if (join->best_positions[i].n_sj_tables == 1)
@@ -18286,6 +18372,7 @@
{
extra.append(STRING_WITH_LEN("; End materialize"));
}
+ */
for (uint part= 0; part < tab->ref.key_parts; part++)
{
@@ -18309,6 +18396,15 @@
}
item_list.push_back(new Item_string(str, len, cs));
}
+ loop_end:
+ if (i+1 == end_table && sjm_nests_cur != sjm_nests_end)
+ {
+ printing_materialize_nest= TRUE;
+ i= sjm_nests[sjm_nests_cur++] - 1;
+ end_table= (i+1) + join->best_positions[i+1].n_sj_tables;
+ select_id= join->join_tab[i+1].emb_sj_nest->sj_subq_pred->get_identifier();
+ }
+
// For next iteration
used_tables|=table->map;
if (result->send_data(item_list))
1
0
[Maria-developers] bzr commit into MariaDB 5.1, with Maria 1.5:maria branch (monty:2834)
by Michael Widenius 29 Mar '10
by Michael Widenius 29 Mar '10
29 Mar '10
#At lp:maria based on revid:sergii@pisem.net-20100324221239-7bj3zf8yv6bgclx1
2834 Michael Widenius 2010-03-28
Fixed compiler warnings and sporadic failures in test cases
modified:
mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test
mysql-test/include/default_mysqld.cnf
mysql-test/lib/My/SafeProcess/safe_process.cc
mysql-test/lib/v1/mysql-test-run.pl
mysql-test/suite/rpl/r/rpl_do_grant.result
mysql-test/suite/rpl/t/rpl_do_grant.test
mysql-test/suite/rpl/t/rpl_name_const.test
mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
mysql-test/t/bug47671-master.opt
mysql-test/t/ctype_latin1_de-master.opt
mysql-test/t/ctype_ucs2_def-master.opt
sql-common/client.c
sql/item.cc
sql/item.h
sql/item_cmpfunc.cc
sql/item_create.cc
sql/item_create.h
sql/item_sum.cc
sql/item_sum.h
sql/set_var.cc
sql/sql_yacc.yy
storage/example/ha_example.h
storage/maria/ma_search.c
storage/maria/maria_def.h
storage/myisam/ft_stopwords.c
storage/xtradb/fil/fil0fil.c
storage/xtradb/include/page0page.h
storage/xtradb/include/page0page.ic
support-files/compiler_warnings.supp
per-file messages:
mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test
Added missing sync_slave_with_master; Fixes random failures
mysql-test/include/default_mysqld.cnf
default-character-set -> character-set-server (removes warning in error files for usage of deprecated options)
mysql-test/lib/My/SafeProcess/safe_process.cc
Fixed compiler warning
mysql-test/lib/v1/mysql-test-run.pl
default-character-set -> character-set-server (removes warning in error files for usage of deprecated options)
mysql-test/suite/rpl/r/rpl_do_grant.result
Updated test results
mysql-test/suite/rpl/t/rpl_do_grant.test
Added missing sync_slave_with_master; Fixes random failures
Had to explictely do stop slave before DROP USER to avoid failure on slave as the user is already dropped on slave.
mysql-test/suite/rpl/t/rpl_name_const.test
Added missing sync_slave_with_master; Fixes random failures
mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
Added missing sync_slave_with_master; Fixes random failures
mysql-test/t/bug47671-master.opt
default-character-set -> character-set-server (removes warning in error files for usage of deprecated options)
mysql-test/t/ctype_latin1_de-master.opt
default-character-set -> character-set-server (removes warning in error files for usage of deprecated options)
mysql-test/t/ctype_ucs2_def-master.opt
default-character-set -> character-set-server (removes warning in error files for usage of deprecated options)
sql-common/client.c
Fixed compiler warning
sql/item.cc
Renamed function to remove compiler warnings (with gcc)
sql/item.h
Renamed function to remove compiler warnings (with gcc)
sql/item_cmpfunc.cc
Renamed function to remove compiler warnings (with gcc)
sql/item_create.cc
Renamed function to remove compiler warnings (with gcc)
sql/item_create.h
Renamed function to remove compiler warnings (with gcc)
sql/item_sum.cc
Renamed function to remove compiler warnings (with gcc)
sql/item_sum.h
Renamed function to remove compiler warnings (with gcc)
sql/set_var.cc
Don't use bit_do_set() / bot_is_set() / bit_do_clear() as this generates compiler warnings
(They are also of no use as we know the value can hold the bits)
sql/sql_yacc.yy
Renamed function to remove compiler warnings (with gcc)
storage/example/ha_example.h
Fixed old read_time() prototype
storage/maria/ma_search.c
Added extra variables to remove compiler warnings
storage/maria/maria_def.h
Added extra variables to remove compiler warnings
storage/myisam/ft_stopwords.c
Added cast to get rid of compiler warning
storage/xtradb/fil/fil0fil.c
Added cast to get rid of compiler warning
storage/xtradb/include/page0page.h
Added const to get rid of compiler warning
storage/xtradb/include/page0page.ic
Added const to get rid of compiler warning
support-files/compiler_warnings.supp
Added suppression of strict-aliasing
=== modified file 'mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test'
--- a/mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test 2010-01-22 09:38:21 +0000
+++ b/mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test 2010-03-28 18:10:00 +0000
@@ -157,3 +157,4 @@ INSERT INTO t1 VALUES (1);
DROP TEMPORARY TABLE t1;
+--sync_slave_with_master
=== modified file 'mysql-test/include/default_mysqld.cnf'
--- a/mysql-test/include/default_mysqld.cnf 2008-04-08 14:51:26 +0000
+++ b/mysql-test/include/default_mysqld.cnf 2010-03-28 18:10:00 +0000
@@ -2,7 +2,7 @@
[mysqld]
open-files-limit= 1024
local-infile
-default-character-set= latin1
+character-set-server= latin1
# Increase default connect_timeout to avoid intermittent
# disconnects when test servers are put under load see BUG#28359
=== modified file 'mysql-test/lib/My/SafeProcess/safe_process.cc'
--- a/mysql-test/lib/My/SafeProcess/safe_process.cc 2009-07-08 12:31:22 +0000
+++ b/mysql-test/lib/My/SafeProcess/safe_process.cc 2010-03-28 18:10:00 +0000
@@ -159,7 +159,7 @@ int main(int argc, char* const argv[] )
signal(SIGCHLD, handle_signal);
signal(SIGABRT, handle_abort);
- sprintf(safe_process_name, "safe_process[%d]", own_pid);
+ sprintf(safe_process_name, "safe_process[%d]", (int) own_pid);
message("Started");
=== modified file 'mysql-test/lib/v1/mysql-test-run.pl'
--- a/mysql-test/lib/v1/mysql-test-run.pl 2010-03-04 08:03:07 +0000
+++ b/mysql-test/lib/v1/mysql-test-run.pl 2010-03-28 18:10:00 +0000
@@ -3965,7 +3965,7 @@ sub mysqld_arguments ($$$$) {
}
}
- mtr_add_arg($args, "%s--default-character-set=latin1", $prefix);
+ mtr_add_arg($args, "%s--character-set-server-set=latin1", $prefix);
mtr_add_arg($args, "%s--language=%s", $prefix, $path_language);
mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix);
=== modified file 'mysql-test/suite/rpl/r/rpl_do_grant.result'
--- a/mysql-test/suite/rpl/r/rpl_do_grant.result 2009-12-06 23:12:11 +0000
+++ b/mysql-test/suite/rpl/r/rpl_do_grant.result 2010-03-28 18:10:00 +0000
@@ -165,10 +165,9 @@ USE bug42217_db;
DROP FUNCTION upgrade_del_func;
DROP FUNCTION upgrade_alter_func;
DROP DATABASE bug42217_db;
-DROP USER 'create_rout_db'@'localhost';
-call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396");
-USE mtr;
call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396");
+stop slave;
+DROP USER 'create_rout_db'@'localhost';
######## BUG#49119 #######
### i) test case from the 'how to repeat section'
stop slave;
=== modified file 'mysql-test/suite/rpl/t/rpl_do_grant.test'
--- a/mysql-test/suite/rpl/t/rpl_do_grant.test 2010-03-04 08:03:07 +0000
+++ b/mysql-test/suite/rpl/t/rpl_do_grant.test 2010-03-28 18:10:00 +0000
@@ -209,12 +209,18 @@ USE bug42217_db;
DROP FUNCTION upgrade_del_func;
DROP FUNCTION upgrade_alter_func;
DROP DATABASE bug42217_db;
-DROP USER 'create_rout_db'@'localhost';
call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396");
+
+sync_slave_with_master;
+
+# Drop the user that was already dropped on the slave
connection slave;
-USE mtr;
-call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396");
+--disable_warnings
+stop slave;
+connection master;
+DROP USER 'create_rout_db'@'localhost';
+--enable_warnings
# BUG#49119: Master crashes when executing 'REVOKE ... ON
# {PROCEDURE|FUNCTION} FROM ...'
=== modified file 'mysql-test/suite/rpl/t/rpl_name_const.test'
--- a/mysql-test/suite/rpl/t/rpl_name_const.test 2009-04-08 23:42:51 +0000
+++ b/mysql-test/suite/rpl/t/rpl_name_const.test 2010-03-28 18:10:00 +0000
@@ -45,3 +45,4 @@ select * from t1 order by id;
connection master;
drop table t1;
drop procedure test_procedure;
+--sync_slave_with_master
=== modified file 'mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test'
--- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test 2007-12-12 10:14:59 +0000
+++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test 2010-03-28 18:10:00 +0000
@@ -53,6 +53,7 @@ UPDATE t1 SET a=99 WHERE a = 0;
SHOW BINLOG EVENTS;
DROP TABLE t1;
+--sync_slave_with_master
# BUG#17620: Replicate (Row Based) Fails when Query Cache enabled on
# slave
=== modified file 'mysql-test/t/bug47671-master.opt'
--- a/mysql-test/t/bug47671-master.opt 2009-11-25 06:55:49 +0000
+++ b/mysql-test/t/bug47671-master.opt 2010-03-28 18:10:00 +0000
@@ -1 +1 @@
---default-character-set=utf8 --skip-character-set-client-handshake
+--character-set-server=utf8 --skip-character-set-client-handshake
=== modified file 'mysql-test/t/ctype_latin1_de-master.opt'
--- a/mysql-test/t/ctype_latin1_de-master.opt 2003-05-21 23:57:27 +0000
+++ b/mysql-test/t/ctype_latin1_de-master.opt 2010-03-28 18:10:00 +0000
@@ -1 +1 @@
---default-character-set=latin1 --default-collation=latin1_german2_ci
+--character-set-server=latin1 --default-collation=latin1_german2_ci
=== modified file 'mysql-test/t/ctype_ucs2_def-master.opt'
--- a/mysql-test/t/ctype_ucs2_def-master.opt 2007-02-19 11:04:38 +0000
+++ b/mysql-test/t/ctype_ucs2_def-master.opt 2010-03-28 18:10:00 +0000
@@ -1 +1 @@
---default-collation=ucs2_unicode_ci --default-character-set=ucs2,latin1
+--default-collation=ucs2_unicode_ci --character-set-server=ucs2,latin1
=== modified file 'sql-common/client.c'
--- a/sql-common/client.c 2010-01-29 18:42:22 +0000
+++ b/sql-common/client.c 2010-03-28 18:10:00 +0000
@@ -1863,7 +1863,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
uint port, const char *unix_socket,ulong client_flag)
{
char buff[NAME_LEN+USERNAME_LENGTH+100];
- char error_string[1024];
char *end,*host_info= NULL;
my_socket sock;
in_addr_t ip_addr;
@@ -2304,6 +2303,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
/* Do the SSL layering. */
struct st_mysql_options *options= &mysql->options;
struct st_VioSSLFd *ssl_fd;
+ char error_string[1024];
/*
Send client_flag, max_packet_size - unencrypted otherwise
=== modified file 'sql/item.cc'
--- a/sql/item.cc 2010-03-04 08:03:07 +0000
+++ b/sql/item.cc 2010-03-28 18:10:00 +0000
@@ -7010,7 +7010,7 @@ bool Item_cache_int::cache_value()
}
-void Item_cache_int::store(Item *item, longlong val_arg)
+void Item_cache_int::store_longlong(Item *item, longlong val_arg)
{
/* An explicit values is given, save it. */
value_cached= TRUE;
=== modified file 'sql/item.h'
--- a/sql/item.h 2010-03-04 08:03:07 +0000
+++ b/sql/item.h 2010-03-28 18:10:00 +0000
@@ -3045,7 +3045,7 @@ public:
Item_cache_int(enum_field_types field_type_arg):
Item_cache(field_type_arg), value(0) {}
- void store(Item *item, longlong val_arg);
+ void store_longlong(Item *item, longlong val_arg);
double val_real();
longlong val_int();
String* val_str(String *str);
=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc 2010-03-04 08:03:07 +0000
+++ b/sql/item_cmpfunc.cc 2010-03-28 18:10:00 +0000
@@ -879,7 +879,7 @@ get_time_value(THD *thd, Item ***item_ar
Item_cache_int *cache= new Item_cache_int();
/* Mark the cache as non-const to prevent re-caching. */
cache->set_used_tables(1);
- cache->store(item, value);
+ cache->store_longlong(item, value);
*cache_arg= cache;
*item_arg= cache_arg;
}
@@ -917,13 +917,13 @@ int Arg_comparator::set_cmp_func(Item_re
cache->set_used_tables(1);
if (!(*a)->is_datetime())
{
- cache->store((*a), const_value);
+ cache->store_longlong((*a), const_value);
a_cache= cache;
a= (Item **)&a_cache;
}
else
{
- cache->store((*b), const_value);
+ cache->store_longlong((*b), const_value);
b_cache= cache;
b= (Item **)&b_cache;
}
@@ -1145,7 +1145,7 @@ get_datetime_value(THD *thd, Item ***ite
Item_cache_int *cache= new Item_cache_int(MYSQL_TYPE_DATETIME);
/* Mark the cache as non-const to prevent re-caching. */
cache->set_used_tables(1);
- cache->store(item, value);
+ cache->store_longlong(item, value);
*cache_arg= cache;
*item_arg= cache_arg;
}
=== modified file 'sql/item_create.cc'
--- a/sql/item_create.cc 2010-03-04 08:03:07 +0000
+++ b/sql/item_create.cc 2010-03-28 18:10:00 +0000
@@ -101,7 +101,7 @@ public:
@param arg1 The first argument of the function
@return An item representing the function call
*/
- virtual Item *create(THD *thd, Item *arg1) = 0;
+ virtual Item *create_1_arg(THD *thd, Item *arg1) = 0;
protected:
/** Constructor. */
@@ -127,7 +127,7 @@ public:
@param arg2 The second argument of the function
@return An item representing the function call
*/
- virtual Item *create(THD *thd, Item *arg1, Item *arg2) = 0;
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0;
protected:
/** Constructor. */
@@ -154,7 +154,7 @@ public:
@param arg3 The third argument of the function
@return An item representing the function call
*/
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0;
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0;
protected:
/** Constructor. */
@@ -171,8 +171,8 @@ protected:
class Create_sp_func : public Create_qfunc
{
public:
- virtual Item *create(THD *thd, LEX_STRING db, LEX_STRING name,
- bool use_explicit_name, List<Item> *item_list);
+ virtual Item *create_with_db(THD *thd, LEX_STRING db, LEX_STRING name,
+ bool use_explicit_name, List<Item> *item_list);
static Create_sp_func s_singleton;
@@ -217,7 +217,7 @@ protected:
class Create_func_abs : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_abs s_singleton;
@@ -230,7 +230,7 @@ protected:
class Create_func_acos : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_acos s_singleton;
@@ -243,7 +243,7 @@ protected:
class Create_func_addtime : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_addtime s_singleton;
@@ -256,7 +256,7 @@ protected:
class Create_func_aes_encrypt : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_aes_encrypt s_singleton;
@@ -269,7 +269,7 @@ protected:
class Create_func_aes_decrypt : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_aes_decrypt s_singleton;
@@ -283,7 +283,7 @@ protected:
class Create_func_area : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_area s_singleton;
@@ -298,7 +298,7 @@ protected:
class Create_func_as_wkb : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_as_wkb s_singleton;
@@ -313,7 +313,7 @@ protected:
class Create_func_as_wkt : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_as_wkt s_singleton;
@@ -327,7 +327,7 @@ protected:
class Create_func_asin : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_asin s_singleton;
@@ -353,7 +353,7 @@ protected:
class Create_func_benchmark : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_benchmark s_singleton;
@@ -366,7 +366,7 @@ protected:
class Create_func_bin : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_bin s_singleton;
@@ -379,7 +379,7 @@ protected:
class Create_func_bit_count : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_bit_count s_singleton;
@@ -392,7 +392,7 @@ protected:
class Create_func_bit_length : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_bit_length s_singleton;
@@ -405,7 +405,7 @@ protected:
class Create_func_ceiling : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_ceiling s_singleton;
@@ -419,7 +419,7 @@ protected:
class Create_func_centroid : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_centroid s_singleton;
@@ -433,7 +433,7 @@ protected:
class Create_func_char_length : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_char_length s_singleton;
@@ -446,7 +446,7 @@ protected:
class Create_func_coercibility : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_coercibility s_singleton;
@@ -459,7 +459,7 @@ protected:
class Create_func_compress : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_compress s_singleton;
@@ -512,7 +512,7 @@ protected:
class Create_func_contains : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_contains s_singleton;
@@ -526,7 +526,7 @@ protected:
class Create_func_conv : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_conv s_singleton;
@@ -539,7 +539,7 @@ protected:
class Create_func_convert_tz : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_convert_tz s_singleton;
@@ -552,7 +552,7 @@ protected:
class Create_func_cos : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_cos s_singleton;
@@ -565,7 +565,7 @@ protected:
class Create_func_cot : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_cot s_singleton;
@@ -578,7 +578,7 @@ protected:
class Create_func_crc32 : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_crc32 s_singleton;
@@ -592,7 +592,7 @@ protected:
class Create_func_crosses : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_crosses s_singleton;
@@ -606,7 +606,7 @@ protected:
class Create_func_date_format : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_date_format s_singleton;
@@ -619,7 +619,7 @@ protected:
class Create_func_datediff : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_datediff s_singleton;
@@ -632,7 +632,7 @@ protected:
class Create_func_dayname : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_dayname s_singleton;
@@ -645,7 +645,7 @@ protected:
class Create_func_dayofmonth : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_dayofmonth s_singleton;
@@ -658,7 +658,7 @@ protected:
class Create_func_dayofweek : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_dayofweek s_singleton;
@@ -671,7 +671,7 @@ protected:
class Create_func_dayofyear : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_dayofyear s_singleton;
@@ -684,7 +684,7 @@ protected:
class Create_func_decode : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_decode s_singleton;
@@ -697,7 +697,7 @@ protected:
class Create_func_degrees : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_degrees s_singleton;
@@ -737,7 +737,7 @@ protected:
class Create_func_dimension : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_dimension s_singleton;
@@ -752,7 +752,7 @@ protected:
class Create_func_disjoint : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_disjoint s_singleton;
@@ -779,7 +779,7 @@ protected:
class Create_func_encode : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_encode s_singleton;
@@ -806,7 +806,7 @@ protected:
class Create_func_endpoint : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_endpoint s_singleton;
@@ -821,7 +821,7 @@ protected:
class Create_func_envelope : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_envelope s_singleton;
@@ -836,7 +836,7 @@ protected:
class Create_func_equals : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_equals s_singleton;
@@ -850,7 +850,7 @@ protected:
class Create_func_exp : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_exp s_singleton;
@@ -877,7 +877,7 @@ protected:
class Create_func_exteriorring : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_exteriorring s_singleton;
@@ -904,7 +904,7 @@ protected:
class Create_func_find_in_set : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_find_in_set s_singleton;
@@ -917,7 +917,7 @@ protected:
class Create_func_floor : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_floor s_singleton;
@@ -930,7 +930,7 @@ protected:
class Create_func_format : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_format s_singleton;
@@ -956,7 +956,7 @@ protected:
class Create_func_from_days : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_from_days s_singleton;
@@ -1013,7 +1013,7 @@ protected:
class Create_func_geometry_type : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_geometry_type s_singleton;
@@ -1028,7 +1028,7 @@ protected:
class Create_func_geometryn : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_geometryn s_singleton;
@@ -1042,7 +1042,7 @@ protected:
class Create_func_get_lock : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_get_lock s_singleton;
@@ -1056,7 +1056,7 @@ protected:
class Create_func_glength : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_glength s_singleton;
@@ -1083,7 +1083,7 @@ protected:
class Create_func_hex : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_hex s_singleton;
@@ -1096,7 +1096,7 @@ protected:
class Create_func_ifnull : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_ifnull s_singleton;
@@ -1109,7 +1109,7 @@ protected:
class Create_func_inet_ntoa : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_inet_ntoa s_singleton;
@@ -1122,7 +1122,7 @@ protected:
class Create_func_inet_aton : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_inet_aton s_singleton;
@@ -1135,7 +1135,7 @@ protected:
class Create_func_instr : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_instr s_singleton;
@@ -1149,7 +1149,7 @@ protected:
class Create_func_interiorringn : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_interiorringn s_singleton;
@@ -1164,7 +1164,7 @@ protected:
class Create_func_intersects : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_intersects s_singleton;
@@ -1178,7 +1178,7 @@ protected:
class Create_func_is_free_lock : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_is_free_lock s_singleton;
@@ -1191,7 +1191,7 @@ protected:
class Create_func_is_used_lock : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_is_used_lock s_singleton;
@@ -1205,7 +1205,7 @@ protected:
class Create_func_isclosed : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_isclosed s_singleton;
@@ -1220,7 +1220,7 @@ protected:
class Create_func_isempty : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_isempty s_singleton;
@@ -1234,7 +1234,7 @@ protected:
class Create_func_isnull : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_isnull s_singleton;
@@ -1248,7 +1248,7 @@ protected:
class Create_func_issimple : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_issimple s_singleton;
@@ -1262,7 +1262,7 @@ protected:
class Create_func_last_day : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_last_day s_singleton;
@@ -1288,7 +1288,7 @@ protected:
class Create_func_lcase : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_lcase s_singleton;
@@ -1314,7 +1314,7 @@ protected:
class Create_func_length : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_length s_singleton;
@@ -1327,7 +1327,7 @@ protected:
class Create_func_ln : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_ln s_singleton;
@@ -1340,7 +1340,7 @@ protected:
class Create_func_load_file : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_load_file s_singleton;
@@ -1379,7 +1379,7 @@ protected:
class Create_func_log10 : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_log10 s_singleton;
@@ -1392,7 +1392,7 @@ protected:
class Create_func_log2 : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_log2 s_singleton;
@@ -1405,7 +1405,7 @@ protected:
class Create_func_lpad : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_lpad s_singleton;
@@ -1418,7 +1418,7 @@ protected:
class Create_func_ltrim : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_ltrim s_singleton;
@@ -1431,7 +1431,7 @@ protected:
class Create_func_makedate : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_makedate s_singleton;
@@ -1444,7 +1444,7 @@ protected:
class Create_func_maketime : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_maketime s_singleton;
@@ -1483,7 +1483,7 @@ protected:
class Create_func_md5 : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_md5 s_singleton;
@@ -1496,7 +1496,7 @@ protected:
class Create_func_monthname : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_monthname s_singleton;
@@ -1509,7 +1509,7 @@ protected:
class Create_func_name_const : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_name_const s_singleton;
@@ -1522,7 +1522,7 @@ protected:
class Create_func_nullif : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_nullif s_singleton;
@@ -1536,7 +1536,7 @@ protected:
class Create_func_numgeometries : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_numgeometries s_singleton;
@@ -1551,7 +1551,7 @@ protected:
class Create_func_numinteriorring : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_numinteriorring s_singleton;
@@ -1566,7 +1566,7 @@ protected:
class Create_func_numpoints : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_numpoints s_singleton;
@@ -1580,7 +1580,7 @@ protected:
class Create_func_oct : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_oct s_singleton;
@@ -1593,7 +1593,7 @@ protected:
class Create_func_ord : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_ord s_singleton;
@@ -1607,7 +1607,7 @@ protected:
class Create_func_overlaps : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_overlaps s_singleton;
@@ -1621,7 +1621,7 @@ protected:
class Create_func_period_add : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_period_add s_singleton;
@@ -1634,7 +1634,7 @@ protected:
class Create_func_period_diff : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_period_diff s_singleton;
@@ -1661,7 +1661,7 @@ protected:
class Create_func_pointn : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_pointn s_singleton;
@@ -1675,7 +1675,7 @@ protected:
class Create_func_pow : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_pow s_singleton;
@@ -1688,7 +1688,7 @@ protected:
class Create_func_quote : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_quote s_singleton;
@@ -1701,7 +1701,7 @@ protected:
class Create_func_radians : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_radians s_singleton;
@@ -1727,7 +1727,7 @@ protected:
class Create_func_release_lock : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_release_lock s_singleton;
@@ -1740,7 +1740,7 @@ protected:
class Create_func_reverse : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_reverse s_singleton;
@@ -1779,7 +1779,7 @@ protected:
class Create_func_rpad : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_rpad s_singleton;
@@ -1792,7 +1792,7 @@ protected:
class Create_func_rtrim : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_rtrim s_singleton;
@@ -1805,7 +1805,7 @@ protected:
class Create_func_sec_to_time : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sec_to_time s_singleton;
@@ -1818,7 +1818,7 @@ protected:
class Create_func_sha : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sha s_singleton;
@@ -1831,7 +1831,7 @@ protected:
class Create_func_sign : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sign s_singleton;
@@ -1844,7 +1844,7 @@ protected:
class Create_func_sin : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sin s_singleton;
@@ -1857,7 +1857,7 @@ protected:
class Create_func_sleep : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sleep s_singleton;
@@ -1870,7 +1870,7 @@ protected:
class Create_func_soundex : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_soundex s_singleton;
@@ -1883,7 +1883,7 @@ protected:
class Create_func_space : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_space s_singleton;
@@ -1896,7 +1896,7 @@ protected:
class Create_func_sqrt : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sqrt s_singleton;
@@ -1910,7 +1910,7 @@ protected:
class Create_func_srid : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_srid s_singleton;
@@ -1925,7 +1925,7 @@ protected:
class Create_func_startpoint : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_startpoint s_singleton;
@@ -1939,7 +1939,7 @@ protected:
class Create_func_str_to_date : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_str_to_date s_singleton;
@@ -1952,7 +1952,7 @@ protected:
class Create_func_strcmp : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_strcmp s_singleton;
@@ -1965,7 +1965,7 @@ protected:
class Create_func_substr_index : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_substr_index s_singleton;
@@ -1978,7 +1978,7 @@ protected:
class Create_func_subtime : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_subtime s_singleton;
@@ -1991,7 +1991,7 @@ protected:
class Create_func_tan : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_tan s_singleton;
@@ -2004,7 +2004,7 @@ protected:
class Create_func_time_format : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_time_format s_singleton;
@@ -2017,7 +2017,7 @@ protected:
class Create_func_time_to_sec : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_time_to_sec s_singleton;
@@ -2030,7 +2030,7 @@ protected:
class Create_func_timediff : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_timediff s_singleton;
@@ -2043,7 +2043,7 @@ protected:
class Create_func_to_days : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_to_days s_singleton;
@@ -2057,7 +2057,7 @@ protected:
class Create_func_touches : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_touches s_singleton;
@@ -2071,7 +2071,7 @@ protected:
class Create_func_ucase : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_ucase s_singleton;
@@ -2084,7 +2084,7 @@ protected:
class Create_func_uncompress : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_uncompress s_singleton;
@@ -2097,7 +2097,7 @@ protected:
class Create_func_uncompressed_length : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_uncompressed_length s_singleton;
@@ -2110,7 +2110,7 @@ protected:
class Create_func_unhex : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_unhex s_singleton;
@@ -2175,7 +2175,7 @@ protected:
class Create_func_weekday : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_weekday s_singleton;
@@ -2188,7 +2188,7 @@ protected:
class Create_func_weekofyear : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_weekofyear s_singleton;
@@ -2202,7 +2202,7 @@ protected:
class Create_func_within : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_within s_singleton;
@@ -2217,7 +2217,7 @@ protected:
class Create_func_x : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_x s_singleton;
@@ -2231,7 +2231,7 @@ protected:
class Create_func_xml_extractvalue : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_xml_extractvalue s_singleton;
@@ -2244,7 +2244,7 @@ protected:
class Create_func_xml_update : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_xml_update s_singleton;
@@ -2258,7 +2258,7 @@ protected:
class Create_func_y : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_y s_singleton;
@@ -2353,7 +2353,7 @@ Create_qfunc::create(THD *thd, LEX_STRIN
if (thd->lex->copy_db_to(&db.str, &db.length))
return NULL;
- return create(thd, db, name, false, item_list);
+ return create_with_db(thd, db, name, false, item_list);
}
@@ -2470,8 +2470,8 @@ Create_udf_func::create(THD *thd, udf_fu
Create_sp_func Create_sp_func::s_singleton;
Item*
-Create_sp_func::create(THD *thd, LEX_STRING db, LEX_STRING name,
- bool use_explicit_name, List<Item> *item_list)
+Create_sp_func::create_with_db(THD *thd, LEX_STRING db, LEX_STRING name,
+ bool use_explicit_name, List<Item> *item_list)
{
int arg_count= 0;
Item *func= NULL;
@@ -2564,7 +2564,7 @@ Create_func_arg1::create(THD *thd, LEX_S
return NULL;
}
- return create(thd, param_1);
+ return create_1_arg(thd, param_1);
}
@@ -2592,7 +2592,7 @@ Create_func_arg2::create(THD *thd, LEX_S
return NULL;
}
- return create(thd, param_1, param_2);
+ return create_2_arg(thd, param_1, param_2);
}
@@ -2622,14 +2622,14 @@ Create_func_arg3::create(THD *thd, LEX_S
return NULL;
}
- return create(thd, param_1, param_2, param_3);
+ return create_3_arg(thd, param_1, param_2, param_3);
}
Create_func_abs Create_func_abs::s_singleton;
Item*
-Create_func_abs::create(THD *thd, Item *arg1)
+Create_func_abs::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_abs(arg1);
}
@@ -2638,7 +2638,7 @@ Create_func_abs::create(THD *thd, Item *
Create_func_acos Create_func_acos::s_singleton;
Item*
-Create_func_acos::create(THD *thd, Item *arg1)
+Create_func_acos::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_acos(arg1);
}
@@ -2647,7 +2647,7 @@ Create_func_acos::create(THD *thd, Item
Create_func_addtime Create_func_addtime::s_singleton;
Item*
-Create_func_addtime::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_addtime::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_add_time(arg1, arg2, 0, 0);
}
@@ -2656,7 +2656,7 @@ Create_func_addtime::create(THD *thd, It
Create_func_aes_encrypt Create_func_aes_encrypt::s_singleton;
Item*
-Create_func_aes_encrypt::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_aes_encrypt::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_aes_encrypt(arg1, arg2);
}
@@ -2665,7 +2665,7 @@ Create_func_aes_encrypt::create(THD *thd
Create_func_aes_decrypt Create_func_aes_decrypt::s_singleton;
Item*
-Create_func_aes_decrypt::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_aes_decrypt::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_aes_decrypt(arg1, arg2);
}
@@ -2675,7 +2675,7 @@ Create_func_aes_decrypt::create(THD *thd
Create_func_area Create_func_area::s_singleton;
Item*
-Create_func_area::create(THD *thd, Item *arg1)
+Create_func_area::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_area(arg1);
}
@@ -2686,7 +2686,7 @@ Create_func_area::create(THD *thd, Item
Create_func_as_wkb Create_func_as_wkb::s_singleton;
Item*
-Create_func_as_wkb::create(THD *thd, Item *arg1)
+Create_func_as_wkb::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_as_wkb(arg1);
}
@@ -2697,7 +2697,7 @@ Create_func_as_wkb::create(THD *thd, Ite
Create_func_as_wkt Create_func_as_wkt::s_singleton;
Item*
-Create_func_as_wkt::create(THD *thd, Item *arg1)
+Create_func_as_wkt::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_as_wkt(arg1);
}
@@ -2707,7 +2707,7 @@ Create_func_as_wkt::create(THD *thd, Ite
Create_func_asin Create_func_asin::s_singleton;
Item*
-Create_func_asin::create(THD *thd, Item *arg1)
+Create_func_asin::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_asin(arg1);
}
@@ -2753,7 +2753,7 @@ Create_func_atan::create_native(THD *thd
Create_func_benchmark Create_func_benchmark::s_singleton;
Item*
-Create_func_benchmark::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_benchmark::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
return new (thd->mem_root) Item_func_benchmark(arg1, arg2);
@@ -2763,7 +2763,7 @@ Create_func_benchmark::create(THD *thd,
Create_func_bin Create_func_bin::s_singleton;
Item*
-Create_func_bin::create(THD *thd, Item *arg1)
+Create_func_bin::create_1_arg(THD *thd, Item *arg1)
{
Item *i10= new (thd->mem_root) Item_int((int32) 10,2);
Item *i2= new (thd->mem_root) Item_int((int32) 2,1);
@@ -2774,7 +2774,7 @@ Create_func_bin::create(THD *thd, Item *
Create_func_bit_count Create_func_bit_count::s_singleton;
Item*
-Create_func_bit_count::create(THD *thd, Item *arg1)
+Create_func_bit_count::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_bit_count(arg1);
}
@@ -2783,7 +2783,7 @@ Create_func_bit_count::create(THD *thd,
Create_func_bit_length Create_func_bit_length::s_singleton;
Item*
-Create_func_bit_length::create(THD *thd, Item *arg1)
+Create_func_bit_length::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_bit_length(arg1);
}
@@ -2792,7 +2792,7 @@ Create_func_bit_length::create(THD *thd,
Create_func_ceiling Create_func_ceiling::s_singleton;
Item*
-Create_func_ceiling::create(THD *thd, Item *arg1)
+Create_func_ceiling::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_ceiling(arg1);
}
@@ -2802,7 +2802,7 @@ Create_func_ceiling::create(THD *thd, It
Create_func_centroid Create_func_centroid::s_singleton;
Item*
-Create_func_centroid::create(THD *thd, Item *arg1)
+Create_func_centroid::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_centroid(arg1);
}
@@ -2812,7 +2812,7 @@ Create_func_centroid::create(THD *thd, I
Create_func_char_length Create_func_char_length::s_singleton;
Item*
-Create_func_char_length::create(THD *thd, Item *arg1)
+Create_func_char_length::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_char_length(arg1);
}
@@ -2821,7 +2821,7 @@ Create_func_char_length::create(THD *thd
Create_func_coercibility Create_func_coercibility::s_singleton;
Item*
-Create_func_coercibility::create(THD *thd, Item *arg1)
+Create_func_coercibility::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_coercibility(arg1);
}
@@ -2873,7 +2873,7 @@ Create_func_concat_ws::create_native(THD
Create_func_compress Create_func_compress::s_singleton;
Item*
-Create_func_compress::create(THD *thd, Item *arg1)
+Create_func_compress::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_compress(arg1);
}
@@ -2893,7 +2893,7 @@ Create_func_connection_id::create(THD *t
Create_func_contains Create_func_contains::s_singleton;
Item*
-Create_func_contains::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_CONTAINS_FUNC);
@@ -2904,7 +2904,7 @@ Create_func_contains::create(THD *thd, I
Create_func_conv Create_func_conv::s_singleton;
Item*
-Create_func_conv::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_conv::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_conv(arg1, arg2, arg3);
}
@@ -2913,7 +2913,7 @@ Create_func_conv::create(THD *thd, Item
Create_func_convert_tz Create_func_convert_tz::s_singleton;
Item*
-Create_func_convert_tz::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_convert_tz::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_convert_tz(arg1, arg2, arg3);
}
@@ -2922,7 +2922,7 @@ Create_func_convert_tz::create(THD *thd,
Create_func_cos Create_func_cos::s_singleton;
Item*
-Create_func_cos::create(THD *thd, Item *arg1)
+Create_func_cos::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_cos(arg1);
}
@@ -2931,7 +2931,7 @@ Create_func_cos::create(THD *thd, Item *
Create_func_cot Create_func_cot::s_singleton;
Item*
-Create_func_cot::create(THD *thd, Item *arg1)
+Create_func_cot::create_1_arg(THD *thd, Item *arg1)
{
Item *i1= new (thd->mem_root) Item_int((char*) "1", 1, 1);
Item *i2= new (thd->mem_root) Item_func_tan(arg1);
@@ -2942,7 +2942,7 @@ Create_func_cot::create(THD *thd, Item *
Create_func_crc32 Create_func_crc32::s_singleton;
Item*
-Create_func_crc32::create(THD *thd, Item *arg1)
+Create_func_crc32::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_crc32(arg1);
}
@@ -2952,7 +2952,7 @@ Create_func_crc32::create(THD *thd, Item
Create_func_crosses Create_func_crosses::s_singleton;
Item*
-Create_func_crosses::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_crosses::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_CROSSES_FUNC);
@@ -2963,7 +2963,7 @@ Create_func_crosses::create(THD *thd, It
Create_func_date_format Create_func_date_format::s_singleton;
Item*
-Create_func_date_format::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_date_format::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_date_format(arg1, arg2, 0);
}
@@ -2972,7 +2972,7 @@ Create_func_date_format::create(THD *thd
Create_func_datediff Create_func_datediff::s_singleton;
Item*
-Create_func_datediff::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_datediff::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
Item *i1= new (thd->mem_root) Item_func_to_days(arg1);
Item *i2= new (thd->mem_root) Item_func_to_days(arg2);
@@ -2984,7 +2984,7 @@ Create_func_datediff::create(THD *thd, I
Create_func_dayname Create_func_dayname::s_singleton;
Item*
-Create_func_dayname::create(THD *thd, Item *arg1)
+Create_func_dayname::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_dayname(arg1);
}
@@ -2993,7 +2993,7 @@ Create_func_dayname::create(THD *thd, It
Create_func_dayofmonth Create_func_dayofmonth::s_singleton;
Item*
-Create_func_dayofmonth::create(THD *thd, Item *arg1)
+Create_func_dayofmonth::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_dayofmonth(arg1);
}
@@ -3002,7 +3002,7 @@ Create_func_dayofmonth::create(THD *thd,
Create_func_dayofweek Create_func_dayofweek::s_singleton;
Item*
-Create_func_dayofweek::create(THD *thd, Item *arg1)
+Create_func_dayofweek::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_weekday(arg1, 1);
}
@@ -3011,7 +3011,7 @@ Create_func_dayofweek::create(THD *thd,
Create_func_dayofyear Create_func_dayofyear::s_singleton;
Item*
-Create_func_dayofyear::create(THD *thd, Item *arg1)
+Create_func_dayofyear::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_dayofyear(arg1);
}
@@ -3020,7 +3020,7 @@ Create_func_dayofyear::create(THD *thd,
Create_func_decode Create_func_decode::s_singleton;
Item*
-Create_func_decode::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_decode::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_decode(arg1, arg2);
}
@@ -3029,7 +3029,7 @@ Create_func_decode::create(THD *thd, Ite
Create_func_degrees Create_func_degrees::s_singleton;
Item*
-Create_func_degrees::create(THD *thd, Item *arg1)
+Create_func_degrees::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_units((char*) "degrees", arg1,
180/M_PI, 0.0);
@@ -3114,7 +3114,7 @@ Create_func_des_encrypt::create_native(T
Create_func_dimension Create_func_dimension::s_singleton;
Item*
-Create_func_dimension::create(THD *thd, Item *arg1)
+Create_func_dimension::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_dimension(arg1);
}
@@ -3125,7 +3125,7 @@ Create_func_dimension::create(THD *thd,
Create_func_disjoint Create_func_disjoint::s_singleton;
Item*
-Create_func_disjoint::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_disjoint::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_DISJOINT_FUNC);
@@ -3157,7 +3157,7 @@ Create_func_elt::create_native(THD *thd,
Create_func_encode Create_func_encode::s_singleton;
Item*
-Create_func_encode::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_encode::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_encode(arg1, arg2);
}
@@ -3205,7 +3205,7 @@ Create_func_encrypt::create_native(THD *
Create_func_endpoint Create_func_endpoint::s_singleton;
Item*
-Create_func_endpoint::create(THD *thd, Item *arg1)
+Create_func_endpoint::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_spatial_decomp(arg1,
Item_func::SP_ENDPOINT);
@@ -3217,7 +3217,7 @@ Create_func_endpoint::create(THD *thd, I
Create_func_envelope Create_func_envelope::s_singleton;
Item*
-Create_func_envelope::create(THD *thd, Item *arg1)
+Create_func_envelope::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_envelope(arg1);
}
@@ -3228,7 +3228,7 @@ Create_func_envelope::create(THD *thd, I
Create_func_equals Create_func_equals::s_singleton;
Item*
-Create_func_equals::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_equals::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_EQUALS_FUNC);
@@ -3239,7 +3239,7 @@ Create_func_equals::create(THD *thd, Ite
Create_func_exp Create_func_exp::s_singleton;
Item*
-Create_func_exp::create(THD *thd, Item *arg1)
+Create_func_exp::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_exp(arg1);
}
@@ -3302,7 +3302,7 @@ Create_func_export_set::create_native(TH
Create_func_exteriorring Create_func_exteriorring::s_singleton;
Item*
-Create_func_exteriorring::create(THD *thd, Item *arg1)
+Create_func_exteriorring::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_spatial_decomp(arg1,
Item_func::SP_EXTERIORRING);
@@ -3334,7 +3334,7 @@ Create_func_field::create_native(THD *th
Create_func_find_in_set Create_func_find_in_set::s_singleton;
Item*
-Create_func_find_in_set::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_find_in_set::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_find_in_set(arg1, arg2);
}
@@ -3343,7 +3343,7 @@ Create_func_find_in_set::create(THD *thd
Create_func_floor Create_func_floor::s_singleton;
Item*
-Create_func_floor::create(THD *thd, Item *arg1)
+Create_func_floor::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_floor(arg1);
}
@@ -3352,7 +3352,7 @@ Create_func_floor::create(THD *thd, Item
Create_func_format Create_func_format::s_singleton;
Item*
-Create_func_format::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_format::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_format(arg1, arg2);
}
@@ -3372,7 +3372,7 @@ Create_func_found_rows::create(THD *thd)
Create_func_from_days Create_func_from_days::s_singleton;
Item*
-Create_func_from_days::create(THD *thd, Item *arg1)
+Create_func_from_days::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_from_days(arg1);
}
@@ -3500,7 +3500,7 @@ Create_func_geometry_from_wkb::create_na
Create_func_geometry_type Create_func_geometry_type::s_singleton;
Item*
-Create_func_geometry_type::create(THD *thd, Item *arg1)
+Create_func_geometry_type::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_geometry_type(arg1);
}
@@ -3511,7 +3511,7 @@ Create_func_geometry_type::create(THD *t
Create_func_geometryn Create_func_geometryn::s_singleton;
Item*
-Create_func_geometryn::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_geometryn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_decomp_n(arg1, arg2,
Item_func::SP_GEOMETRYN);
@@ -3522,7 +3522,7 @@ Create_func_geometryn::create(THD *thd,
Create_func_get_lock Create_func_get_lock::s_singleton;
Item*
-Create_func_get_lock::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_get_lock::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -3534,7 +3534,7 @@ Create_func_get_lock::create(THD *thd, I
Create_func_glength Create_func_glength::s_singleton;
Item*
-Create_func_glength::create(THD *thd, Item *arg1)
+Create_func_glength::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_glength(arg1);
}
@@ -3565,7 +3565,7 @@ Create_func_greatest::create_native(THD
Create_func_hex Create_func_hex::s_singleton;
Item*
-Create_func_hex::create(THD *thd, Item *arg1)
+Create_func_hex::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_hex(arg1);
}
@@ -3574,7 +3574,7 @@ Create_func_hex::create(THD *thd, Item *
Create_func_ifnull Create_func_ifnull::s_singleton;
Item*
-Create_func_ifnull::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_ifnull::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_ifnull(arg1, arg2);
}
@@ -3583,7 +3583,7 @@ Create_func_ifnull::create(THD *thd, Ite
Create_func_inet_ntoa Create_func_inet_ntoa::s_singleton;
Item*
-Create_func_inet_ntoa::create(THD *thd, Item *arg1)
+Create_func_inet_ntoa::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_inet_ntoa(arg1);
}
@@ -3592,7 +3592,7 @@ Create_func_inet_ntoa::create(THD *thd,
Create_func_inet_aton Create_func_inet_aton::s_singleton;
Item*
-Create_func_inet_aton::create(THD *thd, Item *arg1)
+Create_func_inet_aton::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_inet_aton(arg1);
}
@@ -3601,7 +3601,7 @@ Create_func_inet_aton::create(THD *thd,
Create_func_instr Create_func_instr::s_singleton;
Item*
-Create_func_instr::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_instr::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_locate(arg1, arg2);
}
@@ -3611,7 +3611,7 @@ Create_func_instr::create(THD *thd, Item
Create_func_interiorringn Create_func_interiorringn::s_singleton;
Item*
-Create_func_interiorringn::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_interiorringn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_decomp_n(arg1, arg2,
Item_func::SP_INTERIORRINGN);
@@ -3623,7 +3623,7 @@ Create_func_interiorringn::create(THD *t
Create_func_intersects Create_func_intersects::s_singleton;
Item*
-Create_func_intersects::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_intersects::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_INTERSECTS_FUNC);
@@ -3634,7 +3634,7 @@ Create_func_intersects::create(THD *thd,
Create_func_is_free_lock Create_func_is_free_lock::s_singleton;
Item*
-Create_func_is_free_lock::create(THD *thd, Item *arg1)
+Create_func_is_free_lock::create_1_arg(THD *thd, Item *arg1)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -3645,7 +3645,7 @@ Create_func_is_free_lock::create(THD *th
Create_func_is_used_lock Create_func_is_used_lock::s_singleton;
Item*
-Create_func_is_used_lock::create(THD *thd, Item *arg1)
+Create_func_is_used_lock::create_1_arg(THD *thd, Item *arg1)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -3657,7 +3657,7 @@ Create_func_is_used_lock::create(THD *th
Create_func_isclosed Create_func_isclosed::s_singleton;
Item*
-Create_func_isclosed::create(THD *thd, Item *arg1)
+Create_func_isclosed::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_isclosed(arg1);
}
@@ -3668,7 +3668,7 @@ Create_func_isclosed::create(THD *thd, I
Create_func_isempty Create_func_isempty::s_singleton;
Item*
-Create_func_isempty::create(THD *thd, Item *arg1)
+Create_func_isempty::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_isempty(arg1);
}
@@ -3678,7 +3678,7 @@ Create_func_isempty::create(THD *thd, It
Create_func_isnull Create_func_isnull::s_singleton;
Item*
-Create_func_isnull::create(THD *thd, Item *arg1)
+Create_func_isnull::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_isnull(arg1);
}
@@ -3688,7 +3688,7 @@ Create_func_isnull::create(THD *thd, Ite
Create_func_issimple Create_func_issimple::s_singleton;
Item*
-Create_func_issimple::create(THD *thd, Item *arg1)
+Create_func_issimple::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_issimple(arg1);
}
@@ -3698,7 +3698,7 @@ Create_func_issimple::create(THD *thd, I
Create_func_last_day Create_func_last_day::s_singleton;
Item*
-Create_func_last_day::create(THD *thd, Item *arg1)
+Create_func_last_day::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_last_day(arg1);
}
@@ -3744,7 +3744,7 @@ Create_func_last_insert_id::create_nativ
Create_func_lcase Create_func_lcase::s_singleton;
Item*
-Create_func_lcase::create(THD *thd, Item *arg1)
+Create_func_lcase::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_lcase(arg1);
}
@@ -3774,7 +3774,7 @@ Create_func_least::create_native(THD *th
Create_func_length Create_func_length::s_singleton;
Item*
-Create_func_length::create(THD *thd, Item *arg1)
+Create_func_length::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_length(arg1);
}
@@ -3783,7 +3783,7 @@ Create_func_length::create(THD *thd, Ite
Create_func_ln Create_func_ln::s_singleton;
Item*
-Create_func_ln::create(THD *thd, Item *arg1)
+Create_func_ln::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_ln(arg1);
}
@@ -3792,7 +3792,7 @@ Create_func_ln::create(THD *thd, Item *a
Create_func_load_file Create_func_load_file::s_singleton;
Item*
-Create_func_load_file::create(THD *thd, Item *arg1)
+Create_func_load_file::create_1_arg(THD *thd, Item *arg1)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -3881,7 +3881,7 @@ Create_func_log::create_native(THD *thd,
Create_func_log10 Create_func_log10::s_singleton;
Item*
-Create_func_log10::create(THD *thd, Item *arg1)
+Create_func_log10::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_log10(arg1);
}
@@ -3890,7 +3890,7 @@ Create_func_log10::create(THD *thd, Item
Create_func_log2 Create_func_log2::s_singleton;
Item*
-Create_func_log2::create(THD *thd, Item *arg1)
+Create_func_log2::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_log2(arg1);
}
@@ -3899,7 +3899,7 @@ Create_func_log2::create(THD *thd, Item
Create_func_lpad Create_func_lpad::s_singleton;
Item*
-Create_func_lpad::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_lpad::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_lpad(arg1, arg2, arg3);
}
@@ -3908,7 +3908,7 @@ Create_func_lpad::create(THD *thd, Item
Create_func_ltrim Create_func_ltrim::s_singleton;
Item*
-Create_func_ltrim::create(THD *thd, Item *arg1)
+Create_func_ltrim::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_ltrim(arg1);
}
@@ -3917,7 +3917,7 @@ Create_func_ltrim::create(THD *thd, Item
Create_func_makedate Create_func_makedate::s_singleton;
Item*
-Create_func_makedate::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_makedate::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_makedate(arg1, arg2);
}
@@ -3926,7 +3926,7 @@ Create_func_makedate::create(THD *thd, I
Create_func_maketime Create_func_maketime::s_singleton;
Item*
-Create_func_maketime::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_maketime::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_maketime(arg1, arg2, arg3);
}
@@ -4001,7 +4001,7 @@ Create_func_master_pos_wait::create_nati
Create_func_md5 Create_func_md5::s_singleton;
Item*
-Create_func_md5::create(THD *thd, Item *arg1)
+Create_func_md5::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_md5(arg1);
}
@@ -4010,7 +4010,7 @@ Create_func_md5::create(THD *thd, Item *
Create_func_monthname Create_func_monthname::s_singleton;
Item*
-Create_func_monthname::create(THD *thd, Item *arg1)
+Create_func_monthname::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_monthname(arg1);
}
@@ -4019,7 +4019,7 @@ Create_func_monthname::create(THD *thd,
Create_func_name_const Create_func_name_const::s_singleton;
Item*
-Create_func_name_const::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_name_const::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_name_const(arg1, arg2);
}
@@ -4028,7 +4028,7 @@ Create_func_name_const::create(THD *thd,
Create_func_nullif Create_func_nullif::s_singleton;
Item*
-Create_func_nullif::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_nullif::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_nullif(arg1, arg2);
}
@@ -4038,7 +4038,7 @@ Create_func_nullif::create(THD *thd, Ite
Create_func_numgeometries Create_func_numgeometries::s_singleton;
Item*
-Create_func_numgeometries::create(THD *thd, Item *arg1)
+Create_func_numgeometries::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_numgeometries(arg1);
}
@@ -4049,7 +4049,7 @@ Create_func_numgeometries::create(THD *t
Create_func_numinteriorring Create_func_numinteriorring::s_singleton;
Item*
-Create_func_numinteriorring::create(THD *thd, Item *arg1)
+Create_func_numinteriorring::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_numinteriorring(arg1);
}
@@ -4060,7 +4060,7 @@ Create_func_numinteriorring::create(THD
Create_func_numpoints Create_func_numpoints::s_singleton;
Item*
-Create_func_numpoints::create(THD *thd, Item *arg1)
+Create_func_numpoints::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_numpoints(arg1);
}
@@ -4070,7 +4070,7 @@ Create_func_numpoints::create(THD *thd,
Create_func_oct Create_func_oct::s_singleton;
Item*
-Create_func_oct::create(THD *thd, Item *arg1)
+Create_func_oct::create_1_arg(THD *thd, Item *arg1)
{
Item *i10= new (thd->mem_root) Item_int((int32) 10,2);
Item *i8= new (thd->mem_root) Item_int((int32) 8,1);
@@ -4081,7 +4081,7 @@ Create_func_oct::create(THD *thd, Item *
Create_func_ord Create_func_ord::s_singleton;
Item*
-Create_func_ord::create(THD *thd, Item *arg1)
+Create_func_ord::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_ord(arg1);
}
@@ -4091,7 +4091,7 @@ Create_func_ord::create(THD *thd, Item *
Create_func_overlaps Create_func_overlaps::s_singleton;
Item*
-Create_func_overlaps::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_overlaps::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_OVERLAPS_FUNC);
@@ -4102,7 +4102,7 @@ Create_func_overlaps::create(THD *thd, I
Create_func_period_add Create_func_period_add::s_singleton;
Item*
-Create_func_period_add::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_period_add::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_period_add(arg1, arg2);
}
@@ -4111,7 +4111,7 @@ Create_func_period_add::create(THD *thd,
Create_func_period_diff Create_func_period_diff::s_singleton;
Item*
-Create_func_period_diff::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_period_diff::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_period_diff(arg1, arg2);
}
@@ -4130,7 +4130,7 @@ Create_func_pi::create(THD *thd)
Create_func_pointn Create_func_pointn::s_singleton;
Item*
-Create_func_pointn::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_pointn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_decomp_n(arg1, arg2,
Item_func::SP_POINTN);
@@ -4141,7 +4141,7 @@ Create_func_pointn::create(THD *thd, Ite
Create_func_pow Create_func_pow::s_singleton;
Item*
-Create_func_pow::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_pow::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_pow(arg1, arg2);
}
@@ -4150,7 +4150,7 @@ Create_func_pow::create(THD *thd, Item *
Create_func_quote Create_func_quote::s_singleton;
Item*
-Create_func_quote::create(THD *thd, Item *arg1)
+Create_func_quote::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_quote(arg1);
}
@@ -4159,7 +4159,7 @@ Create_func_quote::create(THD *thd, Item
Create_func_radians Create_func_radians::s_singleton;
Item*
-Create_func_radians::create(THD *thd, Item *arg1)
+Create_func_radians::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_units((char*) "radians", arg1,
M_PI/180, 0.0);
@@ -4216,7 +4216,7 @@ Create_func_rand::create_native(THD *thd
Create_func_release_lock Create_func_release_lock::s_singleton;
Item*
-Create_func_release_lock::create(THD *thd, Item *arg1)
+Create_func_release_lock::create_1_arg(THD *thd, Item *arg1)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -4227,7 +4227,7 @@ Create_func_release_lock::create(THD *th
Create_func_reverse Create_func_reverse::s_singleton;
Item*
-Create_func_reverse::create(THD *thd, Item *arg1)
+Create_func_reverse::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_reverse(arg1);
}
@@ -4285,7 +4285,7 @@ Create_func_row_count::create(THD *thd)
Create_func_rpad Create_func_rpad::s_singleton;
Item*
-Create_func_rpad::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_rpad::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_rpad(arg1, arg2, arg3);
}
@@ -4294,7 +4294,7 @@ Create_func_rpad::create(THD *thd, Item
Create_func_rtrim Create_func_rtrim::s_singleton;
Item*
-Create_func_rtrim::create(THD *thd, Item *arg1)
+Create_func_rtrim::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_rtrim(arg1);
}
@@ -4303,7 +4303,7 @@ Create_func_rtrim::create(THD *thd, Item
Create_func_sec_to_time Create_func_sec_to_time::s_singleton;
Item*
-Create_func_sec_to_time::create(THD *thd, Item *arg1)
+Create_func_sec_to_time::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_sec_to_time(arg1);
}
@@ -4312,7 +4312,7 @@ Create_func_sec_to_time::create(THD *thd
Create_func_sha Create_func_sha::s_singleton;
Item*
-Create_func_sha::create(THD *thd, Item *arg1)
+Create_func_sha::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_sha(arg1);
}
@@ -4321,7 +4321,7 @@ Create_func_sha::create(THD *thd, Item *
Create_func_sign Create_func_sign::s_singleton;
Item*
-Create_func_sign::create(THD *thd, Item *arg1)
+Create_func_sign::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_sign(arg1);
}
@@ -4330,7 +4330,7 @@ Create_func_sign::create(THD *thd, Item
Create_func_sin Create_func_sin::s_singleton;
Item*
-Create_func_sin::create(THD *thd, Item *arg1)
+Create_func_sin::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_sin(arg1);
}
@@ -4339,7 +4339,7 @@ Create_func_sin::create(THD *thd, Item *
Create_func_sleep Create_func_sleep::s_singleton;
Item*
-Create_func_sleep::create(THD *thd, Item *arg1)
+Create_func_sleep::create_1_arg(THD *thd, Item *arg1)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -4350,7 +4350,7 @@ Create_func_sleep::create(THD *thd, Item
Create_func_soundex Create_func_soundex::s_singleton;
Item*
-Create_func_soundex::create(THD *thd, Item *arg1)
+Create_func_soundex::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_soundex(arg1);
}
@@ -4359,7 +4359,7 @@ Create_func_soundex::create(THD *thd, It
Create_func_space Create_func_space::s_singleton;
Item*
-Create_func_space::create(THD *thd, Item *arg1)
+Create_func_space::create_1_arg(THD *thd, Item *arg1)
{
/**
TODO: Fix Bug#23637
@@ -4387,7 +4387,7 @@ Create_func_space::create(THD *thd, Item
Create_func_sqrt Create_func_sqrt::s_singleton;
Item*
-Create_func_sqrt::create(THD *thd, Item *arg1)
+Create_func_sqrt::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_sqrt(arg1);
}
@@ -4397,7 +4397,7 @@ Create_func_sqrt::create(THD *thd, Item
Create_func_srid Create_func_srid::s_singleton;
Item*
-Create_func_srid::create(THD *thd, Item *arg1)
+Create_func_srid::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_srid(arg1);
}
@@ -4408,7 +4408,7 @@ Create_func_srid::create(THD *thd, Item
Create_func_startpoint Create_func_startpoint::s_singleton;
Item*
-Create_func_startpoint::create(THD *thd, Item *arg1)
+Create_func_startpoint::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_spatial_decomp(arg1,
Item_func::SP_STARTPOINT);
@@ -4419,7 +4419,7 @@ Create_func_startpoint::create(THD *thd,
Create_func_str_to_date Create_func_str_to_date::s_singleton;
Item*
-Create_func_str_to_date::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_str_to_date::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_str_to_date(arg1, arg2);
}
@@ -4428,7 +4428,7 @@ Create_func_str_to_date::create(THD *thd
Create_func_strcmp Create_func_strcmp::s_singleton;
Item*
-Create_func_strcmp::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_strcmp::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_strcmp(arg1, arg2);
}
@@ -4437,7 +4437,7 @@ Create_func_strcmp::create(THD *thd, Ite
Create_func_substr_index Create_func_substr_index::s_singleton;
Item*
-Create_func_substr_index::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_substr_index::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_substr_index(arg1, arg2, arg3);
}
@@ -4446,7 +4446,7 @@ Create_func_substr_index::create(THD *th
Create_func_subtime Create_func_subtime::s_singleton;
Item*
-Create_func_subtime::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_subtime::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_add_time(arg1, arg2, 0, 1);
}
@@ -4455,7 +4455,7 @@ Create_func_subtime::create(THD *thd, It
Create_func_tan Create_func_tan::s_singleton;
Item*
-Create_func_tan::create(THD *thd, Item *arg1)
+Create_func_tan::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_tan(arg1);
}
@@ -4464,7 +4464,7 @@ Create_func_tan::create(THD *thd, Item *
Create_func_time_format Create_func_time_format::s_singleton;
Item*
-Create_func_time_format::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_time_format::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_date_format(arg1, arg2, 1);
}
@@ -4473,7 +4473,7 @@ Create_func_time_format::create(THD *thd
Create_func_time_to_sec Create_func_time_to_sec::s_singleton;
Item*
-Create_func_time_to_sec::create(THD *thd, Item *arg1)
+Create_func_time_to_sec::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_time_to_sec(arg1);
}
@@ -4482,7 +4482,7 @@ Create_func_time_to_sec::create(THD *thd
Create_func_timediff Create_func_timediff::s_singleton;
Item*
-Create_func_timediff::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_timediff::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_timediff(arg1, arg2);
}
@@ -4491,7 +4491,7 @@ Create_func_timediff::create(THD *thd, I
Create_func_to_days Create_func_to_days::s_singleton;
Item*
-Create_func_to_days::create(THD *thd, Item *arg1)
+Create_func_to_days::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_to_days(arg1);
}
@@ -4501,7 +4501,7 @@ Create_func_to_days::create(THD *thd, It
Create_func_touches Create_func_touches::s_singleton;
Item*
-Create_func_touches::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_touches::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_TOUCHES_FUNC);
@@ -4512,7 +4512,7 @@ Create_func_touches::create(THD *thd, It
Create_func_ucase Create_func_ucase::s_singleton;
Item*
-Create_func_ucase::create(THD *thd, Item *arg1)
+Create_func_ucase::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_ucase(arg1);
}
@@ -4521,7 +4521,7 @@ Create_func_ucase::create(THD *thd, Item
Create_func_uncompress Create_func_uncompress::s_singleton;
Item*
-Create_func_uncompress::create(THD *thd, Item *arg1)
+Create_func_uncompress::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_uncompress(arg1);
}
@@ -4530,7 +4530,7 @@ Create_func_uncompress::create(THD *thd,
Create_func_uncompressed_length Create_func_uncompressed_length::s_singleton;
Item*
-Create_func_uncompressed_length::create(THD *thd, Item *arg1)
+Create_func_uncompressed_length::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_uncompressed_length(arg1);
}
@@ -4539,7 +4539,7 @@ Create_func_uncompressed_length::create(
Create_func_unhex Create_func_unhex::s_singleton;
Item*
-Create_func_unhex::create(THD *thd, Item *arg1)
+Create_func_unhex::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_unhex(arg1);
}
@@ -4620,7 +4620,7 @@ Create_func_version::create(THD *thd)
Create_func_weekday Create_func_weekday::s_singleton;
Item*
-Create_func_weekday::create(THD *thd, Item *arg1)
+Create_func_weekday::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_weekday(arg1, 0);
}
@@ -4629,7 +4629,7 @@ Create_func_weekday::create(THD *thd, It
Create_func_weekofyear Create_func_weekofyear::s_singleton;
Item*
-Create_func_weekofyear::create(THD *thd, Item *arg1)
+Create_func_weekofyear::create_1_arg(THD *thd, Item *arg1)
{
Item *i1= new (thd->mem_root) Item_int((char*) "0", 3, 1);
return new (thd->mem_root) Item_func_week(arg1, i1);
@@ -4640,7 +4640,7 @@ Create_func_weekofyear::create(THD *thd,
Create_func_within Create_func_within::s_singleton;
Item*
-Create_func_within::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_within::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_WITHIN_FUNC);
@@ -4652,7 +4652,7 @@ Create_func_within::create(THD *thd, Ite
Create_func_x Create_func_x::s_singleton;
Item*
-Create_func_x::create(THD *thd, Item *arg1)
+Create_func_x::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_x(arg1);
}
@@ -4662,7 +4662,7 @@ Create_func_x::create(THD *thd, Item *ar
Create_func_xml_extractvalue Create_func_xml_extractvalue::s_singleton;
Item*
-Create_func_xml_extractvalue::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_xml_extractvalue::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_xml_extractvalue(arg1, arg2);
}
@@ -4671,7 +4671,7 @@ Create_func_xml_extractvalue::create(THD
Create_func_xml_update Create_func_xml_update::s_singleton;
Item*
-Create_func_xml_update::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_xml_update::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_xml_update(arg1, arg2, arg3);
}
@@ -4681,7 +4681,7 @@ Create_func_xml_update::create(THD *thd,
Create_func_y Create_func_y::s_singleton;
Item*
-Create_func_y::create(THD *thd, Item *arg1)
+Create_func_y::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_y(arg1);
}
=== modified file 'sql/item_create.h'
--- a/sql/item_create.h 2007-08-15 13:43:08 +0000
+++ b/sql/item_create.h 2010-03-28 18:10:00 +0000
@@ -91,8 +91,9 @@ public:
@param item_list The list of arguments to the function, can be NULL
@return An item representing the parsed function call
*/
- virtual Item* create(THD *thd, LEX_STRING db, LEX_STRING name,
- bool use_explicit_name, List<Item> *item_list) = 0;
+ virtual Item *create_with_db(THD *thd, LEX_STRING db, LEX_STRING name,
+ bool use_explicit_name,
+ List<Item> *item_list) = 0;
protected:
/** Constructor. */
=== modified file 'sql/item_sum.cc'
--- a/sql/item_sum.cc 2010-01-15 15:27:55 +0000
+++ b/sql/item_sum.cc 2010-03-28 18:10:00 +0000
@@ -642,7 +642,7 @@ Item_sum_hybrid::fix_fields(THD *thd, It
default:
DBUG_ASSERT(0);
};
- setup(args[0], NULL);
+ setup_item(args[0], NULL);
/* MIN/MAX can return NULL for empty set indepedent of the used column */
maybe_null= 1;
unsigned_flag=item->unsigned_flag;
@@ -676,7 +676,7 @@ Item_sum_hybrid::fix_fields(THD *thd, It
of the original MIN/MAX object and it is saved in this object's cache.
*/
-void Item_sum_hybrid::setup(Item *item, Item *value_arg)
+void Item_sum_hybrid::setup_item(Item *item, Item *value_arg)
{
value= Item_cache::get_cache(item);
value->setup(item);
@@ -1646,7 +1646,7 @@ void Item_sum_hybrid::no_rows_in_result(
Item *Item_sum_min::copy_or_same(THD* thd)
{
Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this);
- item->setup(args[0], value);
+ item->setup_item(args[0], value);
return item;
}
@@ -1669,7 +1669,7 @@ bool Item_sum_min::add()
Item *Item_sum_max::copy_or_same(THD* thd)
{
Item_sum_max *item= new (thd->mem_root) Item_sum_max(thd, this);
- item->setup(args[0], value);
+ item->setup_item(args[0], value);
return item;
}
=== modified file 'sql/item_sum.h'
--- a/sql/item_sum.h 2010-01-15 15:27:55 +0000
+++ b/sql/item_sum.h 2010-03-28 18:10:00 +0000
@@ -858,7 +858,7 @@ protected:
was_values(item->was_values)
{ }
bool fix_fields(THD *, Item **);
- void setup(Item *item, Item *value_arg);
+ void setup_item(Item *item, Item *value_arg);
void clear();
double val_real();
longlong val_int();
=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc 2010-03-09 19:23:30 +0000
+++ b/sql/set_var.cc 2010-03-28 18:10:00 +0000
@@ -1263,16 +1263,16 @@ uchar *sys_var_set::value_ptr(THD *thd,
void sys_var_set_slave_mode::set_default(THD *thd, enum_var_type type)
{
- slave_exec_mode_options= 0;
- bit_do_set(slave_exec_mode_options, SLAVE_EXEC_MODE_STRICT);
+ slave_exec_mode_options= (ULL(1) << SLAVE_EXEC_MODE_STRICT);
}
bool sys_var_set_slave_mode::check(THD *thd, set_var *var)
{
bool rc= sys_var_set::check(thd, var);
if (!rc &&
- bit_is_set(var->save_result.ulong_value, SLAVE_EXEC_MODE_STRICT) == 1 &&
- bit_is_set(var->save_result.ulong_value, SLAVE_EXEC_MODE_IDEMPOTENT) == 1)
+ test_all_bits(var->save_result.ulong_value,
+ ((ULL(1) << SLAVE_EXEC_MODE_STRICT) |
+ (ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT))))
{
rc= true;
my_error(ER_SLAVE_AMBIGOUS_EXEC_MODE, MYF(0), "");
@@ -1294,15 +1294,16 @@ void fix_slave_exec_mode(enum_var_type t
DBUG_ENTER("fix_slave_exec_mode");
compile_time_assert(sizeof(slave_exec_mode_options) * CHAR_BIT
> SLAVE_EXEC_MODE_LAST_BIT - 1);
- if (bit_is_set(slave_exec_mode_options, SLAVE_EXEC_MODE_STRICT) == 1 &&
- bit_is_set(slave_exec_mode_options, SLAVE_EXEC_MODE_IDEMPOTENT) == 1)
+ if (test_all_bits(slave_exec_mode_options,
+ ((ULL(1) << SLAVE_EXEC_MODE_STRICT) |
+ (ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT))))
{
sql_print_error("Ambiguous slave modes combination."
" STRICT will be used");
- bit_do_clear(slave_exec_mode_options, SLAVE_EXEC_MODE_IDEMPOTENT);
+ slave_exec_mode_options&= ~(ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT);
}
- if (bit_is_set(slave_exec_mode_options, SLAVE_EXEC_MODE_IDEMPOTENT) == 0)
- bit_do_set(slave_exec_mode_options, SLAVE_EXEC_MODE_STRICT);
+ if (!(slave_exec_mode_options & (ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT)))
+ slave_exec_mode_options|= (ULL(1)<< SLAVE_EXEC_MODE_STRICT);
DBUG_VOID_RETURN;
}
=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy 2010-03-04 08:03:07 +0000
+++ b/sql/sql_yacc.yy 2010-03-28 18:10:00 +0000
@@ -8082,7 +8082,7 @@ function_call_generic:
builder= find_qualified_function_builder(thd);
DBUG_ASSERT(builder);
- item= builder->create(thd, $1, $3, true, $5);
+ item= builder->create_with_db(thd, $1, $3, true, $5);
if (! ($$= item))
{
=== modified file 'storage/example/ha_example.h'
--- a/storage/example/ha_example.h 2007-08-13 13:11:25 +0000
+++ b/storage/example/ha_example.h 2010-03-28 18:10:00 +0000
@@ -155,7 +155,8 @@ public:
/** @brief
This method will never be called if you do not implement indexes.
*/
- virtual double read_time(ha_rows rows) { return (double) rows / 20.0+1; }
+ virtual double read_time(uint index, uint ranges, ha_rows rows)
+ { return (double) rows / 20.0+1; }
/*
Everything below are methods that we implement in ha_example.cc.
=== modified file 'storage/maria/ma_search.c'
--- a/storage/maria/ma_search.c 2010-03-09 19:22:24 +0000
+++ b/storage/maria/ma_search.c 2010-03-28 18:10:00 +0000
@@ -76,8 +76,8 @@ int _ma_search(register MARIA_HA *info,
bmove512(info->keyread_buff, page_buff, info->s->block_size);
/* Save position for a possible read next / previous */
- info->int_keypos= info->keyread_buff + (ulonglong) info->int_keypos;
- info->int_maxpos= info->keyread_buff + (ulonglong) info->int_maxpos;
+ info->int_keypos= info->keyread_buff + info->keypos_offset;
+ info->int_maxpos= info->keyread_buff + info->maxpos_offset;
info->int_keytree_version= key->keyinfo->version;
info->last_search_keypage= info->last_keypage;
info->page_changed= 0;
@@ -214,8 +214,8 @@ static int _ma_search_no_save(register M
info->cur_row.trid= _ma_trid_from_key(&info->last_key);
/* Store offset to key */
- info->int_keypos= (uchar*) (keypos - page.buff);
- info->int_maxpos= (uchar*) (maxpos - page.buff);
+ info->keypos_offset= (uint) (keypos - page.buff);
+ info->maxpos_offset= (uint) (maxpos - page.buff);
info->int_nod_flag= nod_flag;
info->last_keypage= pos;
*res_page_link= page_link;
=== modified file 'storage/maria/maria_def.h'
--- a/storage/maria/maria_def.h 2010-03-09 19:22:24 +0000
+++ b/storage/maria/maria_def.h 2010-03-28 18:10:00 +0000
@@ -506,8 +506,10 @@ struct st_maria_handler
uchar *first_mbr_key; /* Searhed spatial key */
uchar *rec_buff; /* Temp buffer for recordpack */
uchar *blob_buff; /* Temp buffer for blobs */
- uchar *int_keypos, /* Save position for next/previous */
- *int_maxpos; /* -""- */
+ uchar *int_keypos; /* Save position for next/previous */
+ uchar *int_maxpos; /* -""- */
+ uint keypos_offset; /* Tmp storage for offset int_keypos */
+ uint maxpos_offset; /* Tmp storage for offset int_maxpos */
uchar *update_field_data; /* Used by update in rows-in-block */
uint int_nod_flag; /* -""- */
uint32 int_keytree_version; /* -""- */
=== modified file 'storage/myisam/ft_stopwords.c'
--- a/storage/myisam/ft_stopwords.c 2010-03-10 10:32:14 +0000
+++ b/storage/myisam/ft_stopwords.c 2010-03-28 18:10:00 +0000
@@ -44,9 +44,10 @@ static void FT_STOPWORD_free(FT_STOPWORD
static int ft_add_stopword(const char *w)
{
FT_STOPWORD sw;
- return !w ||
- (((sw.len= (uint) strlen(sw.pos=(const uchar *)w)) >= ft_min_word_len) &&
- (tree_insert(stopwords3, &sw, 0, stopwords3->custom_arg)==NULL));
+ return (!w ||
+ (((sw.len= (uint) strlen((char*) (sw.pos=(const uchar *)w))) >=
+ ft_min_word_len) &&
+ (tree_insert(stopwords3, &sw, 0, stopwords3->custom_arg)==NULL)));
}
int ft_init_stopwords()
=== modified file 'storage/xtradb/fil/fil0fil.c'
--- a/storage/xtradb/fil/fil0fil.c 2010-01-15 15:58:25 +0000
+++ b/storage/xtradb/fil/fil0fil.c 2010-03-28 18:10:00 +0000
@@ -3168,7 +3168,7 @@ skip_info:
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, id);
for (i = 0; (ulint) i < n_index; i++) {
- if (offset / UNIV_PAGE_SIZE == root_page[i]) {
+ if ((ulint) (offset / UNIV_PAGE_SIZE) == root_page[i]) {
/* this is index root page */
mach_write_to_4(page + FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ FSEG_HDR_SPACE, id);
=== modified file 'storage/xtradb/include/page0page.h'
--- a/storage/xtradb/include/page0page.h 2010-01-06 12:00:14 +0000
+++ b/storage/xtradb/include/page0page.h 2010-03-28 18:10:00 +0000
@@ -517,7 +517,7 @@ UNIV_INLINE
rec_t*
page_rec_get_next(
/*==============*/
- rec_t* rec); /*!< in: pointer to record */
+ const rec_t* rec); /*!< in: pointer to record */
/************************************************************//**
Gets the pointer to the next record on the page.
@return pointer to next record */
=== modified file 'storage/xtradb/include/page0page.ic'
--- a/storage/xtradb/include/page0page.ic 2010-01-06 12:00:14 +0000
+++ b/storage/xtradb/include/page0page.ic 2010-03-28 18:10:00 +0000
@@ -731,7 +731,7 @@ UNIV_INLINE
rec_t*
page_rec_get_next(
/*==============*/
- rec_t* rec) /*!< in: pointer to record */
+ const rec_t* rec) /*!< in: pointer to record */
{
return((rec_t*) page_rec_get_next_low(rec, page_rec_is_comp(rec)));
}
=== modified file 'support-files/compiler_warnings.supp'
--- a/support-files/compiler_warnings.supp 2010-03-10 10:32:14 +0000
+++ b/support-files/compiler_warnings.supp 2010-03-28 18:10:00 +0000
@@ -66,6 +66,11 @@ db_vrfy.c : .*comparison is always false
/usr/share/aclocal/audiofile.m4 : .*
#
+# Ignore strict-aliasing warnings (for now)
+#
+.*: break strict-aliasing rules
+
+#
# Ignore all conversion warnings on windows 64
# (Is safe as we are not yet supporting strings >= 2G)
#
2
2
Hi!
Review of ~maria-captains/maria/5.2-pluggable-auth
(3 day of work!)
> === modified file 'client/mysql.cc'
<cut>
> + /**
> + An example of mysql_authentication_dialog_ask callback.
> +
> + The C function with the name "mysql_authentication_dialog_ask", if exists,
> + will be used by the "dialog" client authentication plugin when user
> + input is needed. This function should be of mysql_authentication_dialog_ask_t
> + type. If the function does not exists, a built-in implementation will be
> + used.
> +
> + @param mysql mysql
> + @param type type of the input
> + 1 - normal string input
> + 2 - password string
> + @param prompt prompt
> + @param buf a buffer to store the use input
> + @param buf_len the length of the buffer
> +
> + @retval a pointer to the user input string.
> + It may be equal to 'buf' or to 'mysql->password'.
> + In all other cases it is assumed to be an allocated
> + string, and the "dialog" plugin will free() it.
> + */
> + extern "C" char *mysql_authentication_dialog_ask(MYSQL *mysql, int type,
I would prefer to have type as my_bool as there is only two options
for it and rename it to 'ask_for_password'. This would make the code
more self_explanatory.
> + const char *prompt,
> + char *buf, int buf_len)
> + {
> + int ch;
> + char *s=buf, *end=buf+buf_len-1;
> +
> + fputs("[mysql] ", stdout);
[mysql] -> [mariadb]
> + fputs(prompt, stdout);
> + fputs(" ", stdout);
> +
> + if (type == 2) /* password */
> + {
> + s= get_tty_password("");
> + strncpy(buf, s, buf_len);
Better to use strnmov() like we use in all other part of the code.
> + my_free(s, MYF(0));
> + }
> + else
> + {
> + for (ch= fgetc(stdin); s < end && ch != '\n' && ch != EOF; ch= fgetc(stdin))
> + *s++= ch;
hm, we should really support backspace too....
Why not simply use fgets() that gives you basic editing?
fgets(buf, buf_len-1, stdin);
if (buf[0] && (s= strend(buf))[-1] == '\n')
*s= 0;
> + *s=0;
> + }
> +
> + return buf;
> + }
> === modified file 'include/my_global.h'
> *** include/my_global.h 2009-12-03 11:19:05 +0000
> --- include/my_global.h 2010-02-19 08:18:09 +0000
> *************** int __void__;
> *** 578,583 ****
> --- 578,591 ----
> #define IF_VALGRIND(A,B) (B)
> #endif
>
> + #ifdef _WIN32
In the rest of my_global.h we use __WIN__
Wouldn't it be better to use the same constant everywhere?
> + #define SO_EXT ".dll"
> + #elif defined(__APPLE__)
> + #define SO_EXT ".dylib"
> + #else
> + #define SO_EXT ".so"
> + #endif
> === modified file 'include/mysql.h'
> *** include/mysql.h 2010-02-01 06:14:12 +0000
> --- include/mysql.h 2010-02-19 08:18:09 +0000
> *************** enum mysql_option
> *** 167,175 ****
> MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
> MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
> MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
> ! MYSQL_OPT_SSL_VERIFY_SERVER_CERT
> };
>
> struct st_mysql_options {
> unsigned int connect_timeout, read_timeout, write_timeout;
> unsigned int port, protocol;
> --- 167,181 ----
> MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
> MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
> MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
> ! MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH
> };
>
> + /**
> + @todo remove the "extension", move st_mysql_options completely
> + out of mysql.h
The reason to have it in mysql.h is to be able to put it into the
MYSQL structure to avoid mallocs (for most cases) if you have MYSQL on
the stack or as a static variable. Don't see how we can easily remove
it, if we want to keep this property.
> --- include/mysql/plugin_auth.h 2010-02-19 08:18:09 +0000
> ***************
> *** 0 ****
> --- 1,83 ----
> + #ifndef MYSQL_PLUGIN_AUTH_INCLUDED
> + /* Copyright (C) 2010 Monty Program Ab
Add your/original author name here too
> === added file 'include/mysql/plugin_auth_common.h'
> *** include/mysql/plugin_auth_common.h 1970-01-01 00:00:00 +0000
> --- include/mysql/plugin_auth_common.h 2010-02-19 08:18:09 +0000
> ***************
> *** 0 ****
> --- 1,105 ----
> + #ifndef MYSQL_PLUGIN_AUTH_COMMON_INCLUDED
> + /* Copyright (C) 2010 Monty Program Ab
Add your/original author name here too
> + /** the max allowed length for a user name */
> + #define MYSQL_USERNAME_LENGTH 48
Shouldn't this be the define USERNAME_LENGTH ?
Otherwise there will be a crash if someone redefines USERNAME_CHAR_LENGTH
<cut>
> + typedef struct st_plugin_vio_info
> + {
> + enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET,
> + MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol;
> + int socket; /**< it's set, if the protocol is SOCKET or TCP */
> + #ifdef _WIN32
_WIN32 -> __WIN__ ?
> + HANDLE handle; /**< it's set, if the protocol is PIPE or MEMORY */
> + #endif
> + } MYSQL_PLUGIN_VIO_INFO;
> +
> === modified file 'libmysqld/lib_sql.cc'
> *** libmysqld/lib_sql.cc 2009-12-03 11:19:05 +0000
> --- libmysqld/lib_sql.cc 2010-03-02 20:32:24 +0000
> *************** static MYSQL_RES * emb_store_result(MYSQ
> *** 413,423 ****
> return mysql_store_result(mysql);
> }
>
> ! int emb_read_change_user_result(MYSQL *mysql,
> ! char *buff __attribute__((unused)),
> ! const char *passwd __attribute__((unused)))
> {
> ! return mysql_errno(mysql);
> }
>
> MYSQL_METHODS embedded_methods=
> --- 412,421 ----
> return mysql_store_result(mysql);
> }
>
> ! int emb_read_change_user_result(MYSQL *mysql)
> {
> ! mysql->net.read_pos= (uchar*)""; // fake an OK packet
> ! return mysql_errno(mysql) ? packet_error : 1;
> }
Add a comment that '1' is packet length.
> *************** void init_embedded_mysql(MYSQL *mysql, i
> *** 584,589 ****
> --- 582,588 ----
> THD *thd = (THD *)mysql->thd;
> thd->mysql= mysql;
> mysql->server_version= server_version;
> + mysql->client_flag= client_flag;
> init_alloc_root(&mysql->field_alloc, 8192, 0);
> }
Was this a bug in the old code ?
(Just curious)
> === modified file 'mysql-test/suite/rpl/r/rpl_stm_000001.result'
> *** mysql-test/suite/rpl/r/rpl_stm_000001.result 2009-11-18 14:50:31 +0000
> --- mysql-test/suite/rpl/r/rpl_stm_000001.result 2010-02-19 08:18:09 +0000
> *************** Warnings:
> *** 66,71 ****
> --- 66,72 ----
> Warning 1364 Field 'ssl_cipher' doesn't have a default value
> Warning 1364 Field 'x509_issuer' doesn't have a default value
> Warning 1364 Field 'x509_subject' doesn't have a default value
> + Warning 1364 Field 'auth_string' doesn't have a default value
Should auth_string have a default value (to not cause a problem for
anyone using --strict mode and is inserting things into the auth
tables?)
Note likely problem, but possible...
IRC: conclusion
- As auth_string is a blob and we don't know the length, it's best to
leave it as it is.
<cut>
> *** plugin/auth/auth_socket.c 1970-01-01 00:00:00 +0000
> --- plugin/auth/auth_socket.c 2010-02-19 08:18:09 +0000
> ***************
> *** 0 ****
> --- 1,93 ----
> + /* Copyright (C) 2010 Monty Program Ab
> +
Add your/author's name here
<cut>
> === added file 'plugin/auth/dialog.c'
> *** plugin/auth/dialog.c 1970-01-01 00:00:00 +0000
> --- plugin/auth/dialog.c 2010-02-23 12:02:00 +0000
> ***************
> *** 0 ****
> --- 1,293 ----
> + /* Copyright (C) 2010 Monty Program Ab
Add your/author's name here
<cut>
> + static int two_questions(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
> + {
> + unsigned char *pkt;
> + int pkt_len;
> +
> + /* send a password question */
> + if (vio->write_packet(vio, PASSWORD_QUESTION "Password, please:", 18))
> + return CR_ERROR;
It's a bit ugly to use concat for sending parameters...
Nicer would be
if (vio->write_packet(vio, PASSWORD_QUESTION, "Password, please:", 18))
Where the command would be stored in a slot of the MYSQL_PLUGIN_VIO on the
server side.
We can look at fixing this if there would be a deamnd for it.
<cut>
> + static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
> + {
> + unsigned char *pkt, cmd= 0;
> + int pkt_len, res;
> + char reply_buf[1024], *reply;
> +
> + do
> + {
> + /* read the prompt */
> + pkt_len= vio->read_packet(vio, &pkt);
> + if (pkt_len < 0)
> + return CR_ERROR;
> +
> + if (pkt == 0)
> + {
> + /*
> + in mysql_change_user() the client sends the first packet, so
> + the first vio->read_packet() does nothing (pkt == 0).
> +
> + We send the "password", assuming the client knows what its doing.
> + (in other words, the dialog plugin should be only set as a default
> + authentication plugin on the client if the first question
> + asks for a password - which will be sent in cleat text, by the way)
cleat -> clear
> *** sql-common/client.c 2010-02-01 06:14:12 +0000
> --- sql-common/client.c 2010-03-02 20:32:24 +0000
> *************** my_bool net_flush(NET *net);
> *** 107,112 ****
> --- 107,113 ----
>
> #include "client_settings.h"
> #include <sql_common.h>
> + #include <mysql/client_plugin.h>
>
> uint mysql_port=0;
> char *mysql_unix_port= 0;
> *************** void net_clear_error(NET *net)
> *** 332,338 ****
> @param ... variable number of arguments
> */
>
> ! static void set_mysql_extended_error(MYSQL *mysql, int errcode,
> const char *sqlstate,
> const char *format, ...)
> {
> --- 333,339 ----
> @param ... variable number of arguments
> */
>
> ! void set_mysql_extended_error(MYSQL *mysql, int errcode,
> const char *sqlstate,
> const char *format, ...)
> {
> *************** static const char *default_options[]=
> *** 1002,1010 ****
> "replication-probe", "enable-reads-from-master", "repl-parse-query",
> "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
> "multi-results", "multi-statements", "multi-queries", "secure-auth",
> ! "report-data-truncation",
> NullS
> };
>
> static TYPELIB option_types={array_elements(default_options)-1,
> "options",default_options, NULL};
> --- 1003,1022 ----
> "replication-probe", "enable-reads-from-master", "repl-parse-query",
> "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
> "multi-results", "multi-statements", "multi-queries", "secure-auth",
> ! "report-data-truncation", "plugin-dir", "default-auth",
> NullS
> };
> + enum option_id {
> + OPT_port=1, OPT_socket, OPT_compress, OPT_password, OPT_pipe, OPT_timeout, OPT_user,
> + OPT_init_command, OPT_host, OPT_database, OPT_debug, OPT_return_found_rows,
> + OPT_ssl_key, OPT_ssl_cert, OPT_ssl_ca, OPT_ssl_capath,
> + OPT_character_sets_dir, OPT_default_character_set, OPT_interactive_timeout,
> + OPT_connect_timeout, OPT_local_infile, OPT_disable_local_infile,
> + OPT_replication_probe, OPT_enable_reads_from_master, OPT_repl_parse_query,
> + OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
> + OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
> + OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth,
> + };
If you add OPT_DUPLICATE= -1 and OPT_ERROR= 1 to the above, you can
cast (find_type(*option+2,&option_types,2)) to the enum and get more
readable code...
> *** 1035,1040 ****
> --- 1047,1060 ----
> return 0;
> }
>
> + #define extension_free(OPTS, X) \
> + if ((OPTS)->extension) \
> + my_free((OPTS)->extension->X, MYF(MY_ALLOW_ZERO_PTR)); \
> + else \
> + (OPTS)->extension= (struct st_mysql_options_extention *) \
> + my_malloc(sizeof(struct st_mysql_options_extention), \
> + MYF(MY_WME | MY_ZEROFILL));
Free is a bad name as we actually create some structures here.
How about using 'extension_reset()' instead ?
> + case OPT_plugin_dir:
> + extension_free(options, plugin_dir);
> + options->extension->plugin_dir= my_strdup(opt_arg, MYF(MY_WME));
> + break;
> + case OPT_default_auth:
> + extension_free(options, default_auth);
> + options->extension->default_auth= my_strdup(opt_arg, MYF(MY_WME));
> + break;
Even better, would be to do:
extension_set_string(options, default_auth, opt_arg);
Which would make the usage compleately clear.
<cut>
> *************** int mysql_init_character_set(MYSQL *mysq
> *** 1856,1861 ****
> --- 1889,2479 ----
> }
> C_MODE_END
>
> + /*********** client side authentication support **************************/
> +
> + typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
> +
> + /* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */
> + typedef struct {
> + int (*read_packet)(struct st_plugin_vio *vio, uchar **buf);
> + int (*write_packet)(struct st_plugin_vio *vio, const uchar *pkt, int pkt_len);
> + void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info);
> + /* -= end of MYSQL_PLUGIN_VIO =- */
> + MYSQL *mysql;
> + auth_plugin_t *plugin; /**< what plugin we're under */
> + const char *db;
> + struct {
> + uchar *pkt; /**< pointer into NET::buff */
> + uint pkt_len;
> + } cached_server_reply;
> + int packets_read, packets_written; /**< counters for send/received packets */
> + int mysql_change_user; /**< if it's mysql_change_user() */
> + int last_read_packet_len; /**< the length of the last *read* packet */
> + } MCPVIO_EXT;
How about changing counters to uint and mysql_change_user to my_bool ?
> + #define native_password_plugin_name "mysql_native_password"
> + #define old_password_plugin_name "mysql_old_password"
Please add defines to start of file (easier to find them)
> + /**
> + sends a client authentication packet (second packet in the 3-way handshake)
> +
> + Packet format (when the server is 4.0 or earlier):
> +
> + Bytes Content
> + ----- ----
> + 2 client capabilities
> + 3 max packet size
> + n user name, \0-terminated
> + 9 scramble_323, \0-terminated
> +
> + Packet format (when the server is 4.1 or newer):
> +
> + Bytes Content
> + ----- ----
> + 4 client capabilities
> + 4 max packet size
> + 1 charset number
> + 23 reserved (always 0)
> + n user name, \0-terminated
> + n plugin auth data (e.g. scramble), length (1 byte) coded
> + n database name, \0-terminated
> + (if CLIENT_CONNECT_WITH_DB is set in the capabilities)
> + n client auth plugin name - \0-terminated string,
> + (if CLIENT_PLUGIN_AUTH is set in the capabilities)
> +
> + @retval 0 ok
> + @retval 1 error
> + */
> + static int send_client_reply_packet(MCPVIO_EXT *mpvio,
> + const uchar *data, int data_len)
> + {
> + MYSQL *mysql= mpvio->mysql;
> + NET *net= &mysql->net;
> + char *buff, *end;
> +
> + /* see end= buff+32 below, fixed size of the packet is 32 bytes */
> + buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN);
> +
> + mysql->client_flag|= mysql->options.client_flag;
> + mysql->client_flag|= CLIENT_CAPABILITIES;
The code would be easier to read (and a bit faster/shorter) if you have
client_flag as a static variable and set mysql->client_flag from this
when all options are set.
> +
> + if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
> + mysql->client_flag|= CLIENT_MULTI_RESULTS;
> +
> + #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
> + if (mysql->options.ssl_key || mysql->options.ssl_cert ||
> + mysql->options.ssl_ca || mysql->options.ssl_capath ||
> + mysql->options.ssl_cipher)
> + mysql->options.use_ssl= 1;
> + if (mysql->options.use_ssl)
> + mysql->client_flag|= CLIENT_SSL;
> + #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/
Note that we from a client embedded with libmysqld, may also want to
connect to a remote MySQL server. At some point we need to test and
fix this. (This is why some part of the old embedded code didn't have
defined(EMBEDDED_LIBRARY) in all possible places.
<cut>
> + #ifdef HAVE_OPENSSL
How come you don't have !defined(EMBEDDED_LIBRARY) here ?
> + }
> + #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
Comment is wrong or ifdef...
<cut>
> + if (data_len)
Add a comment that data_len is always password length here.
> + {
> + if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
> + {
> + *end++= data_len;
> + memcpy(end, data, data_len);
> + end+= data_len;
> + }
<cut>
> + static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, int);
Please put static declarations first in the file.
> + /**
> + vio->read_packet() callback method for client authentication plugins
> +
> + This function is called by a client authentication plugin, when it wants
> + to read data from the server.
> + */
Empty line here (makes things easier to read)
> + static int client_mpvio_read_packet(struct st_plugin_vio *mpv, uchar **buf)
> + {
> + MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
> + MYSQL *mysql= mpvio->mysql;
> + ulong pkt_len;
> +
> + if (mpvio->packets_read == 0 && !mpvio->cached_server_reply.pkt)
> + {
> + /*
> + the server handshake packet came from the wrong plugin,
> + or it's mysql_change_user(). Either way, there is no data
> + for a plugin to read. send a dummy packet to the server
> + to initiate a dialog.
> + */
> + if (client_mpvio_write_packet(mpv, 0, 0))
> + return (int)packet_error;
> + }
> +
> + /* there are cached data left, feed it to a plugin */
> + if (mpvio->cached_server_reply.pkt)
> + {
> + *buf= mpvio->cached_server_reply.pkt;
> + mpvio->cached_server_reply.pkt= 0;
> + mpvio->packets_read++;
> + return mpvio->cached_server_reply.pkt_len;
> + }
Move this test first as this allows you to simplify the current first if.
> +
> + /* otherwise read the data */
> + pkt_len= (*mysql->methods->read_change_user_result)(mysql);
> + mpvio->last_read_packet_len= pkt_len;
> + *buf= mysql->net.read_pos;
> +
> + /* was it a request to change plugins ? */
> + if (**buf == 254)
> + return (int)packet_error; /* if yes, this plugin shan't continue */
shan't -> can't
> + /*
> + the server sends \1\255 or \1\254 instead of just \255 or \254 -
> + for us to not confuse it with an error or "change plugin" packets.
> + We remove this escaping \1 here.
> + */
Please add a comment 'see server_mpvio_write_packet()'
> + if (pkt_len && **buf == 1)
> + {
> + (*buf)++;
> + pkt_len--;
> + }
> + mpvio->packets_read++;
> + return pkt_len;
> + }
Wouldn't be be better to always send a 1 prefix in all cases or at
least for all not native authorization handlers?
(It would make the protocol easier to understand and also remove some
'if' code) here and in server_mpvio_write_packet()'
However, I agree that it may give a problem for the current native auth
handlers.
If there is no easy solution, we may have to live with this for now...
> + /**
> + vio->write_packet() callback method for client authentication plugins
> +
> + This function is called by a client authentication plugin, when it wants
> + to send data to the server.
> +
> + It transparently wraps the data into a change user or authentication
> + handshake packet, if neccessary.
> + */
> + static int client_mpvio_write_packet(struct st_plugin_vio *mpv,
> + const uchar *pkt, int pkt_len)
> + {
> + int res;
> + MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
> +
> + if (mpvio->packets_written == 0)
> + {
> + if (mpvio->mysql_change_user)
> + res= send_change_user_packet(mpvio, pkt, pkt_len);
> + else
> + res= send_client_reply_packet(mpvio, pkt, pkt_len);
It would be nice to not have this if.
As a trick, it's possible to remove all of the above if's.
This would be to set write_packet directly to
send_change_user_packet & send_client_reply_packet
And then end both of these with
mpvio->write_packet=client_mpvio_write_packet;
mpvio->packets_written++;
In this case the packets_written may not even be neccessary to have.
> +
> + /**
> + fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
> + connection
> + */
> + void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info)
> + {
> + bzero(info, sizeof(*info));
> + switch (vio->type) {
> + case VIO_TYPE_TCPIP:
> + info->protocol= MYSQL_VIO_TCP;
> + info->socket= vio->sd;
> + return;
> + case VIO_TYPE_SOCKET:
> + info->protocol= MYSQL_VIO_SOCKET;
> + info->socket= vio->sd;
> + return;
> + case VIO_TYPE_SSL:
> + {
> + struct sockaddr addr;
> + socklen_t addrlen= sizeof(addr);
> + if (getsockname(vio->sd, &addr, &addrlen))
> + return;
> + info->protocol= addr.sa_family == AF_UNIX ?
> + MYSQL_VIO_SOCKET : MYSQL_VIO_TCP;
> + info->socket= vio->sd;
> + return;
> + }
> + #ifdef _WIN32
> + case VIO_TYPE_NAMEDPIPE:
> + info->protocol= MYSQL_VIO_PIPE;
> + info->handle= vio->hPipe;
> + return;
> + case VIO_TYPE_SHARED_MEMORY:
> + info->protocol= MYSQL_VIO_MEMORY;
> + info->handle= vio->handle_client_file_map; /* or what ? */
> + return;
> + #endif
> + default: DBUG_ASSERT(0);
> + }
> + }
As this is not used by MariaDBL by default, add a comment that for now
this is only used by the socket_peercred plugin.
> + int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
> + char *data_plugin, const char *db)
> + {
> + const char *auth_plugin_name;
> + auth_plugin_t *auth_plugin;
> + MCPVIO_EXT mpvio;
> + ulong pkt_length;
> + int res;
> +
> + /* determine the default/initial plugin to use */
> + if (mysql->options.extension && mysql->options.extension->default_auth &&
> + mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
> + auth_plugin_name= mysql->options.extension->default_auth;
> + else
> + auth_plugin_name= mysql->server_capabilities & CLIENT_PROTOCOL_41 ?
> + native_password_plugin_name : old_password_plugin_name;
> +
Better to set auth_plugin directly above.
(Yes, mysql_client_find_plugin() is fast, but setting things directly
is even faster and in this case not more code.
> + if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql,
> + auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
> + return 1; /* oops, not found */
> +
> + mysql->net.last_errno= 0; /* just in case */
> +
> + if (data_plugin && strcmp(data_plugin, auth_plugin_name))
but of course, here you need to use something like auth_plugin->name instead.
<cut>
> + res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
> +
> + compile_time_assert(CR_OK == -1);
> + compile_time_assert(CR_ERROR == 0);
> + if (res > CR_OK && mysql->net.read_pos[0] != 254)
> + {
> + /*
> + the plugin returned an error. write it down in mysql,
> + unless the error code is CR_ERROR and mysql->net.last_errno
> + is already set (the plugin has done it)
> + */
> + if (res > CR_ERROR)
> + set_mysql_error(mysql, res, unknown_sqlstate);
> + else
> + if (!mysql->net.last_errno)
> + set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
> + return 1;
> + }
> +
> + /* read the OK packet (or use the cached value in mysql->net.read_pos */
> + if (res == CR_OK)
> + pkt_length= (*mysql->methods->read_change_user_result)(mysql);
> + else /* res == CR_OK_HANDSHAKE_COMPLETE */
> + pkt_length= mpvio.last_read_packet_len;
Note that here res may be CR_ERROR as mysql->net.read_pos[] can
contain 254 as part of some old 'garbage' data, so the comment is
wrong. I assume that in this case last_read_packet_len is packet_error.
> +
> + if (pkt_length == packet_error)
> + {
> + if (mysql->net.last_errno == CR_SERVER_LOST)
> + set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
> + ER(CR_SERVER_LOST_EXTENDED),
> + "reading authorization packet",
> + errno);
> + return 1;
> + }
> +
> + if (mysql->net.read_pos[0] == 254)
> + {
> + /* The server asked to use a different authentication plugin */
> + if (pkt_length == 1)
> + { /* old "use short scramble" packet */
Please move comment to it's own line. (Hard to read for me)
> + auth_plugin_name= old_password_plugin_name;
> + mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble;
> + mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1;
> + }
> + else
> + { /* new "use different plugin" packet */
Same here
> + uint len;
> + auth_plugin_name= (char*)mysql->net.read_pos + 1;
> + len= strlen(auth_plugin_name);
Here you may want to add a comment that this is safe becasue
my_net_read() guarantees that the packet ends with \0
> MYSQL * STDCALL
> CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
> *************** CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
> *** 1863,1870 ****
> uint port, const char *unix_socket,ulong client_flag)
> {
> char buff[NAME_LEN+USERNAME_LENGTH+100];
> ! char error_string[1024];
> ! char *end,*host_info= NULL;
> my_socket sock;
> in_addr_t ip_addr;
> struct sockaddr_in sock_addr;
> --- 2481,2489 ----
> uint port, const char *unix_socket,ulong client_flag)
> {
> char buff[NAME_LEN+USERNAME_LENGTH+100];
> ! int scramble_data_len, pkt_scramble_len;
> ! char *end,*host_info, *server_version_end, *pkt_end, *scramble_data;
> ! char *scramble_plugin;
> my_socket sock;
> in_addr_t ip_addr;
> struct sockaddr_in sock_addr;
Will we not get a warning on some platform if we remove host_info= NULL ?
(I think this was the reason we added it)
> --- 2812,2840 ----
> PROTOCOL_VERSION);
> goto error;
> }
> ! server_version_end= end= strend((char*) net->read_pos+1);
> mysql->thread_id=uint4korr(end+1);
> end+=5;
> /*
> ! Scramble is split into two parts because old clients do not understand
> long scrambles; here goes the first part.
> */
> ! scramble_data= end;
> ! scramble_data_len= SCRAMBLE_LENGTH_323 + 1;
> ! scramble_plugin= old_password_plugin_name;
> ! end+= scramble_data_len;
>
> ! if (pkt_end >= end + 1)
> mysql->server_capabilities=uint2korr(end);
> ! if (pkt_end >= end + 18)
> {
> /* New protocol with 16 bytes to describe server characteristics */
> mysql->server_language=end[2];
> mysql->server_status=uint2korr(end+3);
> + mysql->server_capabilities|= uint2korr(end+5) << 16;
> + pkt_scramble_len= end[7];
> }
> end+= 18;
Don't we need to check that end + pkt_scramble_len <= pkt_end ?
<cut>
> *** 3185,3190 ****
> --- 3650,3663 ----
> else
> mysql->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
> break;
> + case MYSQL_PLUGIN_DIR:
> + extension_free(&mysql->options, plugin_dir);
> + mysql->options.extension->plugin_dir= my_strdup(arg, MYF(MY_WME));
> + break;
> + case MYSQL_DEFAULT_AUTH:
> + extension_free(&mysql->options, default_auth);
> + mysql->options.extension->default_auth= my_strdup(arg, MYF(MY_WME));
> + break;
-> extension_set_string()
> --- sql-common/client_plugin.c 2010-02-19 08:18:09 +0000
> ***************
> *** 0 ****
> --- 1,427 ----
> + /* Copyright (C) 2010 Monty Program Ab
-> Add author
<cut>
> + static void load_env_plugins(MYSQL *mysql)
> + {
> + char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS");
> +
> + /* no plugins to load */
> + if(!s)
> + return;
> +
> + free_env= plugs= my_strdup(s, MYF(MY_WME));
> + s= NULL;
Remove setting 's' to NULL.
> +
> + do {
> + if ((s= strchr(plugs, ';')))
> + *s= '\0';
> + mysql_load_plugin(mysql, plugs, -1, 0);
> + if(s)
Remove if (not needed)
> + plugs= ++s;
Change to s+1
> + } while (s);
> +
> + my_free(free_env, MYF(0));
> + }
add space after 'if'
> +
> + /********** extern functions to be used by libmysql *********************/
> +
> + /**
> + Initializes the client plugin layer.
> +
> + This function must be called before any other client plugin function.
> +
> + @retval 0 successful
> + @retval != 0 error occured
> + */
> + int mysql_client_plugin_init()
> + {
> + MYSQL mysql;
> + struct st_mysql_client_plugin **builtin;
> +
> + if (initialized)
> + return 0;
> + bzero(&mysql, sizeof(mysql)); /* dummy mysql for set_mysql_extended_error */
> +
> + pthread_mutex_init(&LOCK_load_client_plugin, MY_MUTEX_INIT_SLOW);
> + init_alloc_root(&mem_root, 128, 128);
> +
> + bzero(&plugin_list, sizeof(plugin_list));
> +
> + initialized= 1;
> +
> + pthread_mutex_lock(&LOCK_load_client_plugin);
> +
> + for (builtin= mysql_client_builtins; *builtin; builtin++)
> + add_plugin(&mysql, *builtin, 0, 0, 0);
> +
> + pthread_mutex_unlock(&LOCK_load_client_plugin);
> +
> + load_env_plugins(&mysql);
You don't need mutex_lock() here, as no other thread can access data
until this is setup. You can make this safe by setting initialized to
1 at end of function.
> +
> + return 0;
> + }
> +
> + /**
> + Deinitializes the client plugin layer.
> +
> + Unloades all client plugins and frees any associated resources.
> + */
> + void mysql_client_plugin_deinit()
> + {
> + int i;
> + struct st_client_plugin_int *p;
> +
> + if (!initialized)
> + return;
Shouldn't this be a DBUG_ASSERT() to detect wrong usage?
> --- sql/mysqld.cc 2010-02-19 08:18:09 +0000
> *************** static int init_common_variables(const c
> *** 3490,3495 ****
> --- 3492,3498 ----
> if (init_errmessage()) /* Read error messages from file */
> return 1;
> init_client_errs();
> + mysql_library_init(un,us,ed); /* for replication */
Please add comment. As this can never work, why have it here?
> === modified file 'sql/sql_acl.cc'
> *** sql/sql_acl.cc 2010-02-01 06:14:12 +0000
<cut>
> + struct acl_host_and_ip
> + {
> + char *hostname;
> + long ip,ip_mask; // Used with masked ip:s
> + };
Just a note; For future, we should change all strings to use
LEX_STRING (to avoid calling strlen() and faster compare as we can
skip strings with different lengths).
> + class ACL_ACCESS {
> + public:
> + ulong sort;
> + ulong access;
> + };
> +
> + /* ACL_HOST is used if no host is specified */
> +
> + class ACL_HOST :public ACL_ACCESS
> + {
> + public:
> + acl_host_and_ip host;
> + char *db;
> + };
db is something I wanted to put as LEX_STRING a long time...
(Noting you can do about it just now...)
> +
> + class ACL_USER :public ACL_ACCESS
> + {
> + public:
> + acl_host_and_ip host;
> + uint hostname_length;
> + USER_RESOURCES user_resource;
> + char *user;
> + uint8 salt[SCRAMBLE_LENGTH+1]; // scrambled password in binary form
> + uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 4.0, 20 - 4.1.1
> + enum SSL_type ssl_type;
> + const char *ssl_cipher, *x509_issuer, *x509_subject;
> + LEX_STRING plugin;
> + LEX_STRING auth_string;
> +
> + ACL_USER *copy(MEM_ROOT *root)
> + {
> + ACL_USER *dst= (ACL_USER *)alloc_root(root, sizeof(ACL_USER));
> + if (!dst)
> + return 0;
> + *dst= *this;
> + dst->user= safe_strdup_root(root, user);
> + dst->ssl_cipher= safe_strdup_root(root, ssl_cipher);
> + dst->x509_issuer= safe_strdup_root(root, x509_issuer);
> + dst->x509_subject= safe_strdup_root(root, x509_subject);
> + if (plugin.str == native_password_plugin_name.str ||
> + plugin.str == old_password_plugin_name.str)
> + dst->plugin= plugin;
> + else
> + dst->plugin.str= strmake_root(root, plugin.str, plugin.length);
In theory, it would be better if we didn't have to test for names but
instead have a flag in the plugin if it's dynamic or not.
> + dst->auth_string.str = safe_strdup_root(root, auth_string.str);
> + dst->host.hostname= safe_strdup_root(root, host.hostname);
> + return dst;
> + }
> + };
> *************** static my_bool acl_load(THD *thd, TABLE_
> *** 433,459 ****
> continue;
> }
>
> ! const char *password= get_field(thd->mem_root, table->field[2]);
> uint password_len= password ? strlen(password) : 0;
> set_user_salt(&user, password, password_len);
> ! if (user.salt_len == 0 && password_len != 0)
> ! {
> switch (password_len) {
> case 45: /* 4.1: to be removed */
> ! sql_print_warning("Found 4.1 style password for user '%s@%s'. "
> "Ignoring user. "
> "You should change password for this user.",
> user.user ? user.user : "",
> user.host.hostname ? user.host.hostname : "");
> ! break;
> default:
> sql_print_warning("Found invalid password for user: '%s@%s'; "
> "Ignoring user", user.user ? user.user : "",
> user.host.hostname ? user.host.hostname : "");
> ! break;
> ! }
> }
> ! else // password is correct
> {
> uint next_field;
> user.access= get_access(table,3,&next_field) & GLOBAL_ACLS;
> --- 545,578 ----
> continue;
> }
>
> ! char *password= get_field(thd->mem_root, table->field[2]);
> uint password_len= password ? strlen(password) : 0;
We should change 'get_field' to also return the length of the string.
I can do that as a separate patch if you don't want to do it.
<cut>
> --- 649,681 ----
> ptr= get_field(thd->mem_root, table->field[next_field++]);
> user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
> }
> !
> ! if (table->s->fields >= 41)
> ! {
> ! /* We may have plugin & auth_String fields */
> ! char *tmpstr= get_field(&mem, table->field[next_field++]);
> ! if (tmpstr)
> ! {
> ! if (user.auth_string.length)
> ! {
> ! sql_print_warning("'user' entry '%s@%s' has both a password "
> ! "and an authentication plugin specified. The "
> ! "password will be ignored.",
> ! user.user ? user.user : "",
> ! user.host.hostname ? user.host.hostname : "");
> ! }
> ! user.plugin.str= tmpstr;
> ! user.plugin.length= strlen(tmpstr);
Another strlen() to be removed if we fix get_field()...
> ! user.auth_string.str= get_field(&mem, table->field[next_field++]);
> ! if (!user.auth_string.str)
> ! user.auth_string.str= const_cast<char*>("");
> ! user.auth_string.length= strlen(user.auth_string.str);
and another one...
> ! }
> ! }
> }
> else
> {
> user.ssl_type=SSL_TYPE_NONE;
> #ifndef TO_BE_REMOVED
> if (table->s->fields <= 13)
> { // Without grant
> *************** static int acl_compare(ACL_ACCESS *a,ACL
> *** 836,1081 ****
>
>
> /*
> ! Seek ACL entry for a user, check password, SSL cypher, and if
> ! everything is OK, update THD user data and USER_RESOURCES struct.
> !
> ! IMPLEMENTATION
> ! This function does not check if the user has any sensible privileges:
> ! only user's existence and validity is checked.
> ! Note, that entire operation is protected by acl_cache_lock.
>
> SYNOPSIS
> acl_getroot()
> - thd thread handle. If all checks are OK,
> - thd->security_ctx->priv_user/master_access are updated.
> - thd->security_ctx->host/ip/user are used for checks.
> - mqh user resources; on success mqh is reset, else
> - unchanged
> - passwd scrambled & crypted password, received from client
> - (to check): thd->scramble or thd->scramble_323 is
> - used to decrypt passwd, so they must contain
> - original random string,
> - passwd_len length of passwd, must be one of 0, 8,
> - SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
> - 'thd' and 'mqh' are updated on success; other params are IN.
> -
> - RETURN VALUE
> - 0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are
> - updated
> - 1 user not found or authentication failure
> - 2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format.
> - -1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format.
> - */
> -
> - int acl_getroot(THD *thd, USER_RESOURCES *mqh,
> - const char *passwd, uint passwd_len)
> - {
> - ulong user_access= NO_ACCESS;
> - int res= 1;
> - ACL_USER *acl_user= 0;
> - Security_context *sctx= thd->security_ctx;
> - DBUG_ENTER("acl_getroot");
> -
> - if (!initialized)
> - {
> - /*
> - here if mysqld's been started with --skip-grant-tables option.
> - */
> - sctx->skip_grants();
> - bzero((char*) mqh, sizeof(*mqh));
> - DBUG_RETURN(0);
> - }
> -
> - VOID(pthread_mutex_lock(&acl_cache->lock));
> -
> - /*
> - Find acl entry in user database. Note, that find_acl_user is not the same,
> - because it doesn't take into account the case when user is not empty,
> - but acl_user->user is empty
> - */
> -
> - for (uint i=0 ; i < acl_users.elements ; i++)
> - {
> - ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
> - if (!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user))
> - {
> - if (compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip))
> - {
> - /* check password: it should be empty or valid */
> - if (passwd_len == acl_user_tmp->salt_len)
> - {
> - if (acl_user_tmp->salt_len == 0 ||
> - (acl_user_tmp->salt_len == SCRAMBLE_LENGTH ?
> - check_scramble(passwd, thd->scramble, acl_user_tmp->salt) :
> - check_scramble_323(passwd, thd->scramble,
> - (ulong *) acl_user_tmp->salt)) == 0)
> - {
> - acl_user= acl_user_tmp;
> - res= 0;
> - }
> - }
> - else if (passwd_len == SCRAMBLE_LENGTH &&
> - acl_user_tmp->salt_len == SCRAMBLE_LENGTH_323)
> - res= -1;
> - else if (passwd_len == SCRAMBLE_LENGTH_323 &&
> - acl_user_tmp->salt_len == SCRAMBLE_LENGTH)
> - res= 2;
> - /* linear search complete: */
> - break;
> - }
> - }
> - }
> - /*
> - This was moved to separate tree because of heavy HAVE_OPENSSL case.
> - If acl_user is not null, res is 0.
> - */
> -
> - if (acl_user)
> - {
> - /* OK. User found and password checked continue validation */
> - #ifdef HAVE_OPENSSL
> - Vio *vio=thd->net.vio;
> - SSL *ssl= (SSL*) vio->ssl_arg;
> - X509 *cert;
> - #endif
> -
> - /*
> - At this point we know that user is allowed to connect
> - from given host by given username/password pair. Now
> - we check if SSL is required, if user is using SSL and
> - if X509 certificate attributes are OK
> - */
> - switch (acl_user->ssl_type) {
> - case SSL_TYPE_NOT_SPECIFIED: // Impossible
> - case SSL_TYPE_NONE: // SSL is not required
> - user_access= acl_user->access;
> - break;
> - #ifdef HAVE_OPENSSL
> - case SSL_TYPE_ANY: // Any kind of SSL is ok
> - if (vio_type(vio) == VIO_TYPE_SSL)
> - user_access= acl_user->access;
> - break;
> - case SSL_TYPE_X509: /* Client should have any valid certificate. */
> - /*
> - Connections with non-valid certificates are dropped already
> - in sslaccept() anyway, so we do not check validity here.
> -
> - We need to check for absence of SSL because without SSL
> - we should reject connection.
> - */
> - if (vio_type(vio) == VIO_TYPE_SSL &&
> - SSL_get_verify_result(ssl) == X509_V_OK &&
> - (cert= SSL_get_peer_certificate(ssl)))
> - {
> - user_access= acl_user->access;
> - X509_free(cert);
> - }
> - break;
> - case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
> - /*
> - We do not check for absence of SSL because without SSL it does
> - not pass all checks here anyway.
> - If cipher name is specified, we compare it to actual cipher in
> - use.
> - */
> - if (vio_type(vio) != VIO_TYPE_SSL ||
> - SSL_get_verify_result(ssl) != X509_V_OK)
> - break;
> - if (acl_user->ssl_cipher)
> - {
> - DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
> - acl_user->ssl_cipher,SSL_get_cipher(ssl)));
> - if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl)))
> - user_access= acl_user->access;
> - else
> - {
> - if (global_system_variables.log_warnings)
> - sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'",
> - acl_user->ssl_cipher,
> - SSL_get_cipher(ssl));
> - break;
> - }
> - }
> - /* Prepare certificate (if exists) */
> - DBUG_PRINT("info",("checkpoint 1"));
> - if (!(cert= SSL_get_peer_certificate(ssl)))
> - {
> - user_access=NO_ACCESS;
> - break;
> - }
> - DBUG_PRINT("info",("checkpoint 2"));
> - /* If X509 issuer is specified, we check it... */
> - if (acl_user->x509_issuer)
> - {
> - DBUG_PRINT("info",("checkpoint 3"));
> - char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
> - DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
> - acl_user->x509_issuer, ptr));
> - if (strcmp(acl_user->x509_issuer, ptr))
> - {
> - if (global_system_variables.log_warnings)
> - sql_print_information("X509 issuer mismatch: should be '%s' "
> - "but is '%s'", acl_user->x509_issuer, ptr);
> - free(ptr);
> - X509_free(cert);
> - user_access=NO_ACCESS;
> - break;
> - }
> - user_access= acl_user->access;
> - free(ptr);
> - }
> - DBUG_PRINT("info",("checkpoint 4"));
> - /* X509 subject is specified, we check it .. */
> - if (acl_user->x509_subject)
> - {
> - char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
> - DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
> - acl_user->x509_subject, ptr));
> - if (strcmp(acl_user->x509_subject,ptr))
> - {
> - if (global_system_variables.log_warnings)
> - sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
> - acl_user->x509_subject, ptr);
> - free(ptr);
> - X509_free(cert);
> - user_access=NO_ACCESS;
> - break;
> - }
> - user_access= acl_user->access;
> - free(ptr);
> - }
> - /* Deallocate the X509 certificate. */
> - X509_free(cert);
> - break;
> - #else /* HAVE_OPENSSL */
> - default:
> - /*
> - If we don't have SSL but SSL is required for this user the
> - authentication should fail.
> - */
> - break;
> - #endif /* HAVE_OPENSSL */
> - }
> - sctx->master_access= user_access;
> - sctx->priv_user= acl_user->user ? sctx->user : (char *) "";
> - *mqh= acl_user->user_resource;
> -
> - if (acl_user->host.hostname)
> - strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
> - else
> - *sctx->priv_host= 0;
> - }
> - VOID(pthread_mutex_unlock(&acl_cache->lock));
> - DBUG_RETURN(res);
> - }
> -
> -
> - /*
> - This is like acl_getroot() above, but it doesn't check password,
> - and we don't care about the user resources.
> -
> - SYNOPSIS
> - acl_getroot_no_password()
> sctx Context which should be initialized
> user user name
> host host name
> --- 977,986 ----
<cut>
> --- 6238,6256 ----
> }
> else
> {
> ! push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_PASSWD_LENGTH,
> ! ER(ER_PASSWD_LENGTH), SCRAMBLED_PASSWORD_CHAR_LENGTH);
> return TRUE;
> }
> combo->password.str= passwd_buff;
> }
> !
> ! if (au->plugin.str != native_password_plugin_name.str &&
> ! au->plugin.str != old_password_plugin_name.str)
Also here it would be nice with just:
if (!au->plugin.native_plugin)
...
> + /****************************************************************************
> + AUTHENTICATION CODE
> + including initial connect handshake, invoking appropriate plugins,
> + client-server plugin negotiation, COM_CHANGE_USER, and native
> + MySQL authentication plugins.
> + ****************************************************************************/
> +
> + /* few defines to have less ifdef's in the code below */
> + #ifdef EMBEDDED_LIBRARY
> + #ifdef NO_EMBEDDED_ACCESS_CHECKS
> + #define initialized 0
> + #define decrease_user_connections(X) /* nothing */
> + #define check_for_max_user_connections(X,Y) 0
> + #endif
> + #undef HAVE_OPENSSL
> + #endif
Move the undef after the first #ifdef; Makes the code easier to read
and one doesn't have to worry what each #endif stands for.
> + #ifndef HAVE_OPENSSL
> + #define ssl_acceptor_fd 0
> + #define sslaccept(A,B,C,D) 1
> + #endif
> +
> + /**
> + The internal version of what plugins know as MYSQL_PLUGIN_VIO,
> + basically the context of the authentication session
> + */
> + struct MPVIO_EXT : public MYSQL_PLUGIN_VIO
> + {
> + MYSQL_SERVER_AUTH_INFO auth_info;
> + THD *thd;
> + ACL_USER *acl_user; ///< a copy, independent from acl_users array
> + plugin_ref plugin; ///< what plugin we're under
> + LEX_STRING db; ///< db name from the handshake packet
> + /** when restarting a plugin this caches the last client reply */
> + struct {
> + char *plugin, *pkt; ///< pointers into NET::buff
> + uint pkt_len;
> + } cached_client_reply;
> + /** this caches the first plugin packet for restart request on the client */
> + struct {
> + char *pkt;
> + uint pkt_len;
> + } cached_server_packet;
> + int packets_read, packets_written; ///< counters for send/received packets
> + uint connect_errors; ///< if there were connect errors for this host
> + /** when plugin returns a failure this tells us what really happened */
> + enum { SUCCESS, FAILURE, RESTART } status;
> + };
Change comments from ///< to //
(No reason for new style here)
Also change /** to /*
> +
> + /**
> + a helper function to report an access denied error in all the proper places
> + */
> + static void login_failed_error(THD *thd, bool passwd_used)
> + {
> + my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
> + thd->main_security_ctx.user,
> + thd->main_security_ctx.host_or_ip,
> + passwd_used ? ER(ER_YES) : ER(ER_NO));
> + general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
> + thd->main_security_ctx.user,
> + thd->main_security_ctx.host_or_ip,
> + passwd_used ? ER(ER_YES) : ER(ER_NO));
> + status_var_increment(thd->status_var.access_denied_errors);
> + /*
> + Log access denied messages to the error log when log-warnings = 2
> + so that the overhead of the general query log is not required to track
> + failed connections.
> + */
> + if (global_system_variables.log_warnings > 1)
> + {
> + sql_print_warning(ER(ER_ACCESS_DENIED_ERROR),
> + thd->main_security_ctx.user,
> + thd->main_security_ctx.host_or_ip,
> + passwd_used ? ER(ER_YES) : ER(ER_NO));
> + }
> + }
Both general_log_print() and sql_print_warning() prints error to log
file. Shouldn't we remove the first general_log_print() from above?
(I couldn't find the sql_print_warning() in the old code).
> +
> + /**
> + sends a server handshake initialization packet, the very first packet
> + after the connection was established
> +
> + Packet format:
> +
> + Bytes Content
> + ----- ----
> + 1 protocol version (always 10)
> + n server version string, \0-terminated
> + 4 thread id
> + 8 first 8 bytes of the plugin provided data (scramble)
> + 1 \0 byte, terminating the first part of a scramble
> + 2 server capabilities (two lower bytes)
> + 1 server character set
> + 2 server status
> + 2 server capabilities (two upper bytes)
> + 1 length of the scramble
> + 10 reserved, always 0
> + n rest of the plugin provided data (at least 12 bytes)
> + 1 \0 byte, terminating the second part of a scramble
> +
> + @retval 0 ok
> + @retval 1 error
> + */
Shouldn't this function be in sql_connect.c ?
> + static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
> + const char *data, uint data_len)
> + {
> + DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE);
Add also an assert if data_len > 255.
> +
> + THD *thd= mpvio->thd;
> + char *buff= (char *)my_alloca(1 + SERVER_VERSION_LENGTH + data_len + 64);
> + char scramble_buf[SCRAMBLE_LENGTH];
> + char *end= buff;
> +
> + *end++= protocol_version;
> +
> + thd->client_capabilities= CLIENT_BASIC_FLAGS;
> +
> + if (data_len)
> + {
> + mpvio->cached_server_packet.pkt= (char*)thd->memdup(data, data_len);
> + mpvio->cached_server_packet.pkt_len= data_len;
> + }
> +
> + if (data_len < SCRAMBLE_LENGTH)
> + {
> + if (data_len)
> + { /*
> + the first packet *must* have at least 20 bytes of a scramble.
> + if a plugin provided less, we pad it to 20 with zeros
> + */
> + memcpy(scramble_buf, data, data_len);
> + bzero(scramble_buf+data_len, SCRAMBLE_LENGTH-data_len);
> + data= scramble_buf;
> + }
> + else
> + {
> + /*
> + if the default plugin does not provide the data for the scramble at
> + all, we generate a scramble internally anyway, just in case the
> + user account (that will be known only later) uses a
> + native_password_plugin (which needs a scramble). If we don't send a
> + scramble now - wasting 20 bytes in the packet -
> + native_password_plugin will have to send it in a separate packet,
> + adding one more round trip.
> + */
> + create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
> + data= thd->scramble;
> + }
You could move the above to an else of the first if (data_len) and
move the first part inside the first if.
This saves one-two if's during execution and makes code shorter.
> + data_len= SCRAMBLE_LENGTH;
> + }
> +
> + if (opt_using_transactions)
> + thd->client_capabilities|= CLIENT_TRANSACTIONS;
> +
> + thd->client_capabilities|= CAN_CLIENT_COMPRESS;
> +
> + if (ssl_acceptor_fd)
> + {
> + thd->client_capabilities |= CLIENT_SSL;
> + thd->client_capabilities |= CLIENT_SSL_VERIFY_SERVER_CERT;
> + }
> +
> + end= strnmov(end, server_version, SERVER_VERSION_LENGTH) + 1;
> + int4store((uchar*) end, mpvio->thd->thread_id);
> + end+= 4;
> +
> + /*
> + Old clients does not understand long scrambles, but can ignore packet
> + tail: that's why first part of the scramble is placed here, and second
> + part at the end of packet.
> + */
> + end= (char*)memcpy(end, data, SCRAMBLE_LENGTH_323);
> + end+= SCRAMBLE_LENGTH_323;
> + *end++= 0;
> +
> + int2store(end, thd->client_capabilities);
> + /* write server characteristics: up to 16 bytes allowed */
> + end[2]=(char) default_charset_info->number;
> + int2store(end+3, mpvio->thd->server_status);
> + int2store(end+5, thd->client_capabilities >> 16);
> + end[7]= data_len;
> + bzero(end+8, 10);
> + end+= 18;
> + /* write scramble tail */
> + end= (char*)memcpy(end, data + SCRAMBLE_LENGTH_323,
> + data_len - SCRAMBLE_LENGTH_323);
Note that in old code, we had an end zero after scramble, that you
don't have here. I checked the client code and at least in the .c
client it's safe to nto have the end \0. You should probable check
with other native drivers that it's safe with them too.
(Especially the php driver).
> + end+= data_len - SCRAMBLE_LENGTH_323;
> + end= strmake(end, plugin_name(mpvio->plugin)->str,
> + plugin_name(mpvio->plugin)->length);
> +
> + int res= my_net_write(&mpvio->thd->net, (uchar*) buff, (size_t) (end-buff)) ||
> + net_flush(&mpvio->thd->net);
Please move declaration of 'res' to function start.
> + my_afree(buff);
> + return res;
> + }
> +
> + static uchar switch_plugin_request_buf[]= { 254 };
Move to file start.
> +
> + /**
> + sends a "change plugin" packet, requesting a client to restart authentication
> + using a different authentication plugin
> +
> + Packet format:
> +
> + Bytes Content
> + ----- ----
> + 1 byte with the value 254
> + n client plugin to use, \0-terminated
> + n plugin provided data
> +
> + In a special case of switching from native_password_plugin to
> + old_password_plugin, the packet contains only one - the first - byte,
> + plugin name is omitted, plugin data aren't needed as the scramble was
> + already sent. This one-byte packet is identical to the "use the short
> + scramble" packet in the protocol before plugins were introduced.
> +
> + @retval 0 ok
> + @retval 1 error
> + */
Maybe this also should be in sql_connect.cc ?
> + static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
> + const uchar *data, uint data_len)
> + {
> + DBUG_ASSERT(mpvio->packets_written == 1);
> + DBUG_ASSERT(mpvio->packets_read == 1);
> + NET *net= &mpvio->thd->net;
> +
> + mpvio->status= MPVIO_EXT::FAILURE; // the status is no longer RESTART
> +
> + const char *client_auth_plugin=
> + ((st_mysql_auth *)(plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
> +
> + DBUG_ASSERT(client_auth_plugin);
Wouldn't it be better to make this a LEX_STRING *?
(You can then avoid the strlen() later on)
> +
> + /*
> + we send an old "short 4.0 scramble request", if we need to request a
> + client to use 4.0 auth plugin (short scramble) and the scramble was
> + already sent to the client
> + */
> + bool switch_from_long_to_short_scramble=
Please move all variable declaration to start or in this case, just
change this to one if without a variable
> + my_strcasecmp(system_charset_info, native_password_plugin_name.str,
> + mpvio->cached_client_reply.plugin) == 0 &&
> + client_auth_plugin == old_password_plugin_name.str;
> +
> + if (switch_from_long_to_short_scramble)
> + return my_net_write(net, switch_plugin_request_buf, 1) ||
> + net_flush(net);
Please add to the above comment how
mpvio->cached_client_reply.plugin and client_auth_plugin comes are set?
>From IRC:
client_auth_plugin is set from the data in the users table.
mpvio->cached_client_reply.plugin contains what client tried to use.
> +
> + /*
> + We never request a client to switch from a short to long scramble.
> + Plugin-aware clients can do that, but traditionally it meant to
> + ask an old 4.0 client to use the new 4.1 authentication protocol.
> + */
> + bool switch_from_short_to_long_scramble=
> + my_strcasecmp(system_charset_info, old_password_plugin_name.str,
> + mpvio->cached_client_reply.plugin) == 0 &&
> + client_auth_plugin == native_password_plugin_name.str;
> +
> + if (switch_from_short_to_long_scramble)
Remove variable.
> + {
> + my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
> + general_log_print(mpvio->thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
> + return 1;
> + }
> +
> + return net_write_command(net, switch_plugin_request_buf[0],
> + (uchar*)client_auth_plugin,
> + strlen(client_auth_plugin)+1,
> + (uchar*)data, data_len);
> + }
> +
> + #ifndef NO_EMBEDDED_ACCESS_CHECKS
> + /**
> + Finds acl entry in user database for authentication purposes.
> +
> + Finds a user and copies it into mpvio. Reports an authentication
> + failure if a user is not found.
> +
> + @note find_acl_user is not the same, because it doesn't take into
> + account the case when user is not empty, but acl_user->user is empty
> +
> + @retval 0 found
> + @retval 1 not found
> + */
Please add blank line for each /*^Jstatic expression.
> + static bool find_mpvio_user(MPVIO_EXT *mpvio, Security_context *sctx)
> + {
> + pthread_mutex_lock(&acl_cache->lock);
> + for (uint i=0 ; i < acl_users.elements ; i++)
> + {
> + ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
> + if (!acl_user_tmp->user || (!strcmp(sctx->user, acl_user_tmp->user) &&
> + compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip)))
Fix indentation (move (!strcmp to next line))
Isn't the test wrong ?
Shouldn't it be:
if (((!acl_user_tmp->user ||
(acl_user_tmp->user && strcmp(user, acl_user_tmp->user) == 0))) &&
compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip)
As now compare_hostname() is not called if user is NULL
> +
> + {
> + mpvio->acl_user= acl_user_tmp->copy(mpvio->thd->mem_root);
> + break;
> + }
> + }
> + pthread_mutex_unlock(&acl_cache->lock);
> +
> + if (!mpvio->acl_user)
> + {
> + login_failed_error(mpvio->thd, 0);
> + return 1;
> + }
Add an assert at function start that this is zero.
> +
> + /* user account requires non-default plugin and the client is too old */
> + if (my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
> + native_password_plugin_name.str) &&
> + my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
> + old_password_plugin_name.str) &&
Haveing a 'native' plugin field, would make this test:
if (!mpvio->acl_user->plugin.native_plugin)
I think we really should do this as it makes code shorter and we don't
have to do a lot of name comparisons everywhere.
<cut>
> + mpvio->auth_info.user_name= sctx->user;
> + mpvio->auth_info.auth_string= mpvio->acl_user->auth_string.str;
> + strmake(mpvio->auth_info.authenticated_as, mpvio->acl_user->user ?
> + mpvio->acl_user->user : "", USERNAME_LENGTH);
I plan to fix that acl_user->user is never a null pointer. This will
remove a lot of if's in the code.
> +
> + return 0;
> + }
> + #endif
> +
> + /* the packet format is described in send_change_user_packet() */
> + static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
> + {
> + THD *thd= mpvio->thd;
> + NET *net= &thd->net;
> + Security_context *sctx= thd->security_ctx;
> +
> + char *user= (char*) net->read_pos;
> + char *end= user + packet_length;
> + /* Safe because there is always a trailing \0 at the end of the packet */
> + char *passwd= strend(user)+1;
> + uint user_len= passwd - user - 1;
> + char *db= passwd;
> + char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
> + char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
> + uint dummy_errors;
> +
> + if (passwd >= end)
> + {
> + my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
> + return 1;
> + }
> +
> + /*
> + Old clients send null-terminated string as password; new clients send
> + the size (1 byte) + string (not null-terminated). Hence in case of empty
> + password both send '\0'.
> +
> + This strlen() can't be easily deleted without changing protocol.
> +
> + Cast *passwd to an unsigned char, so that it doesn't extend the sign for
> + *passwd > 127 and become 2**32-127+ after casting to uint.
> + */
> + uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
> + (uchar)(*passwd++) : strlen(passwd));
Move declaration first
> +
> + db+= passwd_len + 1;
Better to do:
db= passwd + passwd_len + 1;
And remove initialization from start.
> + /*
> + Database name is always NUL-terminated, so in case of empty database
> + the packet must contain at least the trailing '\0'.
> + */
> + if (db >= end)
> + {
> + my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
> + return 1;
> + }
> +
> + uint db_len= strlen(db);
> +
> + char *ptr= db + db_len + 1;
Move declarations first.
> +
> + /* Convert database and user names to utf8 */
> + db_buff[db_len= copy_and_convert(db_buff, sizeof(db_buff)-1,
> + system_charset_info, db, db_len,
> + thd->charset(), &dummy_errors)]= 0;
We don't need to set end \0 here as we use make__lex_string() on
db_buff.
> + db= db_buff;
> +
> + user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
> + system_charset_info, user, user_len,
> + thd->charset(), &dummy_errors)]= '\0';
We shouldn't set end \0 here either.
Better to use my_strndup() below.
(It's also faster than my_strdup())
> + user= user_buff;
> +
> + if (ptr+1 < end)
> + {
> + uint cs_number= uint2korr(ptr);
> + thd_init_client_charset(thd, cs_number);
> + thd->update_charset();
Add ptr+= 2 here (Makes rest of code simpler).
> + }
We should first set the character set and then do copy_and_convert()
(The old code on sql_connect() did it that way)
> +
> + if (!(sctx->user= my_strdup(user, MYF(MY_WME))))
> + return 1;
my_strdup -> my_strndup()
> +
> + /* Clear variables that are allocated */
> + thd->user_connect= 0;
> + strmake(sctx->priv_user, sctx->user, USERNAME_LENGTH);
> +
> + if (thd->make_lex_string(&mpvio->db, db, db_len, 0) == 0)
> + return 1; /* The error is set by make_lex_string(). */
> +
> + /*
> + Clear thd->db as it points to something, that will be freed when
> + connection is closed. We don't want to accidentally free a wrong
> + pointer if connect failed.
> + */
> + thd->reset_db(NULL, 0);
> +
> + if (!initialized)
> + {
> + // if mysqld's been started with --skip-grant-tables option
> + mpvio->status= MPVIO_EXT::SUCCESS;
> + return 0;
> + }
> +
> + #ifndef NO_EMBEDDED_ACCESS_CHECKS
> + if (find_mpvio_user(mpvio, sctx))
> + return 1;
> +
> + char *client_plugin;
> + if (thd->client_capabilities & CLIENT_PLUGIN_AUTH)
> + {
> + client_plugin= ptr + 2;
Use client_plugin= ptr;
> + if (client_plugin >= end)
> + {
> + my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
> + return 1;
> + }
> + }
> + else
Add brace here
> + if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
> + client_plugin= native_password_plugin_name.str;
> + else
> + {
> + client_plugin= old_password_plugin_name.str;
> + /*
> + For a passwordless accounts we use native_password_plugin.
> + But when an old 4.0 client connects to it, we change it to
> + old_password_plugin, otherwise MySQL will think that server
> + and client plugins don't match.
> + */
> + if (mpvio->acl_user->auth_string.length == 0)
> + mpvio->acl_user->plugin= old_password_plugin_name;
> + }
> +
> + /* remember the data part of the packet, to present it to plugin in read_packet() */
> + mpvio->cached_client_reply.pkt= passwd;
> + mpvio->cached_client_reply.pkt_len= passwd_len;
> + mpvio->cached_client_reply.plugin= client_plugin;
Consider adding here
mpvio->cached_client_reply.native_plugin= 0 | 1;
(I know it requires a two strcasecmp() when the client packet contains
a plugin, but as this is not the normal case, it's ok.
> + mpvio->status= MPVIO_EXT::RESTART;
> + #endif
> +
> + return 0;
> + }
> +
> + /* the packet format is described in send_client_reply_packet() */
> + static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
> + uchar **buff, ulong pkt_len)
> + {
> + #ifndef EMBEDDED_LIBRARY
> + THD *thd= mpvio->thd;
> + NET *net= &thd->net;
> + char *end;
> +
> + DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE);
> +
> + if (pkt_len < MIN_HANDSHAKE_SIZE)
> + return packet_error;
> +
> + if (mpvio->connect_errors)
> + reset_host_errors(&net->vio->remote.sin_addr);
> +
> + ulong client_capabilities= uint2korr(net->read_pos);
Move declaration to function start
> + if (client_capabilities & CLIENT_PROTOCOL_41)
> + {
> + client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
> + thd->max_client_packet_length= uint4korr(net->read_pos+4);
> + DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
> + thd_init_client_charset(thd, (uint) net->read_pos[8]);
> + thd->update_charset();
> + end= (char*) net->read_pos+32;
> + }
> + else
> + {
> + thd->max_client_packet_length= uint3korr(net->read_pos+2);
> + end= (char*) net->read_pos+5;
> + }
> +
> + /* Disable those bits which are not supported by the client. */
Should be 'server' not 'client' as client_capabilities are initially
set by server.
> + thd->client_capabilities&= client_capabilities;
> +
> + if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
> + thd->variables.sql_mode|= MODE_IGNORE_SPACE;
> +
> + DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
> + if (thd->client_capabilities & CLIENT_SSL)
> + {
> + char error_string[1024] __attribute__((unused));
> +
> + /* Do the SSL layering. */
> + if (!ssl_acceptor_fd)
> + return packet_error;
> +
> + DBUG_PRINT("info", ("IO layer change in progress..."));
> + if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout, error_string))
> + {
> + DBUG_PRINT("error", ("Failed to accept new SSL connection"));
> + return packet_error;
> + }
> +
> + DBUG_PRINT("info", ("Reading user information over SSL layer"));
> + pkt_len= my_net_read(net);
> + if (pkt_len == packet_error || pkt_len < NORMAL_HANDSHAKE_SIZE)
> + {
> + DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
> + pkt_len));
> + return packet_error;
> + }
> + }
> +
> + if (end >= (char*) net->read_pos+ pkt_len +2)
> + return packet_error;
> +
> + if (thd->client_capabilities & CLIENT_INTERACTIVE)
> + thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
> + if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
> + opt_using_transactions)
> + net->return_status= &thd->server_status;
> +
> + char *user= end;
> + char *passwd= strend(user)+1;
> + uint user_len= passwd - user - 1;
> + char *db= passwd;
> + char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
> + char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
> + uint dummy_errors;
Please move variable declaration to function start.
> +
> + /*
> + Old clients send null-terminated string as password; new clients send
> + the size (1 byte) + string (not null-terminated). Hence in case of empty
> + password both send '\0'.
> +
> + This strlen() can't be easily deleted without changing protocol.
> +
> + Cast *passwd to an unsigned char, so that it doesn't extend the sign for
> + *passwd > 127 and become 2**32-127+ after casting to uint.
> + */
> + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
> + (uchar)(*passwd++) : strlen(passwd);
> + db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
> + db + passwd_len + 1 : 0;
> + /* strlen() can't be easily deleted without changing protocol */
> + uint db_len= db ? strlen(db) : 0;
Please clean up the above test to:
(Yes, I know it's old code, but better to fix it now as we are working
on it)
db_len= 0;
db= 0;
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
{
db= passwd + passwd_len + 1;
/* strlen() can't be easily deleted without changing protocol */
db_len= strlen(db);
}
> +
> + if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
> + return packet_error;
> +
> + char *client_plugin= passwd + passwd_len + (db ? db_len + 1 : 0);
client_plugin= passwd + passwd_len + db_len + test(db_len);
> +
> + /* Since 4.1 all database names are stored in utf8 */
> + if (db)
> + {
> + db_buff[db_len= copy_and_convert(db_buff, sizeof(db_buff)-1,
> + system_charset_info,
> + db, db_len,
> + thd->charset(), &dummy_errors)]= 0;
No reason to set \0
> + db= db_buff;
> + }
> +
> + user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
> + system_charset_info, user, user_len,
> + thd->charset(), &dummy_errors)]= '\0';
No reason to set \0
> + user= user_buff;
> +
> + /* If username starts and ends in "'", chop them off */
> + if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
> + {
> + user[user_len-1]= 0;
Remove setting of \0
> + user++;
> + user_len-= 2;
> + }
> +
> + Security_context *sctx= thd->security_ctx;
> +
> + if (thd->make_lex_string(&mpvio->db, db, db_len, 0) == 0)
> + return packet_error; /* The error is set by make_lex_string(). */
> + if (sctx->user)
> + x_free(sctx->user);
> + if (!(sctx->user= my_strdup(user, MYF(MY_WME))))
strdup-> strndup
> + return packet_error; /* The error is set by my_strdup(). */
> +
> + /*
> + Clear thd->db as it points to something, that will be freed when
> + connection is closed. We don't want to accidentally free a wrong
> + pointer if connect failed.
> + */
> + thd->reset_db(NULL, 0);
> +
> + if (!initialized)
> + {
> + // if mysqld's been started with --skip-grant-tables option
> + mpvio->status= MPVIO_EXT::SUCCESS;
> + return packet_error;
> + }
> +
> + if (find_mpvio_user(mpvio, sctx))
> + return packet_error;
> +
> + if (thd->client_capabilities & CLIENT_PLUGIN_AUTH)
> + {
> + if ((client_plugin + strlen(client_plugin)) >
> + (char *)net->read_pos + pkt_len)
> + return packet_error;
> + }
> + else
Add brace
> + if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
> + client_plugin= native_password_plugin_name.str;
> + else
> + {
> + client_plugin= old_password_plugin_name.str;
> + /*
> + For a passwordless accounts we use native_password_plugin.
> + But when an old 4.0 client connects to it, we change it to
> + old_password_plugin, otherwise MySQL will think that server
> + and client plugins don't match.
> + */
> + if (mpvio->acl_user->auth_string.length == 0)
> + mpvio->acl_user->plugin= old_password_plugin_name;
> + }
> +
<cut>
> + /*
> + ok, we don't need to restart the authentication on the server.
> + but if the client used the wrong plugin, we need to restart
> + the authentication on the client. Do it here, the server plugin
> + doesn't need to know.
> + */
> + const char *client_auth_plugin=
> + ((st_mysql_auth *)(plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
Would be better as a LEX_STRING *, so ether comments.
> +
> + if (client_auth_plugin &&
> + my_strcasecmp(system_charset_info, client_plugin, client_auth_plugin))
> + {
> + mpvio->cached_client_reply.plugin= client_plugin;
> + if (send_plugin_request_packet(mpvio,
> + (uchar*)mpvio->cached_server_packet.pkt,
> + mpvio->cached_server_packet.pkt_len))
> + return packet_error;
> +
> + passwd_len= my_net_read(&mpvio->thd->net);
> + passwd = (char*)mpvio->thd->net.read_pos;
> + }
> +
> + *buff= (uchar*)passwd;
> + return passwd_len;
> + #else
> + return 0;
> + #endif
> + }
> +
Add empty line
> + /**
> + vio->write_packet() callback method for server authentication plugins
> +
> + This function is called by a server authentication plugin, when it wants
> + to send data to the client.
> +
> + It transparently wraps the data into a handshake packet,
> + and handles plugin negotiation with the client. If necessary,
> + it escapes the plugin data, if it starts with a mysql protocol packet byte.
> + */
> + static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param,
> + const uchar *packet, int packet_len)
> + {
> + MPVIO_EXT *mpvio= (MPVIO_EXT*)param;
> + int res;
Add empty line
> + /* reset cached_client_reply */
> + mpvio->cached_client_reply.pkt= 0;
<cut>
> + static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
> + {
> + MPVIO_EXT *mpvio= (MPVIO_EXT*)param;
> + ulong pkt_len;
> +
> + if (mpvio->packets_written == 0)
> + {
> + /*
> + plugin wants to read the data without sending anything first.
> + send an empty packet, to start a handshake
> + */
Change 'empty packet' to 'server_handshake_packet'.
Here, the code would be much clearer if we would just use:
mpvio->cached_client_reply.pkt= 0;
mpvio->packets_written++;
if (send_server_handshake_packet(mpvio, 0,0))
> + if (server_mpvio_write_packet(mpvio, 0, 0))
> + pkt_len= packet_error;
> + else
> + pkt_len= my_net_read(&mpvio->thd->net);
> + }
> + else
Move if to after else
> + if (mpvio->cached_client_reply.pkt)
> + {
> + DBUG_ASSERT(mpvio->status == MPVIO_EXT::RESTART);
> + DBUG_ASSERT(mpvio->packets_read > 0);
> + /*
> + if the have the data cached from the last server_mpvio_read_packet
> + (which can be the case if it's a restarted authentication)
> + and a client has used the correct plugin, then we can return the
> + cached data straight away and avoid one round trip.
> + */
> + const char *client_auth_plugin=
> + ((st_mysql_auth *)(plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
> + if (client_auth_plugin == 0 ||
> + my_strcasecmp(system_charset_info, mpvio->cached_client_reply.plugin,
> + client_auth_plugin) == 0)
> + {
> + mpvio->status= MPVIO_EXT::FAILURE;
> + *buf= (uchar*)mpvio->cached_client_reply.pkt;
> + mpvio->cached_client_reply.pkt= 0;
> + mpvio->packets_read++;
> + return (int)mpvio->cached_client_reply.pkt_len;
> + }
> + /*
> + But if the client has used the wrong plugin, the cached data are
> + useless. Furthermore, we have to send a "change plugin" request
> + to the client.
> + */
Here also, it would be clearer if we did:
mpvio->cached_client_reply.pkt= 0;
mpvio->packets_written++;
if (send_plugin_request_packet(mpvio, 0, 0))
(Of course, we can do the packets_written in
send_plugin_request_packet and send_server_handshake_packet() to
remove the above increments.
<cut>
> + /**
> + fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
> + connection
> + */
> + static void server_mpvio_info(MYSQL_PLUGIN_VIO *vio,
> + MYSQL_PLUGIN_VIO_INFO *info)
> + {
> + MPVIO_EXT *mpvio= (MPVIO_EXT*)vio;
> + mpvio_info(mpvio->thd->net.vio, info);
> + }
> +
> + static int acl_check_ssl(THD *thd, ACL_USER *acl_user)
int -> bool
Add function comment (at least regarding return values)
<cut>
> + /**
> + Perform the handshake, authorize the client and update thd sctx variables.
> +
> + @param thd thread handle
> + @param connect_errors number of previous failed connect attemps
> + from this host
> + @param com_change_user_pkt_len size of the COM_CHANGE_USER packet
> + (without the first, command, byte) or 0
> + if it's not a COM_CHANGE_USER (that is, if
> + it's a new connection)
> +
> + @retval 0 success, thd is updated.
> + @retval 1 error
> + */
> + int acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
int -> bool
> + {
> + DBUG_ENTER("acl_authenticate");
Add DBUG_ENTER() after variable declarations.
> + int res, old_status;
> + plugin_ref plugin;
> + MPVIO_EXT mpvio;
> + st_mysql_auth *auth;
> + LEX_STRING *auth_plugin_name= default_auth_plugin_name;
> + bool unlock_plugin;
> + enum enum_server_command command= com_change_user_pkt_len ? COM_CHANGE_USER
> + : COM_CONNECT;
> +
> + compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
> +
> + bzero(&mpvio, sizeof(mpvio));
> + mpvio.read_packet= server_mpvio_read_packet;
> + mpvio.write_packet= server_mpvio_write_packet;
> + mpvio.info= server_mpvio_info;
> + mpvio.thd= thd;
> + mpvio.connect_errors= connect_errors;
> + mpvio.status= MPVIO_EXT::FAILURE;
> +
> + if (com_change_user_pkt_len == 0)
> + thd->scramble[SCRAMBLE_LENGTH]= 1; // it means - there is no scramble yet
Wouldn't it be better to use a separate flag or state for this?
Using part of scramble, even if it's safe, looks strange and hard to
remember. Having a state in MPVIO_EXT of what has taken place could
be a good addition. This could be better than just incrementing
packets_written / packets_read (in the case we ever want to do more
round trips than 2)
> + else
> + {
> + mpvio.packets_written++; // pretend that a server handshake packet was sent
> + mpvio.packets_read++; // take COM_CHANGE_USER packet into account
> +
> + if (parse_com_change_user_packet(&mpvio, com_change_user_pkt_len))
> + DBUG_RETURN(1);
> +
> + DBUG_ASSERT(mpvio.status == MPVIO_EXT::RESTART ||
> + mpvio.status == MPVIO_EXT::SUCCESS);
> + /*
> + we skip the first step of the authentication -
> + the one that starts a default plugin, sends the handshake packet with the
> + scramble and reads the packet with the user name.
> + in COM_CHANGE_USER the client already has the scramble and we already
> + know the user name
> + */
> + goto skip_first;
Noe that 'res' and 'old_status' variables are not set here,
which may be a problem as they could be tested below.
> + }
> +
The 'goto's here are not nice.
A way to fix it is to move the code between 'retry' and 'skip_first'
to a function and use:
if (!mpvio.plugin= get_plugin(auth_plugin_name))
DBUG_RETURN(1);
In the above if and instead of 'goto retry'.
With this, you can remove both 'retry' and 'skip_first'
and replace this with a for (;;) loop.
> + retry:
> + unlock_plugin= false;
> + if (auth_plugin_name->str == native_password_plugin_name.str)
> + plugin= native_password_plugin;
> + else
> + #ifndef EMBEDDED_LIBRARY
> + if (auth_plugin_name->str == old_password_plugin_name.str)
> + plugin= old_password_plugin;
> + else
> + if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
> + MYSQL_AUTHENTICATION_PLUGIN)))
> + unlock_plugin= true;
> + else
> + #endif
> + {
> + /* Server cannot load required plugin. */
> + my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), auth_plugin_name->str);
> + DBUG_RETURN(1);
> + }
> +
> + mpvio.plugin= plugin;
> + auth= (st_mysql_auth*)plugin_decl(plugin)->info;
> +
> + old_status= mpvio.status;
> + res= auth->authenticate_user(&mpvio, &mpvio.auth_info);
> +
> + if (unlock_plugin)
> + plugin_unlock(thd, plugin);
> +
> + skip_first:
<cut>
> +
> + if (res > CR_OK && mpvio.status != MPVIO_EXT::SUCCESS)
How about res != CR_OK ? (More clear)
> + {
> + DBUG_ASSERT(mpvio.status == MPVIO_EXT::FAILURE);
> +
> + if (!thd->is_error())
> + login_failed_error(thd, thd->password);
> + DBUG_RETURN(1);
> + }
<cut>
> + if (command == COM_CONNECT &&
> + !(thd->main_security_ctx.master_access & SUPER_ACL))
> + {
> + pthread_mutex_lock(&LOCK_connection_count);
> + bool count_ok= (*thd->scheduler->connection_count <=
> + *thd->scheduler->max_connections);
Indentation...
> + VOID(pthread_mutex_unlock(&LOCK_connection_count));
> + if (!count_ok)
> + { // too many connections
> + my_error(ER_CON_COUNT_ERROR, MYF(0));
> + DBUG_RETURN(1);
> + }
> + }
> +
> + /*
> + This is the default access rights for the current database. It's
> + set to 0 here because we don't have an active database yet (and we
> + may not have an active database to set.
> + */
> + sctx->db_access=0;
> +
> + /* Change a database if necessary */
> + if (mpvio.db.length)
> + {
> + if (mysql_change_db(thd, &mpvio.db, FALSE))
> + {
> + /* mysql_change_db() has pushed the error message. */
> + if (thd->user_connect)
> + {
> + decrease_user_connections(thd->user_connect);
> + status_var_increment(thd->status_var.access_denied_errors);
> + thd->user_connect= 0;
Move this just after the test (easier to read)
> + }
> + DBUG_RETURN(1);
> + }
> + }
> + static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
> + MYSQL_SERVER_AUTH_INFO *info)
> + {
> + uchar *pkt;
> + int pkt_len;
> + MPVIO_EXT *mpvio=(MPVIO_EXT*)vio;
> + THD *thd=mpvio->thd;
> +
> + if (thd->scramble[SCRAMBLE_LENGTH])
> + {
> + /* no scramble was sent to the client yet, do it now */
> + create_random_string(thd->scramble,
> + pkt_len= SCRAMBLE_LENGTH, &thd->rand);
> + pkt= (uchar*)thd->scramble;
> + if (mpvio->write_packet(mpvio, pkt, pkt_len))
> + return CR_ERROR;
> + }
> +
> + /* ok, the client has got the scramble. read the reply and authenticate */
> + if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
> + return CR_ERROR;
> +
> + #ifdef NO_EMBEDDED_ACCESS_CHECKS
> + return CR_OK;
> + #endif
> +
> + /*
> + legacy: if switch_from_long_to_short_scramble,
> + the password is sent \0-terminated, the pkt_len is always 9 bytes.
> + We need to figure out the correct scramble length here.
> + */
> + if (pkt_len == SCRAMBLE_LENGTH_323+1)
> + pkt_len= strnlen((char*)pkt, pkt_len);
> + if (pkt_len == 0) /* no password */
> + return info->auth_string[0] ? CR_ERROR : CR_OK;
If we want to do things like in the old code, we should here check the
packet length.
if (pkt_len != SCRAMBLE_LENGTH_323)
{
inc_host_errors(&mpvio->thd->net.vio->remote.sin_addr);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return CR_ERROR;
}
> + If the server is running in secure auth mode, short scrambles are
> + forbidden. Extra juggling to report the same error as the old code.
> + */
> + if (opt_secure_auth)
> + {
> + if (thd->client_capabilities & CLIENT_PROTOCOL_41)
> + {
> + my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0),
> + thd->security_ctx->user,
> + thd->security_ctx->host_or_ip);
> + general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
> + thd->security_ctx->user,
> + thd->security_ctx->host_or_ip);
> + }
I think the above error should be tested for and given when we ask for
old scramble. This error is to be given when we get an new format
scramble at start when database has old.
Now we are likely to have a problem that if client sends new password
and server has old, we will request for old one, even if
opt_secure_auth is set, which is not how things worked before.
> + else
> + {
> + my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
> + general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
> + }
> + return CR_ERROR;
> + }
The old code (sql_connect.cc:check_user()) tested first for:
if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
And the other error condition next.
Here things are reversed so we may get other errors than from MySQL.
> +
> + info->password_used = 1;
> +
> + if (pkt_len == SCRAMBLE_LENGTH_323)
> + return check_scramble_323(pkt, thd->scramble,
> + (ulong *)mpvio->acl_user->salt) ? CR_ERROR : CR_OK;
> +
> + inc_host_errors(&mpvio->thd->net.vio->remote.sin_addr);
> + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
> + return CR_ERROR;
If we do the early check, we should of course remove the above if and
the error reporting
> + }
<cut>
> *** sql/sql_insert.cc 2010-02-01 06:14:12 +0000
> --- sql/sql_insert.cc 2010-02-19 08:18:09 +0000
> *************** public:
> *** 1769,1776 ****
> table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
> group_count(0)
> {
> ! thd.security_ctx->user=thd.security_ctx->priv_user=(char*) delayed_user;
> thd.security_ctx->host=(char*) my_localhost;
> thd.current_tablenr=0;
> thd.version=refresh_version;
> thd.command=COM_DELAYED_INSERT;
> --- 1769,1778 ----
> table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
> group_count(0)
> {
> ! thd.security_ctx->user=(char*) delayed_user;
> thd.security_ctx->host=(char*) my_localhost;
> + strmake(thd.security_ctx->priv_user, thd.security_ctx->user,
> + USERNAME_LENGTH);
A little better would be to use delayed_user above, but not that important.
> === modified file 'sql/sql_parse.cc'
> *** sql/sql_parse.cc 2010-02-01 06:14:12 +0000
> case COM_CHANGE_USER:
> {
> status_var_increment(thd->status_var.com_other);
>
> thd->change_user();
> thd->clear_error(); // if errors from rollback
>
> ! /* acl_authenticate() takes the data from net->read_pos */
> ! net->read_pos= (uchar*)packet;
>
> ! uint save_db_length= thd->db_length;
> ! char *save_db= thd->db;
> ! USER_CONN *save_user_connect= thd->user_connect;
> Security_context save_security_ctx= *thd->security_ctx;
> ! CHARSET_INFO *save_character_set_client=
> ! thd->variables.character_set_client;
> ! CHARSET_INFO *save_collation_connection=
> ! thd->variables.collation_connection;
> ! CHARSET_INFO *save_character_set_results=
> ! thd->variables.character_set_results;
Please move declarations to start of case (should make the above one liners)
>
> ! if (acl_authenticate(thd, 0, packet_length))
> {
> x_free(thd->security_ctx->user);
> *thd->security_ctx= save_security_ctx;
> thd->user_connect= save_user_connect;
> thd->db= save_db;
> thd->db_length= save_db_length;
Better to use:
thd->reset_db(save_db, save_db_length);
> + thd->variables.character_set_client= save_character_set_client;
> + thd->variables.collation_connection= save_collation_connection;
> + thd->variables.character_set_results= save_character_set_results;
> + thd->update_charset();
> }
> else
> {
> *** 4348,4355 ****
> if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
> lex->sql_command == SQLCOM_CREATE_PROCEDURE))
> push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> ! ER_PROC_AUTO_GRANT_FAIL,
> ! ER(ER_PROC_AUTO_GRANT_FAIL));
> }
>
> /*
> --- 4280,4287 ----
> if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
> lex->sql_command == SQLCOM_CREATE_PROCEDURE))
> push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> ! ER_PROC_AUTO_GRANT_FAIL, ER(ER_PROC_AUTO_GRANT_FAIL));
> ! thd->clear_error();
Don't understand why this is needed now, but I assume this isn't
critical to understand (except maybe it would be nice to ensure that
this is correct if sp_grant_privileges did get a out-of-memory error)
<cut>
Other things.
You need to add creation of auth_string to:
scripts/mysql_fix_privilege_tables.sql
In old_password_auth_client(), if we get an error from write_packet,
it would be good to do:
set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
ER(CR_SERVER_LOST_EXTENDED),
"sending password information",
errno);
See if you can combine common code from parse_com_change_user_packet()
and parse_client_handshake_packet().
It would also be nice to avoid comparison of strings and even string
pointers and instead compare objects (like pointer to plugin) and
values in plugin object (like if it's native or not).
Other than the above suggestions, it looked good and definitely
something we need!
Regards,
Monty
3
5
[Maria-developers] Updated (by Knielsen): Store in binlog text of statements that caused RBR events (47)
by worklog-noreply@askmonty.org 29 Mar '10
by worklog-noreply@askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Store in binlog text of statements that caused RBR events
CREATION DATE..: Sat, 15 Aug 2009, 23:48
SUPERVISOR.....: Monty
IMPLEMENTOR....:
COPIES TO......: Knielsen, Serg
CATEGORY.......: Server-Sprint
TASK ID........: 47 (http://askmonty.org/worklog/?tid=47)
VERSION........: Server-9.x
STATUS.........: Code-Review
PRIORITY.......: 60
WORKED HOURS...: 40
ESTIMATE.......: 15 (hours remain)
ORIG. ESTIMATE.: 35
PROGRESS NOTES:
-=-=(Knielsen - Mon, 29 Mar 2010, 10:59)=-=-
Status updated.
--- /tmp/wklog.47.old.27790 2010-03-29 10:59:53.000000000 +0000
+++ /tmp/wklog.47.new.27790 2010-03-29 10:59:53.000000000 +0000
@@ -1 +1 @@
-In-Progress
+Code-Review
-=-=(Alexi - Thu, 18 Feb 2010, 19:29)=-=-
Worked 20 hours (alexi)
Worked 20 hours and estimate 15 hours remain (original estimate unchanged).
-=-=(Serg - Fri, 05 Feb 2010, 14:04)=-=-
Observers changed: Knielsen,Serg
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Category updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Server-RawIdeaBin
+Server-Sprint
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Status updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Un-Assigned
+In-Progress
-=-=(Alexi - Thu, 04 Feb 2010, 09:54)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16174 2010-02-04 09:54:13.000000000 +0200
+++ /tmp/wklog.47.new.16174 2010-02-04 09:54:13.000000000 +0200
@@ -171,35 +171,20 @@
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When requesting an event, the slave should inform the master whether
-it should send Annotate_rows events or not. To that end we add a new
-BINLOG_SEND_ANNOTATE_ROWS_EVENT flag used when requesting an event:
+If the replicate-annotate-rows-events option is not set on a slave, there
+is no need for master to send Annotate_rows events to this slave. The slave
+(or mysqlbinlog in remote case), before requesting binlog dump via the
+COM_BINLOG_DUMP command, informs the master whether it should send these
+events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
+command:
+
+ case COM_BINLOG_DUMP_OPTIONS_EXT:
+ thd->binlog_dump_flags_ext= packet[0];
+ my_ok(thd);
+ break;
- #define BINLOG_DUMP_NON_BLOCK 1
- #define BINLOG_SEND_ANNOTATE_ROWS_EVENT 2
-
- pthread_handler_t handle_slave_io(void *arg)
- { ...
- request_dump(mysql, ...);
- ...
- }
-
- int request_dump(MYSQL* mysql, ...)
- { ...
- if (opt_log_slave_updates &&
- mi->io_thd->variables.binlog_annotate_rows_events)
- binlog_flags|= BINLOG_SEND_ANNOTATE_ROWS_EVENT;
- ...
- int2store(buf + 4, binlog_flags);
- ...
- simple_command(mysql, COM_BINLOG_DUMP, buf, ...);
- ...
- }
-
-NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
-simple_command() function, should also use this flag if it wants (in case
-of the --print-annotate-rows-events option set) to recieve Annotate_rows
-events.
+Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
+conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -338,10 +323,4 @@
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
-Also we should notice the introduction of the BINLOG_SEND_ANNOTATE_ROWS_EVENT
-flag taking into account that MySQL/Sun may also introduce a flag with the
-same value to be used in the request_dump-mysql_binlog_send interface.
-But this is mainly the question of merging: if a conflict concerning this
-flag occur, we may simply change the BINLOG_SEND_ANNOTATE_ROWS_EVENT value
-(this does not require additional changes in the code).
-=-=(Alexi - Sun, 20 Dec 2009, 16:00)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.19667 2009-12-20 14:00:56.000000000 +0000
+++ /tmp/wklog.47.new.19667 2009-12-20 14:00:56.000000000 +0000
@@ -196,6 +196,11 @@
...
}
+NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
+simple_command() function, should also use this flag if it wants (in case
+of the --print-annotate-rows-events option set) to recieve Annotate_rows
+events.
+
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -212,8 +217,7 @@
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
- flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT ||
- thd->server_id == 0 /* slave == mysqlbinlog */ )
+ flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
-=-=(Alexi - Sun, 20 Dec 2009, 13:14)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.11350 2009-12-20 13:14:04.000000000 +0200
+++ /tmp/wklog.47.new.11350 2009-12-20 13:14:04.000000000 +0200
@@ -282,23 +282,18 @@
Annotate_rows_log_event* m_annotate_event;
};
-When the saved Annotate_rows object may be deleted? When all corresponding
-Rows events will be processed, i.e. before processing the first non-Rows
-event (note that Annotate_rows object resides in the binary log *after*
-the (possible) 'BEGIN' Query event which accompanies the rows events; note
-also that this deletion is adjusted with the case when some or all
-corresponding Rows events are filtered out by replicate filter rules):
+The saved Annotate_rows object should be deleted when all corresponding
+Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
- if (rli->get_annotate_event() && !IS_RBR_EVENT_TYPE(ev->get_type_code()))
- rli->free_annotate_event();
-
apply_event_and_update_pos(ev, ...);
- if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
+ if (rli->get_annotate_event() && is_last_rows_event(ev))
+ rli->free_annotate_event();
+ else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
@@ -307,10 +302,21 @@
where
- #define IS_RBR_EVENT_TYPE(type) ( (type) == TABLE_MAP_EVENT || \
- (type) == WRITE_ROWS_EVENT || \
+ bool is_last_rows_event(Log_event* ev)
+ {
+ Log_event_type type= ev->get_type_code();
+ if (IS_ROWS_EVENT_TYPE(type))
+ {
+ Rows_log_event* rows= (Rows_log_event*)ev;
+ return rows->get_flags(Rows_log_event::STMT_END_F);
+ }
+
+ return 0;
+ }
+
+ #define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
- (type) == DELETE_ROWS_EVENT )
+ (type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
-=-=(Alexi - Sun, 20 Dec 2009, 09:29)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.32726 2009-12-20 07:29:56.000000000 +0000
+++ /tmp/wklog.47.new.32726 2009-12-20 07:29:56.000000000 +0000
@@ -56,7 +56,7 @@
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
- 00000082 | 00 | 0 - ANNOTATE_RBR_EVENT [51]
+ 00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
-=-=(Alexi - Sat, 19 Dec 2009, 16:10)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16051 2009-12-19 16:10:48.000000000 +0200
+++ /tmp/wklog.47.new.16051 2009-12-19 16:10:48.000000000 +0200
@@ -253,7 +253,7 @@
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
-Rows events is applied):
+Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
------------------------------------------------------------
-=-=(View All Progress Notes, 25 total)=-=-
http://askmonty.org/worklog/index.pl?tid=47&nolimit=1
DESCRIPTION:
Store in binlog (and show in mysqlbinlog output) texts of statements that
caused RBR events
This is needed for (list from Monty):
- Easier to understand why updates happened
- Would make it easier to find out where in application things went
wrong (as you can search for exact strings)
- Allow one to filter things based on comments in the statement.
The cost of this can be that the binlog will be approximately 2x in size
(especially insert of big blob's would be a bit painful), so this should
be an optional feature.
HIGH-LEVEL SPECIFICATION:
Content
~~~~~~~
1. Annotate_rows_log_event
2. Server option: --binlog-annotate-rows-events
3. Server option: --replicate-annotate-rows-events
4. mysqlbinlog option: --print-annotate-rows-events
5. mysqlbinlog output
1. Annotate_rows_log_event [ ANNOTATE_ROWS_EVENT ]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Describes the query which caused the corresponding rows events. Has empty
post-header and contains the query text in its data part. Example:
************************
ANNOTATE_ROWS_EVENT
************************
00000220 | B6 A0 2C 4B | time_when = 1261215926
00000224 | 33 | event_type = 51
00000225 | 64 00 00 00 | server_id = 100
00000229 | 36 00 00 00 | event_len = 54
0000022D | 56 02 00 00 | log_pos = 00000256
00000231 | 00 00 | flags = <none>
------------------------
00000233 | 49 4E 53 45 | query = "INSERT INTO t1 VALUES (1), (2), (3)"
00000237 | 52 54 20 49 |
0000023B | 4E 54 4F 20 |
0000023F | 74 31 20 56 |
00000243 | 41 4C 55 45 |
00000247 | 53 20 28 31 |
0000024B | 29 2C 20 28 |
0000024F | 32 29 2C 20 |
00000253 | 28 33 29 |
************************
In binary log, Annotate_rows event follows the (possible) 'BEGIN' Query event
and precedes the first of Table map events which accompany the corresponding
rows events. (See example in the "mysqlbinlog output" section below.)
2. Server option: --binlog-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the master to write Annotate_rows events to the binary log.
* Variable Name: binlog_annotate_rows_events
* Scope: Global & Session
* Access Type: Dynamic
* Data Type: bool
* Default Value: OFF
NOTE. Session values allows to annotate only some selected statements:
...
SET SESSION binlog_annotate_rows_events=ON;
... statements to be annotated ...
SET SESSION binlog_annotate_rows_events=OFF;
... statements not to be annotated ...
3. Server option: --replicate-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the slave to reproduce Annotate_rows events recieved from the master
in its own binary log (sensible only in pair with log-slave-updates option).
* Variable Name: replicate_annotate_rows_events
* Scope: Global
* Access Type: Read only
* Data Type: bool
* Default Value: OFF
NOTE. Why do we additionally need this 'replicate' option? Why not to make
the slave to reproduce this events when its binlog-annotate-rows-events
global value is ON? Well, because, for example, we may want to configure
the slave which should reproduce Annotate_rows events but has global
binlog-annotate-rows-events = OFF meaning this to be the default value for
the client threads (see also "How slave treats replicate-annotate-rows-events
option" in LLD part).
4. mysqlbinlog option: --print-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With this option, mysqlbinlog prints the content of Annotate_rows events (if
the binary log does contain them). Without this option (i.e. by default),
mysqlbinlog skips Annotate_rows events.
5. mysqlbinlog output
~~~~~~~~~~~~~~~~~~~~~
With --print-annotate-rows-events, mysqlbinlog outputs Annotate_rows events
in a form like this:
...
# at 1646
#091219 12:45:26 server id 100 end_log_pos 1714 Query thread_id=1
exec_time=0 error_code=0
SET TIMESTAMP=1261215926/*!*/;
BEGIN
/*!*/;
# at 1714
# at 1812
# at 1853
# at 1894
# at 1938
#091219 12:45:26 server id 100 end_log_pos 1812 Query: `DELETE t1, t2 FROM
t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.a=t2.a AND t2.a=t3.a`
#091219 12:45:26 server id 100 end_log_pos 1853 Table_map: `test`.`t1`
mapped to number 16
#091219 12:45:26 server id 100 end_log_pos 1894 Table_map: `test`.`t2`
mapped to number 17
#091219 12:45:26 server id 100 end_log_pos 1938 Delete_rows: table id 16
#091219 12:45:26 server id 100 end_log_pos 1982 Delete_rows: table id 17
flags: STMT_END_F
...
LOW-LEVEL DESIGN:
Content
~~~~~~~
1. Annotate_rows event number
2. Outline of Annotate_rows event behavior
3. How Master writes Annotate_rows events to the binary log
4. How slave treats replicate-annotate-rows-events option
5. How slave IO thread requests Annotate_rows events
6. How master executes the request
7. How slave SQL thread processes Annotate_rows events
8. General remarks
1. Annotate_rows event number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To avoid possible event numbers conflict with MySQL/Sun, we leave a gap
between the last MySQL event number and the Annotate_rows event number:
enum Log_event_type
{ ...
INCIDENT_EVENT= 26,
// New MySQL event numbers are to be added here
MYSQL_EVENTS_END,
MARIA_EVENTS_BEGIN= 51,
// New Maria event numbers start from here
ANNOTATE_ROWS_EVENT= 51,
ENUM_END_EVENT
};
together with the corresponding extension of 'post_header_len' array in the
Format description event. (This extension does not affect the compatibility
of the binary log). Here is how Format description event looks like with
this extension:
************************
FORMAT_DESCRIPTION_EVENT
************************
00000004 | A1 A0 2C 4B | time_when = 1261215905
00000008 | 0F | event_type = 15
00000009 | 64 00 00 00 | server_id = 100
0000000D | 7F 00 00 00 | event_len = 127
00000011 | 83 00 00 00 | log_pos = 00000083
00000015 | 01 00 | flags = LOG_EVENT_BINLOG_IN_USE_F
------------------------
00000017 | 04 00 | binlog_ver = 4
00000019 | 35 2E 32 2E | server_ver = 5.2.0-MariaDB-alpha-debug-log
..... ...
0000004B | A1 A0 2C 4B | time_created = 1261215905
0000004F | 13 | common_header_len = 19
------------------------
post_header_len
------------------------
00000050 | 38 | 56 - START_EVENT_V3 [1]
..... ...
00000069 | 02 | 2 - INCIDENT_EVENT [26]
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each Annotate_rows_log_event object has two private members describing the
corresponding query:
char *m_query_txt;
uint m_query_len;
When the object is created for writing to a binary log, this query is taken
from 'thd' (for short, below we omit the 'Annotate_rows_log_event::' prefix
as well as other implementation details):
Annotate_rows_log_event(THD *thd)
{
m_query_txt = thd->query();
m_query_len = thd->query_length();
}
When the object is read from a binary log, the query is taken from the buffer
containing the binary log representation of the event (this buffer is allocated
in Log_event object from which all Log events are derived):
Annotate_rows_log_event(char *buf, uint event_len,
Format_description_log_event *desc)
{
m_query_len = event_len - desc->common_header_len;
m_query_txt = buf + desc->common_header_len;
}
The events are written to the binary log by the Log_event::write() member
which calls virtual write_data_header() and write_data_body() members
("data header" and "post header" are synonym in replication terminology).
In our case, data header is empty and data body is just the query:
bool write_data_body(IO_CACHE *file)
{
return my_b_safe_write(file, (uchar*) m_query_txt, m_query_len);
}
Printing the event is just printing the query:
void Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
{
my_b_printf(&pinfo->head_cache, "\tQuery: `%s`\n", m_query_txt);
}
3. How Master writes Annotate_rows events to the binary log
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The event is written to the binary log just before the group of Table_map
events which precede corresponding Rows events (one query may generate
several Table map events in the binary log, but the corresponding
Annotate_rows event must be written only once before the first Table map
event; hence the boolean variable 'with_annotate' below):
int write_locked_table_maps(THD *thd)
{ ...
bool with_annotate= thd->variables.binlog_annotate_rows_events;
...
for (uint i= 0; i < ... <number of tables> ...; ++i)
{ ...
thd->binlog_write_table_map(table, ..., with_annotate);
with_annotate= 0; // write Annotate_event not more than once
...
}
...
}
int THD::binlog_write_table_map(TABLE *table, ..., bool with_annotate)
{ ...
Table_map_log_event the_event(...);
...
if (with_annotate)
{
Annotate_rows_log_event anno(this);
mysql_bin_log.write(&anno);
}
mysql_bin_log.write(&the_event);
...
}
4. How slave treats replicate-annotate-rows-events option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The replicate-annotate-rows-events option is treated just as the session
value of the binlog_annotate_rows_events variable for the slave IO and
SQL threads. This setting is done during initialization of these threads:
pthread_handler_t handle_slave_io(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_IO);
...
}
pthread_handler_t handle_slave_sql(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_SQL);
...
}
int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
{ ...
thd->variables.binlog_annotate_rows_events=
opt_replicate_annotate_rows_events;
...
}
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the replicate-annotate-rows-events option is not set on a slave, there
is no need for master to send Annotate_rows events to this slave. The slave
(or mysqlbinlog in remote case), before requesting binlog dump via the
COM_BINLOG_DUMP command, informs the master whether it should send these
events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
command:
case COM_BINLOG_DUMP_OPTIONS_EXT:
thd->binlog_dump_flags_ext= packet[0];
my_ok(thd);
break;
Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
case COM_BINLOG_DUMP:
{ ...
flags= uint2korr(packet + 4);
...
mysql_binlog_send(thd, ..., flags);
...
}
void mysql_binlog_send(THD* thd, ..., ushort flags)
{ ...
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
...
}
7. How slave SQL thread processes Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The slave processes each recieved event by "applying" it, i.e. by
calling the Log_event::apply_event() function which in turn calls
the virtual do_apply_event() member specific for each type of the
event.
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev = next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
int apply_event_and_update_pos(Log_event *ev, ...)
{ ...
ev->apply_event(...);
...
}
int Log_event::apply_event(...)
{
return do_apply_event(...);
}
What does it mean to "apply" an Annotate_rows event? It means to set current
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
thd->set_query(m_query_txt, m_query_len);
}
NOTE. I am not sure, but possibly current values of thd->query and
thd->query_length should be saved before calling set_query() and to be
restored on the Annotate_rows_log_event object deletion.
Is it really needed ?
After calling this do_apply_event() function we may not delete the
Annotate_rows_log_event object immediatedly (see exec_relay_log_event()
above) because thd->query now points to the string inside this object.
We may keep the pointer to this object in the Relay_log_info:
class Relay_log_info
{
public:
...
void set_annotate_event(Annotate_rows_log_event*);
Annotate_rows_log_event* get_annotate_event();
void free_annotate_event();
...
private:
Annotate_rows_log_event* m_annotate_event;
};
The saved Annotate_rows object should be deleted when all corresponding
Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (rli->get_annotate_event() && is_last_rows_event(ev))
rli->free_annotate_event();
else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
where
bool is_last_rows_event(Log_event* ev)
{
Log_event_type type= ev->get_type_code();
if (IS_ROWS_EVENT_TYPE(type))
{
Rows_log_event* rows= (Rows_log_event*)ev;
return rows->get_flags(Rows_log_event::STMT_END_F);
}
return 0;
}
#define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
(type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
Kristian noticed that introducing new log event type should be coordinated
somehow with MySQL/Sun:
Kristian: The numeric code for this event must be assigned carefully.
It should be coordinated with MySQL/Sun, otherwise we can get into a
situation where MySQL uses the same numeric code for one event that
MariaDB uses for ANNOTATE_ROWS_EVENT, which would make merging the two
impossible.
Alex: I reserved about 20 numbers not to have possible conflicts
with MySQL.
Kristian: Still, I think it would be appropriate to send a polite email
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0
[Maria-developers] Updated (by Knielsen): Store in binlog text of statements that caused RBR events (47)
by worklog-noreply@askmonty.org 29 Mar '10
by worklog-noreply@askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Store in binlog text of statements that caused RBR events
CREATION DATE..: Sat, 15 Aug 2009, 23:48
SUPERVISOR.....: Monty
IMPLEMENTOR....:
COPIES TO......: Knielsen, Serg
CATEGORY.......: Server-Sprint
TASK ID........: 47 (http://askmonty.org/worklog/?tid=47)
VERSION........: Server-9.x
STATUS.........: Code-Review
PRIORITY.......: 60
WORKED HOURS...: 40
ESTIMATE.......: 15 (hours remain)
ORIG. ESTIMATE.: 35
PROGRESS NOTES:
-=-=(Knielsen - Mon, 29 Mar 2010, 10:59)=-=-
Status updated.
--- /tmp/wklog.47.old.27790 2010-03-29 10:59:53.000000000 +0000
+++ /tmp/wklog.47.new.27790 2010-03-29 10:59:53.000000000 +0000
@@ -1 +1 @@
-In-Progress
+Code-Review
-=-=(Alexi - Thu, 18 Feb 2010, 19:29)=-=-
Worked 20 hours (alexi)
Worked 20 hours and estimate 15 hours remain (original estimate unchanged).
-=-=(Serg - Fri, 05 Feb 2010, 14:04)=-=-
Observers changed: Knielsen,Serg
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Category updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Server-RawIdeaBin
+Server-Sprint
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Status updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Un-Assigned
+In-Progress
-=-=(Alexi - Thu, 04 Feb 2010, 09:54)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16174 2010-02-04 09:54:13.000000000 +0200
+++ /tmp/wklog.47.new.16174 2010-02-04 09:54:13.000000000 +0200
@@ -171,35 +171,20 @@
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When requesting an event, the slave should inform the master whether
-it should send Annotate_rows events or not. To that end we add a new
-BINLOG_SEND_ANNOTATE_ROWS_EVENT flag used when requesting an event:
+If the replicate-annotate-rows-events option is not set on a slave, there
+is no need for master to send Annotate_rows events to this slave. The slave
+(or mysqlbinlog in remote case), before requesting binlog dump via the
+COM_BINLOG_DUMP command, informs the master whether it should send these
+events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
+command:
+
+ case COM_BINLOG_DUMP_OPTIONS_EXT:
+ thd->binlog_dump_flags_ext= packet[0];
+ my_ok(thd);
+ break;
- #define BINLOG_DUMP_NON_BLOCK 1
- #define BINLOG_SEND_ANNOTATE_ROWS_EVENT 2
-
- pthread_handler_t handle_slave_io(void *arg)
- { ...
- request_dump(mysql, ...);
- ...
- }
-
- int request_dump(MYSQL* mysql, ...)
- { ...
- if (opt_log_slave_updates &&
- mi->io_thd->variables.binlog_annotate_rows_events)
- binlog_flags|= BINLOG_SEND_ANNOTATE_ROWS_EVENT;
- ...
- int2store(buf + 4, binlog_flags);
- ...
- simple_command(mysql, COM_BINLOG_DUMP, buf, ...);
- ...
- }
-
-NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
-simple_command() function, should also use this flag if it wants (in case
-of the --print-annotate-rows-events option set) to recieve Annotate_rows
-events.
+Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
+conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -338,10 +323,4 @@
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
-Also we should notice the introduction of the BINLOG_SEND_ANNOTATE_ROWS_EVENT
-flag taking into account that MySQL/Sun may also introduce a flag with the
-same value to be used in the request_dump-mysql_binlog_send interface.
-But this is mainly the question of merging: if a conflict concerning this
-flag occur, we may simply change the BINLOG_SEND_ANNOTATE_ROWS_EVENT value
-(this does not require additional changes in the code).
-=-=(Alexi - Sun, 20 Dec 2009, 16:00)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.19667 2009-12-20 14:00:56.000000000 +0000
+++ /tmp/wklog.47.new.19667 2009-12-20 14:00:56.000000000 +0000
@@ -196,6 +196,11 @@
...
}
+NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
+simple_command() function, should also use this flag if it wants (in case
+of the --print-annotate-rows-events option set) to recieve Annotate_rows
+events.
+
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -212,8 +217,7 @@
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
- flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT ||
- thd->server_id == 0 /* slave == mysqlbinlog */ )
+ flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
-=-=(Alexi - Sun, 20 Dec 2009, 13:14)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.11350 2009-12-20 13:14:04.000000000 +0200
+++ /tmp/wklog.47.new.11350 2009-12-20 13:14:04.000000000 +0200
@@ -282,23 +282,18 @@
Annotate_rows_log_event* m_annotate_event;
};
-When the saved Annotate_rows object may be deleted? When all corresponding
-Rows events will be processed, i.e. before processing the first non-Rows
-event (note that Annotate_rows object resides in the binary log *after*
-the (possible) 'BEGIN' Query event which accompanies the rows events; note
-also that this deletion is adjusted with the case when some or all
-corresponding Rows events are filtered out by replicate filter rules):
+The saved Annotate_rows object should be deleted when all corresponding
+Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
- if (rli->get_annotate_event() && !IS_RBR_EVENT_TYPE(ev->get_type_code()))
- rli->free_annotate_event();
-
apply_event_and_update_pos(ev, ...);
- if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
+ if (rli->get_annotate_event() && is_last_rows_event(ev))
+ rli->free_annotate_event();
+ else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
@@ -307,10 +302,21 @@
where
- #define IS_RBR_EVENT_TYPE(type) ( (type) == TABLE_MAP_EVENT || \
- (type) == WRITE_ROWS_EVENT || \
+ bool is_last_rows_event(Log_event* ev)
+ {
+ Log_event_type type= ev->get_type_code();
+ if (IS_ROWS_EVENT_TYPE(type))
+ {
+ Rows_log_event* rows= (Rows_log_event*)ev;
+ return rows->get_flags(Rows_log_event::STMT_END_F);
+ }
+
+ return 0;
+ }
+
+ #define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
- (type) == DELETE_ROWS_EVENT )
+ (type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
-=-=(Alexi - Sun, 20 Dec 2009, 09:29)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.32726 2009-12-20 07:29:56.000000000 +0000
+++ /tmp/wklog.47.new.32726 2009-12-20 07:29:56.000000000 +0000
@@ -56,7 +56,7 @@
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
- 00000082 | 00 | 0 - ANNOTATE_RBR_EVENT [51]
+ 00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
-=-=(Alexi - Sat, 19 Dec 2009, 16:10)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16051 2009-12-19 16:10:48.000000000 +0200
+++ /tmp/wklog.47.new.16051 2009-12-19 16:10:48.000000000 +0200
@@ -253,7 +253,7 @@
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
-Rows events is applied):
+Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
------------------------------------------------------------
-=-=(View All Progress Notes, 25 total)=-=-
http://askmonty.org/worklog/index.pl?tid=47&nolimit=1
DESCRIPTION:
Store in binlog (and show in mysqlbinlog output) texts of statements that
caused RBR events
This is needed for (list from Monty):
- Easier to understand why updates happened
- Would make it easier to find out where in application things went
wrong (as you can search for exact strings)
- Allow one to filter things based on comments in the statement.
The cost of this can be that the binlog will be approximately 2x in size
(especially insert of big blob's would be a bit painful), so this should
be an optional feature.
HIGH-LEVEL SPECIFICATION:
Content
~~~~~~~
1. Annotate_rows_log_event
2. Server option: --binlog-annotate-rows-events
3. Server option: --replicate-annotate-rows-events
4. mysqlbinlog option: --print-annotate-rows-events
5. mysqlbinlog output
1. Annotate_rows_log_event [ ANNOTATE_ROWS_EVENT ]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Describes the query which caused the corresponding rows events. Has empty
post-header and contains the query text in its data part. Example:
************************
ANNOTATE_ROWS_EVENT
************************
00000220 | B6 A0 2C 4B | time_when = 1261215926
00000224 | 33 | event_type = 51
00000225 | 64 00 00 00 | server_id = 100
00000229 | 36 00 00 00 | event_len = 54
0000022D | 56 02 00 00 | log_pos = 00000256
00000231 | 00 00 | flags = <none>
------------------------
00000233 | 49 4E 53 45 | query = "INSERT INTO t1 VALUES (1), (2), (3)"
00000237 | 52 54 20 49 |
0000023B | 4E 54 4F 20 |
0000023F | 74 31 20 56 |
00000243 | 41 4C 55 45 |
00000247 | 53 20 28 31 |
0000024B | 29 2C 20 28 |
0000024F | 32 29 2C 20 |
00000253 | 28 33 29 |
************************
In binary log, Annotate_rows event follows the (possible) 'BEGIN' Query event
and precedes the first of Table map events which accompany the corresponding
rows events. (See example in the "mysqlbinlog output" section below.)
2. Server option: --binlog-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the master to write Annotate_rows events to the binary log.
* Variable Name: binlog_annotate_rows_events
* Scope: Global & Session
* Access Type: Dynamic
* Data Type: bool
* Default Value: OFF
NOTE. Session values allows to annotate only some selected statements:
...
SET SESSION binlog_annotate_rows_events=ON;
... statements to be annotated ...
SET SESSION binlog_annotate_rows_events=OFF;
... statements not to be annotated ...
3. Server option: --replicate-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the slave to reproduce Annotate_rows events recieved from the master
in its own binary log (sensible only in pair with log-slave-updates option).
* Variable Name: replicate_annotate_rows_events
* Scope: Global
* Access Type: Read only
* Data Type: bool
* Default Value: OFF
NOTE. Why do we additionally need this 'replicate' option? Why not to make
the slave to reproduce this events when its binlog-annotate-rows-events
global value is ON? Well, because, for example, we may want to configure
the slave which should reproduce Annotate_rows events but has global
binlog-annotate-rows-events = OFF meaning this to be the default value for
the client threads (see also "How slave treats replicate-annotate-rows-events
option" in LLD part).
4. mysqlbinlog option: --print-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With this option, mysqlbinlog prints the content of Annotate_rows events (if
the binary log does contain them). Without this option (i.e. by default),
mysqlbinlog skips Annotate_rows events.
5. mysqlbinlog output
~~~~~~~~~~~~~~~~~~~~~
With --print-annotate-rows-events, mysqlbinlog outputs Annotate_rows events
in a form like this:
...
# at 1646
#091219 12:45:26 server id 100 end_log_pos 1714 Query thread_id=1
exec_time=0 error_code=0
SET TIMESTAMP=1261215926/*!*/;
BEGIN
/*!*/;
# at 1714
# at 1812
# at 1853
# at 1894
# at 1938
#091219 12:45:26 server id 100 end_log_pos 1812 Query: `DELETE t1, t2 FROM
t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.a=t2.a AND t2.a=t3.a`
#091219 12:45:26 server id 100 end_log_pos 1853 Table_map: `test`.`t1`
mapped to number 16
#091219 12:45:26 server id 100 end_log_pos 1894 Table_map: `test`.`t2`
mapped to number 17
#091219 12:45:26 server id 100 end_log_pos 1938 Delete_rows: table id 16
#091219 12:45:26 server id 100 end_log_pos 1982 Delete_rows: table id 17
flags: STMT_END_F
...
LOW-LEVEL DESIGN:
Content
~~~~~~~
1. Annotate_rows event number
2. Outline of Annotate_rows event behavior
3. How Master writes Annotate_rows events to the binary log
4. How slave treats replicate-annotate-rows-events option
5. How slave IO thread requests Annotate_rows events
6. How master executes the request
7. How slave SQL thread processes Annotate_rows events
8. General remarks
1. Annotate_rows event number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To avoid possible event numbers conflict with MySQL/Sun, we leave a gap
between the last MySQL event number and the Annotate_rows event number:
enum Log_event_type
{ ...
INCIDENT_EVENT= 26,
// New MySQL event numbers are to be added here
MYSQL_EVENTS_END,
MARIA_EVENTS_BEGIN= 51,
// New Maria event numbers start from here
ANNOTATE_ROWS_EVENT= 51,
ENUM_END_EVENT
};
together with the corresponding extension of 'post_header_len' array in the
Format description event. (This extension does not affect the compatibility
of the binary log). Here is how Format description event looks like with
this extension:
************************
FORMAT_DESCRIPTION_EVENT
************************
00000004 | A1 A0 2C 4B | time_when = 1261215905
00000008 | 0F | event_type = 15
00000009 | 64 00 00 00 | server_id = 100
0000000D | 7F 00 00 00 | event_len = 127
00000011 | 83 00 00 00 | log_pos = 00000083
00000015 | 01 00 | flags = LOG_EVENT_BINLOG_IN_USE_F
------------------------
00000017 | 04 00 | binlog_ver = 4
00000019 | 35 2E 32 2E | server_ver = 5.2.0-MariaDB-alpha-debug-log
..... ...
0000004B | A1 A0 2C 4B | time_created = 1261215905
0000004F | 13 | common_header_len = 19
------------------------
post_header_len
------------------------
00000050 | 38 | 56 - START_EVENT_V3 [1]
..... ...
00000069 | 02 | 2 - INCIDENT_EVENT [26]
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each Annotate_rows_log_event object has two private members describing the
corresponding query:
char *m_query_txt;
uint m_query_len;
When the object is created for writing to a binary log, this query is taken
from 'thd' (for short, below we omit the 'Annotate_rows_log_event::' prefix
as well as other implementation details):
Annotate_rows_log_event(THD *thd)
{
m_query_txt = thd->query();
m_query_len = thd->query_length();
}
When the object is read from a binary log, the query is taken from the buffer
containing the binary log representation of the event (this buffer is allocated
in Log_event object from which all Log events are derived):
Annotate_rows_log_event(char *buf, uint event_len,
Format_description_log_event *desc)
{
m_query_len = event_len - desc->common_header_len;
m_query_txt = buf + desc->common_header_len;
}
The events are written to the binary log by the Log_event::write() member
which calls virtual write_data_header() and write_data_body() members
("data header" and "post header" are synonym in replication terminology).
In our case, data header is empty and data body is just the query:
bool write_data_body(IO_CACHE *file)
{
return my_b_safe_write(file, (uchar*) m_query_txt, m_query_len);
}
Printing the event is just printing the query:
void Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
{
my_b_printf(&pinfo->head_cache, "\tQuery: `%s`\n", m_query_txt);
}
3. How Master writes Annotate_rows events to the binary log
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The event is written to the binary log just before the group of Table_map
events which precede corresponding Rows events (one query may generate
several Table map events in the binary log, but the corresponding
Annotate_rows event must be written only once before the first Table map
event; hence the boolean variable 'with_annotate' below):
int write_locked_table_maps(THD *thd)
{ ...
bool with_annotate= thd->variables.binlog_annotate_rows_events;
...
for (uint i= 0; i < ... <number of tables> ...; ++i)
{ ...
thd->binlog_write_table_map(table, ..., with_annotate);
with_annotate= 0; // write Annotate_event not more than once
...
}
...
}
int THD::binlog_write_table_map(TABLE *table, ..., bool with_annotate)
{ ...
Table_map_log_event the_event(...);
...
if (with_annotate)
{
Annotate_rows_log_event anno(this);
mysql_bin_log.write(&anno);
}
mysql_bin_log.write(&the_event);
...
}
4. How slave treats replicate-annotate-rows-events option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The replicate-annotate-rows-events option is treated just as the session
value of the binlog_annotate_rows_events variable for the slave IO and
SQL threads. This setting is done during initialization of these threads:
pthread_handler_t handle_slave_io(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_IO);
...
}
pthread_handler_t handle_slave_sql(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_SQL);
...
}
int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
{ ...
thd->variables.binlog_annotate_rows_events=
opt_replicate_annotate_rows_events;
...
}
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the replicate-annotate-rows-events option is not set on a slave, there
is no need for master to send Annotate_rows events to this slave. The slave
(or mysqlbinlog in remote case), before requesting binlog dump via the
COM_BINLOG_DUMP command, informs the master whether it should send these
events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
command:
case COM_BINLOG_DUMP_OPTIONS_EXT:
thd->binlog_dump_flags_ext= packet[0];
my_ok(thd);
break;
Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
case COM_BINLOG_DUMP:
{ ...
flags= uint2korr(packet + 4);
...
mysql_binlog_send(thd, ..., flags);
...
}
void mysql_binlog_send(THD* thd, ..., ushort flags)
{ ...
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
...
}
7. How slave SQL thread processes Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The slave processes each recieved event by "applying" it, i.e. by
calling the Log_event::apply_event() function which in turn calls
the virtual do_apply_event() member specific for each type of the
event.
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev = next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
int apply_event_and_update_pos(Log_event *ev, ...)
{ ...
ev->apply_event(...);
...
}
int Log_event::apply_event(...)
{
return do_apply_event(...);
}
What does it mean to "apply" an Annotate_rows event? It means to set current
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
thd->set_query(m_query_txt, m_query_len);
}
NOTE. I am not sure, but possibly current values of thd->query and
thd->query_length should be saved before calling set_query() and to be
restored on the Annotate_rows_log_event object deletion.
Is it really needed ?
After calling this do_apply_event() function we may not delete the
Annotate_rows_log_event object immediatedly (see exec_relay_log_event()
above) because thd->query now points to the string inside this object.
We may keep the pointer to this object in the Relay_log_info:
class Relay_log_info
{
public:
...
void set_annotate_event(Annotate_rows_log_event*);
Annotate_rows_log_event* get_annotate_event();
void free_annotate_event();
...
private:
Annotate_rows_log_event* m_annotate_event;
};
The saved Annotate_rows object should be deleted when all corresponding
Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (rli->get_annotate_event() && is_last_rows_event(ev))
rli->free_annotate_event();
else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
where
bool is_last_rows_event(Log_event* ev)
{
Log_event_type type= ev->get_type_code();
if (IS_ROWS_EVENT_TYPE(type))
{
Rows_log_event* rows= (Rows_log_event*)ev;
return rows->get_flags(Rows_log_event::STMT_END_F);
}
return 0;
}
#define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
(type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
Kristian noticed that introducing new log event type should be coordinated
somehow with MySQL/Sun:
Kristian: The numeric code for this event must be assigned carefully.
It should be coordinated with MySQL/Sun, otherwise we can get into a
situation where MySQL uses the same numeric code for one event that
MariaDB uses for ANNOTATE_ROWS_EVENT, which would make merging the two
impossible.
Alex: I reserved about 20 numbers not to have possible conflicts
with MySQL.
Kristian: Still, I think it would be appropriate to send a polite email
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0