Merge remote-tracking branch 'origin/bb-10.2-ext' into 10.3

This commit is contained in:
Alexander Barkov 2017-04-07 20:10:18 +04:00
commit 3edfe79712
124 changed files with 8380 additions and 639 deletions

View File

@ -48,6 +48,8 @@
#define HA_OPEN_INTERNAL_TABLE 512U
#define HA_OPEN_NO_PSI_CALL 1024U /* Don't call/connect PSI */
#define HA_OPEN_MERGE_TABLE 2048U
#define HA_OPEN_FOR_CREATE 4096U
/*
Allow opening even if table is incompatible as this is for ALTER TABLE which
will fix the table structure.
@ -351,6 +353,7 @@ enum ha_base_keytype {
#define HA_CREATE_RELIES_ON_SQL_LAYER 128U
#define HA_CREATE_INTERNAL_TABLE 256U
#define HA_PRESERVE_INSERT_ORDER 512U
#define HA_CREATE_NO_ROLLBACK 1024U
/* Flags used by start_bulk_insert */
@ -500,7 +503,9 @@ enum ha_base_keytype {
#define HA_ERR_DECRYPTION_FAILED 192 /* Table encrypted but decypt failed */
#define HA_ERR_FK_DEPTH_EXCEEDED 193 /* FK cascade depth exceeded */
#define HA_ERR_TABLESPACE_MISSING 194 /* Missing Tablespace */
#define HA_ERR_LAST 194 /* Copy of last error nr * */
#define HA_ERR_SEQUENCE_INVALID_DATA 195
#define HA_ERR_SEQUENCE_RUN_OUT 196
#define HA_ERR_LAST 196 /* Copy of last error nr * */
/* Number of different errors */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)

View File

@ -105,7 +105,9 @@ static const char *handler_error_messages[]=
"Too many words in a FTS phrase or proximity search",
"Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.",
"Foreign key cascade delete/update exceeds max depth",
"Tablespace is missing for table"
"Tablespace is missing for table",
"Sequence has been run out",
"Sequence values are conflicting"
};
#endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */

View File

@ -113,6 +113,8 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/wsrep_dummy.cc ../sql/encryption.cc
../sql/item_windowfunc.cc ../sql/sql_window.cc
../sql/sql_cte.cc
../sql/sql_sequence.cc ../sql/sql_sequence.h
../sql/ha_sequence.cc ../sql/ha_sequence.h
../sql/temporary_tables.cc
../sql/session_tracker.cc
${GEN_SOURCES}

View File

@ -194,6 +194,7 @@ my @DEFAULT_SUITES= qw(
roles-
rpl-
sys_vars-
sql_sequence-
unit-
vcol-
wsrep-
@ -4234,7 +4235,7 @@ sub extract_server_log ($$) {
push(@lines, $line);
if (scalar(@lines) > 1000000) {
$Ferr = undef;
mtr_warning("Too much log from test, bailing out from extracting");
mtr_warning("Too much log in $error_log, bailing out from extracting");
return ();
}
}

View File

@ -160,7 +160,7 @@ Note 1050 Table 'v1' already exists
DROP VIEW IF EXISTS v1;
DROP VIEW IF EXISTS v1;
Warnings:
Note 1051 Unknown table 'test.v1'
Note 4067 Unknown VIEW: 'test.v1'
SHOW BINLOG EVENTS;
Log_name Pos Event_type Server_id End_log_pos Info
# # Format_desc 1 # VER

View File

@ -55,5 +55,5 @@ id
DROP VIEW IF EXISTS v1;
DROP VIEW IF EXISTS v1;
Warnings:
Note 1051 Unknown table 'test.v1'
Note 4067 Unknown VIEW: 'test.v1'
DROP TABLE t1;

View File

@ -198,7 +198,7 @@ ERROR 42S02: Unknown table 'test.table1'
DROP TABLE table1,table2;
ERROR 42S02: Unknown table 'test.table1,test.table2'
DROP VIEW view1,view2,view3,view4;
ERROR 42S02: Unknown table 'test.view1,test.view2,test.view3,test.view4'
ERROR 42S02: Unknown VIEW: 'test.view1,test.view2,test.view3,test.view4'
DROP TABLE IF EXISTS table1;
Warnings:
@ -209,10 +209,10 @@ Note 1051 Unknown table 'test.table1'
Note 1051 Unknown table 'test.table2'
DROP VIEW IF EXISTS view1,view2,view3,view4;
Warnings:
Note 1051 Unknown table 'test.view1'
Note 1051 Unknown table 'test.view2'
Note 1051 Unknown table 'test.view3'
Note 1051 Unknown table 'test.view4'
Note 4067 Unknown VIEW: 'test.view1'
Note 4067 Unknown VIEW: 'test.view2'
Note 4067 Unknown VIEW: 'test.view3'
Note 4067 Unknown VIEW: 'test.view4'
# Test error message when trigger does not find table
CREATE TABLE table1(a int);

View File

@ -1428,7 +1428,7 @@ Warnings:
Note 1305 FUNCTION test.test_function does not exist
drop view if exists v1;
Warnings:
Note 1051 Unknown table 'test.v1'
Note 4067 Unknown VIEW: 'test.v1'
create table test (col1 varchar(30));
create function test_function() returns varchar(30)
begin

View File

@ -1408,7 +1408,7 @@ performance-schema-max-rwlock-instances -1
performance-schema-max-socket-classes 10
performance-schema-max-socket-instances -1
performance-schema-max-stage-classes 150
performance-schema-max-statement-classes 187
performance-schema-max-statement-classes 189
performance-schema-max-table-handles -1
performance-schema-max-table-instances -1
performance-schema-max-thread-classes 50

View File

@ -415,7 +415,7 @@ select @@profiling;
drop table if exists t1, t2, t3;
drop view if exists v1;
Warnings:
Note 1051 Unknown table 'test.v1'
Note 4067 Unknown VIEW: 'test.v1'
drop function if exists f1;
set session profiling = OFF;
set global profiling_history_size= @start_value;

View File

@ -3,7 +3,7 @@ Warnings:
Note 1051 Unknown table 'test.t1'
drop view if exists view_t1;
Warnings:
Note 1051 Unknown table 'test.view_t1'
Note 4067 Unknown VIEW: 'test.view_t1'
SET sql_mode=ONLY_FULL_GROUP_BY;
CREATE TABLE t1 (
pk INT,

View File

@ -3211,7 +3211,7 @@ drop procedure bug10961|
DROP PROCEDURE IF EXISTS bug6866|
DROP VIEW IF EXISTS tv|
Warnings:
Note 1051 Unknown table 'test.tv'
Note 4067 Unknown VIEW: 'test.tv'
DROP TABLE IF EXISTS tt1,tt2,tt3|
Warnings:
Note 1051 Unknown table 'test.tt1'

View File

@ -4,7 +4,7 @@ CREATE FUNCTION myfunc_double RETURNS REAL SONAME "UDF_EXAMPLE_LIB";
CREATE FUNCTION myfunc_nonexist RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
ERROR HY000: Can't find symbol 'myfunc_nonexist' in library
CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
CREATE FUNCTION sequence RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
CREATE FUNCTION udf_sequence RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
CREATE FUNCTION lookup RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
CREATE FUNCTION reverse_lookup
RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
@ -226,7 +226,7 @@ DROP FUNCTION myfunc_double;
DROP FUNCTION myfunc_nonexist;
ERROR 42000: FUNCTION test.myfunc_nonexist does not exist
DROP FUNCTION myfunc_int;
DROP FUNCTION sequence;
DROP FUNCTION udf_sequence;
DROP FUNCTION lookup;
DROP FUNCTION reverse_lookup;
DROP FUNCTION avgcost;
@ -340,32 +340,32 @@ DROP FUNCTION check_const_len;
DROP PROCEDURE check_const_len_sp;
DROP TRIGGER check_const_len_trigger;
DROP TABLE const_len_bug;
CREATE FUNCTION sequence RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
CREATE FUNCTION udf_sequence RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (a INT PRIMARY KEY);
INSERT INTO t1 VALUES (4),(3),(2),(1);
INSERT INTO t2 SELECT * FROM t1;
SELECT sequence() AS seq, a FROM t1 ORDER BY seq ASC;
SELECT udf_sequence() AS seq, a FROM t1 ORDER BY seq ASC;
seq a
1 4
2 3
3 2
4 1
SELECT sequence() AS seq, a FROM t1 ORDER BY seq DESC;
SELECT udf_sequence() AS seq, a FROM t1 ORDER BY seq DESC;
seq a
4 1
3 2
2 3
1 4
SELECT * FROM t1 WHERE a = sequence();
SELECT * FROM t1 WHERE a = udf_sequence();
a
SELECT * FROM t2 WHERE a = sequence();
SELECT * FROM t2 WHERE a = udf_sequence();
a
1
2
3
4
DROP FUNCTION sequence;
DROP FUNCTION udf_sequence;
DROP TABLE t1,t2;
drop function if exists test.metaphon;
drop function if exists metaphon;

View File

@ -1,6 +1,6 @@
create function sequence returns integer soname "UDF_EXAMPLE_LIB";
create table t1 (n int key not null auto_increment, msg int as (sequence()) virtual);
create function udf_sequence returns integer soname "UDF_EXAMPLE_LIB";
create table t1 (n int key not null auto_increment, msg int as (udf_sequence()) virtual);
select * from t1;
n msg
drop table t1;
drop function sequence;
drop function udf_sequence;

View File

@ -197,7 +197,7 @@ c d
2 5
3 10
drop view v100;
ERROR 42S02: Unknown table 'test.v100'
ERROR 42S02: Unknown VIEW: 'test.v100'
drop view t1;
ERROR HY000: 'test.t1' is not VIEW
drop table v1;
@ -2894,7 +2894,7 @@ Tables_in_test
t1
v1
DROP VIEW v2,v1;
ERROR 42S02: Unknown table 'test.v2'
ERROR 42S02: Unknown VIEW: 'test.v2'
SHOW TABLES;
Tables_in_test
t1
@ -5222,7 +5222,7 @@ CREATE TABLE t4 (i4 INT);
INSERT INTO t4 VALUES (1),(2);
DROP VIEW IF EXISTS v1;
Warnings:
Note 1051 Unknown table 'test.v1'
Note 4067 Unknown VIEW: 'test.v1'
CREATE VIEW v1 AS select coalesce(j1,i3) AS v1_field1 from t2 join t3 left join t1 on ( i1 = i2 );
CREATE VIEW v2 AS select v1_field1 from t4 join v1;
prepare my_stmt from "select v1_field1 from v2";

View File

@ -85,8 +85,6 @@ DROP TRIGGER trig_2;
Invoking view view_retval_2 returning value from function func_retval_1 returning value from unsafe UUID() function.
CREATE VIEW view_retval_2 AS SELECT func_retval_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave
* binlog_format = STATEMENT: expect 1 warnings.
INSERT INTO t2 SELECT * FROM view_retval_2;
Warnings:
@ -149,8 +147,6 @@ DROP TRIGGER trig_2;
Invoking view view_sidef_2 invoking function func_sidef_1 invoking unsafe UUID() function.
CREATE VIEW view_sidef_2 AS SELECT func_sidef_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave
* binlog_format = STATEMENT: expect 1 warnings.
INSERT INTO t2 SELECT * FROM view_sidef_2;
Warnings:
@ -411,8 +407,6 @@ DROP TRIGGER trig_2;
Invoking view view_retval_2 returning value from function func_retval_1 returning value from unsafe @@hostname variable.
CREATE VIEW view_retval_2 AS SELECT func_retval_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave
* binlog_format = STATEMENT: expect 1 warnings.
INSERT INTO t2 SELECT * FROM view_retval_2;
Warnings:
@ -475,8 +469,6 @@ DROP TRIGGER trig_2;
Invoking view view_sidef_2 invoking function func_sidef_1 invoking unsafe @@hostname variable.
CREATE VIEW view_sidef_2 AS SELECT func_sidef_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave
* binlog_format = STATEMENT: expect 1 warnings.
INSERT INTO t2 SELECT * FROM view_sidef_2;
Warnings:
@ -657,8 +649,6 @@ DROP TRIGGER trig_2;
Invoking view view_sidef_2 invoking function func_sidef_1 invoking unsafe SELECT...LIMIT statement.
CREATE VIEW view_sidef_2 AS SELECT func_sidef_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted
* binlog_format = STATEMENT: expect 1 warnings.
INSERT INTO t2 SELECT * FROM view_sidef_2;
Warnings:
@ -1049,8 +1039,6 @@ DROP TRIGGER trig_2;
Invoking view view_sidef_2 invoking function func_sidef_1 invoking unsafe update of two autoinc columns.
CREATE VIEW view_sidef_2 AS SELECT func_sidef_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly
* binlog_format = STATEMENT: expect 1 warnings.
INSERT INTO t2 SELECT * FROM view_sidef_2;
Warnings:
@ -1245,8 +1233,6 @@ DROP TRIGGER trig_2;
Invoking view view_retval_2 returning value from function func_retval_1 returning value from unsafe UDF.
CREATE VIEW view_retval_2 AS SELECT func_retval_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a UDF which may not return the same value on the slave
* binlog_format = STATEMENT: expect 1 warnings.
INSERT INTO t2 SELECT * FROM view_retval_2;
Warnings:
@ -1309,8 +1295,6 @@ DROP TRIGGER trig_2;
Invoking view view_sidef_2 invoking function func_sidef_1 invoking unsafe UDF.
CREATE VIEW view_sidef_2 AS SELECT func_sidef_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a UDF which may not return the same value on the slave
* binlog_format = STATEMENT: expect 1 warnings.
INSERT INTO t2 SELECT * FROM view_sidef_2;
Warnings:
@ -1551,8 +1535,6 @@ DROP TRIGGER trig_2;
Invoking view view_sidef_2 invoking function func_sidef_1 invoking unsafe use of mysql.general_log.
CREATE VIEW view_sidef_2 AS SELECT func_sidef_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses the general log, slow query log, or performance_schema table(s). This is unsafe because system tables may differ on slaves
* binlog_format = STATEMENT: expect 1 warnings.
INSERT INTO t2 SELECT * FROM view_sidef_2;
Warnings:
@ -1823,14 +1805,6 @@ DROP TRIGGER trig_2;
Invoking view view_sidef_2 invoking function func_sidef_1 invoking statement that is unsafe in many ways.
CREATE VIEW view_sidef_2 AS SELECT func_sidef_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses the general log, slow query log, or performance_schema table(s). This is unsafe because system tables may differ on slaves
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a UDF which may not return the same value on the slave
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements writing to a table with an auto-increment column after selecting from another table are unsafe because the order in which rows are retrieved determines what (if any) rows will be written. This order cannot be predicted and may differ on master and the slave
* binlog_format = STATEMENT: expect 7 warnings.
INSERT INTO t2 SELECT * FROM view_sidef_2;
Warnings:
@ -2099,9 +2073,6 @@ DROP TRIGGER trig_2;
Invoking view view_sidef_2 invoking function func_sidef_1 invoking statement that is unsafe several times.
CREATE VIEW view_sidef_2 AS SELECT func_sidef_1();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave
* binlog_format = STATEMENT: expect 2 warnings.
INSERT INTO t2 SELECT * FROM view_sidef_2;
Warnings:
@ -2235,9 +2206,6 @@ DROP TRIGGER trig_1;
Invoking view view_sidef_1 invoking statement that is unsafe several times.
CREATE VIEW view_sidef_1 AS SELECT multi_unsafe_func();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave
* binlog_format = STATEMENT: expect 2 warnings.
INSERT INTO t1 SELECT * FROM view_sidef_1;
Warnings:
@ -2281,9 +2249,6 @@ DROP TRIGGER trig_2;
Invoking view view_sidef_2 invoking view view_sidef_1 invoking statement that is unsafe several times.
CREATE VIEW view_sidef_2 AS SELECT * FROM view_sidef_1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave
* binlog_format = STATEMENT: expect 2 warnings.
INSERT INTO t2 SELECT * FROM view_sidef_2;
Warnings:

View File

@ -0,0 +1,60 @@
SET sql_mode=ORACLE;
CREATE SEQUENCE s1;
SHOW CREATE SEQUENCE s1;
Table Create Table
s1 CREATE SEQUENCE "s1" start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle
SELECT s1.currval;
s1.currval
NULL
SELECT s1.nextval;
s1.nextval
1
SELECT s1.nextval;
s1.nextval
2
SELECT s1.nextval;
s1.nextval
3
EXPLAIN EXTENDED SELECT s1.nextval;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select nextval("test"."s1") AS "s1.nextval"
SELECT nextval(s1);
nextval(s1)
4
EXPLAIN EXTENDED SELECT s1.currval;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select lastval("test"."s1") AS "s1.currval"
SELECT lastval(s1);
lastval(s1)
4
DROP SEQUENCE s1;
CREATE SEQUENCE s1;
CREATE VIEW v1 AS SELECT s1.nextval AS a;
SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='v1';
VIEW_DEFINITION
select nextval(`test`.`s1`) AS `a`
SELECT * FROM v1;
a
1
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE VIEW "v1" AS select nextval("test"."s1") AS "a" latin1 latin1_swedish_ci
DROP VIEW v1;
DROP SEQUENCE s1;
CREATE SEQUENCE s1;
CREATE VIEW v1 AS SELECT s1.currval AS a;
SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='v1';
VIEW_DEFINITION
select lastval(`test`.`s1`) AS `a`
SELECT * FROM v1;
a
NULL
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE VIEW "v1" AS select lastval("test"."s1") AS "a" latin1 latin1_swedish_ci
DROP VIEW v1;
DROP SEQUENCE s1;

View File

@ -0,0 +1,33 @@
--source include/have_binlog_format_row.inc
SET sql_mode=ORACLE;
CREATE SEQUENCE s1;
SHOW CREATE SEQUENCE s1;
SELECT s1.currval;
SELECT s1.nextval;
SELECT s1.nextval;
SELECT s1.nextval;
EXPLAIN EXTENDED SELECT s1.nextval;
SELECT nextval(s1);
EXPLAIN EXTENDED SELECT s1.currval;
SELECT lastval(s1);
DROP SEQUENCE s1;
CREATE SEQUENCE s1;
CREATE VIEW v1 AS SELECT s1.nextval AS a;
SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='v1';
SELECT * FROM v1;
SHOW CREATE VIEW v1;
DROP VIEW v1;
DROP SEQUENCE s1;
CREATE SEQUENCE s1;
CREATE VIEW v1 AS SELECT s1.currval AS a;
SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='v1';
SELECT * FROM v1;
SHOW CREATE VIEW v1;
DROP VIEW v1;
DROP SEQUENCE s1;

View File

@ -4314,7 +4314,7 @@ CREATE VIEW v2 AS Select * from test.v1;
ERROR 42S02: Table 'test.v1' doesn't exist
DROP VIEW IF EXISTS v2;
Warnings:
Note 1051 Unknown table 'test.v2'
Note 4067 Unknown VIEW: 'test.v2'
Testcase 3.3.1.25
--------------------------------------------------------------------------------
@ -7566,7 +7566,7 @@ Call sp1() ;
ERROR 42000: PROCEDURE test.sp1 does not exist
Drop view if exists test.v1 ;
Warnings:
Note 1051 Unknown table 'test.v1'
Note 4067 Unknown VIEW: 'test.v1'
Drop procedure sp1 ;
ERROR 42000: PROCEDURE test.sp1 does not exist
@ -21307,12 +21307,12 @@ CREATE TABLE t1 ( f1 VARCHAR(1000) ) ENGINE = innodb ;
CREATE VIEW v1 AS SELECT f1 FROM t1;
DROP VIEW v1;
DROP VIEW v1;
ERROR 42S02: Unknown table 'test.v1'
ERROR 42S02: Unknown VIEW: 'test.v1'
CREATE VIEW v1 AS SELECT f1 FROM t1;
DROP VIEW IF EXISTS v1;
DROP VIEW IF EXISTS v1;
Warnings:
Note 1051 Unknown table 'test.v1'
Note 4067 Unknown VIEW: 'test.v1'
Testcase 3.3.1.68
--------------------------------------------------------------------------------
@ -21324,31 +21324,31 @@ CREATE VIEW v1_base AS SELECT * FROM t1;
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_top ;
DROP VIEW v1_top;
ERROR 42S02: Unknown table 'test.v1_top'
ERROR 42S02: Unknown VIEW: 'test.v1_top'
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_base ;
DROP VIEW v1_base;
ERROR 42S02: Unknown table 'test.v1_base'
ERROR 42S02: Unknown VIEW: 'test.v1_base'
DROP VIEW v1_top;
CREATE VIEW v1_base AS SELECT * FROM t1;
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_top CASCADE ;
DROP VIEW v1_top;
ERROR 42S02: Unknown table 'test.v1_top'
ERROR 42S02: Unknown VIEW: 'test.v1_top'
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_base CASCADE ;
DROP VIEW v1_base;
ERROR 42S02: Unknown table 'test.v1_base'
ERROR 42S02: Unknown VIEW: 'test.v1_base'
DROP VIEW v1_top;
CREATE VIEW v1_base AS SELECT * FROM t1;
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_top RESTRICT ;
DROP VIEW v1_top;
ERROR 42S02: Unknown table 'test.v1_top'
ERROR 42S02: Unknown VIEW: 'test.v1_top'
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_base RESTRICT ;
DROP VIEW v1_base;
ERROR 42S02: Unknown table 'test.v1_base'
ERROR 42S02: Unknown VIEW: 'test.v1_base'
DROP VIEW v1_top;
Testcase 3.3.1.69, 3.3.1.70, 3.3.1.A5

View File

@ -4315,7 +4315,7 @@ CREATE VIEW v2 AS Select * from test.v1;
ERROR 42S02: Table 'test.v1' doesn't exist
DROP VIEW IF EXISTS v2;
Warnings:
Note 1051 Unknown table 'test.v2'
Note 4067 Unknown VIEW: 'test.v2'
Testcase 3.3.1.25
--------------------------------------------------------------------------------
@ -7567,7 +7567,7 @@ Call sp1() ;
ERROR 42000: PROCEDURE test.sp1 does not exist
Drop view if exists test.v1 ;
Warnings:
Note 1051 Unknown table 'test.v1'
Note 4067 Unknown VIEW: 'test.v1'
Drop procedure sp1 ;
ERROR 42000: PROCEDURE test.sp1 does not exist
@ -21309,12 +21309,12 @@ CREATE TABLE t1 ( f1 VARCHAR(1000) ) ENGINE = memory ;
CREATE VIEW v1 AS SELECT f1 FROM t1;
DROP VIEW v1;
DROP VIEW v1;
ERROR 42S02: Unknown table 'test.v1'
ERROR 42S02: Unknown VIEW: 'test.v1'
CREATE VIEW v1 AS SELECT f1 FROM t1;
DROP VIEW IF EXISTS v1;
DROP VIEW IF EXISTS v1;
Warnings:
Note 1051 Unknown table 'test.v1'
Note 4067 Unknown VIEW: 'test.v1'
Testcase 3.3.1.68
--------------------------------------------------------------------------------
@ -21326,31 +21326,31 @@ CREATE VIEW v1_base AS SELECT * FROM t1;
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_top ;
DROP VIEW v1_top;
ERROR 42S02: Unknown table 'test.v1_top'
ERROR 42S02: Unknown VIEW: 'test.v1_top'
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_base ;
DROP VIEW v1_base;
ERROR 42S02: Unknown table 'test.v1_base'
ERROR 42S02: Unknown VIEW: 'test.v1_base'
DROP VIEW v1_top;
CREATE VIEW v1_base AS SELECT * FROM t1;
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_top CASCADE ;
DROP VIEW v1_top;
ERROR 42S02: Unknown table 'test.v1_top'
ERROR 42S02: Unknown VIEW: 'test.v1_top'
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_base CASCADE ;
DROP VIEW v1_base;
ERROR 42S02: Unknown table 'test.v1_base'
ERROR 42S02: Unknown VIEW: 'test.v1_base'
DROP VIEW v1_top;
CREATE VIEW v1_base AS SELECT * FROM t1;
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_top RESTRICT ;
DROP VIEW v1_top;
ERROR 42S02: Unknown table 'test.v1_top'
ERROR 42S02: Unknown VIEW: 'test.v1_top'
CREATE VIEW v1_top AS SELECT * FROM v1_base;
DROP VIEW v1_base RESTRICT ;
DROP VIEW v1_base;
ERROR 42S02: Unknown table 'test.v1_base'
ERROR 42S02: Unknown VIEW: 'test.v1_base'
DROP VIEW v1_top;
Testcase 3.3.1.69, 3.3.1.70, 3.3.1.A5

View File

@ -2745,7 +2745,7 @@ CREATE VIEW v1 AS SELECT f1 FROM t1;
# DROP VIEW
DROP VIEW v1;
--error ER_BAD_TABLE_ERROR
--error ER_UNKNOWN_VIEW
DROP VIEW v1;
CREATE VIEW v1 AS SELECT f1 FROM t1;
@ -2792,7 +2792,7 @@ while ($num1)
# DROP VIEW v1_top < |RESTRICD|CASCADE> must be successful.
eval $aux1 ;
# Check, that v1_top really no more exists + cleanup for the second sub test
--error ER_BAD_TABLE_ERROR
--error ER_UNKNOWN_VIEW
DROP VIEW v1_top;
CREATE VIEW v1_top AS SELECT * FROM v1_base;

View File

@ -96,10 +96,10 @@ connection master;
DROP VIEW v1;
DROP TABLE t1;
DROP VIEW v1;
ERROR 42S02: Unknown table 'test.v1'
ERROR 42S02: Unknown VIEW: 'test.v1'
DROP VIEW IF EXISTS v2;
Warnings:
Note 1051 Unknown table 'test.v2'
Note 4067 Unknown VIEW: 'test.v2'
# Syncing slave with master
connection slave;
SELECT * FROM v1;

View File

@ -9,9 +9,9 @@ create view v1 as select * from t1;
create view v2 as select * from t2;
create view v3 as select * from t3;
drop view not_exist_view;
ERROR 42S02: Unknown table 'test.not_exist_view'
ERROR 42S02: Unknown VIEW: 'test.not_exist_view'
drop view v1, not_exist_view;
ERROR 42S02: Unknown table 'test.not_exist_view'
ERROR 42S02: Unknown VIEW: 'test.not_exist_view'
select * from v1;
ERROR 42S02: Table 'test.v1' doesn't exist
drop view v2, v3;

View File

@ -0,0 +1,44 @@
include/master-slave.inc
[connection master]
create or replace table t1(id int)engine=innodb;
create or replace table t3(id int)engine=myisam;
create or replace function t99 (a int)
returns int(10)
MODIFIES SQL DATA
begin
if (a > 100)
then
insert into t3 values (a);
end if;
return a;
end//
begin;
insert into t1 values(t99(1));
insert into t1 values(t99(101));
commit;
select * from t1;
id
1
101
select * from t3;
id
101
insert into t1 values(t99(1));
drop function t99;
drop table t1,t3;
connection slave;
connection master;
CREATE TABLE t1 (i INT) ENGINE=InnoDB;
CREATE TABLE t2 (j INT) ENGINE=MyISAM;
CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW
BEGIN
SET @a = unknown_column_just_to_raise_an_error;
INSERT INTO t2 VALUES (NULL) ;
END||
INSERT INTO t1 VALUES (1);
ERROR 42S22: Unknown column 'unknown_column_just_to_raise_an_error' in 'field list'
connection slave;
connection master;
drop trigger tr;
drop table t1,t2;
include/rpl_end.inc

View File

@ -41,7 +41,7 @@ connection master;
DROP VIEW v1;
DROP TABLE t1;
--error ER_BAD_TABLE_ERROR
--error ER_UNKNOWN_VIEW
DROP VIEW v1;
DROP VIEW IF EXISTS v2;

View File

@ -13,9 +13,9 @@ create table t3 (c int);
create view v1 as select * from t1;
create view v2 as select * from t2;
create view v3 as select * from t3;
--error 1051
--error ER_UNKNOWN_VIEW
drop view not_exist_view;
--error 1051
--error ER_UNKNOWN_VIEW
drop view v1, not_exist_view;
--error 1146
select * from v1;

View File

@ -0,0 +1,72 @@
#
# Test mixing transactional and non transactional tables
#
--source include/master-slave.inc
--source include/have_innodb.inc
--source include/have_binlog_format_row.inc
#
# Test updating conditionally a non transactinal table in a function
# This verifies that we don't write only a table map for a non transactional,
# without any row events
# The original bug caused a crash on the slave when doing a sync_slave
#
create or replace table t1(id int)engine=innodb;
create or replace table t3(id int)engine=myisam;
delimiter //;
create or replace function t99 (a int)
returns int(10)
MODIFIES SQL DATA
begin
if (a > 100)
then
insert into t3 values (a);
end if;
return a;
end//
delimiter ;//
begin;
insert into t1 values(t99(1));
insert into t1 values(t99(101));
commit;
select * from t1;
select * from t3;
insert into t1 values(t99(1));
drop function t99;
drop table t1,t3;
sync_slave_with_master;
connection master;
#
# MDEV-8203
# Assertion `!current_stmt_is_commit || !rgi->tables_to_lock' failed in
# Query_log_event::do_apply_event(rpl_group_info*, const char*, uint32)
#
CREATE TABLE t1 (i INT) ENGINE=InnoDB;
CREATE TABLE t2 (j INT) ENGINE=MyISAM;
--delimiter ||
CREATE TRIGGER tr AFTER INSERT ON t1 FOR EACH ROW
BEGIN
SET @a = unknown_column_just_to_raise_an_error;
INSERT INTO t2 VALUES (NULL) ;
END||
--delimiter ;
--error ER_BAD_FIELD_ERROR
INSERT INTO t1 VALUES (1);
--sync_slave_with_master
connection master;
drop trigger tr;
drop table t1,t2;
# End of 4.1 tests
--source include/rpl_end.inc

View File

@ -0,0 +1,31 @@
create or replace sequence s1 cache 3;
select next value for s1, min_value from s1 where max_value> 1;
next value for s1 min_value
1 1
select next value for s1, min_value from s1 where max_value> 2;
next value for s1 min_value
2 1
select next value for s1, min_value from s1 where max_value> 3;
next value for s1 min_value
3 1
select next value for s1, min_value from s1 where max_value> 4;
next value for s1 min_value
4 1
drop sequence s1;
"Runnig SHOW BINLOG EVENTS"
Log_name Pos Event_type Server_id End_log_pos Info
# # Gtid 1 # GTID #-#-#
# # Query 1 # use `test`; create or replace sequence s1 cache 3
# # Gtid 1 # BEGIN GTID #-#-#
# # Annotate_rows 1 # select next value for s1, min_value from s1 where max_value> 1
# # Table_map 1 # table_id: 30 (test.s1)
# # Write_rows_v1 1 # table_id: 30 flags: STMT_END_F
# # Query 1 # COMMIT
# # Gtid 1 # BEGIN GTID #-#-#
# # Annotate_rows 1 # select next value for s1, min_value from s1 where max_value> 4
# # Table_map 1 # table_id: 30 (test.s1)
# # Write_rows_v1 1 # table_id: 30 flags: STMT_END_F
# # Query 1 # COMMIT
# # Gtid 1 # GTID #-#-#
# # Query 1 # use `test`; DROP TABLE `s1` /* generated by server */
RESET MASTER;

View File

@ -0,0 +1,26 @@
--source include/have_udf.inc
--source include/have_log_bin.inc
--source include/binlog_start_pos.inc
#
# Testing binary logging of sequences
#
--let $pos=`select $binlog_start_pos + 73`
--let $binlog_file=query_get_value(SHOW MASTER STATUS, File, 1)
--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1)
create or replace sequence s1 cache 3;
select next value for s1, min_value from s1 where max_value> 1;
select next value for s1, min_value from s1 where max_value> 2;
select next value for s1, min_value from s1 where max_value> 3;
select next value for s1, min_value from s1 where max_value> 4;
drop sequence s1;
--echo "Runnig SHOW BINLOG EVENTS"
--replace_column 1 # 2 # 5 #
--replace_regex /xid=[0-9]+/xid=XX/ /GTID [0-9]+-[0-9]+-[0-9]+/GTID #-#-#/ /Server.ver.*/VERSIONS/
--disable_query_log
--eval SHOW BINLOG EVENTS FROM $binlog_start;
--enable_query_log
RESET MASTER;

View File

@ -0,0 +1,497 @@
drop table if exists t1;
Warnings:
Note 1051 Unknown table 'test.t1'
create or replace sequence t1 engine=myisam;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`next_value` bigint(21) NOT NULL COMMENT 'next not cached value',
`min_value` bigint(21) NOT NULL COMMENT 'min value',
`max_value` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` tinyint(1) unsigned NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'How many cycles has been done'
) ENGINE=MyISAM SEQUENCE=1
select * from t1;
next_value min_value max_value start increment cache cycle round
1 1 9223372036854775806 1 1 1000 0 0
create or replace sequence t1 engine=innodb;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=InnoDB
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`next_value` bigint(21) NOT NULL COMMENT 'next not cached value',
`min_value` bigint(21) NOT NULL COMMENT 'min value',
`max_value` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` tinyint(1) unsigned NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'How many cycles has been done'
) ENGINE=InnoDB SEQUENCE=1
select * from t1;
next_value min_value max_value start increment cache cycle round
1 1 9223372036854775806 1 1 1000 0 0
create or replace sequence t1 engine=maria;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=Aria
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`next_value` bigint(21) NOT NULL COMMENT 'next not cached value',
`min_value` bigint(21) NOT NULL COMMENT 'min value',
`max_value` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` tinyint(1) unsigned NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'How many cycles has been done'
) ENGINE=Aria SEQUENCE=1
select * from t1;
next_value min_value max_value start increment cache cycle round
1 1 9223372036854775806 1 1 1000 0 0
create or replace sequence t1 engine=archive;
ERROR HY000: Table storage engine 'ARCHIVE' does not support the create option 'SEQUENCE'
show create table t1;
ERROR 42S02: Table 'test.t1' doesn't exist
create or replace sequence t1 start with 10;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 10 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
select * from t1;
next_value min_value max_value start increment cache cycle round
10 1 9223372036854775806 10 1 1000 0 0
create or replace sequence t1 minvalue=11;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 11 minvalue 11 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
select * from t1;
next_value min_value max_value start increment cache cycle round
11 11 9223372036854775806 11 1 1000 0 0
create or replace sequence t1 maxvalue=13 increment by -1;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 13 minvalue -9223372036854775807 maxvalue 13 increment by -1 cache 1000 nocycle ENGINE=MyISAM
select * from t1;
next_value min_value max_value start increment cache cycle round
13 -9223372036854775807 13 13 -1 1000 0 0
create or replace sequence t1 increment by -1 cache 100;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with -1 minvalue -9223372036854775807 maxvalue -1 increment by -1 cache 100 nocycle ENGINE=MyISAM
select * from t1;
next_value min_value max_value start increment cache cycle round
-1 -9223372036854775807 -1 -1 -1 100 0 0
create or replace sequence t1 cycle;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 cycle ENGINE=MyISAM
select * from t1;
next_value min_value max_value start increment cache cycle round
1 1 9223372036854775806 1 1 1000 1 0
create or replace sequence t1 nocycle;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
select * from t1;
next_value min_value max_value start increment cache cycle round
1 1 9223372036854775806 1 1 1000 0 0
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 cycle minvalue= 14;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 14 minvalue 14 maxvalue 9223372036854775806 increment by 1 cache 1000 cycle ENGINE=MyISAM
select * from t1;
next_value min_value max_value start increment cache cycle round
14 14 9223372036854775806 14 1 1000 1 0
create or replace sequence t1 cycle increment by -1;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with -1 minvalue -9223372036854775807 maxvalue -1 increment by -1 cache 1000 cycle ENGINE=MyISAM
drop sequence t1;
create sequence if not exists t1;
create sequence if not exists t1 start with 10;
Warnings:
Note 1050 Table 't1' already exists
select * from t1;
next_value min_value max_value start increment cache cycle round
1 1 9223372036854775806 1 1 1000 0 0
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
create or replace sequence t1 start with 10 minvalue=10 maxvalue=11 nocache cycle;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 10 minvalue 10 maxvalue 11 increment by 1 nocache cycle ENGINE=MyISAM
select * from t1;
next_value min_value max_value start increment cache cycle round
10 10 11 10 1 0 1 0
create or replace sequence t1 start with 10 minvalue=-10 maxvalue=11 cache=10 cycle increment by 10;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 10 minvalue -10 maxvalue 11 increment by 10 cache 10 cycle ENGINE=MyISAM
select * from t1;
next_value min_value max_value start increment cache cycle round
10 -10 11 10 10 10 1 0
create or replace sequence t1 start with 10 NO MAXVALUE NO MINVALUE;
create or replace sequence t1 start with 10 maxvalue 10;
create or replace sequence t1 start with 10 minvalue 10;
create or replace sequence t1 start with 10 minvalue 10 maxvalue 11 cycle;
create or replace sequence t1 start with 10 maxvalue=9223372036854775806;
create or replace sequence t1 start with 10 minvalue=-9223372036854775807;
drop sequence if exists t1;
create sequence t1 increment by 0;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 0 cache 1000 nocycle ENGINE=MyISAM
select * from t1;
next_value min_value max_value start increment cache cycle round
1 1 9223372036854775806 1 0 1000 0 0
drop sequence t1;
create table t1 (a int);
show create sequence t1;
ERROR HY000: 'test.t1' is not SEQUENCE
drop sequence t1;
ERROR 42S02: 'test.t1' is not a SEQUENCE
drop sequence if exists t1;
Warnings:
Note 4066 Unknown SEQUENCE: 'test.t1'
create sequence t1 start with 10 maxvalue=9;
ERROR HY000: Sequence 'test.t1' values are conflicting
create sequence t1 minvalue= 100 maxvalue=10;
ERROR HY000: Sequence 'test.t1' values are conflicting
create sequence t1 start with 9 minvalue=10;
ERROR HY000: Sequence 'test.t1' values are conflicting
create or replace sequence t1 maxvalue=13, increment by -1;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ' increment by -1' at line 1
create or replace sequence t1 start with= 10 maxvalue=13;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '= 10 maxvalue=13' at line 1
create or replace sequence t1 maxvalue=13, increment= -1;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ' increment= -1' at line 1
create or replace sequence t1 start with 10 min_value=1 NO MINVALUE;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NO MINVALUE' at line 1
create or replace sequence t1 start with 10 min_value=1 NO MINVALUE;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NO MINVALUE' at line 1
create sequence t1 start with 10 maxvalue=9223372036854775807;
ERROR HY000: Sequence 'test.t1' values are conflicting
create sequence t1 start with 10 minvalue=-9223372036854775808;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '9223372036854775808' at line 1
create or replace sequence t1 start with 10 NO MINVALUE minvalue=1;
drop sequence t1;
create sequence t1;
show fields from t1;
Field Type Null Key Default Extra
next_value bigint(21) NO NULL
min_value bigint(21) NO NULL
max_value bigint(21) NO NULL
start bigint(21) NO NULL
increment bigint(21) NO NULL
cache bigint(21) NO NULL
cycle tinyint(1) unsigned NO NULL
round bigint(21) NO NULL
flush tables;
show fields from t1;
Field Type Null Key Default Extra
next_value bigint(21) NO NULL
min_value bigint(21) NO NULL
max_value bigint(21) NO NULL
start bigint(21) NO NULL
increment bigint(21) NO NULL
cache bigint(21) NO NULL
cycle tinyint(1) unsigned NO NULL
round bigint(21) NO NULL
create or replace sequence t1 engine=aria;
show fields from t1;
Field Type Null Key Default Extra
next_value bigint(21) NO NULL
min_value bigint(21) NO NULL
max_value bigint(21) NO NULL
start bigint(21) NO NULL
increment bigint(21) NO NULL
cache bigint(21) NO NULL
cycle tinyint(1) unsigned NO NULL
round bigint(21) NO NULL
show fields from t1;
Field Type Null Key Default Extra
next_value bigint(21) NO NULL
min_value bigint(21) NO NULL
max_value bigint(21) NO NULL
start bigint(21) NO NULL
increment bigint(21) NO NULL
cache bigint(21) NO NULL
cycle tinyint(1) unsigned NO NULL
round bigint(21) NO NULL
flush tables;
create or replace sequence t1 comment= "test 1";
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM COMMENT='test 1'
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`next_value` bigint(21) NOT NULL COMMENT 'next not cached value',
`min_value` bigint(21) NOT NULL COMMENT 'min value',
`max_value` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` tinyint(1) unsigned NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'How many cycles has been done'
) ENGINE=MyISAM SEQUENCE=1 COMMENT='test 1'
create or replace sequence t1 comment= "test 2" min_rows=1 max_rows=2;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM COMMENT='test 2'
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`next_value` bigint(21) NOT NULL COMMENT 'next not cached value',
`min_value` bigint(21) NOT NULL COMMENT 'min value',
`max_value` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` tinyint(1) unsigned NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'How many cycles has been done'
) ENGINE=MyISAM MIN_ROWS=1 MAX_ROWS=2 SEQUENCE=1 COMMENT='test 2'
create or replace sequence t1 start=1 increment= 2;
create or replace sequence t1 start 1 increment 2;
drop sequence t1;
CREATE TABLE t1 (
`next_value` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) sequence=1;
show create sequence t1;
Table Create Table
t1 CREATE SEQUENCE `t1` start with 1 minvalue 1 maxvalue 9223372036854775806 increment by 1 cache 1000 nocycle ENGINE=MyISAM
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`next_value` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) ENGINE=MyISAM SEQUENCE=1
drop sequence t1;
CREATE OR REPLACE TABLE t1 (
`next_val` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) sequence=1;
ERROR HY000: Sequence 'test.t1' table structure is invalid (next_val)
CREATE OR REPLACE TABLE t1 (
`next_value` int(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) sequence=1;
ERROR HY000: Sequence 'test.t1' table structure is invalid (next_value)
CREATE OR REPLACE TABLE t1 (
`next_val` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` bigint(21) unsigned NOT NULL, /* error */
`round` bigint(21) NOT NULL
) sequence=1;
ERROR HY000: Sequence 'test.t1' table structure is invalid (next_val)
CREATE OR REPLACE TABLE t1 (
`next_value` bigint(21),
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) sequence=1;
ERROR HY000: Sequence 'test.t1' table structure is invalid (next_value)
CREATE OR REPLACE TABLE t1 (
`next_value` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL,
extra_field bigint(21)
) sequence=1;
ERROR HY000: Sequence 'test.t1' table structure is invalid (Wrong number of columns)
CREATE OR REPLACE TABLE t1 (
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`next_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) sequence=1;
ERROR HY000: Sequence 'test.t1' table structure is invalid (min_value)
CREATE OR REPLACE TABLE t1 (
`next_value` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL,
key key1 (next_value)
) sequence=1;
ERROR HY000: Sequence 'test.t1' table structure is invalid (Sequence tables cannot have any keys)
drop sequence if exists t1;
Warnings:
Note 4066 Unknown SEQUENCE: 'test.t1'
create sequence t1;
create sequence t2;
create table t3 (a int) engine=myisam;
select table_catalog, table_schema, table_name, table_type from information_schema.tables where table_catalog="test";
table_catalog table_schema table_name table_type
CREATE SEQUENCE s1;
drop sequence s1;
drop sequence if exists t1,t2,t3,t4;
Warnings:
Note 4066 Unknown SEQUENCE: 'test.t3'
Note 4066 Unknown SEQUENCE: 'test.t4'
drop table if exists t1,t2,t3;
Warnings:
Note 1051 Unknown table 'test.t1'
Note 1051 Unknown table 'test.t2'
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
CREATE SEQUENCE s1;
drop table t1,t2,s1;
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
CREATE SEQUENCE s1;
drop table if exists t1,t2,s1,s2;
Warnings:
Note 1051 Unknown table 'test.s2'
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
CREATE SEQUENCE s1;
drop sequence t1,t2,s1,s2;
ERROR 42S02: Unknown SEQUENCE: 'test.t1,test.t2,test.s2'
drop table if exists t1,t2;
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
CREATE SEQUENCE s1;
drop sequence if exists t1,t2,s1,s2;
Warnings:
Note 4066 Unknown SEQUENCE: 'test.t1'
Note 4066 Unknown SEQUENCE: 'test.t2'
Note 4066 Unknown SEQUENCE: 'test.s2'
drop table if exists t1,t2;
CREATE TEMPORARY SEQUENCE s1;
DROP SEQUENCE s1;
DROP TEMPORARY SEQUENCE s1;
ERROR 42S02: Unknown SEQUENCE: 'test.s1'
CREATE TEMPORARY SEQUENCE s1;
CREATE SEQUENCE s2;
CREATE TEMPORARY TABLE t1 (a int);
CREATE TABLE t2 (a int);
DROP TEMPORARY SEQUENCE t1,t2,s1,s2;
ERROR 42S02: Unknown SEQUENCE: 'test.t1,test.t2,test.s2'
DROP TEMPORARY SEQUENCE s1;
ERROR 42S02: Unknown SEQUENCE: 'test.s1'
DROP TEMPORARY TABLE t1;
DROP TABLE t1,t2,s1,s2;
ERROR 42S02: Unknown table 'test.t1,test.s1'
create view v1 as (select 1);
CREATE SEQUENCE s1;
DROP SEQUENCE s1,v1;
ERROR 42S02: 'test.v1' is a view
drop view v1;
CREATE TEMPORARY SEQUENCE t1;
select next value for t1;
next value for t1
1
drop temporary table t1;
select previous value for t1;
ERROR 42S02: Table 'test.t1' doesn't exist
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 10;
select next value for t1;
next value for t1
1
select previous value for t1;
previous value for t1
1
CREATE TEMPORARY SEQUENCE t1 start with 100 minvalue 100 maxvalue 200 increment by 1 cache 10;
select previous value for t1;
previous value for t1
NULL
select next value for t1;
next value for t1
100
select previous value for t1;
previous value for t1
100
drop temporary sequence t1;
select previous value for t1;
previous value for t1
1
drop sequence t1;
CREATE TEMPORARY SEQUENCE t1 engine=innodb;
select next value for t1;
next value for t1
1
drop temporary table t1;
select previous value for t1;
ERROR 42S02: Table 'test.t1' doesn't exist
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 10 engine=innodb;
select next value for t1;
next value for t1
1
select previous value for t1;
previous value for t1
1
CREATE TEMPORARY SEQUENCE t1 start with 100 minvalue 100 maxvalue 200 increment by 1 cache 10 engine=innodb;
select previous value for t1;
previous value for t1
NULL
select next value for t1;
next value for t1
100
select previous value for t1;
previous value for t1
100
drop temporary sequence t1;
select previous value for t1;
previous value for t1
1
drop sequence t1;
create table t1 (a int) engine=sql_sequence;
ERROR 42000: Unknown storage engine 'sql_sequence'

View File

@ -0,0 +1,374 @@
#
# Test create options with sequences
#
--source include/have_innodb.inc
--source include/have_archive.inc
drop table if exists t1;
#
# Check some sample engines
#
create or replace sequence t1 engine=myisam;
show create sequence t1;
show create table t1;
select * from t1;
create or replace sequence t1 engine=innodb;
show create sequence t1;
show create table t1;
select * from t1;
create or replace sequence t1 engine=maria;
show create sequence t1;
show create table t1;
select * from t1;
--error ER_ILLEGAL_HA_CREATE_OPTION
create or replace sequence t1 engine=archive;
#
# The following error should be fixed. We shouldn't delete old table on errors
#
--error ER_NO_SUCH_TABLE
show create table t1;
# Check start values
create or replace sequence t1 start with 10;
show create sequence t1;
select * from t1;
create or replace sequence t1 minvalue=11;
show create sequence t1;
select * from t1;
create or replace sequence t1 maxvalue=13 increment by -1;
show create sequence t1;
select * from t1;
create or replace sequence t1 increment by -1 cache 100;
show create sequence t1;
select * from t1;
create or replace sequence t1 cycle;
show create sequence t1;
select * from t1;
create or replace sequence t1 nocycle;
show create sequence t1;
select * from t1;
show create sequence t1;
create or replace sequence t1 cycle minvalue= 14;
show create sequence t1;
select * from t1;
create or replace sequence t1 cycle increment by -1;
show create sequence t1;
drop sequence t1;
create sequence if not exists t1;
create sequence if not exists t1 start with 10;
select * from t1;
show create sequence t1;
create or replace sequence t1 start with 10 minvalue=10 maxvalue=11 nocache cycle;
show create sequence t1;
select * from t1;
create or replace sequence t1 start with 10 minvalue=-10 maxvalue=11 cache=10 cycle increment by 10;
show create sequence t1;
select * from t1;
# NO MINVALUE, NO MAXVALUE
create or replace sequence t1 start with 10 NO MAXVALUE NO MINVALUE;
# Some edge cases
create or replace sequence t1 start with 10 maxvalue 10;
create or replace sequence t1 start with 10 minvalue 10;
create or replace sequence t1 start with 10 minvalue 10 maxvalue 11 cycle;
create or replace sequence t1 start with 10 maxvalue=9223372036854775806;
create or replace sequence t1 start with 10 minvalue=-9223372036854775807;
drop sequence if exists t1;
create sequence t1 increment by 0;
show create sequence t1;
select * from t1;
drop sequence t1;
#
# Wrong usage and arguments to create sequence
#
create table t1 (a int);
--error ER_WRONG_OBJECT
show create sequence t1;
--error ER_NOT_SEQUENCE2
drop sequence t1;
drop sequence if exists t1;
--error ER_SEQUENCE_INVALID_DATA
create sequence t1 start with 10 maxvalue=9;
--error ER_SEQUENCE_INVALID_DATA
create sequence t1 minvalue= 100 maxvalue=10;
--error ER_SEQUENCE_INVALID_DATA
create sequence t1 start with 9 minvalue=10;
--error ER_PARSE_ERROR
create or replace sequence t1 maxvalue=13, increment by -1;
--error ER_PARSE_ERROR
create or replace sequence t1 start with= 10 maxvalue=13;
--error ER_PARSE_ERROR
create or replace sequence t1 maxvalue=13, increment= -1;
--error ER_PARSE_ERROR
create or replace sequence t1 start with 10 min_value=1 NO MINVALUE;
--error ER_PARSE_ERROR
create or replace sequence t1 start with 10 min_value=1 NO MINVALUE;
--error ER_SEQUENCE_INVALID_DATA
create sequence t1 start with 10 maxvalue=9223372036854775807;
--error ER_PARSE_ERROR
create sequence t1 start with 10 minvalue=-9223372036854775808;
# This should probably give an error
create or replace sequence t1 start with 10 NO MINVALUE minvalue=1;
drop sequence t1;
#
# Test with LIST COLUMNS as first command
#
create sequence t1;
show fields from t1;
flush tables;
show fields from t1;
create or replace sequence t1 engine=aria;
show fields from t1;
show fields from t1;
flush tables;
#
# Test with other create options
#
create or replace sequence t1 comment= "test 1";
show create sequence t1;
show create table t1;
create or replace sequence t1 comment= "test 2" min_rows=1 max_rows=2;
show create sequence t1;
show create table t1;
create or replace sequence t1 start=1 increment= 2;
create or replace sequence t1 start 1 increment 2;
drop sequence t1;
#
# test with create table
#
CREATE TABLE t1 (
`next_value` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) sequence=1;
show create sequence t1;
show create table t1;
drop sequence t1;
# Wrong column name
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
CREATE OR REPLACE TABLE t1 (
`next_val` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) sequence=1;
# Wrong type
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
CREATE OR REPLACE TABLE t1 (
`next_value` int(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) sequence=1;
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
CREATE OR REPLACE TABLE t1 (
`next_val` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` bigint(21) unsigned NOT NULL, /* error */
`round` bigint(21) NOT NULL
) sequence=1;
# Missing NOT NULL
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
CREATE OR REPLACE TABLE t1 (
`next_value` bigint(21),
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) sequence=1;
# Extra field
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
CREATE OR REPLACE TABLE t1 (
`next_value` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL,
extra_field bigint(21)
) sequence=1;
# Wrong field order
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
CREATE OR REPLACE TABLE t1 (
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`next_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL
) sequence=1;
# key
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
CREATE OR REPLACE TABLE t1 (
`next_value` bigint(21) NOT NULL,
`min_value` bigint(21) NOT NULL,
`max_value` bigint(21) NOT NULL,
`start` bigint(21) NOT NULL,
`increment` bigint(21) NOT NULL,
`cache` bigint(21) NOT NULL,
`cycle` tinyint(1) unsigned NOT NULL,
`round` bigint(21) NOT NULL,
key key1 (next_value)
) sequence=1;
drop sequence if exists t1;
#
# DROP SEQUENCE
#
create sequence t1;
create sequence t2;
create table t3 (a int) engine=myisam;
select table_catalog, table_schema, table_name, table_type from information_schema.tables where table_catalog="test";
CREATE SEQUENCE s1;
drop sequence s1;
drop sequence if exists t1,t2,t3,t4;
drop table if exists t1,t2,t3;
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
CREATE SEQUENCE s1;
drop table t1,t2,s1;
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
CREATE SEQUENCE s1;
drop table if exists t1,t2,s1,s2;
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
CREATE SEQUENCE s1;
--error ER_UNKNOWN_SEQUENCES
drop sequence t1,t2,s1,s2;
drop table if exists t1,t2;
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
CREATE SEQUENCE s1;
drop sequence if exists t1,t2,s1,s2;
drop table if exists t1,t2;
CREATE TEMPORARY SEQUENCE s1;
DROP SEQUENCE s1;
--error ER_UNKNOWN_SEQUENCES
DROP TEMPORARY SEQUENCE s1;
CREATE TEMPORARY SEQUENCE s1;
CREATE SEQUENCE s2;
CREATE TEMPORARY TABLE t1 (a int);
CREATE TABLE t2 (a int);
--error ER_UNKNOWN_SEQUENCES
DROP TEMPORARY SEQUENCE t1,t2,s1,s2;
--error ER_UNKNOWN_SEQUENCES
DROP TEMPORARY SEQUENCE s1;
DROP TEMPORARY TABLE t1;
--error ER_BAD_TABLE_ERROR
DROP TABLE t1,t2,s1,s2;
create view v1 as (select 1);
CREATE SEQUENCE s1;
--error ER_IT_IS_A_VIEW
DROP SEQUENCE s1,v1;
drop view v1;
#
# CREATE TEMPORARY SEQUENCE
#
CREATE TEMPORARY SEQUENCE t1;
select next value for t1;
drop temporary table t1;
--error ER_NO_SUCH_TABLE
select previous value for t1;
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 10;
select next value for t1;
select previous value for t1;
CREATE TEMPORARY SEQUENCE t1 start with 100 minvalue 100 maxvalue 200 increment by 1 cache 10;
select previous value for t1;
select next value for t1;
select previous value for t1;
drop temporary sequence t1;
select previous value for t1;
drop sequence t1;
CREATE TEMPORARY SEQUENCE t1 engine=innodb;
select next value for t1;
drop temporary table t1;
--error ER_NO_SUCH_TABLE
select previous value for t1;
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 10 engine=innodb;
select next value for t1;
select previous value for t1;
CREATE TEMPORARY SEQUENCE t1 start with 100 minvalue 100 maxvalue 200 increment by 1 cache 10 engine=innodb;
select previous value for t1;
select next value for t1;
select previous value for t1;
drop temporary sequence t1;
select previous value for t1;
drop sequence t1;
#
# Check that we can't create anything with the sequence engine
#
--error ER_UNKNOWN_STORAGE_ENGINE
create table t1 (a int) engine=sql_sequence;

View File

@ -0,0 +1,2 @@
gtid : Disabled until Monty has time to check the result
replication : Disabled until Monty has time to check the result

View File

@ -0,0 +1,3 @@
--binlog_format=row
--query_cache_type=1
--log-slave-updates

View File

@ -0,0 +1,4 @@
--binlog_format=row
--query_cache_type=1
--read_only=true
--log-slave-updates

View File

@ -0,0 +1,722 @@
include/master-slave.inc
Warnings:
Note #### Sending passwords in plain text without SSL/TLS is extremely insecure.
Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information.
[connection master]
create database s_db;
grant all on s_db.* to normal_1@'%' identified by 'pass';
grant all on test.* to normal_2@'%' identified by 'pass';
grant all on s_db.* to normal_3@'%' identified by 'pass';
grant all on test.* to normal_4@'%' identified by 'pass';
set global read_only=on;
###########################################
master and slave sync sequence.
###########################################
use s_db;
create sequence s1;
show create table s1;
Table Create Table
s1 CREATE SEQUENCE `s1` (
`currval` bigint(21) NOT NULL COMMENT 'current value',
`nextval` bigint(21) NOT NULL COMMENT 'next value',
`minvalue` bigint(21) NOT NULL COMMENT 'min value',
`maxvalue` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` bigint(21) NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'already how many round'
) ENGINE=InnoDB DEFAULT CHARSET=latin1
use s_db;
show create table s1;
Table Create Table
s1 CREATE SEQUENCE `s1` (
`currval` bigint(21) NOT NULL COMMENT 'current value',
`nextval` bigint(21) NOT NULL COMMENT 'next value',
`minvalue` bigint(21) NOT NULL COMMENT 'min value',
`maxvalue` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` bigint(21) NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'already how many round'
) ENGINE=InnoDB DEFAULT CHARSET=latin1
use s_db;
drop sequence s1;
###########################################
not support create table engine=sequence.
###########################################
create table t(id int)engine=sequence;
ERROR HY000: Table storage engine 'sequence' does not support the create option 'SEQUENCE'
create table t(id int)engine=innodb;
alter table t engine=sequence;
ERROR HY000: Table storage engine 'sequence' does not support the create option 'SEQUENCE'
drop table t;
###########################################
not support alter sequence table.
###########################################
create sequence s2;
alter table s2 add id int;
ERROR HY000: Table storage engine 'sequence' does not support the create option 'SEQUENCE'
alter table s2 add index ind_x(start);
ERROR HY000: Table storage engine 'sequence' does not support the create option 'SEQUENCE'
drop sequence s2;
###########################################
not support create temproary sequence.
###########################################
create temporary sequence s2;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'sequence s2' at line 1
###########################################
all invalid sequence value
###########################################
use s_db;
create sequence s2 start with 1
minvalue 1
maxvalue 100000
increment by 1
cache 10000
cycle;
drop sequence s2;
create sequence s2 start with 1
minvalue 1
maxvalue 100000
increment by 1
cache 10000
nocycle;
drop sequence s2;
create sequence s2 start with 1
minvalue 1
maxvalue 100000
increment by 1
nocache
nocycle;
drop sequence s2;
create sequence s2 start with 1
minvalue 5
maxvalue 100000
increment by 1
nocache
nocycle;
ERROR HY000: Sequence 's_db.s2' structure or number is invalid.
create sequence s2 start with 1
minvalue 5
maxvalue 5
increment by 1
nocache
nocycle;
ERROR HY000: Sequence 's_db.s2' structure or number is invalid.
create sequence s2 start with 1
minvalue 5
maxvalue 4
increment by 1
nocache
nocycle;
ERROR HY000: Sequence 's_db.s2' structure or number is invalid.
create sequence s2 start with 1
minvalue 5
maxvalue 4
increment by 0
nocache
nocycle;
ERROR HY000: Sequence 's_db.s2' structure or number is invalid.
###########################################
global read lock prevent query sequence
###########################################
use s_db;
create sequence s_db.s1;
flush table with read lock;
select * for s1;
ERROR HY000: Can't execute the query because you have a conflicting read lock
unlock tables;
drop sequence s_db.s1;
###########################################
session setting
###########################################
use s_db;
create sequence s1;
set session sequence_read_skip_cache=true;
select * for s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 0 1 9223372036854775807 1 1 10000 0 0
select nextval for s1;
nextval
0
select * for s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 0 1 9223372036854775807 1 1 10000 0 0
select nextval for s1;
nextval
0
set session sequence_read_skip_cache=false;
select * for s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 1 1 9223372036854775807 1 1 10000 0 0
select nextval for s1;
nextval
2
select * for s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 3 1 9223372036854775807 1 1 10000 0 0
select nextval for s1;
nextval
4
drop sequence s1;
###########################################
query cache test
###########################################
use s_db;
show global variables like 'query_cache_type';
Variable_name Value
query_cache_type ON
show status like 'Qcache_hits';
Variable_name Value
Qcache_hits 0
show status like 'Qcache_inserts';
Variable_name Value
Qcache_inserts 0
###########################################
priv test
###########################################
create sequence s_db.s1;
select * for s_db.s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 1 1 9223372036854775807 1 1 10000 0 0
create sequence s_db.s2;
drop sequence s_db.s2;
select * for s_db.s1;
ERROR 42000: SELECT command denied to user 'normal_2'@'localhost' for table 's1'
create sequence s_db.s2;
ERROR 42000: CREATE command denied to user 'normal_2'@'localhost' for table 's2'
drop sequence s_db.s1;
###########################################
run out sequence value
###########################################
use s_db;
create sequence s_t start with 1 cache 2 maxvalue 5;
create table t(id int);
insert into t values(1111);
insert into t select nextval for s_t;
insert into t select nextval for s_t;
insert into t select nextval for s_t;
insert into t select nextval for s_t;
insert into t select nextval for s_t;
insert into t select nextval for s_t;
ERROR HY000: Sequence 's_db.s_t' has been run out.
insert into t select nextval for s_t;
ERROR HY000: Sequence 's_db.s_t' has been run out.
commit;
select * from t;
id
1111
1
2
3
4
5
use s_db;
select * from t;
id
1111
1
2
3
4
5
use s_db;
drop sequence s_t;
drop table t;
###########################################
read_only prevent query sequence
###########################################
create sequence s_db.s1;
show global variables like 'read_only';
Variable_name Value
read_only OFF
select * for s_db.s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 1 1 9223372036854775807 1 1 10000 0 0
show global variables like 'read_only';
Variable_name Value
read_only ON
select * for s_db.s1;
ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
drop sequence s_db.s1;
###########################################
update based table
###########################################
use s_db;
create sequence s_t start with 1 minvalue 1 maxvalue 20 increment by 1 cache 5 cycle;
use s_db;
select * from s_t;
currval nextval minvalue maxvalue start increment cache cycle round
0 0 1 20 1 1 5 1 0
select nextval for s_t;
nextval
1
select nextval from s_t;
nextval
7
------------------------------------------
master update nextval;
------------------------------------------
select nextval for s_t;
nextval
2
update s_t set nextval= 11;
commit;
select * from s_t;
currval nextval minvalue maxvalue start increment cache cycle round
0 11 1 20 1 1 5 1 0
------------------------------------------
show slave nextval;
------------------------------------------
select * from s_t;
currval nextval minvalue maxvalue start increment cache cycle round
0 11 1 20 1 1 5 1 0
set session sequence_read_skip_cache=off;
select * for s_t;
currval nextval minvalue maxvalue start increment cache cycle round
0 11 1 20 1 1 5 1 0
select * from s_t;
currval nextval minvalue maxvalue start increment cache cycle round
0 17 1 20 1 1 5 1 0
------------------------------------------
update into invalid sequence
------------------------------------------
select nextval for s_t;
nextval
12
update s_t set nextval= 11,start=10, minvalue=11;
commit;
create table t_1(id int);
insert into t_1 value(1111);
select nextval for s_t;
ERROR HY000: Sequence 's_db.s_t' structure or number is invalid.
insert into t_1 select nextval for s_t;
ERROR HY000: Sequence 's_db.s_t' structure or number is invalid.
commit;
select * from t_1;
id
1111
------------------------------------------
delete sequence row
------------------------------------------
delete from s_t;
commit;
select nextval for s_t;
nextval
drop sequence s_t;
drop table t_1;
###########################################
test transaction context (innodb)
###########################################
------------------------------------------
transaction table and sequence
normal transaction commit
------------------------------------------
use s_db;
set session sequence_read_skip_cache=off;
create sequence s_1 cache 5;
create table t_1(id int)engine=innodb;
begin;
insert into t_1 values(1111);
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 values(2222);
commit;
select * from t_1;
id
1111
1
2
2222
set session sequence_read_skip_cache=off;
use s_db;
select * from t_1;
id
1111
1
2
2222
------------------------------------------
normal transaction rollback
------------------------------------------
begin;
insert into t_1 values(3333);
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
select * from t_1;
id
1111
1
2
2222
3333
3
4
5
6
7
8
9
10
rollback;
select * from t_1;
id
1111
1
2
2222
select nextval for s_1;
nextval
11
set session sequence_read_skip_cache=off;
use s_db;
select * from t_1;
id
1111
1
2
2222
use s_db;
drop sequence s_1;
drop table t_1;
###########################################
test transaction context (myisam)
###########################################
------------------------------------------
transaction table and sequence
normal transaction commit
------------------------------------------
use s_db;
set session sequence_read_skip_cache=off;
create sequence s_1 cache 5;
create table t_1(id int)engine=myisam;
begin;
insert into t_1 values(1111);
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 values(2222);
commit;
select * from t_1;
id
1111
1
2
2222
set session sequence_read_skip_cache=off;
use s_db;
select * from t_1;
id
1111
1
2
2222
------------------------------------------
normal transaction rollback
------------------------------------------
begin;
insert into t_1 values(3333);
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
insert into t_1 select nextval for s_1;
select * from t_1;
id
1111
1
2
2222
3333
3
4
5
6
7
8
9
10
rollback;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
select * from t_1;
id
1111
1
2
2222
3333
3
4
5
6
7
8
9
10
select nextval for s_1;
nextval
11
set session sequence_read_skip_cache=off;
use s_db;
select * from t_1;
id
1111
1
2
2222
3333
3
4
5
6
7
8
9
10
use s_db;
drop sequence s_1;
drop table t_1;
###########################################
close binlog
###########################################
use s_db;
create sequence s1 cache 2;
select nextval for s1;
nextval
1
select nextval for s1;
nextval
2
select nextval for s1;
nextval
3
select nextval for s1;
nextval
4
commit;
select * from s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 7 1 9223372036854775807 1 1 2 0 0
use s_db;
select * from s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 7 1 9223372036854775807 1 1 2 0 0
------------------------------------------
close session binlog.
------------------------------------------
set session sql_log_bin=off;
select nextval for s1;
nextval
5
select nextval for s1;
nextval
6
select nextval for s1;
nextval
7
select nextval for s1;
nextval
8
set session sql_log_bin=on;
select * from s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 10 1 9223372036854775807 1 1 2 0 0
use s_db;
select * from s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 7 1 9223372036854775807 1 1 2 0 0
use s_db;
drop sequence s1;
###########################################
statement binlog
###########################################
------------------------------------------
set binlog_format=statement
------------------------------------------
set session sequence_read_skip_cache=off;
set session binlog_format=statement;
show session variables like '%binlog_format%';
Variable_name Value
binlog_format STATEMENT
create sequence s1 cache 2;
select nextval for s1;
ERROR HY000: Sequence requires binlog_format= row
set session binlog_format=row;
select * for s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 1 1 9223372036854775807 1 1 2 0 0
use s_db;
select * from s1;
currval nextval minvalue maxvalue start increment cache cycle round
0 4 1 9223372036854775807 1 1 2 0 0
set session sequence_read_skip_cache=off;
use s_db;
drop sequence s1;
###########################################
test savepoint
###########################################
set session sequence_read_skip_cache=off;
set session binlog_format=row;
create sequence s1 cache 2;
create table t1(id int)engine=innodb;
begin;
insert into t1 values(1111);
savepoint sp1;
insert into t1 select nextval for s1;
insert into t1 select nextval for s1;
insert into t1 select nextval for s1;
insert into t1 values(2222);
select * from t1;
id
1111
1
2
3
2222
rollback to sp1;
select * from t1;
id
1111
select nextval for s1;
nextval
4
commit;
drop sequence s1;
drop table t1;
###########################################
test proc
###########################################
set session sequence_read_skip_cache=off;
use s_db;
create table t(id int)engine=innodb;
create procedure p1()
begin
create sequence s1 cache 2;
end//
create procedure p2()
begin
insert into t select nextval for s1;
commit;
end//
call p1();
call p2();
call p2();
call p2();
call p2();
select * from t;
id
1
2
3
4
use s_db;
select * from t;
id
1
2
3
4
drop table t;
drop sequence s1;
drop procedure p1;
drop procedure p2;
###########################################
test trigger
###########################################
set session sequence_read_skip_cache=off;
use s_db;
create sequence s1 cache 2;
create table t1(id int)engine=innodb;
create table t2(id int)engine=innodb;
CREATE TRIGGER tri_1
before INSERT ON t2 FOR EACH ROW
BEGIN
INSERT INTO t1 select nextval for s1;
END//
begin;
insert into t2 values(1111);
insert into t2 values(1111);
insert into t2 values(1111);
insert into t2 values(1111);
select * from t2;
id
1111
1111
1111
1111
select * from t1;
id
1
2
3
4
rollback;
select * from t2;
id
select * from t1;
id
select nextval for s1;
nextval
5
drop trigger tri_1;
drop table t1;
drop table t2;
drop sequence s1;
###########################################
test function
###########################################
set session sequence_read_skip_cache=off;
use s_db;
create sequence s1 cache 2;
create table t1(id int)engine=innodb;
CREATE function f1() returns int
BEGIN
INSERT INTO t1 select nextval for s1;
return (1);
END//
begin;
select f1();
f1()
1
select f1();
f1()
1
select f1();
f1()
1
select f1();
f1()
1
select * from t1;
id
1
2
3
4
rollback;
select * from t1;
id
select nextval for s1;
nextval
5
drop function f1;
drop table t1;
drop sequence s1;
use s_db;
drop database s_db;
drop user normal_1@'%';
drop user normal_2@'%';
drop user normal_3@'%';
drop user normal_4@'%';
include/rpl_end.inc

View File

@ -0,0 +1,660 @@
--source include/have_binlog_format_row.inc
--source include/master-slave.inc
--source include/have_innodb.inc
connection master;
create database s_db;
grant all on s_db.* to normal_1@'%' identified by 'pass';
grant all on test.* to normal_2@'%' identified by 'pass';
grant all on s_db.* to normal_3@'%' identified by 'pass';
grant all on test.* to normal_4@'%' identified by 'pass';
--sync_slave_with_master
connect(m_normal_1, 127.0.0.1, normal_1, pass, s_db, $MASTER_MYPORT);
connect(m_normal_2, 127.0.0.1, normal_2, pass, test, $MASTER_MYPORT);
connect(s_normal_3, 127.0.0.1, normal_3, pass, s_db, $SLAVE_MYPORT);
connect(s_normal_4, 127.0.0.1, normal_4, pass, test, $SLAVE_MYPORT);
connection slave;
set global read_only=on;
--echo ###########################################
--echo master and slave sync sequence.
--echo ###########################################
connection master;
use s_db;
create sequence s1;
show create table s1;
--sync_slave_with_master
connection slave;
use s_db;
show create table s1;
connection master;
use s_db;
drop sequence s1;
--echo ###########################################
--echo not support create table engine=sequence.
--echo ###########################################
connection master;
--error ER_UNKNOWN_STORAGE_ENGINE
create table t(id int)engine=sequence;
create table t(id int)engine=innodb;
--error ER_UNKNOWN_STORAGE_ENGINE
alter table t engine=sequence;
drop table t;
--echo ###########################################
--echo not support alter sequence table.
--echo ###########################################
connection master;
create sequence s2;
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
alter table s2 add id int;
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
alter table s2 add index ind_x(start);
drop sequence s2;
--echo ###########################################
--echo Support create temporary sequence.
--echo ###########################################
connection master;
create temporary sequence s2;
drop temporary sequence s2;
--echo ###########################################
--echo all invalid sequence value
--echo ###########################################
connection master;
use s_db;
create sequence s2 start with 1
minvalue 1
maxvalue 100000
increment by 1
cache 10000
cycle;
drop sequence s2;
create sequence s2 start with 1
minvalue 1
maxvalue 100000
increment by 1
cache 10000
nocycle;
drop sequence s2;
create sequence s2 start with 1
minvalue 1
maxvalue 100000
increment by 1
nocache
nocycle;
drop sequence s2;
--error ER_SEQUENCE_INVALID_DATA
create sequence s2 start with 1
minvalue 5
maxvalue 100000
increment by 1
nocache
nocycle;
--error ER_SEQUENCE_INVALID_DATA
create sequence s2 start with 1
minvalue 5
maxvalue 5
increment by 1
nocache
nocycle;
--error ER_SEQUENCE_INVALID_DATA
create sequence s2 start with 1
minvalue 5
maxvalue 4
increment by 1
nocache
nocycle;
--error ER_SEQUENCE_INVALID_DATA
create sequence s2 start with 1
minvalue 5
maxvalue 4
increment by 0
nocache
nocycle;
--echo ###########################################
--echo global read lock prevent query sequence
--echo ###########################################
connection master;
use s_db;
create sequence s_db.s1;
flush table with read lock;
--error ER_CANT_UPDATE_WITH_READLOCK
select next value for s1;
unlock tables;
drop sequence s_db.s1;
--echo ###########################################
--echo query cache test
--echo ###########################################
connection master;
use s_db;
show global variables like 'query_cache_type';
show status like 'Qcache_hits';
show status like 'Qcache_inserts';
--echo ###########################################
--echo priv test
--echo ###########################################
connection m_normal_1;
create sequence s_db.s1;
select next value for s_db.s1;
create sequence s_db.s2;
drop sequence s_db.s2;
connection m_normal_2;
--error ER_TABLEACCESS_DENIED_ERROR
select next value for s_db.s1;
--error ER_TABLEACCESS_DENIED_ERROR
create sequence s_db.s2;
connection m_normal_1;
drop sequence s_db.s1;
--echo ###########################################
--echo run out sequence value
--echo ###########################################
connection m_normal_1;
use s_db;
create sequence s_t start with 1 cache 2 maxvalue 5;
create table t(id int);
insert into t values(1111);
insert into t select next value for s_t;
insert into t select next value for s_t;
insert into t select next value for s_t;
insert into t select next value for s_t;
insert into t select next value for s_t;
--error ER_SEQUENCE_RUN_OUT
insert into t select next value for s_t;
--error ER_SEQUENCE_RUN_OUT
insert into t select next value for s_t;
commit;
select * from t;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from t;
connection m_normal_1;
use s_db;
drop sequence s_t;
drop table t;
--echo ###########################################
--echo read_only prevent query sequence
--echo ###########################################
connection m_normal_1;
create sequence s_db.s1;
show global variables like 'read_only';
select next value for s_db.s1;
connection s_normal_3;
show global variables like 'read_only';
--error ER_OPTION_PREVENTS_STATEMENT
select next value for s_db.s1;
connection m_normal_1;
drop sequence s_db.s1;
--echo ###########################################
--echo update based table
--echo ###########################################
connection m_normal_1;
use s_db;
create sequence s_t start with 1 minvalue 1 maxvalue 20 increment by 1 cache 5 cycle;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from s_t;
connection m_normal_1;
select next value for s_t;
connection master;
--sync_slave_with_master
connection s_normal_3;
select * from s_t;
--echo ------------------------------------------
--echo master update nextval;
--echo ------------------------------------------
connection m_normal_1;
select next value for s_t;
update s_t set next_value= 11;
commit;
select * from s_t;
connection master;
--sync_slave_with_master
--echo ------------------------------------------
--echo show slave nextval;
--echo ------------------------------------------
connection s_normal_3;
select * from s_t;
connection m_normal_1;
select next value for s_t;
select * from s_t;
connection master;
--sync_slave_with_master
connection s_normal_3;
select * from s_t;
--echo ------------------------------------------
--echo update into invalid sequence
--echo ------------------------------------------
connection m_normal_1;
select * from s_t;
--error ER_SEQUENCE_INVALID_DATA
update s_t set next_value= 11,start=10, min_value=11;
commit;
create table t_1(id int);
insert into t_1 value(1111);
select next value for s_t;
insert into t_1 select next value for s_t;
commit;
select * from t_1;
--echo ------------------------------------------
--echo delete sequence row
--echo ------------------------------------------
connection m_normal_1;
--error ER_ILLEGAL_HA
delete from s_t;
commit;
select next value for s_t;
connection m_normal_1;
drop sequence s_t;
drop table t_1;
--echo ###########################################
--echo test transaction context (innodb)
--echo ###########################################
--echo ------------------------------------------
--echo transaction table and sequence
--echo normal transaction commit
--echo ------------------------------------------
connection m_normal_1;
use s_db;
create sequence s_1 cache 5;
create table t_1(id int)engine=innodb;
begin;
insert into t_1 values(1111);
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 values(2222);
commit;
select * from t_1;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from t_1;
--echo ------------------------------------------
--echo normal transaction rollback
--echo ------------------------------------------
connection m_normal_1;
begin;
insert into t_1 values(3333);
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
select * from t_1;
rollback;
select * from t_1;
select next value for s_1;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from t_1;
connection m_normal_1;
use s_db;
drop sequence s_1;
drop table t_1;
--echo ###########################################
--echo test transaction context (myisam)
--echo ###########################################
--echo ------------------------------------------
--echo transaction table and sequence
--echo normal transaction commit
--echo ------------------------------------------
connection m_normal_1;
use s_db;
create sequence s_1 cache 5;
create table t_1(id int)engine=myisam;
begin;
insert into t_1 values(1111);
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 values(2222);
commit;
select * from t_1;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from t_1;
--echo ------------------------------------------
--echo normal transaction rollback
--echo ------------------------------------------
connection m_normal_1;
begin;
insert into t_1 values(3333);
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
select * from t_1;
rollback;
select * from t_1;
select next value for s_1;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from t_1;
connection m_normal_1;
use s_db;
drop sequence s_1;
drop table t_1;
--echo ###########################################
--echo close binlog
--echo ###########################################
connection m_normal_1;
use s_db;
create sequence s1 cache 2;
select next value for s1;
select next value for s1;
select next value for s1;
select next value for s1;
commit;
select * from s1;
connection master;
--sync_slave_with_master
connection slave;
use s_db;
select * from s1;
--echo ------------------------------------------
--echo close session binlog.
--echo ------------------------------------------
connection master;
set session sql_log_bin=off;
select next value for s1;
select next value for s1;
select next value for s1;
select next value for s1;
set session sql_log_bin=on;
select * from s1;
connection master;
--sync_slave_with_master
connection slave;
use s_db;
select * from s1;
connection m_normal_1;
use s_db;
drop sequence s1;
--echo ###########################################
--echo statement binlog
--echo ###########################################
--echo ------------------------------------------
--echo set binlog_format=statement
--echo ------------------------------------------
connection master;
set session binlog_format=statement;
show session variables like '%binlog_format%';
create sequence s1 cache 2;
--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
select next value for s1;
set session binlog_format=row;
select next value for s1;
connection master;
--sync_slave_with_master
connection slave;
use s_db;
select * from s1;
connection m_normal_1;
use s_db;
drop sequence s1;
--echo ###########################################
--echo test savepoint
--echo ###########################################
connection master;
set session binlog_format=row;
create sequence s1 cache 2;
create table t1(id int)engine=innodb;
begin;
insert into t1 values(1111);
savepoint sp1;
insert into t1 select next value for s1;
insert into t1 select next value for s1;
insert into t1 select next value for s1;
insert into t1 values(2222);
select * from t1;
rollback to sp1;
select * from t1;
select next value for s1;
commit;
drop sequence s1;
drop table t1;
--echo ###########################################
--echo test proc
--echo ###########################################
connection m_normal_1;
use s_db;
create table t(id int)engine=innodb;
delimiter //;
create procedure p1()
begin
create sequence s1 cache 2;
end//
create procedure p2()
begin
insert into t select next value for s1;
commit;
end//
delimiter ;//
call p1();
call p2();
call p2();
call p2();
call p2();
select * from t;
connection master;
--sync_slave_with_master
connection slave;
use s_db;
select * from t;
connection m_normal_1;
drop table t;
drop sequence s1;
drop procedure p1;
drop procedure p2;
--echo ###########################################
--echo test trigger
--echo ###########################################
connection m_normal_1;
use s_db;
create sequence s1 cache 2;
create table t1(id int)engine=innodb;
create table t2(id int)engine=innodb;
delimiter //;
CREATE TRIGGER tri_1
before INSERT ON t2 FOR EACH ROW
BEGIN
INSERT INTO t1 select next value for s1;
END//
delimiter ;//
begin;
insert into t2 values(1111);
insert into t2 values(1111);
insert into t2 values(1111);
insert into t2 values(1111);
select * from t2;
select * from t1;
rollback;
select * from t2;
select * from t1;
select next value for s1;
drop trigger tri_1;
drop table t1;
drop table t2;
drop sequence s1;
--echo ###########################################
--echo test function
--echo ###########################################
connection m_normal_1;
use s_db;
create sequence s1 cache 2;
create table t1(id int)engine=innodb;
delimiter //;
CREATE function f1() returns int
BEGIN
INSERT INTO t1 select next value for s1;
return (1);
END//
delimiter ;//
begin;
select f1();
select f1();
select f1();
select f1();
select * from t1;
rollback;
select * from t1;
select next value for s1;
drop function f1;
drop table t1;
drop sequence s1;
connection master;
use s_db;
drop database s_db;
drop user normal_1@'%';
drop user normal_2@'%';
drop user normal_3@'%';
drop user normal_4@'%';
--sync_slave_with_master
--source include/rpl_end.inc

View File

@ -0,0 +1,404 @@
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 2 cycle;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`next_value` bigint(21) NOT NULL COMMENT 'next not cached value',
`min_value` bigint(21) NOT NULL COMMENT 'min value',
`max_value` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` tinyint(1) unsigned NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'How many cycles has been done'
) ENGINE=MyISAM SEQUENCE=1
select next value for t1;
next value for t1
1
select next_value,round from t1;
next_value round
3 0
select next value for t1;
next value for t1
2
select next_value,round from t1;
next_value round
3 0
select next value for t1;
next value for t1
3
select next_value,round from t1;
next_value round
5 0
select next value for t1;
next value for t1
4
select next_value,round from t1;
next_value round
5 0
select next value for t1;
next value for t1
5
select next_value,round from t1;
next_value round
7 0
select next value for t1;
next value for t1
6
select next_value,round from t1;
next_value round
7 0
select next value for t1;
next value for t1
7
select next_value,round from t1;
next_value round
9 0
select next value for t1;
next value for t1
8
select next_value,round from t1;
next_value round
9 0
select next value for t1;
next value for t1
9
select next_value,round from t1;
next_value round
11 0
select next value for t1;
next value for t1
10
select next_value,round from t1;
next_value round
11 0
select next value for t1;
next value for t1
1
select next_value,round from t1;
next_value round
3 1
select NEXT VALUE for t1,seq from seq_1_to_20;
NEXT VALUE for t1 seq
2 1
3 2
4 3
5 4
6 5
7 6
8 7
9 8
10 9
1 10
2 11
3 12
4 13
5 14
6 15
7 16
8 17
9 18
10 19
1 20
drop sequence t1;
CREATE SEQUENCE t1 minvalue 1 maxvalue 10 increment by -1 cache 2 cycle engine=aria;
select next value for t1;
next value for t1
10
select next_value,round from t1;
next_value round
8 0
select next value for t1;
next value for t1
9
select next_value,round from t1;
next_value round
8 0
select next value for t1;
next value for t1
8
select next_value,round from t1;
next_value round
6 0
select next value for t1;
next value for t1
7
select next_value,round from t1;
next_value round
6 0
select next value for t1;
next value for t1
6
select next_value,round from t1;
next_value round
4 0
select next value for t1;
next value for t1
5
select next_value,round from t1;
next_value round
4 0
select next value for t1;
next value for t1
4
select next_value,round from t1;
next_value round
2 0
select next value for t1;
next value for t1
3
select next_value,round from t1;
next_value round
2 0
select next value for t1;
next value for t1
2
select next_value,round from t1;
next_value round
0 0
select next value for t1;
next value for t1
1
select next_value,round from t1;
next_value round
0 0
select next value for t1;
next value for t1
10
select next_value,round from t1;
next_value round
8 1
select NEXT VALUE for t1,seq from seq_1_to_20;
NEXT VALUE for t1 seq
9 1
8 2
7 3
6 4
5 5
4 6
3 7
2 8
1 9
10 10
9 11
8 12
7 13
6 14
5 15
4 16
3 17
2 18
1 19
10 20
drop sequence t1;
CREATE SEQUENCE t1 start with 8 minvalue 1 maxvalue 10 increment by 1 cache 2 nocycle;
select next value for t1;
next value for t1
8
select next value for t1;
next value for t1
9
select next value for t1;
next value for t1
10
select previous value for t1;
previous value for t1
10
select next value for t1;
ERROR HY000: Sequence 'test.t1' has run out
select previous value for t1;
previous value for t1
NULL
select next value for t1;
ERROR HY000: Sequence 'test.t1' has run out
drop sequence t1;
create sequence s1 start with 1 cache 2 maxvalue 5;
select next value for s1;
next value for s1
1
select next value for s1;
next value for s1
2
select next value for s1;
next value for s1
3
select next value for s1;
next value for s1
4
select next value for s1;
next value for s1
5
select next value for s1;
ERROR HY000: Sequence 'test.s1' has run out
drop sequence s1;
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 100 increment by 1 cache 10;
select next value for t1;
next value for t1
1
select * from t1;
next_value min_value max_value start increment cache cycle round
11 1 100 1 1 10 0 0
flush tables;
select next value for t1;
next value for t1
11
select nextval(t1);
nextval(t1)
12
drop sequence t1;
CREATE SEQUENCE t9 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
select previous value for t9;
previous value for t9
NULL
select next value for t9;
next value for t9
1
select previous value for t9, lastval(t9);
previous value for t9 lastval(t9)
1 1
select next value for t9;
next value for t9
2
select previous value for t9, lastval(t9);
previous value for t9 lastval(t9)
2 2
select seq, previous value for t9, NEXT VALUE for t9, previous value for t9 from seq_1_to_20;
seq previous value for t9 NEXT VALUE for t9 previous value for t9
1 2 3 3
2 3 4 4
3 4 5 5
4 5 6 6
5 6 7 7
6 7 8 8
7 8 9 9
8 9 10 10
9 10 1 1
10 1 2 2
11 2 3 3
12 3 4 4
13 4 5 5
14 5 6 6
15 6 7 7
16 7 8 8
17 8 9 9
18 9 10 10
19 10 1 1
20 1 2 2
select * from t9;
next_value min_value max_value start increment cache cycle round
6 1 10 1 1 5 1 2
drop sequence t9;
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
select next value for t1;
next value for t1
1
select previous value for t1;
previous value for t1
1
flush tables;
select previous value for t1;
previous value for t1
1
drop sequence t1;
select previous value for t1;
ERROR 42S02: Table 'test.t1' doesn't exist
CREATE SEQUENCE t1 start with 5 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
select previous value for t1;
previous value for t1
NULL
select next value for t1;
next value for t1
5
select previous value for t1;
previous value for t1
5
drop sequence t1;
CREATE or replace SEQUENCE s1 MINVALUE 1 MAXVALUE 9999999999
INCREMENT BY 1 START WITH 3984356 CACHE 20 CYCLE engine=innodb;
show create table s1;
Table Create Table
s1 CREATE TABLE `s1` (
`next_value` bigint(21) NOT NULL COMMENT 'next not cached value',
`min_value` bigint(21) NOT NULL COMMENT 'min value',
`max_value` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` tinyint(1) unsigned NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'How many cycles has been done'
) ENGINE=InnoDB SEQUENCE=1
select * from s1;
next_value min_value max_value start increment cache cycle round
3984356 1 9999999999 3984356 1 20 1 0
select NEXT VALUE FOR s1;
NEXT VALUE FOR s1
3984356
select NEXT VALUE FOR s1;
NEXT VALUE FOR s1
3984357
select NEXT VALUE FOR s1;
NEXT VALUE FOR s1
3984358
select * from s1;
next_value min_value max_value start increment cache cycle round
3984376 1 9999999999 3984356 1 20 1 0
FLUSH TABLES;
select * from s1;
next_value min_value max_value start increment cache cycle round
3984376 1 9999999999 3984356 1 20 1 0
select NEXT VALUE FOR s1;
NEXT VALUE FOR s1
3984376
select * from s1;
next_value min_value max_value start increment cache cycle round
3984396 1 9999999999 3984356 1 20 1 0
drop sequence s1;
CREATE SEQUENCE t1 start with 5 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
explain select next value for t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
explain select next value for t1, min_value from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
drop table t1;
CREATE SEQUENCE s1;
CREATE TABLE t1 (a int);
insert into t1 values (next value for s1);
insert into t1 values (next value for s1);
select * from t1;
a
1
2
drop table t1,s1;
CREATE SEQUENCE s1;
CREATE TABLE t1 (a int primary key auto_increment, b int default 0) engine=myisam;
insert into t1 values (),(),(),(),(),(),();
update t1 set b= next value for s1 where a <= 3;
select * from t1;
a b
1 1
2 2
3 3
4 0
5 0
6 0
7 0
drop table t1,s1;
CREATE OR REPLACE SEQUENCE s1 MINVALUE 1 MAXVALUE 9999999999 INCREMENT BY 1 START WITH 3984356 nocache CYCLE engine='innodb';
select * from s1;
next_value min_value max_value start increment cache cycle round
3984356 1 9999999999 3984356 1 0 1 0
select next value for s1;
next value for s1
3984356
drop sequence s1;
create table t1 (a int);
select next value for t1;
ERROR 42S02: 'test.t1' is not a SEQUENCE
drop table t1;
create sequence t1;
select next value for t1;
next value for t1
1
select next value for t1, min_value;
ERROR 42S22: Unknown column 'min_value' in 'field list'
drop sequence t1;

View File

@ -0,0 +1,201 @@
--source include/have_sequence.inc
--source include/have_innodb.inc
#
# Test sequence generation
#
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 2 cycle;
show create table t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select NEXT VALUE for t1,seq from seq_1_to_20;
drop sequence t1;
CREATE SEQUENCE t1 minvalue 1 maxvalue 10 increment by -1 cache 2 cycle engine=aria;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select next value for t1;
select next_value,round from t1;
select NEXT VALUE for t1,seq from seq_1_to_20;
drop sequence t1;
CREATE SEQUENCE t1 start with 8 minvalue 1 maxvalue 10 increment by 1 cache 2 nocycle;
select next value for t1;
select next value for t1;
select next value for t1;
select previous value for t1;
--error ER_SEQUENCE_RUN_OUT
select next value for t1;
select previous value for t1;
--error ER_SEQUENCE_RUN_OUT
select next value for t1;
drop sequence t1;
create sequence s1 start with 1 cache 2 maxvalue 5;
select next value for s1;
select next value for s1;
select next value for s1;
select next value for s1;
select next value for s1;
--error ER_SEQUENCE_RUN_OUT
select next value for s1;
drop sequence s1;
#
# Test that flush tables jumps to next next_value
#
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 100 increment by 1 cache 10;
select next value for t1;
select * from t1;
flush tables;
select next value for t1;
select nextval(t1);
drop sequence t1;
#
# Test currval/previous
#
CREATE SEQUENCE t9 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
select previous value for t9;
select next value for t9;
select previous value for t9, lastval(t9);
select next value for t9;
select previous value for t9, lastval(t9);
select seq, previous value for t9, NEXT VALUE for t9, previous value for t9 from seq_1_to_20;
select * from t9;
drop sequence t9;
#
# Check what happens when one refers to a sequence that has been closed/deleted
#
CREATE SEQUENCE t1 start with 1 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
select next value for t1;
select previous value for t1;
flush tables;
select previous value for t1;
drop sequence t1;
--error ER_NO_SUCH_TABLE
select previous value for t1;
CREATE SEQUENCE t1 start with 5 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
select previous value for t1;
select next value for t1;
select previous value for t1;
drop sequence t1;
# This failed in an early build
CREATE or replace SEQUENCE s1 MINVALUE 1 MAXVALUE 9999999999
INCREMENT BY 1 START WITH 3984356 CACHE 20 CYCLE engine=innodb;
show create table s1;
select * from s1;
select NEXT VALUE FOR s1;
select NEXT VALUE FOR s1;
select NEXT VALUE FOR s1;
select * from s1;
FLUSH TABLES;
select * from s1;
select NEXT VALUE FOR s1;
select * from s1;
drop sequence s1;
#
# Explain
#
CREATE SEQUENCE t1 start with 5 minvalue 1 maxvalue 10 increment by 1 cache 5 cycle;
explain select next value for t1;
explain select next value for t1, min_value from t1;
drop table t1;
#
# Using insert with NEXT VALUE
#
CREATE SEQUENCE s1;
CREATE TABLE t1 (a int);
insert into t1 values (next value for s1);
insert into t1 values (next value for s1);
select * from t1;
drop table t1,s1;
#
# Using update with NEXT VALUE
#
CREATE SEQUENCE s1;
CREATE TABLE t1 (a int primary key auto_increment, b int default 0) engine=myisam;
insert into t1 values (),(),(),(),(),(),();
update t1 set b= next value for s1 where a <= 3;
select * from t1;
drop table t1,s1;
#
# NO CACHE and InnoDB
#
CREATE OR REPLACE SEQUENCE s1 MINVALUE 1 MAXVALUE 9999999999 INCREMENT BY 1 START WITH 3984356 nocache CYCLE engine='innodb';
select * from s1;
select next value for s1;
drop sequence s1;
#
# Some error testing
#
create table t1 (a int);
--error ER_NOT_SEQUENCE
select next value for t1;
drop table t1;
create sequence t1;
select next value for t1;
--error ER_BAD_FIELD_ERROR
select next value for t1, min_value;
drop sequence t1;

View File

@ -0,0 +1,25 @@
create sequence s1 cache 2 engine=innodb;
connection default;
show global variables like 'innodb_read_only';
Variable_name Value
innodb_read_only ON
use test;
set session binlog_format= row;
###########################################
read_only create error.
###########################################
show global variables like 'innodb_read_only';
Variable_name Value
innodb_read_only ON
use test;
create sequence s2 cache 5 engine=innodb;
ERROR HY000: Can't create table `test`.`s2` (errno: 165 "Table is read only")
###########################################
read_only query error.
###########################################
select next value for s1;
ERROR HY000: Table 's1' is read only
select next value for s1;
ERROR HY000: Table 's1' is read only
select next value for s1;
ERROR HY000: Table 's1' is read only

View File

@ -0,0 +1,39 @@
--source include/have_innodb.inc
#
# Test innodb read only
#
create sequence s1 cache 2 engine=innodb;
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server 10
--source include/wait_until_disconnected.inc
--enable_reconnect
--exec echo "restart":--innodb_read_only=1 > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--source include/wait_until_connected_again.inc
connection default;
show global variables like 'innodb_read_only';
use test;
set session binlog_format= row;
--echo ###########################################
--echo read_only create error.
--echo ###########################################
show global variables like 'innodb_read_only';
use test;
--error ER_CANT_CREATE_TABLE
create sequence s2 cache 5 engine=innodb;
--echo ###########################################
--echo read_only query error.
--echo ###########################################
--error ER_OPEN_AS_READONLY
select next value for s1;
--error ER_OPEN_AS_READONLY
select next value for s1;
--error ER_OPEN_AS_READONLY
select next value for s1;

View File

@ -0,0 +1 @@
--binlog_format=row --query_cache_type=1

View File

@ -0,0 +1 @@
--binlog_format=row --query_cache_type=1 --read_only=true

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,881 @@
--source include/have_binlog_format_row.inc
--source include/master-slave.inc
--source include/have_innodb.inc
#
# This test is originally sequence.test from Jianwei modified for MariaDB
# To test basic sequence functionallity together with replication
#
connection master;
create database s_db;
grant all on s_db.* to normal_1@'%' identified by 'pass';
grant all on test.* to normal_2@'%' identified by 'pass';
grant all on s_db.* to normal_3@'%' identified by 'pass';
grant all on test.* to normal_4@'%' identified by 'pass';
--sync_slave_with_master
connect(m_normal_1, 127.0.0.1, normal_1, pass, s_db, $MASTER_MYPORT);
connect(m_normal_2, 127.0.0.1, normal_2, pass, test, $MASTER_MYPORT);
connect(s_normal_3, 127.0.0.1, normal_3, pass, s_db, $SLAVE_MYPORT);
connect(s_normal_4, 127.0.0.1, normal_4, pass, test, $SLAVE_MYPORT);
connection slave;
set global read_only=on;
--echo ###########################################
--echo master and slave sync sequence.
--echo ###########################################
connection master;
use s_db;
create sequence s1;
show create table s1;
--sync_slave_with_master
connection slave;
use s_db;
show create table s1;
connection master;
use s_db;
drop sequence s1;
--echo ###########################################
--echo not support create table engine=sequence.
--echo ###########################################
connection master;
--error ER_UNKNOWN_STORAGE_ENGINE
create table t(id int)engine=sequence;
create table t(id int)engine=innodb;
--error ER_UNKNOWN_STORAGE_ENGINE
alter table t engine=sequence;
drop table t;
--echo ###########################################
--echo not support alter sequence table.
--echo ###########################################
connection master;
create sequence s2;
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
alter table s2 add id int;
--error ER_SEQUENCE_INVALID_TABLE_STRUCTURE
alter table s2 add index ind_x(start);
drop sequence s2;
--echo ###########################################
--echo support create sequence
--echo ###########################################
connection master;
create table t_1(id int);
--error ER_WRONG_OBJECT
show create sequence t_1;
drop table t_1;
--error ER_PARSE_ERROR
CREATE SEQUENCE `s2` (
`currval` bigint(21) NOT NULL COMMENT 'current value',
`nextval` bigint(21) NOT NULL COMMENT 'next value',
`minvalue` bigint(21) NOT NULL COMMENT 'min value',
`maxvalue` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` bigint(21) NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'already how many round'
) ENGINE=InnoDB sequence=1;
CREATE TABLE `s2` (
`next_value` bigint(21) NOT NULL COMMENT 'next value',
`min_value` bigint(21) NOT NULL COMMENT 'min value',
`max_value` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` tinyint(1) unsigned NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'already how many round'
) ENGINE=InnoDB sequence=1;
insert into s2 values(0, 1, 10, 1, 2, 1, 1, 0);
commit;
--error ER_PARSE_ERROR
select * for s2;
select NEXT VALUE for s2;
select NEXT VALUE for s2;
select NEXT VALUE for s2;
select * from s2;
commit;
connection master;
--sync_slave_with_master
select * from s2;
connection slave;
select * from s2;
connection master;
drop sequence s2;
CREATE TABLE `s2` (
`next_value` bigint(21) NOT NULL COMMENT 'next value',
`min_value` bigint(21) NOT NULL COMMENT 'min value',
`max_value` bigint(21) NOT NULL COMMENT 'max value',
`start` bigint(21) NOT NULL COMMENT 'start value',
`increment` bigint(21) NOT NULL COMMENT 'increment value',
`cache` bigint(21) NOT NULL COMMENT 'cache size',
`cycle` tinyint(1) unsigned NOT NULL COMMENT 'cycle state',
`round` bigint(21) NOT NULL COMMENT 'already how many round'
) ENGINE=myisam DEFAULT CHARSET=latin1 sequence=1;
show create sequence s2;
drop sequence s2;
--echo ###########################################
--echo select sequence syntax test
--echo ###########################################
connection master;
create sequence s2;
create table t2 (id int);
select * from s2;
select * from t2;
insert into t2 select next value for s2;
commit;
select NEXT VALUE for s2;
--error ER_NOT_SEQUENCE
select NEXT VALUE for t2;
select * from s2, t2;
--error ER_PARSE_ERROR
select * for s2;
--error ER_PARSE_ERROR
select * for s2, t2;
connection master;
drop sequence s2;
drop table t2;
--echo ###########################################
--echo support rename, not support truncate
--echo ###########################################
connection master;
create sequence s2;
alter table s2 rename to s2_1;
rename table s2_1 to s2_2;
show create sequence s2_2;
select * from s2_2;
--error ER_ILLEGAL_HA
truncate table s2_2;
rename table s2_2 to s2;
drop sequence s2;
--echo ###########################################
--echo all invalid sequence value
--echo ###########################################
connection master;
use s_db;
create sequence s2 start with 1
minvalue 1
maxvalue 100000
increment by 1
cache 10000
cycle;
drop sequence s2;
create sequence s2 start with 1
minvalue 1
maxvalue 100000
increment by 1
cache 10000
nocycle;
drop sequence s2;
create sequence s2 start with 1
minvalue 1
maxvalue 100000
increment by 1
nocache
nocycle;
drop sequence s2;
--error ER_SEQUENCE_INVALID_DATA
create sequence s2 start with 1
minvalue 5
maxvalue 100000
increment by 1
nocache
nocycle;
--error ER_SEQUENCE_INVALID_DATA
create sequence s2 start with 1
minvalue 5
maxvalue 5
increment by 1
nocache
nocycle;
--error ER_SEQUENCE_INVALID_DATA
create sequence s2 start with 1
minvalue 5
maxvalue 4
increment by 1
nocache
nocycle;
--error ER_SEQUENCE_INVALID_DATA
create sequence s2 start with 1
minvalue 5
maxvalue 4
increment by 0
nocache
nocycle;
--echo ###########################################
--echo global read lock prevent query sequence
--echo ###########################################
connection master;
use s_db;
create sequence s_db.s1;
flush table with read lock;
--error ER_CANT_UPDATE_WITH_READLOCK
select NEXT VALUE for s1;
unlock tables;
drop sequence s_db.s1;
--echo ###########################################
--echo query cache test
--echo ###########################################
connection master;
use s_db;
flush status;
show global variables like 'query_cache_type';
show status like 'Qcache_hits';
show status like 'Qcache_inserts';
--echo ###########################################
--echo priv test
--echo ###########################################
connection m_normal_1;
create sequence s_db.s1;
select NEXT VALUE for s_db.s1;
create sequence s_db.s2;
drop sequence s_db.s2;
connection m_normal_2;
--error ER_TABLEACCESS_DENIED_ERROR
select NEXT VALUE for s_db.s1;
--error ER_TABLEACCESS_DENIED_ERROR
create sequence s_db.s2;
connection m_normal_1;
drop sequence s_db.s1;
--echo ###########################################
--echo run out sequence value
--echo ###########################################
connection m_normal_1;
use s_db;
create sequence s_t start with 1 cache 2 maxvalue 5;
create table t(id int);
insert into t values(1111);
insert into t select next value for s_t;
insert into t select next value for s_t;
insert into t select next value for s_t;
insert into t select next value for s_t;
insert into t select next value for s_t;
--error ER_SEQUENCE_RUN_OUT
insert into t select next value for s_t;
--error ER_SEQUENCE_RUN_OUT
insert into t select next value for s_t;
commit;
select * from t;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from t;
connection m_normal_1;
use s_db;
drop sequence s_t;
drop table t;
--echo ###########################################
--echo read_only prevent query sequence
--echo ###########################################
connection m_normal_1;
create sequence s_db.s1;
show global variables like 'read_only';
select * from s_db.s1;
connection s_normal_3;
show global variables like 'read_only';
--error ER_OPTION_PREVENTS_STATEMENT
select next value for s_db.s1;
connection m_normal_1;
drop sequence s_db.s1;
--echo ###########################################
--echo update based table
--echo ###########################################
connection m_normal_1;
use s_db;
create sequence s_t start with 1 minvalue 1 maxvalue 20 increment by 1 cache 5 cycle engine=innodb;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from s_t;
connection m_normal_1;
select next value for s_t;
connection master;
--sync_slave_with_master
connection s_normal_3;
select next_value from s_t;
--echo ------------------------------------------
--echo master update nextval;
--echo ------------------------------------------
connection m_normal_1;
select next value for s_t;
update s_t set next_value= 11;
commit;
select * from s_t;
SELECT NEXT VALUE for s_t;
connection master;
--sync_slave_with_master
--echo ------------------------------------------
--echo show slave nextval;
--echo ------------------------------------------
connection s_normal_3;
select * from s_t;
connection m_normal_1;
select next value for s_t;
connection master;
--sync_slave_with_master
connection s_normal_3;
select * from s_t;
--echo ------------------------------------------
--echo update into invalid sequence
--echo ------------------------------------------
connection m_normal_1;
select next value for s_t;
select * from s_t;
--error ER_SEQUENCE_INVALID_DATA
update s_t set min_value=11, max_value=9;
select * from s_t;
--error ER_SEQUENCE_INVALID_DATA
update s_t set next_value= 12, start=10, min_value=11, max_value=20;
select * from s_t;
--echo ------------------------------------------
--echo delete sequence row
--echo ------------------------------------------
connection m_normal_1;
--error ER_ILLEGAL_HA
delete from s_t;
commit;
select next value for s_t;
connection m_normal_1;
drop sequence s_t;
--echo ###########################################
--echo test transaction context (innodb)
--echo ###########################################
--echo ------------------------------------------
--echo transaction table and sequence
--echo normal transaction commit
--echo ------------------------------------------
connection m_normal_1;
use s_db;
create sequence s_1 cache 5 engine=innodb;
create table t_1(id int)engine=innodb;
begin;
insert into t_1 values(1111);
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 values(2222);
commit;
select * from t_1;
select * from s_1;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from t_1;
--echo ------------------------------------------
--echo normal transaction rollback
--echo ------------------------------------------
connection m_normal_1;
begin;
insert into t_1 values(3333);
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
select * from t_1;
rollback;
select * from t_1;
select * from s_1;
select next value for s_1;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from t_1;
connection m_normal_1;
use s_db;
drop sequence s_1;
drop table t_1;
--echo ###########################################
--echo test transaction context (myisam)
--echo ###########################################
--echo ------------------------------------------
--echo transaction table and sequence
--echo normal transaction commit
--echo ------------------------------------------
connection m_normal_1;
use s_db;
create sequence s_1 cache 5;
create table t_1(id int)engine=myisam;
begin;
insert into t_1 values(1111);
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 values(2222);
commit;
select * from t_1;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from t_1;
--echo ------------------------------------------
--echo normal transaction rollback
--echo ------------------------------------------
connection m_normal_1;
begin;
insert into t_1 values(3333);
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
insert into t_1 select next value for s_1;
select * from t_1;
rollback;
select * from t_1;
select next value for s_1;
connection master;
--sync_slave_with_master
connection s_normal_3;
use s_db;
select * from t_1;
connection m_normal_1;
use s_db;
drop sequence s_1;
drop table t_1;
--echo ###########################################
--echo close binlog
--echo ###########################################
connection m_normal_1;
use s_db;
create sequence s1 cache 2;
select next value for s1;
select next value for s1;
select next value for s1;
select next value for s1;
commit;
select * from s1;
connection master;
--sync_slave_with_master
connection slave;
use s_db;
select * from s1;
--echo ------------------------------------------
--echo close session binlog.
--echo ------------------------------------------
connection master;
set session sql_log_bin=off;
select next value for s1;
select next value for s1;
select next value for s1;
select next value for s1;
set session sql_log_bin=on;
select * from s1;
connection master;
--sync_slave_with_master
connection slave;
use s_db;
select * from s1;
connection m_normal_1;
use s_db;
drop sequence s1;
--echo ###########################################
--echo statement binlog
--echo ###########################################
--echo ------------------------------------------
--echo set binlog_format=statement
--echo ------------------------------------------
connection master;
set session binlog_format=statement;
show session variables like '%binlog_format%';
create sequence s1 cache 2;
--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
select next value for s1;
set session binlog_format=row;
select next value for s1;
connection master;
--sync_slave_with_master
connection slave;
use s_db;
select * from s1;
connection m_normal_1;
use s_db;
drop sequence s1;
--echo ------------------------------------------
--echo set binlog_format=mixed
--echo ------------------------------------------
connection master;
set session binlog_format=mixed;
show session variables like '%binlog_format%';
create sequence s1 cache 2;
select next value for s1;
set session binlog_format=row;
select next value for s1;
connection master;
--sync_slave_with_master
connection slave;
use s_db;
select * from s1;
connection m_normal_1;
use s_db;
drop sequence s1;
--echo ###########################################
--echo test savepoint
--echo ###########################################
connection master;
--sync_slave_with_master
set session binlog_format=row;
create sequence s1 cache 2;
create table t1(id int)engine=innodb;
begin;
insert into t1 values(1111);
savepoint sp1;
insert into t1 select next value for s1;
insert into t1 select next value for s1;
insert into t1 select next value for s1;
insert into t1 values(2222);
select * from t1;
rollback to sp1;
select * from t1;
select next value for s1;
commit;
drop sequence s1;
drop table t1;
connection master;
--sync_slave_with_master
--echo ###########################################
--echo create as
--echo ###########################################
connection m_normal_1;
create sequence s1 cache 2;
create table t as select next value for s1;
select * from t;
drop sequence s1;
drop table t;
connection master;
--sync_slave_with_master
--echo ###########################################
--echo test proc
--echo ###########################################
connection m_normal_1;
use s_db;
create table t(id int)engine=innodb;
delimiter //;
create procedure p1()
begin
create sequence s1 cache 2;
end//
create procedure p2()
begin
insert into t select next value for s1;
commit;
end//
delimiter ;//
call p1();
call p2();
call p2();
call p2();
call p2();
select * from t;
connection master;
--sync_slave_with_master
connection slave;
use s_db;
select * from t;
connection m_normal_1;
drop table t;
drop sequence s1;
drop procedure p1;
drop procedure p2;
--echo ###########################################
--echo test trigger
--echo ###########################################
connection m_normal_1;
use s_db;
create sequence s1 cache 2;
create table t1(id int)engine=innodb;
create table t2(id int)engine=innodb;
delimiter //;
CREATE TRIGGER tri_1
before INSERT ON t2 FOR EACH ROW
BEGIN
INSERT INTO t1 select next value for s1;
END//
delimiter ;//
begin;
insert into t2 values(1111);
insert into t2 values(1111);
insert into t2 values(1111);
insert into t2 values(1111);
select * from t2;
select * from t1;
rollback;
select * from t2;
select * from t1;
select next value for s1;
drop trigger tri_1;
drop table t1;
drop table t2;
drop sequence s1;
--echo ###########################################
--echo test function
--echo ###########################################
connection m_normal_1;
use s_db;
create sequence s1 cache 2;
create table t1(id int)engine=innodb;
delimiter //;
CREATE function f1() returns int
BEGIN
INSERT INTO t1 select next value for s1;
return (1);
END//
delimiter ;//
begin;
select f1();
select f1();
select f1();
select f1();
select * from t1;
rollback;
select * from t1;
select next value for s1;
drop function f1;
drop table t1;
drop sequence s1;
--echo ###########################################
--echo test value boundary
--echo ###########################################
connection m_normal_1;
use s_db;
--echo ------------------------------------------
--echo round increment by round
--echo ------------------------------------------
create sequence s1 start with 5 minvalue 2 maxvalue 7 cache 1 cycle;
select next value for s1;
select next value for s1;
select next value for s1;
select next value for s1;
select next value for s1;
drop sequence s1;
create sequence s1 start with 5 minvalue 2 maxvalue 7 cache 10 nocycle;
select next value for s1;
select next value for s1;
select next value for s1;
--error ER_SEQUENCE_RUN_OUT
select next value for s1;
select * from s1;
drop sequence s1;
create sequence s1 start with 2 minvalue 1 maxvalue 3 increment by 3 nocache cycle;
select next value for s1;
select * from s1;
select next value for s1;
select * from s1;
select next value for s1;
select * from s1;
select next value for s1;
select * from s1;
select next value for s1;
select * from s1;
drop sequence s1;
create sequence s1 start with 2 minvalue 1 maxvalue 3 increment by 3 cache 2 nocycle;
select next value for s1;
--error ER_SEQUENCE_RUN_OUT
select next value for s1;
drop sequence s1;
--echo ------------------------------------------
--echo beyond ulonglong maxvalue
--echo ------------------------------------------
create sequence s1 start with 9223372036854775805 minvalue 9223372036854775804 maxvalue 9223372036854775806 cache 1 cycle;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
drop sequence s1;
create sequence s1 start with 9223372036854775805 minvalue 9223372036854775804 maxvalue 9223372036854775806 cache 10 cycle;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
select next value for s1, round from s1;
drop sequence s1;
connection master;
use s_db;
drop database s_db;
drop user normal_1@'%';
drop user normal_2@'%';
drop user normal_3@'%';
drop user normal_4@'%';
--sync_slave_with_master
--source include/rpl_end.inc

View File

@ -3105,9 +3105,9 @@ READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME PERFORMANCE_SCHEMA_MAX_STATEMENT_CLASSES
SESSION_VALUE NULL
GLOBAL_VALUE 187
GLOBAL_VALUE 189
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 187
DEFAULT_VALUE 189
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Maximum number of statement instruments.

View File

@ -288,7 +288,7 @@ DROP TABLE t1;
DROP TABLE table1;
--error ER_BAD_TABLE_ERROR
DROP TABLE table1,table2;
--error ER_BAD_TABLE_ERROR
--error ER_UNKNOWN_VIEW
DROP VIEW view1,view2,view3,view4;
--echo
DROP TABLE IF EXISTS table1;

View File

@ -25,7 +25,7 @@ eval CREATE FUNCTION myfunc_nonexist RETURNS INTEGER SONAME "$UDF_EXAMPLE_SO";
--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB
eval CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "$UDF_EXAMPLE_SO";
--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB
eval CREATE FUNCTION sequence RETURNS INTEGER SONAME "$UDF_EXAMPLE_SO";
eval CREATE FUNCTION udf_sequence RETURNS INTEGER SONAME "$UDF_EXAMPLE_SO";
--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB
eval CREATE FUNCTION lookup RETURNS STRING SONAME "$UDF_EXAMPLE_SO";
--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB
@ -238,7 +238,7 @@ DROP FUNCTION myfunc_double;
--error ER_SP_DOES_NOT_EXIST
DROP FUNCTION myfunc_nonexist;
DROP FUNCTION myfunc_int;
DROP FUNCTION sequence;
DROP FUNCTION udf_sequence;
DROP FUNCTION lookup;
DROP FUNCTION reverse_lookup;
DROP FUNCTION avgcost;
@ -401,19 +401,19 @@ DROP TABLE const_len_bug;
#
--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB
eval CREATE FUNCTION sequence RETURNS INTEGER SONAME "$UDF_EXAMPLE_SO";
eval CREATE FUNCTION udf_sequence RETURNS INTEGER SONAME "$UDF_EXAMPLE_SO";
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (a INT PRIMARY KEY);
INSERT INTO t1 VALUES (4),(3),(2),(1);
INSERT INTO t2 SELECT * FROM t1;
SELECT sequence() AS seq, a FROM t1 ORDER BY seq ASC;
SELECT sequence() AS seq, a FROM t1 ORDER BY seq DESC;
SELECT udf_sequence() AS seq, a FROM t1 ORDER BY seq ASC;
SELECT udf_sequence() AS seq, a FROM t1 ORDER BY seq DESC;
SELECT * FROM t1 WHERE a = sequence();
SELECT * FROM t2 WHERE a = sequence();
SELECT * FROM t1 WHERE a = udf_sequence();
SELECT * FROM t2 WHERE a = udf_sequence();
DROP FUNCTION sequence;
DROP FUNCTION udf_sequence;
DROP TABLE t1,t2;
#

View File

@ -5,10 +5,10 @@
# MDEV-8644 Using a UDF in a virtual column causes a crash when stopping the server
#
--replace_result $UDF_EXAMPLE_SO UDF_EXAMPLE_LIB
eval create function sequence returns integer soname "$UDF_EXAMPLE_SO";
create table t1 (n int key not null auto_increment, msg int as (sequence()) virtual);
eval create function udf_sequence returns integer soname "$UDF_EXAMPLE_SO";
create table t1 (n int key not null auto_increment, msg int as (udf_sequence()) virtual);
select * from t1;
source include/restart_mysqld.inc;
drop table t1;
drop function sequence;
drop function udf_sequence;

View File

@ -125,7 +125,7 @@ select * from v1;
select * from v2;
# try to drop nonexistent VIEW
-- error ER_BAD_TABLE_ERROR
--error ER_UNKNOWN_VIEW
drop view v100;
# try to drop table with DROP VIEW
@ -2782,7 +2782,7 @@ CREATE TABLE t1 (id INT);
CREATE VIEW v1 AS SELECT id FROM t1;
SHOW TABLES;
--error ER_BAD_TABLE_ERROR
--error ER_UNKNOWN_VIEW
DROP VIEW v2,v1;
SHOW TABLES;

View File

@ -293,7 +293,7 @@ static void warn(const char *format,...)
{
void *frame[SF_REMEMBER_FRAMES + SF_FRAMES_SKIP];
int frames= backtrace(frame, array_elements(frame));
fprintf(stderr, " ");
fprintf(stderr, " at ");
if (frames < SF_REMEMBER_FRAMES + SF_FRAMES_SKIP)
frame[frames]= 0;
print_stack(frame + SF_FRAMES_SKIP);
@ -318,7 +318,8 @@ static int bad_ptr(const char *where, void *ptr)
}
if (irem->marker != MAGICSTART)
{
warn("Error: %s unallocated data or underrun buffer", where);
DBUG_PRINT("error",("Unallocated data or underrun buffer %p", ptr));
warn("Error: %s unallocated data or underrun buffer %p", ptr, where);
return 1;
}
@ -328,7 +329,8 @@ static int bad_ptr(const char *where, void *ptr)
magicend[2] != MAGICEND2 ||
magicend[3] != MAGICEND3)
{
warn("Error: %s overrun buffer ", where);
DBUG_PRINT("error",("Overrun buffer %p", ptr));
warn("Error: %s overrun buffer %p", where);
fprintf(stderr, "Allocated at ");
print_stack(irem->frame);
return 1;

View File

@ -144,6 +144,7 @@ SET (SQL_SOURCE
sql_type.cc sql_type.h
item_windowfunc.cc sql_window.cc
sql_cte.cc sql_cte.h
sql_sequence.cc sql_sequence.h ha_sequence.h
${WSREP_SOURCES}
table_cache.cc encryption.cc temporary_tables.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
@ -166,6 +167,8 @@ ENDIF()
MYSQL_ADD_PLUGIN(partition ha_partition.cc STORAGE_ENGINE DEFAULT STATIC_ONLY
RECOMPILE_FOR_EMBEDDED)
MYSQL_ADD_PLUGIN(sql_sequence ha_sequence.cc STORAGE_ENGINE MANDATORY STATIC_ONLY
RECOMPILE_FOR_EMBEDDED)
ADD_LIBRARY(sql STATIC ${SQL_SOURCE})
ADD_DEPENDENCIES(sql GenServerSource)

View File

@ -320,8 +320,8 @@ bool parse_option_list(THD* thd, handlerton *hton, void *option_struct_arg,
*current* value of the underlying sysvar.
2. But only if the underlying sysvar value is different from the
sysvar's default.
3. If it's ALTER TABLE and the sysvar option was not explicitly
mentioned - do nothing, do not add it to the list.
3. If it's ALTER TABLE or CREATE_SEQUENCE and the sysvar option was
not explicitly mentioned - do nothing, do not add it to the list.
4. But if it was ALTER TABLE with sysvar option = DEFAULT, we
add it to the list (under the same condition #2).
5. If we're here parsing the option list from the .frm file
@ -329,7 +329,6 @@ bool parse_option_list(THD* thd, handlerton *hton, void *option_struct_arg,
do not add it to the list (makes no sense anyway) and
use the *default* value of the underlying sysvar. Because
sysvar value can change, but it should not affect existing tables.
This is how it's implemented: the current sysvar value is added
to the list if suppress_warning is FALSE (meaning a table is created,
that is CREATE TABLE or ALTER TABLE) and it's actually a CREATE TABLE

View File

@ -18,6 +18,7 @@
#include "sql_priv.h"
#include "sql_class.h"
#include "sql_table.h"
#include "ha_sequence.h"
static int read_string(File file, uchar**to, size_t length)
{
@ -46,33 +47,40 @@ static int read_string(File file, uchar**to, size_t length)
engine_name is a LEX_STRING, where engine_name->str must point to
a buffer of at least NAME_CHAR_LEN+1 bytes.
@retval FRMTYPE_ERROR error
@retval FRMTYPE_TABLE table
@retval FRMTYPE_VIEW view
@param[out] is_sequence 1 if table is a SEQUENCE, 0 otherwise
@retval TABLE_TYPE_UNKNOWN error
@retval TABLE_TYPE_TABLE table
@retval TABLE_TYPE_SEQUENCE sequence table
@retval TABLE_TYPE_VIEW view
*/
frm_type_enum dd_frm_type(THD *thd, char *path, LEX_STRING *engine_name)
Table_type dd_frm_type(THD *thd, char *path, LEX_STRING *engine_name,
bool *is_sequence)
{
File file;
uchar header[10]; //"TYPE=VIEW\n" it is 10 characters
uchar header[40]; //"TYPE=VIEW\n" it is 10 characters
size_t error;
frm_type_enum type= FRMTYPE_ERROR;
Table_type type= TABLE_TYPE_UNKNOWN;
uchar dbt;
DBUG_ENTER("dd_frm_type");
if ((file= mysql_file_open(key_file_frm, path, O_RDONLY | O_SHARE, MYF(0))) < 0)
DBUG_RETURN(FRMTYPE_ERROR);
*is_sequence= 0;
if ((file= mysql_file_open(key_file_frm, path, O_RDONLY | O_SHARE, MYF(0)))
< 0)
DBUG_RETURN(TABLE_TYPE_UNKNOWN);
error= mysql_file_read(file, (uchar*) header, sizeof(header), MYF(MY_NABP));
if (error)
goto err;
if (!strncmp((char*) header, "TYPE=VIEW\n", sizeof(header)))
if (!strncmp((char*) header, "TYPE=VIEW\n", 10))
{
type= FRMTYPE_VIEW;
type= TABLE_TYPE_VIEW;
goto err;
}
type= FRMTYPE_TABLE;
type= TABLE_TYPE_NORMAL;
if (!is_binary_frm_header(header) || !engine_name)
goto err;
@ -91,6 +99,9 @@ frm_type_enum dd_frm_type(THD *thd, char *path, LEX_STRING *engine_name)
}
}
if (((header[39] >> 4) & 3) == HA_CHOICE_YES)
*is_sequence= 1;
/* read the true engine name */
{
MY_STAT state;

View File

@ -1,6 +1,7 @@
#ifndef DATADICT_INCLUDED
#define DATADICT_INCLUDED
/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2010, Oracle and/or its affiliates.
Copyright (c) 2017 MariaDB corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,11 +22,12 @@
Data dictionary API.
*/
enum frm_type_enum
enum Table_type
{
FRMTYPE_ERROR= 0,
FRMTYPE_TABLE,
FRMTYPE_VIEW
TABLE_TYPE_UNKNOWN,
TABLE_TYPE_NORMAL, /* Normal table */
TABLE_TYPE_SEQUENCE,
TABLE_TYPE_VIEW
};
/*
@ -35,11 +37,14 @@ enum frm_type_enum
Prefer to use ha_table_exists() instead.
To check whether it's an frm of a view, use dd_frm_is_view().
*/
frm_type_enum dd_frm_type(THD *thd, char *path, LEX_STRING *engine_name);
enum Table_type dd_frm_type(THD *thd, char *path, LEX_STRING *engine_name,
bool *is_sequence);
static inline bool dd_frm_is_view(THD *thd, char *path)
{
return dd_frm_type(thd, path, NULL) == FRMTYPE_VIEW;
bool not_used2;
return dd_frm_type(thd, path, NULL, &not_used2) == TABLE_TYPE_VIEW;
}
bool dd_recreate_table(THD *thd, const char *db, const char *table_name,

View File

@ -77,7 +77,9 @@
HA_DUPLICATE_POS | \
HA_CAN_SQL_HANDLER | \
HA_CAN_INSERT_DELAYED | \
HA_READ_BEFORE_WRITE_REMOVAL)
HA_READ_BEFORE_WRITE_REMOVAL |\
HA_CAN_TABLES_WITHOUT_ROLLBACK)
static const char *ha_par_ext= ".par";
/****************************************************************************

View File

@ -429,6 +429,7 @@ public:
virtual THR_LOCK_DATA **store_lock(THD * thd, THR_LOCK_DATA ** to,
enum thr_lock_type lock_type);
virtual int external_lock(THD * thd, int lock_type);
LEX_STRING *engine_name() { return hton_name(table->part_info->default_engine_type); }
/*
When table is locked a statement is started by calling start_stmt
instead of external_lock

417
sql/ha_sequence.cc Normal file
View File

@ -0,0 +1,417 @@
/*
Copyright (c) 2017, Aliyun and/or its affiliates.
Copyright (c) 2017, MariaDB corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <my_global.h>
#include "sql_list.h"
#include "table.h"
#include "sql_sequence.h"
#include "ha_sequence.h"
#include "sql_plugin.h"
#include "mysql/plugin.h"
#include "sql_priv.h"
#include "sql_parse.h"
#include "sql_table.h"
#include "sql_update.h"
#include "sql_base.h"
#include "log_event.h"
/*
Table flags we should inherit and disable from the original engine.
We add HA_STATS_RECORDS_IS_EXACT as ha_sequence::info() will ensure
that records is always 1
*/
#define SEQUENCE_ENABLED_TABLE_FLAGS (HA_STATS_RECORDS_IS_EXACT | \
HA_PERSISTENT_TABLE)
#define SEQUENCE_DISABLED_TABLE_FLAGS (HA_CAN_SQL_HANDLER | \
HA_CAN_INSERT_DELAYED | \
HA_BINLOG_STMT_CAPABLE)
handlerton *sql_sequence_hton;
/*
Create a sequence handler
*/
ha_sequence::ha_sequence(handlerton *hton, TABLE_SHARE *share)
:handler(hton, share), sequence_locked(0)
{
sequence= share->sequence;
DBUG_ASSERT(share->sequence);
}
/**
Destructor method must remove the underlying handler
*/
ha_sequence::~ha_sequence()
{
delete file;
}
/**
Sequence table open method
@param name Path to file (dbname and tablename)
@param mode mode
@param flags Flags how to open file
RETURN VALUES
@retval 0 Success
@retval != 0 Failure
*/
int ha_sequence::open(const char *name, int mode, uint flags)
{
int error;
DBUG_ENTER("ha_sequence::open");
DBUG_ASSERT(table->s == table_share && file);
file->table= table;
if (!(error= file->open(name, mode, flags)))
{
/*
Copy values set by handler::open() in the underlying handler
Reuse original storage engine data for duplicate key reference
It would be easier to do this if we would have another handler
call: fixup_after_open()...
*/
ref= file->ref;
ref_length= file->ref_length;
dup_ref= file->dup_ref;
/*
ha_open() sets the following for us. We have to set this for the
underlying handler
*/
file->cached_table_flags= file->table_flags();
file->reset_statistics();
internal_tmp_table= file->internal_tmp_table=
MY_TEST(flags & HA_OPEN_INTERNAL_TABLE);
reset_statistics();
/* Don't try to read the inital row the call is part of create code */
if (!(flags & (HA_OPEN_FOR_CREATE | HA_OPEN_FOR_REPAIR)))
{
if ((error= table->s->sequence->read_initial_values(table)))
file->ha_close();
}
}
DBUG_RETURN(error);
}
/*
Clone the sequence. Needed if table is used by range optimization
(Very, very unlikely)
*/
handler *ha_sequence::clone(const char *name, MEM_ROOT *mem_root)
{
ha_sequence *new_handler;
DBUG_ENTER("ha_sequence::clone");
if (!(new_handler= new (mem_root) ha_sequence(ht, table_share)))
DBUG_RETURN(NULL);
/*
Allocate new_handler->ref here because otherwise ha_open will allocate it
on this->table->mem_root and we will not be able to reclaim that memory
when the clone handler object is destroyed.
*/
if (!(new_handler->ref= (uchar*) alloc_root(mem_root,
ALIGN_SIZE(ref_length)*2)))
goto err;
if (new_handler->ha_open(table, name,
table->db_stat,
HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_NO_PSI_CALL))
goto err;
/* Reuse original storage engine data for duplicate key reference */
new_handler->ref= file->ref;
new_handler->ref_length= file->ref_length;
new_handler->dup_ref= file->dup_ref;
DBUG_RETURN((handler*) new_handler);
err:
delete new_handler;
DBUG_RETURN(NULL);
}
/*
Map the create table to the original storage engine
*/
int ha_sequence::create(const char *name, TABLE *form,
HA_CREATE_INFO *create_info)
{
DBUG_ASSERT(create_info->sequence);
/* Sequence tables has one and only one row */
create_info->max_rows= create_info->min_rows= 1;
return (file->create(name, form, create_info));
}
/**
Sequence write row method.
A sequence table has only one row. Any inserts in the table
will update this row.
@retval 0 Success
@retval != 0 Failure
NOTES:
sequence_locked is set if we are called from SEQUENCE::next_value
In this case the mutex is already locked and we should not update
the sequence with 'buf' as the sequence object is already up to date.
*/
int ha_sequence::write_row(uchar *buf)
{
int error;
DBUG_ENTER("ha_sequence::write_row");
DBUG_ASSERT(table->record[0] == buf);
row_already_logged= 0;
if (!sequence->initialized)
{
/* This calls is from ha_open() as part of create table */
DBUG_RETURN(file->write_row(buf));
}
/*
User tries to write a row
- Check that row is an accurate object
- Update the first row in the table
*/
sequence_definition tmp_seq;
tmp_seq.read_fields(table);
if (tmp_seq.check_and_adjust())
DBUG_RETURN(HA_ERR_SEQUENCE_INVALID_DATA);
/*
Lock sequence to ensure that no one can come in between
while sequence, table and binary log are updated.
*/
if (!sequence_locked) // If not from next_value()
sequence->lock();
if (!(error= file->update_first_row(buf)))
{
Log_func *log_func= Write_rows_log_event::binlog_row_logging_function;
if (!sequence_locked)
sequence->copy(&tmp_seq);
rows_changed++;
/* We have to do the logging while we hold the sequence mutex */
error= binlog_log_row(table, 0, buf, log_func);
row_already_logged= 1;
}
sequence->all_values_used= 0;
if (!sequence_locked)
sequence->unlock();
DBUG_RETURN(error);
}
int ha_sequence::update_row(const uchar *old_data, uchar *new_data)
{
int error;
sequence_definition tmp_seq;
DBUG_ENTER("ha_sequence::update_row");
DBUG_ASSERT(new_data == table->record[0]);
row_already_logged= 0;
tmp_seq.read_fields(table);
if (tmp_seq.check_and_adjust())
DBUG_RETURN(HA_ERR_SEQUENCE_INVALID_DATA);
/*
Lock sequence to ensure that no one can come in between
while sequence, table and binary log is updated.
*/
sequence->lock();
if (!(error= file->update_row(old_data, new_data)))
{
sequence->copy(&tmp_seq);
rows_changed++;
/* We have to do the logging while we hold the sequence mutex */
error= binlog_log_row(table, old_data, new_data,
Update_rows_log_event::binlog_row_logging_function);
row_already_logged= 1;
}
sequence->all_values_used= 0;
sequence->unlock();
DBUG_RETURN(error);
}
/*
Inherit the sequence base table flags.
*/
handler::Table_flags ha_sequence::table_flags() const
{
DBUG_ENTER("ha_sequence::table_flags");
DBUG_RETURN((file->table_flags() & ~SEQUENCE_DISABLED_TABLE_FLAGS) |
SEQUENCE_ENABLED_TABLE_FLAGS);
}
int ha_sequence::info(uint flag)
{
DBUG_ENTER("ha_sequence::info");
file->info(flag);
/* Inform optimizer that we have always only one record */
stats= file->stats;
stats.records= 1;
DBUG_RETURN(false);
}
int ha_sequence::external_lock(THD *thd, int lock_type)
{
int error= file->external_lock(thd, lock_type);
/*
Copy lock flag to satisfy DBUG_ASSERT checks in ha_* functions in
handler.cc when we later call it with file->ha_..()
*/
file->m_lock_type= lock_type;
return error;
}
/*
Squence engine error deal method
*/
void ha_sequence::print_error(int error, myf errflag)
{
char *sequence_db= table_share->db.str;
char *sequence_name= table_share->table_name.str;
DBUG_ENTER("ha_sequence::print_error");
switch (error) {
case HA_ERR_SEQUENCE_INVALID_DATA:
{
my_error(ER_SEQUENCE_INVALID_DATA, MYF(errflag), sequence_db,
sequence_name);
DBUG_VOID_RETURN;
}
case HA_ERR_SEQUENCE_RUN_OUT:
{
my_error(ER_SEQUENCE_RUN_OUT, MYF(errflag), sequence_db, sequence_name);
DBUG_VOID_RETURN;
}
case HA_ERR_WRONG_COMMAND:
my_error(ER_ILLEGAL_HA, MYF(0), "SEQUENCE", table_share->db.str,
table_share->table_name.str);
DBUG_VOID_RETURN;
}
file->print_error(error, errflag);
DBUG_VOID_RETURN;
}
/*****************************************************************************
Sequence plugin interface
*****************************************************************************/
/*
Create an new handler
*/
static handler *sequence_create_handler(handlerton *hton,
TABLE_SHARE *share,
MEM_ROOT *mem_root)
{
DBUG_ENTER("sequence_create_handler");
DBUG_RETURN(new (mem_root) ha_sequence(hton, share));
}
/*
Sequence engine end.
SYNOPSIS
sequence_end()
p handlerton.
type panic type.
RETURN VALUES
0 Success
!=0 Failure
*/
static int sequence_end(handlerton* hton,
ha_panic_function type __attribute__((unused)))
{
DBUG_ENTER("sequence_end");
DBUG_RETURN(0);
}
/*
Sequence engine init.
SYNOPSIS
sequence_initialize()
@param p handlerton.
retval 0 Success
retval !=0 Failure
*/
static int sequence_initialize(void *p)
{
handlerton *local_sequence_hton= (handlerton *)p;
DBUG_ENTER("sequence_initialize");
local_sequence_hton->state= SHOW_OPTION_YES;
local_sequence_hton->db_type= DB_TYPE_SEQUENCE;
local_sequence_hton->create= sequence_create_handler;
local_sequence_hton->panic= sequence_end;
local_sequence_hton->flags= (HTON_NOT_USER_SELECTABLE |
HTON_HIDDEN |
HTON_TEMPORARY_NOT_SUPPORTED |
HTON_ALTER_NOT_SUPPORTED |
HTON_NO_PARTITION);
DBUG_RETURN(0);
}
static struct st_mysql_storage_engine sequence_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
maria_declare_plugin(sql_sequence)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
&sequence_storage_engine,
"SQL_SEQUENCE",
"jianwei.zhao @ Aliyun & Monty @ MariaDB corp",
"Sequence Storage Engine for CREATE SEQUENCE",
PLUGIN_LICENSE_GPL,
sequence_initialize, /* Plugin Init */
NULL, /* Plugin Deinit */
0x0100, /* 1.0 */
NULL, /* status variables */
NULL, /* system variables */
"1.0", /* string version */
MariaDB_PLUGIN_MATURITY_ALPHA /* maturity */
}
maria_declare_plugin_end;

138
sql/ha_sequence.h Normal file
View File

@ -0,0 +1,138 @@
#ifndef HA_SEQUENCE_INCLUDED
#define HA_SEQUENCE_INCLUDED
/*
Copyright (c) 2017 Aliyun and/or its affiliates.
Copyright (c) 2017 MariaDB corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sql_sequence.h"
#include "table.h"
#include "handler.h"
extern handlerton *sql_sequence_hton;
/*
Sequence engine handler.
The sequence engine is a logic engine. It doesn't store any data.
All the sequence data stored into the base table which must support
non rollback writes (HA_CAN_TABLES_WITHOUT_ROLLBACK)
The sequence data (SEQUENCE class) is stored in TABLE_SHARE->sequence
TABLE RULES:
1. When table is created, one row is automaticlly inserted into
the table. The table will always have one and only one row.
2. Any inserts or updates to the table will be validated.
3. Inserts will overwrite the original row.
4. DELETE and TRUNCATE will not affect the table.
Instead a warning will be given.
5. Cache will be reset for any updates.
CACHE RULES:
SEQUENCE class is used to cache values that sequence defined.
1. If hit cache, we can query back the sequence nextval directly
instead of reading the underlying table.
2. When run out of values, the sequence engine will reserve new values
in update the base table.
3. The cache is invalidated if any update on based table.
*/
class ha_sequence :public handler
{
private:
handler *file;
SEQUENCE *sequence; /* From table_share->sequence */
public:
ha_sequence(handlerton *hton, TABLE_SHARE *share);
~ha_sequence();
/* virtual function that are re-implemented for sequence */
int open(const char *name, int mode, uint test_if_locked);
int create(const char *name, TABLE *form,
HA_CREATE_INFO *create_info);
handler *clone(const char *name, MEM_ROOT *mem_root);
int write_row(uchar *buf);
int update_row(const uchar *old_data, uchar *new_data);
Table_flags table_flags() const;
/* One can't delete from sequence engine */
int delete_row(const uchar *buf)
{ return HA_ERR_WRONG_COMMAND; }
/* One can't delete from sequence engine */
int truncate()
{ return HA_ERR_WRONG_COMMAND; }
/* Can't use query cache */
uint8 table_cache_type()
{ return HA_CACHE_TBL_NOCACHE; }
void print_error(int error, myf errflag);
int info(uint);
LEX_STRING *engine_name() { return hton_name(file->ht); }
int external_lock(THD *thd, int lock_type);
/* Functions that are directly mapped to the underlying handler */
int rnd_init(bool scan)
{ return file->rnd_init(scan); }
int rnd_next(uchar *buf)
{ return file->rnd_next(buf); }
int rnd_end()
{ return file->rnd_end(); }
int rnd_pos(uchar *buf, uchar *pos)
{ return file->rnd_pos(buf, pos); }
void position(const uchar *record)
{ return file->position(record); }
const char *table_type() const
{ return file->table_type(); }
ulong index_flags(uint inx, uint part, bool all_parts) const
{ return file->index_flags(inx, part, all_parts); }
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type)
{ return file->store_lock(thd, to, lock_type); }
int close(void)
{ return file->close(); }
const char **bas_ext() const
{ return file->bas_ext(); }
int delete_table(const char*name)
{ return file->delete_table(name); }
int rename_table(const char *from, const char *to)
{ return file->rename_table(from, to); }
void unbind_psi()
{ return file->unbind_psi(); }
void rebind_psi()
{ return file->rebind_psi(); }
bool auto_repair(int error) const
{ return file->auto_repair(error); }
int repair(THD* thd, HA_CHECK_OPT* check_opt)
{ return file->repair(thd, check_opt); }
bool check_and_repair(THD *thd)
{ return file->check_and_repair(thd); }
bool is_crashed() const
{ return file->is_crashed(); }
/* New methods */
void register_original_handler(handler *file_arg)
{
file= file_arg;
init(); /* Update cached_table_flags */
}
/* To inform handler that sequence is already locked by called */
bool sequence_locked;
};
#endif

View File

@ -41,6 +41,7 @@
#include <mysql/psi/mysql_table.h>
#include "debug_sync.h" // DEBUG_SYNC
#include "sql_audit.h"
#include "ha_sequence.h"
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
@ -291,7 +292,6 @@ handler *get_ha_partition(partition_info *part_info)
}
#endif
static const char **handler_errmsgs;
C_MODE_START
@ -618,7 +618,7 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
/*
This is entirely for legacy. We will create a new "disk based" hton and a
"memory" hton which will be configurable longterm. We should be able to
remove partition and myisammrg.
remove partition.
*/
switch (hton->db_type) {
case DB_TYPE_HEAP:
@ -630,6 +630,9 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
case DB_TYPE_PARTITION_DB:
partition_hton= hton;
break;
case DB_TYPE_SEQUENCE:
sql_sequence_hton= hton;
break;
default:
break;
};
@ -2426,6 +2429,11 @@ err:
return NULL;
}
LEX_STRING *handler::engine_name()
{
return hton_name(ht);
}
double handler::keyread_time(uint index, uint ranges, ha_rows rows)
{
@ -2549,6 +2557,7 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
}
reset_statistics();
internal_tmp_table= MY_TEST(test_if_locked & HA_OPEN_INTERNAL_TABLE);
DBUG_RETURN(error);
}
@ -2797,10 +2806,11 @@ int handler::ha_rnd_init_with_error(bool scan)
/**
Read first row (only) from a table.
Read first row (only) from a table. Used for reading tables with
only one row, either based on table statistics or if table is a SEQUENCE.
This is never called for InnoDB tables, as these table types
has the HA_STATS_RECORDS_IS_EXACT set.
This is never called for normal InnoDB tables, as these table types
does not have HA_STATS_RECORDS_IS_EXACT set.
*/
int handler::read_first_row(uchar * buf, uint primary_key)
{
@ -3992,7 +4002,7 @@ void handler::mark_trx_read_write_internal()
*/
if (ha_info->is_started())
{
DBUG_ASSERT(has_transactions());
DBUG_ASSERT(has_transaction_manager());
/*
table_share can be NULL in ha_delete_table(). See implementation
of standalone function ha_delete_table() in sql_base.cc.
@ -5033,22 +5043,28 @@ private:
loaded, frm is invalid), the return value will be true, but
*hton will be NULL.
*/
bool ha_table_exists(THD *thd, const char *db, const char *table_name,
handlerton **hton)
handlerton **hton, bool *is_sequence)
{
handlerton *dummy;
bool dummy2;
DBUG_ENTER("ha_table_exists");
if (hton)
*hton= 0;
else if (engines_with_discover)
hton= &dummy;
if (!is_sequence)
is_sequence= &dummy2;
*is_sequence= 0;
TDC_element *element= tdc_lock_share(thd, db, table_name);
if (element && element != MY_ERRPTR)
{
if (hton)
*hton= element->share->db_type();
*is_sequence= element->share->table_type == TABLE_TYPE_SEQUENCE;
tdc_unlock_share(element);
DBUG_RETURN(TRUE);
}
@ -5066,7 +5082,7 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name,
char engine_buf[NAME_CHAR_LEN + 1];
LEX_STRING engine= { engine_buf, 0 };
if (dd_frm_type(thd, path, &engine) != FRMTYPE_VIEW)
if (dd_frm_type(thd, path, &engine, is_sequence) != TABLE_TYPE_VIEW)
{
plugin_ref p= plugin_lock_by_name(thd, &engine, MYSQL_STORAGE_ENGINE_PLUGIN);
*hton= p ? plugin_hton(p) : NULL;
@ -5089,7 +5105,6 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name,
DBUG_RETURN(TRUE);
}
if (need_full_discover_for_existence)
{
TABLE_LIST table;
@ -5778,8 +5793,6 @@ static int write_locked_table_maps(THD *thd)
}
typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
static int check_wsrep_max_ws_rows();
static int binlog_log_row_internal(TABLE* table,
@ -5820,10 +5833,10 @@ static int binlog_log_row_internal(TABLE* table,
return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
}
static inline int binlog_log_row(TABLE* table,
const uchar *before_record,
const uchar *after_record,
Log_func *log_func)
int binlog_log_row(TABLE* table,
const uchar *before_record,
const uchar *after_record,
Log_func *log_func)
{
if (!table->file->check_table_binlog_row_based(1))
return 0;
@ -5975,7 +5988,7 @@ int handler::ha_write_row(uchar *buf)
{ error= write_row(buf); })
MYSQL_INSERT_ROW_DONE(error);
if (likely(!error))
if (likely(!error) && !row_already_logged)
{
rows_changed++;
error= binlog_log_row(table, 0, buf, log_func);
@ -6007,7 +6020,7 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
{ error= update_row(old_data, new_data);})
MYSQL_UPDATE_ROW_DONE(error);
if (likely(!error))
if (likely(!error) && !row_already_logged)
{
rows_changed++;
error= binlog_log_row(table, old_data, new_data, log_func);
@ -6015,6 +6028,28 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
return error;
}
/*
Update first row. Only used by sequence tables
*/
int handler::update_first_row(uchar *new_data)
{
int error;
if (!(error= ha_rnd_init(1)))
{
int end_error;
if (!(error= ha_rnd_next(table->record[1])))
error= update_row(table->record[1], new_data);
end_error= ha_rnd_end();
if (!error)
error= end_error;
/* Logging would be wrong if update_row works but ha_rnd_end fails */
DBUG_ASSERT(!end_error || error != 0);
}
return error;
}
int handler::ha_delete_row(const uchar *buf)
{
int error;

View File

@ -42,9 +42,11 @@
#include <ft_global.h>
#include <keycache.h>
#include <mysql/psi/mysql_table.h>
#include "sql_sequence.h"
class Alter_info;
class Virtual_column_info;
class sequence_definition;
// the following is for checking tables
@ -261,6 +263,24 @@ enum enum_alter_inplace_result {
*/
#define HA_CONCURRENT_OPTIMIZE (1ULL << 46)
/*
If the storage engine support tables that will not roll back on commit
In addition the table should not lock rows and support READ and WRITE
UNCOMMITTED.
This is useful for implementing things like SEQUENCE but can also in
the future be useful to do logging that should never roll back.
*/
#define HA_CAN_TABLES_WITHOUT_ROLLBACK (1ULL << 47)
/*
Mainly for usage by SEQUENCE engine. Setting this flag means
that the table will never roll back and that all operations
for this table should stored in the non transactional log
space that will always be written, even on rollback.
*/
#define HA_PERSISTENT_TABLE (1ULL << 48)
/*
Set of all binlog flags. Currently only contain the capabilities
flags.
@ -380,6 +400,7 @@ enum enum_alter_inplace_result {
#define HA_LEX_CREATE_TMP_TABLE 1U
#define HA_CREATE_TMP_ALTER 8U
#define HA_LEX_CREATE_SEQUENCE 16U
#define HA_MAX_REC_LENGTH 65535
@ -434,7 +455,8 @@ enum legacy_db_type
DB_TYPE_PERFORMANCE_SCHEMA=28,
DB_TYPE_ARIA=42,
DB_TYPE_TOKUDB=43,
DB_TYPE_FIRST_DYNAMIC=44,
DB_TYPE_SEQUENCE=44,
DB_TYPE_FIRST_DYNAMIC=45,
DB_TYPE_DEFAULT=127 // Must be last
};
/*
@ -522,6 +544,8 @@ given at all. */
*/
#define HA_CREATE_USED_STATS_SAMPLE_PAGES (1UL << 24)
/* Create a sequence */
#define HA_CREATE_USED_SEQUENCE (1UL << 25)
/*
This is master database for most of system tables. However there
@ -1694,6 +1718,7 @@ struct Table_scope_and_contents_source_st
engine_option_value *option_list; ///< list of table create options
enum_stats_auto_recalc stats_auto_recalc;
bool varchar; ///< 1 if table has a VARCHAR
bool sequence; // If SEQUENCE=1 was used
List<Virtual_column_info> *check_constraint_list;
@ -1707,6 +1732,7 @@ struct Table_scope_and_contents_source_st
TABLE_LIST *pos_in_locked_tables;
MDL_ticket *mdl_ticket;
bool table_was_deleted;
sequence_definition *seq_create_info;
void init()
{
@ -2656,6 +2682,8 @@ public:
bool mark_trx_read_write_done; /* mark_trx_read_write was called */
bool check_table_binlog_row_based_done; /* check_table_binlog.. was called */
bool check_table_binlog_row_based_result; /* cached check_table_binlog... */
/* Set to 1 if handler logged last insert/update/delete operation */
bool row_already_logged;
/*
TRUE <=> the engine guarantees that returned records are within the range
being scanned.
@ -2758,6 +2786,7 @@ public:
mark_trx_read_write_done(0),
check_table_binlog_row_based_done(0),
check_table_binlog_row_based_result(0),
row_already_logged(0),
in_range_check_pushed_down(FALSE),
key_used_on_scan(MAX_KEY),
active_index(MAX_KEY), keyread(MAX_KEY),
@ -2995,8 +3024,24 @@ public:
virtual double keyread_time(uint index, uint ranges, ha_rows rows);
virtual const key_map *keys_to_use_for_scanning() { return &key_map_empty; }
/*
True if changes to the table is persistent (no rollback)
This is manly used to decide how to log changes to the table in
the binary log.
*/
bool has_transactions()
{ return (ha_table_flags() & HA_NO_TRANSACTIONS) == 0; }
{
return ((ha_table_flags() & (HA_NO_TRANSACTIONS | HA_PERSISTENT_TABLE))
== 0);
}
/*
True if the underlaying table doesn't support transactions
*/
bool has_transaction_manager()
{
return ((ha_table_flags() & HA_NO_TRANSACTIONS) == 0);
}
/**
This method is used to analyse the error to see whether the error
@ -3915,7 +3960,7 @@ public:
return 0;
}
LEX_STRING *engine_name() { return hton_name(ht); }
virtual LEX_STRING *engine_name();
TABLE* get_table() { return table; }
TABLE_SHARE* get_table_share() { return table_share; }
@ -4007,6 +4052,12 @@ private:
return HA_ERR_WRONG_COMMAND;
}
/*
Optimized function for updating the first row. Only used by sequence
tables
*/
virtual int update_first_row(uchar *new_data);
virtual int delete_row(const uchar *buf __attribute__((unused)))
{
return HA_ERR_WRONG_COMMAND;
@ -4069,6 +4120,7 @@ protected:
enum ha_rkey_function find_flag)
{ return HA_ERR_WRONG_COMMAND; }
friend class ha_partition;
friend class ha_sequence;
public:
/**
This method is similar to update_row, however the handler doesn't need
@ -4299,7 +4351,7 @@ int ha_discover_table(THD *thd, TABLE_SHARE *share);
int ha_discover_table_names(THD *thd, LEX_STRING *db, MY_DIR *dirp,
Discovered_table_list *result, bool reusable);
bool ha_table_exists(THD *thd, const char *db, const char *table_name,
handlerton **hton= 0);
handlerton **hton= 0, bool *is_sequence= 0);
#endif
/* key cache */
@ -4357,6 +4409,11 @@ inline const char *table_case_name(HA_CREATE_INFO *info, const char *name)
return ((lower_case_table_names == 2 && info->alias) ? info->alias : name);
}
typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
int binlog_log_row(TABLE* table,
const uchar *before_record,
const uchar *after_record,
Log_func *log_func);
#define TABLE_IO_WAIT(TRACKER, PSI, OP, INDEX, FLAGS, PAYLOAD) \
{ \

View File

@ -53,6 +53,7 @@
#include "sp.h"
#include "set_var.h"
#include "debug_sync.h"
#include "sql_base.h"
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define sp_restore_security_context(A,B) while (0) {}
@ -6940,3 +6941,147 @@ longlong Item_func_cursor_rowcount::val_int()
sp_cursor *c= get_open_cursor_or_error();
return !(null_value= !c) ? c->row_count() : 0;
}
/*****************************************************************************
SEQUENCE functions
*****************************************************************************/
longlong Item_func_nextval::val_int()
{
longlong value;
int error;
const char *key;
TABLE *table= table_list->table;
uint length= get_table_def_key(table_list, &key);
THD *thd= table->in_use;
SEQUENCE_LAST_VALUE *entry;
char buff[80];
String key_buff(buff,sizeof(buff), &my_charset_bin);
DBUG_ASSERT(table && table->s->sequence);
DBUG_ENTER("Item_func_nextval::val_int");
if (table->s->tmp_table != NO_TMP_TABLE)
{
/*
Temporary tables has an extra \0 at end to distinguish it from
normal tables
*/
key_buff.copy(key, length, &my_charset_bin);
key_buff.append((char) 0);
key= key_buff.ptr();
length++;
}
if (!(entry= ((SEQUENCE_LAST_VALUE*)
my_hash_search(&thd->sequences, (uchar*) key, length))))
{
if (!(key= (char*) my_memdup(key, length, MYF(MY_WME))) ||
!(entry= new SEQUENCE_LAST_VALUE((uchar*) key, length)))
{
/* EOM, error given */
my_free((char*) key);
delete entry;
null_value= 1;
DBUG_RETURN(0);
}
if (my_hash_insert(&thd->sequences, (uchar*) entry))
{
/* EOM, error given */
delete entry;
null_value= 1;
DBUG_RETURN(0);
}
}
entry->null_value= null_value= 0;
value= table->s->sequence->next_value(table,0, &error);
entry->value= value;
entry->set_version(table);
if (error) // Warning already printed
entry->null_value= null_value= 1; // For not strict mode
DBUG_RETURN(value);
}
/* Print for nextval and lastval */
void Item_func_nextval::print(String *str, enum_query_type query_type)
{
char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
const char *d_name= table_list->db, *t_name= table_list->table_name;
bool use_db_name= d_name && d_name[0];
THD *thd= current_thd;
str->append(func_name());
str->append('(');
/*
for next_val we assume that table_list has been updated to contain
the current db.
*/
if (lower_case_table_names > 0)
{
strmake(t_name_buff, t_name, MAX_ALIAS_NAME-1);
my_casedn_str(files_charset_info, t_name_buff);
t_name= t_name_buff;
if (use_db_name)
{
strmake(d_name_buff, d_name, MAX_ALIAS_NAME-1);
my_casedn_str(files_charset_info, d_name_buff);
d_name= d_name_buff;
}
}
if (use_db_name)
{
append_identifier(thd, str, d_name, (uint)strlen(d_name));
str->append('.');
}
append_identifier(thd, str, t_name, (uint) strlen(t_name));
str->append(')');
}
/* Return last used value for sequence or NULL if sequence hasn't been used */
longlong Item_func_lastval::val_int()
{
const char *key;
SEQUENCE_LAST_VALUE *entry;
uint length= get_table_def_key(table_list, &key);
THD *thd= table_list->table->in_use;
char buff[80];
String key_buff(buff,sizeof(buff), &my_charset_bin);
DBUG_ENTER("Item_func_lastval::val_int");
if (table_list->table->s->tmp_table != NO_TMP_TABLE)
{
/*
Temporary tables has an extra \0 at end to distinguish it from
normal tables
*/
key_buff.copy(key, length, &my_charset_bin);
key_buff.append((char) 0);
key= key_buff.ptr();
length++;
}
if (!(entry= ((SEQUENCE_LAST_VALUE*)
my_hash_search(&thd->sequences, (uchar*) key, length))))
{
/* Sequence not used */
null_value= 1;
DBUG_RETURN(0);
}
if (entry->check_version(table_list->table))
{
/* Table droped and re-created, remove current version */
my_hash_delete(&thd->sequences, (uchar*) entry);
null_value= 1;
DBUG_RETURN(0);
}
null_value= entry->null_value;
DBUG_RETURN(entry->value);
}

View File

@ -2769,6 +2769,48 @@ public:
};
/* Implementation for sequences: NEXT VALUE FOR sequence and NEXTVAL() */
class Item_func_nextval :public Item_int_func
{
protected:
TABLE_LIST *table_list;
public:
Item_func_nextval(THD *thd, TABLE_LIST *table):
Item_int_func(thd), table_list(table) {}
longlong val_int();
const char *func_name() const { return "nextval"; }
void fix_length_and_dec()
{
unsigned_flag= 0;
max_length= MAX_BIGINT_WIDTH;
maybe_null= 1; /* In case of errors */
}
bool const_item() const { return 0; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_nextval>(thd, mem_root, this); }
void print(String *str, enum_query_type query_type);
bool check_vcol_func_processor(void *arg)
{
return mark_unsupported_function(func_name(), "()", arg,
VCOL_NON_DETERMINISTIC);
}
};
/* Implementation for sequences: LASTVAL(sequence), PostgreSQL style */
class Item_func_lastval :public Item_func_nextval
{
public:
Item_func_lastval(THD *thd, TABLE_LIST *table):
Item_func_nextval(thd, table) {}
longlong val_int();
const char *func_name() const { return "lastval"; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_lastval>(thd, mem_root, this); }
};
Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
LEX_STRING component);
extern bool check_reserved_words(LEX_STRING *name);

View File

@ -160,6 +160,7 @@ static SYMBOL symbols[] = {
{ "CURRENT_USER", SYM(CURRENT_USER)},
{ "CURSOR", SYM(CURSOR_SYM)},
{ "CURSOR_NAME", SYM(CURSOR_NAME_SYM)},
{ "CYCLE", SYM(CYCLE_SYM)},
{ "DATA", SYM(DATA_SYM)},
{ "DATABASE", SYM(DATABASE)},
{ "DATABASES", SYM(DATABASES)},
@ -287,6 +288,7 @@ static SYMBOL symbols[] = {
{ "IMPORT", SYM(IMPORT)},
{ "INTERSECT", SYM(INTERSECT_SYM)},
{ "IN", SYM(IN_SYM)},
{ "INCREMENT", SYM(INCREMENT_SYM)},
{ "INDEX", SYM(INDEX_SYM)},
{ "INDEXES", SYM(INDEXES)},
{ "INFILE", SYM(INFILE)},
@ -324,6 +326,7 @@ static SYMBOL symbols[] = {
{ "LANGUAGE", SYM(LANGUAGE_SYM)},
{ "LAST", SYM(LAST_SYM)},
{ "LAST_VALUE", SYM(LAST_VALUE)},
{ "LASTVAL", SYM(LASTVAL_SYM)},
{ "LEADING", SYM(LEADING)},
{ "LEAVE", SYM(LEAVE_SYM)},
{ "LEAVES", SYM(LEAVES)},
@ -379,7 +382,7 @@ static SYMBOL symbols[] = {
{ "MAX_STATEMENT_TIME", SYM(MAX_STATEMENT_TIME_SYM)},
{ "MAX_UPDATES_PER_HOUR", SYM(MAX_UPDATES_PER_HOUR)},
{ "MAX_USER_CONNECTIONS", SYM(MAX_USER_CONNECTIONS_SYM)},
{ "MAXVALUE", SYM(MAX_VALUE_SYM)},
{ "MAXVALUE", SYM(MAXVALUE_SYM)},
{ "MEDIUM", SYM(MEDIUM_SYM)},
{ "MEDIUMBLOB", SYM(MEDIUMBLOB)},
{ "MEDIUMINT", SYM(MEDIUMINT)},
@ -393,6 +396,7 @@ static SYMBOL symbols[] = {
{ "MINUTE", SYM(MINUTE_SYM)},
{ "MINUTE_MICROSECOND", SYM(MINUTE_MICROSECOND_SYM)},
{ "MINUTE_SECOND", SYM(MINUTE_SECOND_SYM)},
{ "MINVALUE", SYM(MINVALUE_SYM)},
{ "MIN_ROWS", SYM(MIN_ROWS)},
{ "MOD", SYM(MOD_SYM)},
{ "MODE", SYM(MODE_SYM)},
@ -412,7 +416,12 @@ static SYMBOL symbols[] = {
{ "NCHAR", SYM(NCHAR_SYM)},
{ "NEW", SYM(NEW_SYM)},
{ "NEXT", SYM(NEXT_SYM)},
{ "NEXTVAL", SYM(NEXTVAL_SYM)},
{ "NO", SYM(NO_SYM)},
{ "NOMAXVALUE", SYM(NOMAXVALUE_SYM)},
{ "NOMINVALUE", SYM(NOMINVALUE_SYM)},
{ "NOCACHE", SYM(NOCACHE_SYM)},
{ "NOCYCLE", SYM(NOCYCLE_SYM)},
{ "NO_WAIT", SYM(NO_WAIT_SYM)},
{ "NOWAIT", SYM(NOWAIT_SYM)},
{ "NODEGROUP", SYM(NODEGROUP_SYM)},
@ -467,6 +476,7 @@ static SYMBOL symbols[] = {
{ "PREPARE", SYM(PREPARE_SYM)},
{ "PRESERVE", SYM(PRESERVE_SYM)},
{ "PREV", SYM(PREV_SYM)},
{ "PREVIOUS", SYM(PREVIOUS_SYM)},
{ "PRIMARY", SYM(PRIMARY_SYM)},
{ "PRIVILEGES", SYM(PRIVILEGES)},
{ "PROCEDURE", SYM(PROCEDURE_SYM)},
@ -547,6 +557,7 @@ static SYMBOL symbols[] = {
{ "SELECT", SYM(SELECT_SYM)},
{ "SENSITIVE", SYM(SENSITIVE_SYM)},
{ "SEPARATOR", SYM(SEPARATOR_SYM)},
{ "SEQUENCE", SYM(SEQUENCE_SYM)},
{ "SERIAL", SYM(SERIAL_SYM)},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM)},
{ "SESSION", SYM(SESSION_SYM)},

View File

@ -261,7 +261,7 @@ static void track_table_access(THD *thd, TABLE **tables, size_t count)
if (t)
tst->add_trx_state(thd, t->reginfo.lock_type,
t->file->has_transactions());
t->file->has_transaction_manager());
}
}
}
@ -439,10 +439,10 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
This will work even if get_lock_data fails (next unlock will free all)
*/
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag)
{
MYSQL_LOCK *sql_lock=
get_lock_data(thd, table, count, GET_LOCK_UNLOCK | GET_LOCK_ON_THD);
get_lock_data(thd, table, count, GET_LOCK_UNLOCK | GET_LOCK_ON_THD | flag);
if (sql_lock)
mysql_unlock_tables(thd, sql_lock, 0);
}
@ -539,7 +539,7 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
DBUG_ASSERT(table->lock_position == i);
/* Unlock the table. */
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
mysql_unlock_some_tables(thd, &table, /* table count */ 1, 0);
/* Decrement table_count in advance, making below expressions easier */
old_tables= --locked->table_count;
@ -733,6 +733,7 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
@param flags One of:
- GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
- GET_LOCK_STORE_LOCKS : Store lock info in TABLE
- GET_LOCK_SKIP_SEQUENCES : Ignore sequences (for temporary unlock)
*/
MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
@ -750,7 +751,8 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
TABLE *t= table_ptr[i];
if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE &&
t->s->tmp_table != INTERNAL_TMP_TABLE)
t->s->tmp_table != INTERNAL_TMP_TABLE &&
(!(flags & GET_LOCK_SKIP_SEQUENCES) || t->s->sequence == 0))
{
lock_count+= t->file->lock_count();
table_count++;
@ -781,7 +783,8 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
THR_LOCK_DATA **locks_start;
table= table_ptr[i];
if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE ||
table->s->tmp_table == INTERNAL_TMP_TABLE)
table->s->tmp_table == INTERNAL_TMP_TABLE ||
((flags & GET_LOCK_SKIP_SEQUENCES) && table->s->sequence))
continue;
lock_type= table->reginfo.lock_type;
DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT);

View File

@ -31,7 +31,7 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags);
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock);
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag);
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock);
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table);
@ -47,6 +47,7 @@ bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type,
#define GET_LOCK_STORE_LOCKS 1
#define GET_LOCK_ACTION_MASK 1
#define GET_LOCK_ON_THD (1 << 1)
#define GET_LOCK_SKIP_SEQUENCES (1 << 2)
MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags);
void reset_lock_data(MYSQL_LOCK *sql_lock, bool unlock);

View File

@ -61,6 +61,8 @@
#define MAX_LOG_BUFFER_SIZE 1024
#define MAX_TIME_SIZE 32
#define MY_OFF_T_UNDEF (~(my_off_t)0UL)
/* Truncate cache log files bigger than this */
#define CACHE_FILE_TRUNC_SIZE 65536
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
@ -250,7 +252,8 @@ void make_default_log_name(char **out, const char* log_ext, bool once)
class binlog_cache_data
{
public:
binlog_cache_data(): m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF),
binlog_cache_data(): m_pending(0), status(0),
before_stmt_pos(MY_OFF_T_UNDEF),
incident(FALSE), changes_to_non_trans_temp_table_flag(FALSE),
saved_max_binlog_cache_size(0), ptr_binlog_cache_use(0),
ptr_binlog_cache_disk_use(0)
@ -262,9 +265,22 @@ public:
close_cached_file(&cache_log);
}
/*
Return 1 if there is no relevant entries in the cache
This is:
- Cache is empty
- There are row or critical (DDL?) events in the cache
The status test is needed to avoid writing entries with only
a table map entry, which would crash in do_apply_event() on the slave
as it assumes that there is always a row entry after a table map.
*/
bool empty() const
{
return pending() == NULL && my_b_tell(&cache_log) == 0;
return (pending() == NULL &&
(my_b_write_tell(&cache_log) == 0 ||
((status & (LOGGED_ROW_EVENT | LOGGED_CRITICAL)) == 0)));
}
Rows_log_event *pending() const
@ -299,23 +315,19 @@ public:
void reset()
{
compute_statistics();
truncate(0);
if(cache_log.file != -1)
bool cache_was_empty= empty();
bool truncate_file= (cache_log.file != -1 &&
my_b_write_tell(&cache_log) > CACHE_FILE_TRUNC_SIZE);
truncate(0,1); // Forget what's in cache
if (!cache_was_empty)
compute_statistics();
if (truncate_file)
my_chsize(cache_log.file, 0, 0, MYF(MY_WME));
changes_to_non_trans_temp_table_flag= FALSE;
status= 0;
incident= FALSE;
before_stmt_pos= MY_OFF_T_UNDEF;
/*
The truncate function calls reinit_io_cache that calls
my_b_flush_io_cache which may increase disk_writes. This breaks
the disk_writes use by the binary log which aims to compute the
ratio between in-memory cache usage and disk cache usage. To
avoid this undesirable behavior, we reset the variable after
truncating the cache.
*/
cache_log.disk_writes= 0;
DBUG_ASSERT(empty());
}
@ -376,6 +388,11 @@ public:
cache_log.end_of_file= saved_max_binlog_cache_size;
}
void add_status(enum_logged_status status_arg)
{
status|= status_arg;
}
/*
Cache to store data before copying it to the binary log.
*/
@ -388,6 +405,13 @@ private:
*/
Rows_log_event *m_pending;
/*
Bit flags for what has been writting to cache. Used to
discard logs without any data changes.
see enum_logged_status;
*/
uint32 status;
/*
Binlog position before the start of the current statement.
*/
@ -410,11 +434,16 @@ private:
*/
void compute_statistics()
{
if (!empty())
statistic_increment(*ptr_binlog_cache_use, &LOCK_status);
if (cache_log.disk_writes != 0)
{
statistic_increment(*ptr_binlog_cache_use, &LOCK_status);
if (cache_log.disk_writes != 0)
statistic_increment(*ptr_binlog_cache_disk_use, &LOCK_status);
#ifdef REAL_STATISTICS
statistic_add(*ptr_binlog_cache_disk_use,
cache_log.disk_writes, &LOCK_status);
#else
statistic_increment(*ptr_binlog_cache_disk_use, &LOCK_status);
#endif
cache_log.disk_writes= 0;
}
}
@ -443,7 +472,7 @@ private:
It truncates the cache to a certain position. This includes deleting the
pending event.
*/
void truncate(my_off_t pos)
void truncate(my_off_t pos, bool reset_cache=0)
{
DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
if (pending())
@ -451,7 +480,7 @@ private:
delete pending();
set_pending(0);
}
reinit_io_cache(&cache_log, WRITE_CACHE, pos, 0, 0);
reinit_io_cache(&cache_log, WRITE_CACHE, pos, 0, reset_cache);
cache_log.end_of_file= saved_max_binlog_cache_size;
}
@ -459,6 +488,13 @@ private:
binlog_cache_data(const binlog_cache_data& info);
};
void Log_event_writer::add_status(enum_logged_status status)
{
if (likely(cache_data))
cache_data->add_status(status);
}
class binlog_cache_mngr {
public:
binlog_cache_mngr(my_off_t param_max_binlog_stmt_cache_size,
@ -5207,12 +5243,14 @@ end:
DBUG_RETURN(error);
}
bool MYSQL_BIN_LOG::write_event(Log_event *ev, IO_CACHE *file)
bool MYSQL_BIN_LOG::write_event(Log_event *ev, binlog_cache_data *cache_data,
IO_CACHE *file)
{
Log_event_writer writer(file, &crypto);
Log_event_writer writer(file, 0, &crypto);
if (crypto.scheme && file == &log_file)
writer.ctx= alloca(crypto.ctx_size);
if (cache_data)
cache_data->add_status(ev->logged_status());
return writer.write(ev);
}
@ -5649,10 +5687,11 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
binlog_cache_mngr *const cache_mngr=
(binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
binlog_cache_data *cache_data= (cache_mngr->
get_binlog_cache_data(is_transactional));
IO_CACHE *file= &cache_data->cache_log;
Log_event_writer writer(file, cache_data);
IO_CACHE *file=
cache_mngr->get_binlog_cache_log(use_trans_cache(this, is_transactional));
Log_event_writer writer(file);
if (with_annotate && *with_annotate)
{
Annotate_rows_log_event anno(table->in_use, is_transactional, false);
@ -5788,7 +5827,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
if (Rows_log_event* pending= cache_data->pending())
{
Log_event_writer writer(&cache_data->cache_log);
Log_event_writer writer(&cache_data->cache_log, cache_data);
/*
Write pending event to the cache.
@ -6200,8 +6239,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
goto err;
is_trans_cache= use_trans_cache(thd, using_trans);
file= cache_mngr->get_binlog_cache_log(is_trans_cache);
cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache);
file= &cache_data->cache_log;
if (thd->lex->stmt_accessed_non_trans_temp_table())
cache_data->set_changes_to_non_trans_temp_table();
@ -6225,21 +6264,19 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
Annotate_rows_log_event anno(thd, using_trans, direct);
/* Annotate event should be written not more than once */
*with_annotate= 0;
if (write_event(&anno, file))
if (write_event(&anno, cache_data, file))
goto err;
}
if (thd)
{
if (!thd->is_current_stmt_binlog_format_row())
{
if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
{
Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
thd->first_successful_insert_id_in_prev_stmt_for_binlog,
using_trans, direct);
if (write_event(&e, file))
if (write_event(&e, cache_data, file))
goto err;
}
if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
@ -6250,14 +6287,14 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT,
thd->auto_inc_intervals_in_cur_stmt_for_binlog.
minimum(), using_trans, direct);
if (write_event(&e, file))
if (write_event(&e, cache_data, file))
goto err;
}
if (thd->rand_used)
{
Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2,
using_trans, direct);
if (write_event(&e, file))
if (write_event(&e, cache_data, file))
goto err;
}
if (thd->user_var_events.elements)
@ -6281,7 +6318,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
flags,
using_trans,
direct);
if (write_event(&e, file))
if (write_event(&e, cache_data, file))
goto err;
}
}
@ -6291,7 +6328,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
/*
Write the event.
*/
if (write_event(event_info, file) ||
if (write_event(event_info, cache_data, file) ||
DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
goto err;
@ -6676,7 +6713,8 @@ public:
CacheWriter(THD *thd_arg, IO_CACHE *file_arg, bool do_checksum,
Binlog_crypt_data *cr)
: Log_event_writer(file_arg, cr), remains(0), thd(thd_arg), first(true)
: Log_event_writer(file_arg, 0, cr), remains(0), thd(thd_arg),
first(true)
{ checksum_len= do_checksum ? BINLOG_CHECKSUM_LEN : 0; }
~CacheWriter()
@ -6684,6 +6722,7 @@ public:
int write(uchar* pos, size_t len)
{
DBUG_ENTER("CacheWriter::write");
if (first)
write_header(pos, len);
else
@ -6692,7 +6731,7 @@ public:
remains -= len;
if ((first= !remains))
write_footer();
return 0;
DBUG_RETURN(0);
}
private:
THD *thd;

View File

@ -415,8 +415,10 @@ private:
( ((ulong)(c)>>1) == BINLOG_COOKIE_DUMMY_ID )
class binlog_cache_mngr;
class binlog_cache_data;
struct rpl_gtid;
struct wait_for_commit;
class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
{
private:
@ -743,8 +745,8 @@ public:
void stop_union_events(THD *thd);
bool is_query_in_union(THD *thd, query_id_t query_id_param);
bool write_event(Log_event *ev, IO_CACHE *file);
bool write_event(Log_event *ev) { return write_event(ev, &log_file); }
bool write_event(Log_event *ev, binlog_cache_data *data, IO_CACHE *file);
bool write_event(Log_event *ev) { return write_event(ev, 0, &log_file); }
bool write_event_buffer(uchar* buf,uint len);
bool append(Log_event* ev);

View File

@ -4075,10 +4075,12 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
switch (lex->sql_command)
{
case SQLCOM_DROP_TABLE:
case SQLCOM_DROP_SEQUENCE:
use_cache= (lex->tmp_table() && thd->in_multi_stmt_transaction_mode());
break;
case SQLCOM_CREATE_TABLE:
case SQLCOM_CREATE_SEQUENCE:
/*
If we are using CREATE ... SELECT or if we are a slave
executing BEGIN...COMMIT (generated by CREATE...SELECT) we
@ -5318,7 +5320,8 @@ compare_errors:
has already been dropped. To ignore such irrelevant "table does
not exist errors", we silently clear the error if TEMPORARY was used.
*/
if (thd->lex->sql_command == SQLCOM_DROP_TABLE &&
if ((thd->lex->sql_command == SQLCOM_DROP_TABLE ||
thd->lex->sql_command == SQLCOM_DROP_SEQUENCE) &&
thd->lex->tmp_table() &&
thd->is_error() && thd->get_stmt_da()->sql_errno() == ER_BAD_TABLE_ERROR &&
!expected_error)
@ -9292,7 +9295,7 @@ int Create_file_log_event::do_apply_event(rpl_group_info *rgi)
char *ext;
int fd = -1;
IO_CACHE file;
Log_event_writer lew(&file);
Log_event_writer lew(&file, 0);
int error = 1;
Relay_log_info const *rli= rgi->rli;
@ -11322,7 +11325,8 @@ Annotate_rows_log_event::Annotate_rows_log_event(THD *thd,
bool direct)
: Log_event(thd, 0, using_trans),
m_save_thd_query_txt(0),
m_save_thd_query_len(0)
m_save_thd_query_len(0),
m_used_query_txt(0)
{
m_query_txt= thd->query();
m_query_len= thd->query_length();
@ -11336,7 +11340,8 @@ Annotate_rows_log_event::Annotate_rows_log_event(const char *buf,
const Format_description_log_event *desc)
: Log_event(buf, desc),
m_save_thd_query_txt(0),
m_save_thd_query_len(0)
m_save_thd_query_len(0),
m_used_query_txt(0)
{
m_query_len= event_len - desc->common_header_len;
m_query_txt= (char*) buf + desc->common_header_len;
@ -11344,10 +11349,14 @@ Annotate_rows_log_event::Annotate_rows_log_event(const char *buf,
Annotate_rows_log_event::~Annotate_rows_log_event()
{
DBUG_ENTER("Annotate_rows_log_event::~Annotate_rows_log_event");
#ifndef MYSQL_CLIENT
if (m_save_thd_query_txt)
thd->set_query(m_save_thd_query_txt, m_save_thd_query_len);
else if (m_used_query_txt)
thd->reset_query();
#endif
DBUG_VOID_RETURN;
}
int Annotate_rows_log_event::get_data_size()
@ -11431,6 +11440,7 @@ int Annotate_rows_log_event::do_apply_event(rpl_group_info *rgi)
{
m_save_thd_query_txt= thd->query();
m_save_thd_query_len= thd->query_length();
m_used_query_txt= 1;
thd->set_query(m_query_txt, m_query_len);
return 0;
}
@ -11982,7 +11992,7 @@ int Table_map_log_event::do_apply_event(rpl_group_info *rgi)
table_list->table_id= DBUG_EVALUATE_IF("inject_tblmap_same_id_maps_diff_table", 0, m_table_id);
table_list->updating= 1;
table_list->required_type= FRMTYPE_TABLE;
table_list->required_type= TABLE_TYPE_NORMAL;
DBUG_PRINT("debug", ("table: %s is mapped to %u", table_list->table_name,
table_list->table_id));

View File

@ -716,6 +716,21 @@ enum Log_event_type
ENUM_END_EVENT /* end marker */
};
/*
Bit flags for what has been writting to cache. Used to
discard logs with table map events but not row events and
nothing else important. This is stored by cache.
*/
enum enum_logged_status
{
LOGGED_TABLE_MAP= 1,
LOGGED_ROW_EVENT= 2,
LOGGED_NO_DATA= 4,
LOGGED_CRITICAL= 8
};
static inline bool LOG_EVENT_IS_QUERY(enum Log_event_type type)
{
return type == QUERY_EVENT || type == QUERY_COMPRESSED_EVENT;
@ -785,6 +800,7 @@ class THD;
class Format_description_log_event;
class Relay_log_info;
class binlog_cache_data;
#ifdef MYSQL_CLIENT
enum enum_base64_output_mode {
@ -896,6 +912,7 @@ typedef struct st_print_event_info
This class encapsulates writing of Log_event objects to IO_CACHE.
Automatically calculates the checksum and encrypts the data, if necessary.
*/
class Log_event_writer
{
public:
@ -907,13 +924,16 @@ public:
int write_data(const uchar *pos, size_t len);
int write_footer();
my_off_t pos() { return my_b_safe_tell(file); }
void add_status(enum_logged_status status);
Log_event_writer(IO_CACHE *file_arg, Binlog_crypt_data *cr= 0)
Log_event_writer(IO_CACHE *file_arg, binlog_cache_data *cache_data_arg,
Binlog_crypt_data *cr= 0)
: bytes_written(0), ctx(0),
file(file_arg), crypto(cr) { }
file(file_arg), cache_data(cache_data_arg), crypto(cr) { }
private:
IO_CACHE *file;
binlog_cache_data *cache_data;
/**
Placeholder for event checksum while writing to binlog.
*/
@ -1236,7 +1256,7 @@ public:
bool is_more);
void print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
bool is_more);
#endif
#endif /* MYSQL_SERVER */
/* The following code used for Flashback */
#ifdef MYSQL_CLIENT
@ -1382,6 +1402,7 @@ public:
}
#endif
virtual Log_event_type get_type_code() = 0;
virtual enum_logged_status logged_status() { return LOGGED_CRITICAL; }
virtual bool is_valid() const = 0;
virtual my_off_t get_header_len(my_off_t len) { return len; }
void set_artificial_event() { flags |= LOG_EVENT_ARTIFICIAL_F; }
@ -3361,6 +3382,7 @@ public:
const Format_description_log_event *description_event);
~Gtid_log_event() { }
Log_event_type get_type_code() { return GTID_EVENT; }
enum_logged_status logged_status() { return LOGGED_NO_DATA; }
int get_data_size()
{
return GTID_HEADER_LEN + ((flags2 & FL_GROUP_COMMIT_ID) ? 2 : 0);
@ -3857,6 +3879,7 @@ public:
virtual int get_data_size();
virtual Log_event_type get_type_code();
enum_logged_status logged_status() { return LOGGED_NO_DATA; }
virtual bool is_valid() const;
virtual bool is_part_of_group() { return 1; }
@ -3885,6 +3908,7 @@ private:
uint m_query_len;
char *m_save_thd_query_txt;
uint m_save_thd_query_len;
bool m_used_query_txt;
};
/**
@ -4271,6 +4295,7 @@ public:
const char *get_db_name() const { return m_dbnam; }
virtual Log_event_type get_type_code() { return TABLE_MAP_EVENT; }
virtual enum_logged_status logged_status() { return LOGGED_TABLE_MAP; }
virtual bool is_valid() const { return m_memory != NULL; /* we check malloc */ }
virtual bool is_part_of_group() { return 1; }
@ -4398,6 +4423,7 @@ public:
flag_set get_flags(flag_set flags_arg) const { return m_flags & flags_arg; }
Log_event_type get_type_code() { return m_type; } /* Specific type (_V1 etc) */
enum_logged_status logged_status() { return LOGGED_ROW_EVENT; }
virtual Log_event_type get_general_type_code() = 0; /* General rows op type, no version */
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
@ -5160,6 +5186,7 @@ inline int Log_event_writer::write(Log_event *ev)
ev->writer= this;
int res= ev->write();
IF_DBUG(ev->writer= 0,); // writer must be set before every Log_event::write
add_status(ev->logged_status());
return res;
}

View File

@ -919,7 +919,8 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_PARTITION_LOCK_auto_inc;
PSI_mutex_key key_RELAYLOG_LOCK_index;
PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state,
key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry;
key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry,
key_LOCK_SEQUENCE;
PSI_mutex_key key_LOCK_stats,
key_LOCK_global_user_client_stats, key_LOCK_global_table_stats,
@ -1004,6 +1005,7 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_slave_state, "LOCK_slave_state", 0},
{ &key_LOCK_start_thread, "LOCK_start_thread", PSI_FLAG_GLOBAL},
{ &key_LOCK_binlog_state, "LOCK_binlog_state", 0},
{ &key_LOCK_SEQUENCE, "SQUENCE::LOCK_SEQUENCE", 0},
{ &key_LOCK_rpl_thread, "LOCK_rpl_thread", 0},
{ &key_LOCK_rpl_thread_pool, "LOCK_rpl_thread_pool", 0},
{ &key_LOCK_parallel_entry, "LOCK_parallel_entry", 0}
@ -3784,6 +3786,7 @@ SHOW_VAR com_status_vars[]= {
{"create_index", STMT_STATUS(SQLCOM_CREATE_INDEX)},
{"create_procedure", STMT_STATUS(SQLCOM_CREATE_PROCEDURE)},
{"create_role", STMT_STATUS(SQLCOM_CREATE_ROLE)},
{"create_sequence", STMT_STATUS(SQLCOM_CREATE_SEQUENCE)},
{"create_server", STMT_STATUS(SQLCOM_CREATE_SERVER)},
{"create_table", STMT_STATUS(SQLCOM_CREATE_TABLE)},
{"create_temporary_table", COM_STATUS(com_create_tmp_table)},
@ -3802,6 +3805,7 @@ SHOW_VAR com_status_vars[]= {
{"drop_procedure", STMT_STATUS(SQLCOM_DROP_PROCEDURE)},
{"drop_role", STMT_STATUS(SQLCOM_DROP_ROLE)},
{"drop_server", STMT_STATUS(SQLCOM_DROP_SERVER)},
{"drop_sequence", STMT_STATUS(SQLCOM_DROP_SEQUENCE)},
{"drop_table", STMT_STATUS(SQLCOM_DROP_TABLE)},
{"drop_temporary_table", COM_STATUS(com_drop_tmp_table)},
{"drop_trigger", STMT_STATUS(SQLCOM_DROP_TRIGGER)},

View File

@ -300,7 +300,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_relay_log_info_log_space_lock, key_relay_log_info_run_lock,
key_rpl_group_info_sleep_lock,
key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data,
key_LOCK_start_thread,
key_LOCK_start_thread, key_LOCK_SEQUENCE,
key_LOCK_error_messages, key_LOCK_thread_count, key_PARTITION_LOCK_auto_inc;
extern PSI_mutex_key key_RELAYLOG_LOCK_index;
extern PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state,

View File

@ -7466,3 +7466,21 @@ ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD
eng "Row variable '%-.192s' does not have a field '%-.192s'"
ER_END_IDENTIFIER_DOES_NOT_MATCH
eng "END identifier '%-.192s' does not match '%-.192s'"
ER_SEQUENCE_RUN_OUT
eng "Sequence '%-.64s.%-.64s' has run out"
ER_SEQUENCE_INVALID_DATA
eng "Sequence '%-.64s.%-.64s' values are conflicting"
ER_SEQUENCE_INVALID_TABLE_STRUCTURE
eng "Sequence '%-.64s.%-.64s' table structure is invalid (%s)"
ER_SEQUENCE_ACCESS_ERROR
eng "Sequence '%-.64s.%-.64s' access error"
ER_SEQUENCE_BINLOG_FORMAT
eng "Sequences requires binlog_format mixed or row"
ER_NOT_SEQUENCE 42S02
eng "'%-.64s.%-.64s' is not a SEQUENCE"
ER_NOT_SEQUENCE2 42S02
eng "'%-.192s' is not a SEQUENCE"
ER_UNKNOWN_SEQUENCES 42S02
eng "Unknown SEQUENCE: '%-.300s'"
ER_UNKNOWN_VIEW 42S02
eng "Unknown VIEW: '%-.300s'"

View File

@ -234,12 +234,14 @@ sp_get_flags_for_command(LEX *lex)
flags= sp_head::CONTAINS_DYNAMIC_SQL;
break;
case SQLCOM_CREATE_TABLE:
case SQLCOM_CREATE_SEQUENCE:
if (lex->tmp_table())
flags= 0;
else
flags= sp_head::HAS_COMMIT_OR_ROLLBACK;
break;
case SQLCOM_DROP_TABLE:
case SQLCOM_DROP_SEQUENCE:
if (lex->tmp_table())
flags= 0;
else
@ -4407,7 +4409,8 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
{
SP_TABLE *tab;
if (lex_for_tmp_check->sql_command == SQLCOM_DROP_TABLE &&
if ((lex_for_tmp_check->sql_command == SQLCOM_DROP_TABLE ||
lex_for_tmp_check->sql_command == SQLCOM_DROP_SEQUENCE) &&
lex_for_tmp_check->tmp_table())
return TRUE;
@ -4471,7 +4474,8 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check)
{
if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE))))
return FALSE;
if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
if ((lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE ||
lex_for_tmp_check->sql_command == SQLCOM_CREATE_SEQUENCE) &&
lex_for_tmp_check->query_tables == table &&
lex_for_tmp_check->tmp_table())
{

View File

@ -6438,7 +6438,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
{
if (!(rights & CREATE_ACL))
{
if (!ha_table_exists(thd, table_list->db, table_list->table_name, 0))
if (!ha_table_exists(thd, table_list->db, table_list->table_name))
{
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
DBUG_RETURN(TRUE);

View File

@ -341,16 +341,17 @@ static bool open_only_one_table(THD* thd, TABLE_LIST* table,
if (lex->alter_info.flags & Alter_info::ALTER_ADMIN_PARTITION ||
!is_view_operator_func)
{
table->required_type=FRMTYPE_TABLE;
DBUG_ASSERT(!lex->only_view);
table->required_type= TABLE_TYPE_NORMAL;
DBUG_ASSERT(lex->table_type != TABLE_TYPE_VIEW);
}
else if (lex->only_view)
else if (lex->table_type == TABLE_TYPE_VIEW)
{
table->required_type= FRMTYPE_VIEW;
table->required_type= lex->table_type;
}
else if (!lex->only_view && lex->sql_command == SQLCOM_REPAIR)
else if ((lex->table_type != TABLE_TYPE_VIEW) &&
lex->sql_command == SQLCOM_REPAIR)
{
table->required_type= FRMTYPE_TABLE;
table->required_type= TABLE_TYPE_NORMAL;
}
if (lex->sql_command == SQLCOM_CHECK ||

View File

@ -1934,6 +1934,11 @@ retry_share:
DBUG_RETURN(true);
}
#endif
if (table_list->sequence && table->s->table_type != TABLE_TYPE_SEQUENCE)
{
my_error(ER_NOT_SEQUENCE, MYF(0), table_list->db, table_list->alias);
DBUG_RETURN(true);
}
table->init(thd, table_list);
@ -3650,8 +3655,9 @@ lock_table_names(THD *thd, const DDL_options_st &options,
DBUG_RETURN(FALSE);
/* Check if CREATE TABLE without REPLACE was used */
create_table= thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
!options.or_replace();
create_table= ((thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE) &&
!options.or_replace());
if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
{
@ -4518,7 +4524,7 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
/* Set requested lock type. */
table_l->lock_type= lock_type;
/* Allow to open real tables only. */
table_l->required_type= FRMTYPE_TABLE;
table_l->required_type= TABLE_TYPE_NORMAL;
/* Open the table. */
if (open_and_lock_tables(thd, table_l, FALSE, flags,
@ -4574,7 +4580,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
THD_STAGE_INFO(thd, stage_opening_tables);
thd->current_tablenr= 0;
/* open_ltable can be used only for BASIC TABLEs */
table_list->required_type= FRMTYPE_TABLE;
table_list->required_type= TABLE_TYPE_NORMAL;
/* This function can't properly handle requests for such metadata locks. */
DBUG_ASSERT(table_list->mdl_request.type < MDL_SHARED_UPGRADABLE);
@ -5602,6 +5608,13 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
strcmp(db_name, table_list->db)))))
DBUG_RETURN(0);
/*
Don't allow usage of fields in sequence table that is opened as part of
NEXT VALUE for sequence_name
*/
if (table_list->sequence)
DBUG_RETURN(0);
*actual_table= NULL;
if (table_list->field_translation)

View File

@ -11,7 +11,13 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
Note that sql_builtin.cc is automatically built by sql_bultin.cc.in
and cmake/plugin.cmake
*/
#include <my_global.h>
#include <mysql/plugin.h>

View File

@ -101,6 +101,23 @@ extern "C" void free_user_var(user_var_entry *entry)
my_free(entry);
}
/* Functions for last-value-from-sequence hash */
extern "C" uchar *get_sequence_last_key(SEQUENCE_LAST_VALUE *entry,
size_t *length,
my_bool not_used
__attribute__((unused)))
{
*length= entry->length;
return (uchar*) entry->key;
}
extern "C" void free_sequence_last(SEQUENCE_LAST_VALUE *entry)
{
delete entry;
}
bool Key_part_spec::operator==(const Key_part_spec& other) const
{
return length == other.length &&
@ -879,6 +896,9 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(my_hash_get_key) get_var_key,
(my_hash_free_key) free_user_var, HASH_THREAD_SPECIFIC);
my_hash_init(&sequences, system_charset_info, SEQUENCES_HASH_SIZE, 0, 0,
(my_hash_get_key) get_sequence_last_key,
(my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC);
sp_proc_cache= NULL;
sp_func_cache= NULL;
@ -1428,6 +1448,9 @@ void THD::change_user(void)
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(my_hash_get_key) get_var_key,
(my_hash_free_key) free_user_var, 0);
my_hash_init(&sequences, system_charset_info, SEQUENCES_HASH_SIZE, 0, 0,
(my_hash_get_key) get_sequence_last_key,
(my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC);
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
}
@ -1484,6 +1507,7 @@ void THD::cleanup(void)
#endif /* defined(ENABLED_DEBUG_SYNC) */
my_hash_free(&user_vars);
my_hash_free(&sequences);
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
auto_inc_intervals_forced.empty();
@ -5699,7 +5723,7 @@ int xid_cache_iterate(THD *thd, my_hash_walk_action action, void *arg)
int THD::decide_logging_format(TABLE_LIST *tables)
{
DBUG_ENTER("THD::decide_logging_format");
DBUG_PRINT("info", ("Query: %s", query()));
DBUG_PRINT("info", ("Query: %.*s", (uint) query_length(), query()));
DBUG_PRINT("info", ("variables.binlog_format: %lu",
variables.binlog_format));
DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
@ -5866,7 +5890,9 @@ int THD::decide_logging_format(TABLE_LIST *tables)
if (prev_write_table && prev_write_table->file->ht !=
table->table->file->ht)
multi_write_engine= TRUE;
if (table->table->s->non_determinstic_insert)
if (table->table->s->non_determinstic_insert &&
lex->sql_command != SQLCOM_CREATE_SEQUENCE &&
lex->sql_command != SQLCOM_CREATE_TABLE)
has_write_tables_with_unsafe_statements= true;
trans= table->table->file->has_transactions();

View File

@ -699,6 +699,7 @@ typedef struct system_variables
ulong session_track_transaction_info;
my_bool session_track_schema;
my_bool session_track_state_change;
my_bool sequence_read_skip_cache;
ulong threadpool_priority;
@ -2219,6 +2220,8 @@ public:
chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK.
*/
HASH ull_hash;
/* Hash of used seqeunces (for PREVIOUS value) */
HASH sequences;
#ifndef DBUG_OFF
uint dbug_sentry; // watch out for memory corruption
#endif
@ -2423,6 +2426,8 @@ private:
uint binlog_table_maps;
public:
void issue_unsafe_warnings();
void reset_unsafe_warnings()
{ binlog_unsafe_warning_flags= 0; }
uint get_binlog_table_maps() const {
return binlog_table_maps;
@ -5716,6 +5721,14 @@ public:
SP Bulk execution optimized
*/
#define CF_SP_BULK_OPTIMIZED (1U << 20)
/**
If command creates or drops a table
*/
#define CF_SCHEMA_CHANGE (1U << 21)
/**
If command creates or drops a database
*/
#define CF_DB_CHANGE (1U << 22)
/* Bits in server_command_flags */

View File

@ -96,6 +96,8 @@ enum enum_sql_command {
SQLCOM_ALTER_USER,
SQLCOM_SHOW_CREATE_USER,
SQLCOM_EXECUTE_IMMEDIATE,
SQLCOM_CREATE_SEQUENCE,
SQLCOM_DROP_SEQUENCE,
/*
When a command is added here, be sure it's also added in mysqld.cc

View File

@ -114,6 +114,7 @@
#define MAX_ACCEPT_RETRY 10 // Test accept this many times
#define MAX_FIELDS_BEFORE_HASH 32
#define USER_VARS_HASH_SIZE 16
#define SEQUENCES_HASH_SIZE 16
#define TABLE_OPEN_CACHE_MIN 400
#define TABLE_OPEN_CACHE_DEFAULT 2000
#define TABLE_DEF_CACHE_DEFAULT 400

View File

@ -902,7 +902,8 @@ mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
thd->push_internal_handler(&err_handler);
if (!thd->killed &&
!(tables &&
mysql_rm_table_no_locks(thd, tables, true, false, true, true, false)))
mysql_rm_table_no_locks(thd, tables, true, false, true, false, true,
false)))
{
/*
We temporarily disable the binary log while dropping the objects

View File

@ -286,7 +286,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen)
mdl_savepoint= thd->mdl_context.mdl_savepoint();
/* for now HANDLER can be used only for real TABLES */
tables->required_type= FRMTYPE_TABLE;
tables->required_type= TABLE_TYPE_NORMAL;
/*
We use open_tables() here, rather than, say,

View File

@ -4120,7 +4120,7 @@ static TABLE *create_table_from_items(THD *thd,
if (!mysql_create_table_no_lock(thd, create_table->db,
create_table->table_name,
create_info, alter_info, NULL,
select_field_count))
select_field_count, create_table))
{
DEBUG_SYNC(thd,"create_table_select_before_open");

View File

@ -750,7 +750,7 @@ void LEX::start(THD *thd_arg)
in_sum_func= NULL;
used_tables= 0;
only_view= FALSE;
table_type= TABLE_TYPE_UNKNOWN;
reset_slave_info.all= false;
limit_rows_examined= 0;
limit_rows_examined_cnt= ULONGLONG_MAX;
@ -3379,6 +3379,7 @@ void LEX::set_trg_event_type_for_tables()
REPLACE SELECT is handled later in this method.
*/
case SQLCOM_CREATE_TABLE:
case SQLCOM_CREATE_SEQUENCE:
new_trg_event_map|= static_cast<uint8>
(1 << static_cast<int>(TRG_EVENT_INSERT));
break;
@ -6394,6 +6395,39 @@ Item *LEX::create_item_ident(THD *thd,
sp_variable *spv;
if (spcont && (spv= spcont->find_variable(a, false)))
return create_item_spvar_row_field(thd, a, b, spv, pos_in_q, length_in_q);
if ((thd->variables.sql_mode & MODE_ORACLE) && b.length == 7)
{
if (!my_strnncoll(system_charset_info,
(const uchar *) b.str, 7,
(const uchar *) "NEXTVAL", 7))
{
TABLE_LIST *table;
Table_ident *table_ident;
if (!(table_ident= new (thd->mem_root) Table_ident(a)) ||
!(table= current_select->add_table_to_list(thd, table_ident, 0,
TL_OPTION_SEQUENCE,
TL_WRITE_ALLOW_WRITE,
MDL_SHARED_WRITE)))
return NULL;
return new (thd->mem_root) Item_func_nextval(thd, table);
}
else if (!my_strnncoll(system_charset_info,
(const uchar *) b.str, 7,
(const uchar *) "CURRVAL", 7))
{
TABLE_LIST *table;
Table_ident *table_ident;
if (!(table_ident= new (thd->mem_root) Table_ident(a)) ||
!(table= current_select->add_table_to_list(thd, table_ident, 0,
TL_OPTION_SEQUENCE,
TL_READ,
MDL_SHARED_READ)))
return NULL;
return new (thd->mem_root) Item_func_lastval(thd, table);
}
}
return create_item_ident_nospvar(thd, a, b);
}
@ -6951,3 +6985,21 @@ int set_statement_var_if_exists(THD *thd, const char *var_name,
}
return 0;
}
bool LEX::sp_add_cfetch(THD *thd, const LEX_STRING &name)
{
uint offset;
sp_instr_cfetch *i;
if (!spcont->find_cursor(name, &offset, false))
{
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), name.str);
return true;
}
i= new (thd->mem_root)
sp_instr_cfetch(sphead->instructions(), spcont, offset);
if (i == NULL || sphead->add_instr(i))
return true;
return false;
}

View File

@ -249,6 +249,7 @@ enum enum_drop_mode
#define TL_OPTION_FORCE_INDEX 2
#define TL_OPTION_IGNORE_LEAVES 4
#define TL_OPTION_ALIAS 8
#define TL_OPTION_SEQUENCE 16
typedef List<Item> List_item;
typedef Mem_root_array<ORDER*, true> Group_list_ptrs;
@ -2632,6 +2633,7 @@ struct LEX: public Query_tables_list
*/
LEX_USER *definer;
Table_type table_type; /* Used for SHOW CREATE */
List<Key_part_spec> ref_list;
List<LEX_USER> users_list;
List<LEX_COLUMN> columns;
@ -2804,7 +2806,6 @@ public:
Event_parse_data *event_parse_data;
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
/*
field_list was created for view and should be removed before PS/SP
rexecuton
@ -3533,6 +3534,8 @@ public:
create_info.add(options);
return check_create_options(create_info);
}
bool sp_add_cfetch(THD *thd, const LEX_STRING &name);
bool set_command_with_check(enum_sql_command command,
uint scope,
DDL_options_st options)

View File

@ -101,6 +101,7 @@
#include "set_var.h"
#include "log_slow.h"
#include "sql_bootstrap.h"
#include "sql_sequence.h"
#include "my_json_writer.h"
@ -448,6 +449,7 @@ static bool stmt_causes_implicit_commit(THD *thd, uint mask)
switch (lex->sql_command) {
case SQLCOM_DROP_TABLE:
case SQLCOM_DROP_SEQUENCE:
skip= (lex->tmp_table() ||
(thd->variables.option_bits & OPTION_GTID_BEGIN));
break;
@ -456,6 +458,7 @@ static bool stmt_causes_implicit_commit(THD *thd, uint mask)
skip= (lex->tmp_table());
break;
case SQLCOM_CREATE_TABLE:
case SQLCOM_CREATE_SEQUENCE:
/*
If CREATE TABLE of non-temporary table and the table is not part
if a BEGIN GTID ... COMMIT group, do a implicit commit.
@ -542,19 +545,25 @@ void init_update_queries(void)
*/
sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS |
CF_CAN_GENERATE_ROW_EVENTS;
CF_CAN_GENERATE_ROW_EVENTS |
CF_SCHEMA_CHANGE;
sql_command_flags[SQLCOM_CREATE_SEQUENCE]= (CF_CHANGES_DATA |
CF_REEXECUTION_FRAGILE |
CF_AUTO_COMMIT_TRANS |
CF_SCHEMA_CHANGE);
sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS;
sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS |
CF_INSERTS_DATA;
sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE;
sql_command_flags[SQLCOM_DROP_SEQUENCE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE;
sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS | CF_REPORT_PROGRESS |
CF_INSERTS_DATA;
sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE;
sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE;
sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
@ -721,6 +730,7 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_TRUNCATE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT;
/* We don't want to replicate DROP for temp tables in row format */
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT;
sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT;
/* One can change replication mode with SET */
sql_command_flags[SQLCOM_SET_OPTION]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT;
@ -763,6 +773,7 @@ void init_update_queries(void)
*/
sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_PREOPEN_TMP_TABLES;
sql_command_flags[SQLCOM_TRUNCATE]|= CF_PREOPEN_TMP_TABLES;
@ -795,7 +806,9 @@ void init_update_queries(void)
have to be closed before temporary tables are pre-opened.
*/
sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_CREATE_SEQUENCE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_TRUNCATE]|= CF_HA_CLOSE;
sql_command_flags[SQLCOM_REPAIR]|= CF_HA_CLOSE;
@ -813,8 +826,10 @@ void init_update_queries(void)
even temporary table DDL should be disallowed.
*/
sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_SEQUENCE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_TABLE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_RENAME_TABLE]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_DROP_INDEX]|= CF_DISALLOW_IN_RO_TRANS;
@ -1407,7 +1422,7 @@ out:
This is a helper function to mysql_execute_command.
@note SQLCOM_MULTI_UPDATE is an exception and delt with elsewhere.
@note SQLCOM_MULTI_UPDATE is an exception and dealt with elsewhere.
@see mysql_execute_command
@returns Status code
@ -1425,13 +1440,12 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
LEX *lex= thd->lex;
const my_bool user_is_super=
((ulong)(thd->security_ctx->master_access & SUPER_ACL) ==
(ulong)SUPER_ACL);
if (user_is_super)
/* Super user is allowed to do changes */
if (((ulong)(thd->security_ctx->master_access & SUPER_ACL) ==
(ulong)SUPER_ACL))
DBUG_RETURN(FALSE);
/* Check if command doesn't update anything */
if (!(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA))
DBUG_RETURN(FALSE);
@ -1439,29 +1453,17 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
if (lex->sql_command == SQLCOM_UPDATE_MULTI)
DBUG_RETURN(FALSE);
const my_bool create_temp_tables=
(lex->sql_command == SQLCOM_CREATE_TABLE) && lex->tmp_table();
/* Check if we created and dropped temporary tables */
if ((sql_command_flags[lex->sql_command] & CF_SCHEMA_CHANGE) &&
lex->tmp_table())
DBUG_RETURN(FALSE);
const my_bool drop_temp_tables=
(lex->sql_command == SQLCOM_DROP_TABLE) && lex->tmp_table();
const my_bool update_real_tables=
some_non_temp_table_to_be_updated(thd, all_tables) &&
!(create_temp_tables || drop_temp_tables);
const my_bool create_or_drop_databases=
(lex->sql_command == SQLCOM_CREATE_DB) ||
(lex->sql_command == SQLCOM_DROP_DB);
if (update_real_tables || create_or_drop_databases)
{
/*
An attempt was made to modify one or more non-temporary tables.
*/
DBUG_RETURN(TRUE);
}
/* Check if we created or dropped databases */
if ((sql_command_flags[lex->sql_command] & CF_DB_CHANGE))
DBUG_RETURN(TRUE);
if (some_non_temp_table_to_be_updated(thd, all_tables))
DBUG_RETURN(TRUE);
/* Assuming that only temporary tables are modified. */
DBUG_RETURN(FALSE);
@ -3192,7 +3194,8 @@ mysql_execute_command(THD *thd)
*/
if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
!(lex->sql_command == SQLCOM_SET_OPTION) &&
!(lex->sql_command == SQLCOM_DROP_TABLE &&
!((lex->sql_command == SQLCOM_DROP_TABLE ||
lex->sql_command == SQLCOM_DROP_SEQUENCE) &&
lex->tmp_table() && lex->if_exists()) &&
all_tables_not_ok(thd, all_tables))
{
@ -3817,6 +3820,7 @@ mysql_execute_command(THD *thd)
res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX);
break;
}
case SQLCOM_CREATE_SEQUENCE:
case SQLCOM_CREATE_TABLE:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
@ -4074,6 +4078,7 @@ mysql_execute_command(THD *thd)
/* Regular CREATE TABLE */
res= mysql_create_table(thd, create_table, &create_info, &alter_info);
}
if (!res)
{
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
@ -4282,9 +4287,9 @@ end_with_restore_list:
*/
DBUG_PRINT("debug", ("lex->only_view: %d, table: %s.%s",
lex->only_view,
lex->table_type == TABLE_TYPE_VIEW,
first_table->db, first_table->table_name));
if (lex->only_view)
if (lex->table_type == TABLE_TYPE_VIEW)
{
if (check_table_access(thd, SELECT_ACL, first_table, FALSE, 1, FALSE))
{
@ -4298,7 +4303,6 @@ end_with_restore_list:
/* Ignore temporary tables if this is "SHOW CREATE VIEW" */
first_table->open_type= OT_BASE_ONLY;
}
else
{
@ -4806,6 +4810,7 @@ end_with_restore_list:
}
break;
}
case SQLCOM_DROP_SEQUENCE:
case SQLCOM_DROP_TABLE:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
@ -4816,7 +4821,7 @@ end_with_restore_list:
}
else
{
status_var_decrement(thd->status_var.com_stat[SQLCOM_DROP_TABLE]);
status_var_decrement(thd->status_var.com_stat[lex->sql_command]);
status_var_increment(thd->status_var.com_drop_tmp_table);
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
@ -4846,10 +4851,13 @@ end_with_restore_list:
lex->create_info.set(DDL_options_st::OPT_IF_EXISTS);
/* DDL and binlog write order are protected by metadata locks. */
res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table());
res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table(),
lex->table_type == TABLE_TYPE_SEQUENCE);
/* when dropping temporary tables if @@session_track_state_change is ON then
send the boolean tracker in the OK packet */
/*
When dropping temporary tables if @@session_track_state_change is ON
then send the boolean tracker in the OK packet
*/
if(!res && (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
@ -8095,6 +8103,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
/* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */
ptr->force_index= MY_TEST(table_options & TL_OPTION_FORCE_INDEX);
ptr->ignore_leaves= MY_TEST(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->sequence= MY_TEST(table_options & TL_OPTION_SEQUENCE);
ptr->derived= table->sel;
if (!ptr->derived && is_infoschema_db(ptr->db, ptr->db_length))
{
@ -8135,8 +8144,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->cacheable_table= !table->is_derived_table();
ptr->index_hints= index_hints_arg;
ptr->option= option ? option->str : 0;
/* check that used name is unique */
if (lock_type != TL_IGNORE)
/* check that used name is unique. Sequences are ignored */
if (lock_type != TL_IGNORE && !ptr->sequence)
{
TABLE_LIST *first_table= table_list.first;
if (lex->sql_command == SQLCOM_CREATE_VIEW)
@ -8146,7 +8155,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
tables=tables->next_local)
{
if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
!strcmp(ptr->db, tables->db))
!strcmp(ptr->db, tables->db) && ! tables->sequence)
{
my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
DBUG_RETURN(0); /* purecov: tested */
@ -8154,7 +8163,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
}
/* Store the table reference preceding the current one. */
if (table_list.elements > 0)
if (table_list.elements > 0 && !ptr->sequence)
{
/*
table_list.next points to the last inserted TABLE_LIST->next_local'
@ -8179,8 +8188,11 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
Notice that as a side effect here we set the next_local field of the
previous table reference to 'ptr'. Here we also add one element to the
list 'table_list'.
We don't store sequences into the local list to hide them from INSERT
and SELECT.
*/
table_list.link_in_list(ptr, &ptr->next_local);
if (!ptr->sequence)
table_list.link_in_list(ptr, &ptr->next_local);
ptr->next_name_resolution_table= NULL;
#ifdef WITH_PARTITION_STORAGE_ENGINE
ptr->partition_names= partition_names;

View File

@ -1651,9 +1651,10 @@ int plugin_init(int *argc, char **argv, int flags)
build_table_filename(path, sizeof(path) - 1, "mysql", "plugin", reg_ext, 0);
char engine_name_buf[NAME_CHAR_LEN + 1];
LEX_STRING maybe_myisam= { engine_name_buf, 0 };
frm_type_enum frm_type= dd_frm_type(NULL, path, &maybe_myisam);
bool is_sequence;
Table_type frm_type= dd_frm_type(NULL, path, &maybe_myisam, &is_sequence);
/* if mysql.plugin table is MyISAM - load it right away */
if (frm_type == FRMTYPE_TABLE && !strcasecmp(maybe_myisam.str, "MyISAM"))
if (frm_type == TABLE_TYPE_NORMAL && !strcasecmp(maybe_myisam.str, "MyISAM"))
{
plugin_load(&tmp_root);
flags|= PLUGIN_INIT_SKIP_PLUGIN_TABLE;

View File

@ -2388,6 +2388,7 @@ static bool check_prepared_statement(Prepared_statement *stmt)
}
break;
case SQLCOM_CREATE_TABLE:
case SQLCOM_CREATE_SEQUENCE:
res= mysql_test_create_table(stmt);
break;
case SQLCOM_SHOW_CREATE:
@ -2489,6 +2490,7 @@ static bool check_prepared_statement(Prepared_statement *stmt)
*/
case SQLCOM_SHOW_EXPLAIN:
case SQLCOM_DROP_TABLE:
case SQLCOM_DROP_SEQUENCE:
case SQLCOM_RENAME_TABLE:
case SQLCOM_ALTER_TABLE:
case SQLCOM_COMMIT:

View File

@ -1550,7 +1550,14 @@ JOIN::optimize_inner()
}
if (const_tables && !thd->locked_tables_mode &&
!(select_options & SELECT_NO_UNLOCK))
mysql_unlock_some_tables(thd, table, const_tables);
{
/*
Unlock all tables, except sequences, as accessing these may still
require table updates
*/
mysql_unlock_some_tables(thd, table, const_tables,
GET_LOCK_SKIP_SEQUENCES);
}
if (!conds && outer_join)
{
/* Handle the case where we have an OUTER JOIN without a WHERE */

670
sql/sql_sequence.cc Normal file
View File

@ -0,0 +1,670 @@
/*
Copyright (c) 2017, MariaDB Corporation, Alibaba Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sql_class.h"
#include "sql_list.h"
#include "sql_sequence.h"
#include "ha_sequence.h"
#include "sql_base.h"
#include "transaction.h"
#include "lock.h"
struct Field_definition
{
const char *field_name;
uint length;
enum enum_field_types sql_type;
LEX_STRING comment;
ulong flags;
};
/*
Structure for all SEQUENCE tables
Note that the first field is named "next_val" to all us to have
NEXTVAL a reserved word that will on access be changed to
NEXTVAL(sequence_table). For this to work, the table can't have
a column named NEXTVAL.
*/
#define FL (NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG)
static Field_definition sequence_structure[]=
{
{"next_value", 21, MYSQL_TYPE_LONGLONG, {C_STRING_WITH_LEN("next not cached value")},
FL},
{"min_value", 21, MYSQL_TYPE_LONGLONG, {C_STRING_WITH_LEN("min value")}, FL},
{"max_value", 21, MYSQL_TYPE_LONGLONG, {C_STRING_WITH_LEN("max value")}, FL},
{"start", 21, MYSQL_TYPE_LONGLONG, {C_STRING_WITH_LEN("start value")}, FL},
{"increment", 21, MYSQL_TYPE_LONGLONG,
{C_STRING_WITH_LEN("increment value")}, FL},
{"cache", 21, MYSQL_TYPE_LONGLONG, {C_STRING_WITH_LEN("cache size")}, FL},
{"cycle", 1, MYSQL_TYPE_TINY, {C_STRING_WITH_LEN("cycle state")},
FL | UNSIGNED_FLAG },
{"round", 21, MYSQL_TYPE_LONGLONG,
{C_STRING_WITH_LEN("How many cycles has been done")}, FL},
{NULL, 0, MYSQL_TYPE_LONGLONG, {C_STRING_WITH_LEN("")}, 0}
};
#undef FL
#define MAX_AUTO_INCREMENT_VALUE 65535
/*
Check whether sequence values are valid.
Sets default values for fields that are not used, according to Oracle spec.
Note that reserved_until is not checked as it's ok that it's outside of
the range (to indicate that sequence us used up).
RETURN VALUES
false valid
true invalid
*/
bool sequence_definition::check_and_adjust()
{
longlong max_increment;
DBUG_ENTER("sequence_definition::check");
/*
If min_value is not set, set it to LONGLONG_MIN or 1, depending on
increment
*/
if (!(used_fields & seq_field_used_min_value))
min_value= increment < 0 ? LONGLONG_MIN+1 : 1;
/*
If min_value is not set, set it to LONGLONG_MAX or -1, depending on
increment
*/
if (!(used_fields & seq_field_used_max_value))
max_value= increment < 0 ? -1 : LONGLONG_MAX-1;
if (!(used_fields & seq_field_used_start))
{
/* Use min_value or max_value for start depending on increment */
start= increment < 0 ? max_value : min_value;
}
/* To ensure that cache * increment will never overflow */
max_increment= increment ? labs(increment) : MAX_AUTO_INCREMENT_VALUE;
if (max_value >= start &&
max_value > min_value &&
start >= min_value &&
max_value != LONGLONG_MAX &&
min_value != LONGLONG_MIN &&
cache < (LONGLONG_MAX - max_increment) / max_increment)
DBUG_RETURN(FALSE);
DBUG_RETURN(TRUE);
}
/*
Read sequence values from a table
*/
void sequence_definition::read_fields(TABLE *table)
{
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
reserved_until= table->field[0]->val_int();
min_value= table->field[1]->val_int();
max_value= table->field[2]->val_int();
start= table->field[3]->val_int();
increment= table->field[4]->val_int();
cache= table->field[5]->val_int();
cycle= table->field[6]->val_int();
round= table->field[7]->val_int();
dbug_tmp_restore_column_map(table->read_set, old_map);
used_fields= ~(uint) 0;
print_dbug();
}
/*
Store sequence into a table row
*/
void sequence_definition::store_fields(TABLE *table)
{
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
/* zero possible delete markers & null bits */
memcpy(table->record[0], table->s->default_values, table->s->null_bytes);
table->field[0]->store(reserved_until, 0);
table->field[1]->store(min_value, 0);
table->field[2]->store(max_value, 0);
table->field[3]->store(start, 0);
table->field[4]->store(increment, 0);
table->field[5]->store(cache, 0);
table->field[6]->store((longlong) cycle != 0, 0);
table->field[7]->store((longlong) round, 1);
dbug_tmp_restore_column_map(table->write_set, old_map);
print_dbug();
}
/*
Check the sequence fields through seq_fields when create sequence.qq
RETURN VALUES
false Success
true Failure
*/
bool check_sequence_fields(LEX *lex, List<Create_field> *fields)
{
Create_field *field;
List_iterator_fast<Create_field> it(*fields);
uint field_count;
uint field_no;
const char *reason;
DBUG_ENTER("check_sequence_fields");
field_count= fields->elements;
if (field_count != array_elements(sequence_structure)-1)
{
reason= "Wrong number of columns";
goto err;
}
if (lex->alter_info.key_list.elements > 0)
{
reason= "Sequence tables cannot have any keys";
goto err;
}
for (field_no= 0; (field= it++); field_no++)
{
Field_definition *field_def= &sequence_structure[field_no];
if (my_strcasecmp(system_charset_info, field_def->field_name,
field->field_name) ||
field->flags != field_def->flags ||
field->sql_type != field_def->sql_type)
{
reason= field->field_name;
goto err;
}
}
DBUG_RETURN(FALSE);
err:
my_error(ER_SEQUENCE_INVALID_TABLE_STRUCTURE, MYF(0),
lex->select_lex.table_list.first->db,
lex->select_lex.table_list.first->table_name, reason);
DBUG_RETURN(TRUE);
}
/*
Create the fields for a SEQUENCE TABLE
RETURN VALUES
false Success
true Failure (out of memory)
*/
bool prepare_sequence_fields(THD *thd, List<Create_field> *fields)
{
Field_definition *field_info;
DBUG_ENTER("prepare_sequence_fields");
for (field_info= sequence_structure; field_info->field_name ; field_info++)
{
Create_field *new_field;
if (unlikely(!(new_field= new Create_field())))
DBUG_RETURN(TRUE); /* purify inspected */
new_field->field_name= field_info->field_name;
new_field->sql_type= field_info->sql_type;
new_field->length= field_info->length;
new_field->char_length= field_info->length;
new_field->comment= field_info->comment;
new_field->flags= field_info->flags;
if (unlikely(fields->push_back(new_field)))
DBUG_RETURN(TRUE); /* purify inspected */
}
DBUG_RETURN(FALSE);
}
/*
Initialize the sequence table record as part of CREATE SEQUENCE
Store one row with sequence information.
RETURN VALUES
false Success
true Failure. Error reported.
NOTES
This function is called as part of CREATE SEQUENCE. When called
there are now active transactions and no open tables.
There is also a MDL lock on the table.
*/
bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list)
{
int error;
TABLE *table;
TABLE_LIST::enum_open_strategy save_open_strategy;
sequence_definition *seq= lex->create_info.seq_create_info;
bool temporary_table= table_list->table != 0;
MY_BITMAP *save_write_set;
DBUG_ENTER("sequence_insert");
/* If not temporary table */
if (!temporary_table)
{
/* Table was locked as part of create table. Free it but keep MDL locks */
close_thread_tables(thd);
table_list->lock_type= TL_WRITE_DEFAULT;
table_list->updating= 1;
/*
The FOR CREATE flag is needed to ensure that ha_open() doesn't try to
read the not yet existing row in the sequence table
*/
thd->open_options|= HA_OPEN_FOR_CREATE;
save_open_strategy= table_list->open_strategy;
table_list->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
table_list->open_type= OT_BASE_ONLY;
error= open_and_lock_tables(thd, table_list, FALSE,
MYSQL_LOCK_IGNORE_TIMEOUT |
MYSQL_OPEN_HAS_MDL_LOCK);
table_list->open_strategy= save_open_strategy;
thd->open_options&= ~HA_OPEN_FOR_CREATE;
if (error)
DBUG_RETURN(TRUE); /* purify inspected */
}
table= table_list->table;
/*
seq is 0 if sequence was created with CREATE TABLE instead of
CREATE SEQUENCE
*/
if (!seq)
{
if (!(seq= new (thd->mem_root) sequence_definition))
DBUG_RETURN(TRUE); // EOM
}
seq->reserved_until= seq->start;
seq->store_fields(table);
/* Store the sequence values in table share */
table->s->sequence->copy(seq);
/*
Sequence values will be replicated as a statement
like 'create sequence'. So disable binary log temporarily
*/
tmp_disable_binlog(thd);
save_write_set= table->write_set;
table->write_set= &table->s->all_set;
error= table->file->ha_write_row(table->record[0]);
reenable_binlog(thd);
table->write_set= save_write_set;
if (error)
table->file->print_error(error, MYF(0));
else
{
/*
Sequence structure is up to date and table has one row,
sequence is now usable
*/
table->s->sequence->initialized= 1;
}
trans_commit_stmt(thd);
trans_commit_implicit(thd);
if (!temporary_table)
close_thread_tables(thd);
thd->mdl_context.release_transactional_locks();
DBUG_RETURN(error);
}
/* Create a SQUENCE object */
SEQUENCE::SEQUENCE() :initialized(0), all_values_used(0), table(0)
{
mysql_mutex_init(key_LOCK_SEQUENCE, &mutex, MY_MUTEX_INIT_SLOW);
}
SEQUENCE::~SEQUENCE()
{
mysql_mutex_destroy(&mutex);
}
/**
Read values from the sequence tables to table_share->sequence.
This is called from ha_open() when the table is not yet locked
*/
int SEQUENCE::read_initial_values(TABLE *table_arg)
{
int error= 0;
enum thr_lock_type save_lock_type;
MDL_request mdl_request; // Empty constructor!
DBUG_ENTER("SEQUENCE::read_initial_values");
if (likely(initialized))
DBUG_RETURN(0);
table= table_arg;
mysql_mutex_lock(&mutex);
if (unlikely(!initialized))
{
MYSQL_LOCK *lock;
bool mdl_lock_used= 0;
THD *thd= table->in_use;
bool has_active_transaction= !thd->transaction.stmt.is_empty();
/*
There is already a mdl_ticket for this table. However, for list_fields
the MDL lock is of type MDL_SHARED_HIGH_PRIO which is not usable
for doing a able lock. Get a proper read lock to solve this.
*/
if (table->mdl_ticket == 0)
{
MDL_request_list mdl_requests;
mdl_lock_used= 1;
/*
This happens if first request is SHOW CREATE TABLE or LIST FIELDS
where we don't have a mdl lock on the table
*/
mdl_request.init(MDL_key::TABLE,
table->s->db.str,
table->s->table_name.str,
MDL_SHARED_READ, MDL_EXPLICIT);
mdl_requests.push_front(&mdl_request);
if (thd->mdl_context.acquire_locks(&mdl_requests,
thd->variables.lock_wait_timeout))
DBUG_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT);
}
save_lock_type= table->reginfo.lock_type;
table->reginfo.lock_type= TL_READ;
if (!(lock= mysql_lock_tables(thd, &table, 1,
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY)))
{
if (mdl_lock_used)
thd->mdl_context.release_lock(mdl_request.ticket);
DBUG_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT);
}
if (!(error= read_stored_values()))
initialized= 1;
mysql_unlock_tables(thd, lock, 0);
if (mdl_lock_used)
thd->mdl_context.release_lock(mdl_request.ticket);
/* Reset value to default */
table->reginfo.lock_type= save_lock_type;
/*
Doing mysql_lock_tables() may have started a read only transaction.
If that happend, it's better that we commit it now, as a lot of
code assumes that there is no active stmt transaction directly after
open_tables()
*/
if (!has_active_transaction && !thd->transaction.stmt.is_empty())
trans_commit_stmt(thd);
}
mysql_mutex_unlock(&mutex);
DBUG_RETURN(error);
}
/*
Read data from sequence table and update values
Done when table is opened
*/
int SEQUENCE::read_stored_values()
{
int error;
my_bitmap_map *save_read_set;
DBUG_ENTER("SEQUENCE::read_stored_values");
mysql_mutex_assert_owner(&mutex);
save_read_set= tmp_use_all_columns(table, table->read_set);
error= table->file->ha_read_first_row(table->record[0], MAX_KEY);
tmp_restore_column_map(table->read_set, save_read_set);
if (error)
{
table->file->print_error(error, MYF(0));
DBUG_RETURN(error);
}
read_fields(table);
adjust_values();
all_values_used= 0;
DBUG_RETURN(0);
}
/*
Adjust values after reading a the stored state
*/
void SEQUENCE::adjust_values()
{
offset= 0;
next_free_value= reserved_until;
if (!(real_increment= increment))
{
longlong off, to_add;
/* Use auto_increment_increment and auto_increment_offset */
if ((real_increment= global_system_variables.auto_increment_increment)
!= 1)
offset= global_system_variables.auto_increment_offset;
/*
Ensure that next_free_value has the right offset, so that we
can generate a serie by just adding real_increment.
*/
off= next_free_value % real_increment;
if (off < 0)
off+= real_increment;
to_add= (real_increment + offset - off) % real_increment;
/*
Check if add will make next_free_value bigger than max_value,
taken into account that next_free_value or max_value addition
may overflow
*/
if (next_free_value > max_value - to_add ||
next_free_value + to_add > max_value)
next_free_value= max_value+1;
else
{
next_free_value+= to_add;
DBUG_ASSERT(next_free_value % real_increment == offset &&
next_free_value >= reserved_until);
}
}
}
/**
Get next value for sequence
@param in table Sequence table
@param in second_round
1 if recursive call (out of values once)
@param out error Set this to <> 0 in case of error
push_warning_printf(WARN_LEVEL_WARN) has been called
 @retval 0 Next number or error. Check error variable
# Next sequence number
NOTES:
Return next_free_value and increment next_free_value to next allowed
value or reserved_value if out of range
if next_free_value >= reserved_value reserve a new range by writing
a record to the sequence table.
The state of the variables:
next_free_value contains next value to use. It may be
bigger than max_value or less than min_value if end of sequence.
reserved_until contains the last value written to the file. All
values up to this one can be used.
If next_free_value >= reserved_until we have to reserve new
values from the sequence.
*/
longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error)
{
longlong res_value, org_reserved_until, add_to;
bool out_of_values;
MY_BITMAP *save_rpl_write_set, *save_write_set;
DBUG_ENTER("SEQUENCE::next_value");
*error= 0;
if (!second_round)
lock();
res_value= next_free_value;
/* Increment next_free_value */
if (real_increment > 0)
{
if (next_free_value + real_increment > max_value ||
next_free_value > max_value - real_increment)
next_free_value= max_value + 1;
else
next_free_value+= real_increment;
}
else
{
if (next_free_value + real_increment < min_value ||
next_free_value < min_value - real_increment)
next_free_value= min_value - 1;
else
next_free_value+= real_increment;
}
if ((real_increment > 0 && res_value < reserved_until) ||
(real_increment < 0 && res_value > reserved_until))
{
unlock();
DBUG_RETURN(res_value);
}
if (all_values_used)
goto err;
org_reserved_until= reserved_until;
/*
Out of cached values, reserve 'cache' new ones
The cache value is checked on insert so the following can't
overflow
*/
add_to= cache ? real_increment * cache : 1;
out_of_values= 0;
if (real_increment > 0)
{
if (reserved_until + add_to > max_value ||
reserved_until > max_value - add_to)
{
reserved_until= max_value + 1;
out_of_values= res_value >= reserved_until;
}
else
reserved_until+= add_to;
}
else
{
if (reserved_until + add_to < min_value ||
reserved_until < min_value - add_to)
{
reserved_until= min_value - 1;
out_of_values= res_value <= reserved_until;
}
else
reserved_until+= add_to;
}
if (out_of_values)
{
if (!cycle || second_round)
goto err;
round++;
reserved_until= real_increment >0 ? min_value : max_value;
adjust_values(); // Fix next_free_value
/*
We have to do everything again to ensure that the given range was
not empty, which could happen if increment == 0
*/
DBUG_RETURN(next_value(table, 1, error));
}
/* Log a full insert (ok as table is small) */
save_rpl_write_set= table->rpl_write_set;
/* Update table */
save_write_set= table->write_set;
table->rpl_write_set= table->write_set= &table->s->all_set;
store_fields(table);
/* Tell ha_sequence::write_row that we already hold the mutex */
((ha_sequence*) table->file)->sequence_locked= 1;
if ((*error= table->file->ha_write_row(table->record[0])))
{
table->file->print_error(*error, MYF(0));
/* Restore original range */
reserved_until= org_reserved_until;
next_free_value= res_value;
}
((ha_sequence*) table->file)->sequence_locked= 0;
table->rpl_write_set= save_rpl_write_set;
table->write_set= save_write_set;
unlock();
DBUG_RETURN(res_value);
err:
unlock();
my_error(ER_SEQUENCE_RUN_OUT, MYF(0), table->s->db.str,
table->s->table_name.str);
*error= ER_SEQUENCE_RUN_OUT;
all_values_used= 1;
DBUG_RETURN(0);
}
/*
The following functions is to detect if a table has been dropped
and re-created since last call to PREVIOUS VALUE.
This is needed as we don't delete dropped sequences from THD->sequence
for DROP TABLE.
*/
bool SEQUENCE_LAST_VALUE::check_version(TABLE *table)
{
DBUG_ASSERT(table->s->tabledef_version.length == MY_UUID_SIZE);
return memcmp(table->s->tabledef_version.str, table_version,
MY_UUID_SIZE) != 0;
}
void SEQUENCE_LAST_VALUE::set_version(TABLE *table)
{
memcpy(table_version, table->s->tabledef_version.str, MY_UUID_SIZE);
}

133
sql/sql_sequence.h Normal file
View File

@ -0,0 +1,133 @@
/* Copyright (c) 2017, MariaDB corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef SQL_SEQUENCE_INCLUDED
#define SQL_SEQUENCE_INCLUDED
#define seq_field_used_min_value 1
#define seq_field_used_max_value 2
#define seq_field_used_start 4
/**
sequence_definition is used when defining a sequence as part of create
*/
class sequence_definition :public Sql_alloc
{
public:
sequence_definition():
min_value(1), max_value(LONGLONG_MAX-1), start(1), increment(1),
cache(1000), round(0), cycle(0), used_fields(0)
{}
longlong reserved_until;
longlong min_value;
longlong max_value;
longlong start;
longlong increment;
longlong cache;
ulonglong round;
bool cycle;
uint used_fields; // Which fields where used in CREATE
bool check_and_adjust();
void store_fields(TABLE *table);
void read_fields(TABLE *table);
void print_dbug()
{
DBUG_PRINT("sequence", ("reserved: %lld start: %lld increment: %lld min_value: %lld max_value: %lld cache: %lld round: %lld",
reserved_until, start, increment, min_value,
max_value, cache, round));
}
};
/**
SEQUENCE is in charge of managing the sequence values.
It's also responsible to generate new values and updating the sequence
table (engine=SQL_SEQUENCE) trough it's specialized handler interface.
If increment is 0 then the sequence will be be using
auto_increment_increment and auto_increment_offset variables, just like
AUTO_INCREMENT is using.
*/
class SEQUENCE :public sequence_definition
{
public:
SEQUENCE();
~SEQUENCE();
int read_initial_values(TABLE *table);
int read_stored_values();
void lock()
{
mysql_mutex_lock(&mutex);
}
void unlock()
{
mysql_mutex_unlock(&mutex);
}
/* This must be called after sequence data has been updated */
void adjust_values();
void copy(sequence_definition *seq)
{
sequence_definition::operator= (*seq);
adjust_values();
}
longlong next_value(TABLE *table, bool second_round, int *error);
bool initialized; // If row has been read
bool all_values_used;
private:
TABLE *table;
mysql_mutex_t mutex;
longlong next_free_value;
/*
The following values are the values from sequence_definition
merged with global auto_increment_offset and auto_increment_increment
*/
longlong real_increment;
longlong offset;
};
/**
Class to cache last value of NEXT VALUE from the sequence
*/
class SEQUENCE_LAST_VALUE
{
public:
SEQUENCE_LAST_VALUE(uchar *key_arg, uint length_arg)
:key(key_arg), length(length_arg)
{}
~SEQUENCE_LAST_VALUE()
{ my_free((void*) key); }
/* Returns 1 if table hasn't been dropped or re-created */
bool check_version(TABLE *table);
void set_version(TABLE *table);
const uchar *key;
uint length;
bool null_value;
longlong value;
uchar table_version[MY_UUID_SIZE];
};
class Create_field;
extern bool prepare_sequence_fields(THD *thd, List<Create_field> *fields);
extern bool check_sequence_fields(LEX *lex, List<Create_field> *fields);
extern bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list);
#endif /* SQL_SEQUENCE_INCLUDED */

View File

@ -58,10 +58,11 @@
#include "lock.h" // MYSQL_OPEN_IGNORE_FLUSH
#include "debug_sync.h"
#include "keycaches.h"
#include "ha_sequence.h"
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
enum enum_i_s_events_fields
{
ISE_EVENT_CATALOG= 0,
@ -130,6 +131,8 @@ static void get_cs_converted_string_value(THD *thd,
#endif
static int show_create_view(THD *thd, TABLE_LIST *table, String *buff);
static int show_create_sequence(THD *thd, TABLE_LIST *table_list,
String *packet);
static const LEX_STRING *view_algorithm(TABLE_LIST *table);
@ -1169,12 +1172,19 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list,
}
/* TODO: add environment variables show when it become possible */
if (thd->lex->only_view && !table_list->view)
if (thd->lex->table_type == TABLE_TYPE_VIEW && !table_list->view)
{
my_error(ER_WRONG_OBJECT, MYF(0),
table_list->db, table_list->table_name, "VIEW");
goto exit;
}
else if (thd->lex->table_type == TABLE_TYPE_SEQUENCE &&
table_list->table->s->table_type != TABLE_TYPE_SEQUENCE)
{
my_error(ER_WRONG_OBJECT, MYF(0),
table_list->db, table_list->table_name, "SEQUENCE");
goto exit;
}
buffer->length(0);
@ -1183,6 +1193,8 @@ mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list,
if ((table_list->view ?
show_create_view(thd, table_list, buffer) :
thd->lex->table_type == TABLE_TYPE_SEQUENCE ?
show_create_sequence(thd, table_list, buffer) :
show_create_table(thd, table_list, buffer, NULL, WITHOUT_DB_NAME)))
goto exit;
@ -1761,6 +1773,179 @@ static void append_create_options(THD *thd, String *packet,
packet->append(STRING_WITH_LEN(" */"));
}
/**
Add table options to end of CREATE statement
@param schema_table 1 if schema table
@param sequence 1 if sequence. If sequence, we flush out options
not relevant for sequences.
*/
static void add_table_options(THD *thd, TABLE *table,
Table_specification_st *create_info_arg,
bool schema_table, bool sequence,
String *packet)
{
sql_mode_t sql_mode= thd->variables.sql_mode;
TABLE_SHARE *share= table->s;
handlerton *hton;
HA_CREATE_INFO create_info;
bool check_options= (!(sql_mode & MODE_IGNORE_BAD_TABLE_OPTIONS) &&
!create_info_arg);
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (table->part_info)
hton= table->part_info->default_engine_type;
else
#endif
hton= table->file->ht;
bzero((char*) &create_info, sizeof(create_info));
/* Allow update_create_info to update row type, page checksums and options */
create_info.row_type= share->row_type;
create_info.page_checksum= share->page_checksum;
create_info.options= share->db_create_options;
table->file->update_create_info(&create_info);
/*
IF check_create_info
THEN add ENGINE only if it was used when creating the table
*/
if (!create_info_arg ||
(create_info_arg->used_fields & HA_CREATE_USED_ENGINE))
{
LEX_STRING *engine_name= table->file->engine_name();
if (sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
packet->append(STRING_WITH_LEN(" TYPE="));
else
packet->append(STRING_WITH_LEN(" ENGINE="));
packet->append(engine_name->str, engine_name->length);
}
if (sequence)
goto end_options;
/*
Add AUTO_INCREMENT=... if there is an AUTO_INCREMENT column,
and NEXT_ID > 1 (the default). We must not print the clause
for engines that do not support this as it would break the
import of dumps, but as of this writing, the test for whether
AUTO_INCREMENT columns are allowed and wether AUTO_INCREMENT=...
is supported is identical, !(file->table_flags() & HA_NO_AUTO_INCREMENT))
Because of that, we do not explicitly test for the feature,
but may extrapolate its existence from that of an AUTO_INCREMENT column.
*/
if (create_info.auto_increment_value > 1)
{
packet->append(STRING_WITH_LEN(" AUTO_INCREMENT="));
packet->append_ulonglong(create_info.auto_increment_value);
}
if (share->table_charset && !(sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
share->table_type != TABLE_TYPE_SEQUENCE)
{
/*
IF check_create_info
THEN add DEFAULT CHARSET only if it was used when creating the table
*/
if (!create_info_arg ||
(create_info_arg->used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
{
packet->append(STRING_WITH_LEN(" DEFAULT CHARSET="));
packet->append(share->table_charset->csname);
if (!(share->table_charset->state & MY_CS_PRIMARY))
{
packet->append(STRING_WITH_LEN(" COLLATE="));
packet->append(table->s->table_charset->name);
}
}
}
if (share->min_rows)
{
packet->append(STRING_WITH_LEN(" MIN_ROWS="));
packet->append_ulonglong(share->min_rows);
}
if (share->max_rows && !schema_table && !sequence)
{
packet->append(STRING_WITH_LEN(" MAX_ROWS="));
packet->append_ulonglong(share->max_rows);
}
if (share->avg_row_length)
{
packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
packet->append_ulonglong(share->avg_row_length);
}
if (create_info.options & HA_OPTION_PACK_KEYS)
packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
if (create_info.options & HA_OPTION_NO_PACK_KEYS)
packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
if (share->db_create_options & HA_OPTION_STATS_PERSISTENT)
packet->append(STRING_WITH_LEN(" STATS_PERSISTENT=1"));
if (share->db_create_options & HA_OPTION_NO_STATS_PERSISTENT)
packet->append(STRING_WITH_LEN(" STATS_PERSISTENT=0"));
if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_ON)
packet->append(STRING_WITH_LEN(" STATS_AUTO_RECALC=1"));
else if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_OFF)
packet->append(STRING_WITH_LEN(" STATS_AUTO_RECALC=0"));
if (share->stats_sample_pages != 0)
{
packet->append(STRING_WITH_LEN(" STATS_SAMPLE_PAGES="));
packet->append_ulonglong(share->stats_sample_pages);
}
/* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
if (create_info.options & HA_OPTION_CHECKSUM)
packet->append(STRING_WITH_LEN(" CHECKSUM=1"));
if (create_info.page_checksum != HA_CHOICE_UNDEF)
{
packet->append(STRING_WITH_LEN(" PAGE_CHECKSUM="));
packet->append(ha_choice_values[create_info.page_checksum], 1);
}
if (create_info.options & HA_OPTION_DELAY_KEY_WRITE)
packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1"));
if (create_info.row_type != ROW_TYPE_DEFAULT)
{
packet->append(STRING_WITH_LEN(" ROW_FORMAT="));
packet->append(ha_row_type[(uint) create_info.row_type]);
}
if (share->transactional != HA_CHOICE_UNDEF)
{
packet->append(STRING_WITH_LEN(" TRANSACTIONAL="));
packet->append(ha_choice_values[(uint) share->transactional], 1);
}
if (share->table_type == TABLE_TYPE_SEQUENCE)
packet->append(STRING_WITH_LEN(" SEQUENCE=1"));
if (table->s->key_block_size)
{
packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
packet->append_ulonglong(table->s->key_block_size);
}
table->file->append_create_info(packet);
end_options:
if (share->comment.length)
{
packet->append(STRING_WITH_LEN(" COMMENT="));
append_unescaped(packet, share->comment.str, share->comment.length);
}
if (share->connect_string.length)
{
packet->append(STRING_WITH_LEN(" CONNECTION="));
append_unescaped(packet, share->connect_string.str, share->connect_string.length);
}
append_create_options(thd, packet, share->option_list, check_options,
hton->table_options);
append_directory(thd, packet, "DATA", create_info.data_file_name);
append_directory(thd, packet, "INDEX", create_info.index_file_name);
}
/*
Build a CREATE TABLE statement for a table.
@ -1790,7 +1975,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
enum_with_db_name with_db_name)
{
List<Item> field_list;
char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH];
char tmp[MAX_FIELD_WIDTH], *for_str, def_value_buf[MAX_FIELD_WIDTH];
const char *alias;
String type;
String def_value;
@ -1798,9 +1983,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
uint primary_key;
KEY *key_info;
TABLE *table= table_list->table;
handler *file= table->file;
TABLE_SHARE *share= table->s;
HA_CREATE_INFO create_info;
sql_mode_t sql_mode= thd->variables.sql_mode;
bool foreign_db_mode= sql_mode & (MODE_POSTGRESQL | MODE_ORACLE |
MODE_MSSQL | MODE_DB2 |
@ -1811,8 +1994,8 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
!foreign_db_mode;
bool check_options= !(sql_mode & MODE_IGNORE_BAD_TABLE_OPTIONS) &&
!create_info_arg;
handlerton *hton;
my_bitmap_map *old_map;
handlerton *hton;
int error= 0;
DBUG_ENTER("show_create_table");
DBUG_PRINT("enter",("table: %s", table->s->table_name.str));
@ -1822,7 +2005,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
hton= table->part_info->default_engine_type;
else
#endif
hton= file->ht;
hton= table->file->ht;
restore_record(table, s->default_values); // Get empty record
@ -1971,12 +2154,6 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
}
key_info= table->key_info;
bzero((char*) &create_info, sizeof(create_info));
/* Allow update_create_info to update row type, page checksums and options */
create_info.row_type= share->row_type;
create_info.page_checksum= share->page_checksum;
create_info.options= share->db_create_options;
file->update_create_info(&create_info);
primary_key= share->primary_key;
for (uint i=0 ; i < share->keys ; i++,key_info++)
@ -2043,10 +2220,10 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
to the CREATE TABLE statement
*/
if ((for_str= file->get_foreign_key_create_info()))
if ((for_str= table->file->get_foreign_key_create_info()))
{
packet->append(for_str, strlen(for_str));
file->free_foreign_key_create_info(for_str);
table->file->free_foreign_key_create_info(for_str);
}
/* Add table level check constraints */
@ -2073,146 +2250,9 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN("\n)"));
if (show_table_options)
{
/*
IF check_create_info
THEN add ENGINE only if it was used when creating the table
*/
if (!create_info_arg ||
(create_info_arg->used_fields & HA_CREATE_USED_ENGINE))
{
if (sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
packet->append(STRING_WITH_LEN(" TYPE="));
else
packet->append(STRING_WITH_LEN(" ENGINE="));
packet->append(hton_name(hton));
}
add_table_options(thd, table, create_info_arg,
table_list->schema_table != 0, 0, packet);
/*
Add AUTO_INCREMENT=... if there is an AUTO_INCREMENT column,
and NEXT_ID > 1 (the default). We must not print the clause
for engines that do not support this as it would break the
import of dumps, but as of this writing, the test for whether
AUTO_INCREMENT columns are allowed and wether AUTO_INCREMENT=...
is supported is identical, !(file->table_flags() & HA_NO_AUTO_INCREMENT))
Because of that, we do not explicitly test for the feature,
but may extrapolate its existence from that of an AUTO_INCREMENT column.
*/
if (create_info.auto_increment_value > 1)
{
char *end;
packet->append(STRING_WITH_LEN(" AUTO_INCREMENT="));
end= longlong10_to_str(create_info.auto_increment_value, buff,10);
packet->append(buff, (uint) (end - buff));
}
if (share->table_charset && !(sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
{
/*
IF check_create_info
THEN add DEFAULT CHARSET only if it was used when creating the table
*/
if (!create_info_arg ||
(create_info_arg->used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
{
packet->append(STRING_WITH_LEN(" DEFAULT CHARSET="));
packet->append(share->table_charset->csname);
if (!(share->table_charset->state & MY_CS_PRIMARY))
{
packet->append(STRING_WITH_LEN(" COLLATE="));
packet->append(table->s->table_charset->name);
}
}
}
if (share->min_rows)
{
char *end;
packet->append(STRING_WITH_LEN(" MIN_ROWS="));
end= longlong10_to_str(share->min_rows, buff, 10);
packet->append(buff, (uint) (end- buff));
}
if (share->max_rows && !table_list->schema_table)
{
char *end;
packet->append(STRING_WITH_LEN(" MAX_ROWS="));
end= longlong10_to_str(share->max_rows, buff, 10);
packet->append(buff, (uint) (end - buff));
}
if (share->avg_row_length)
{
char *end;
packet->append(STRING_WITH_LEN(" AVG_ROW_LENGTH="));
end= longlong10_to_str(share->avg_row_length, buff,10);
packet->append(buff, (uint) (end - buff));
}
if (create_info.options & HA_OPTION_PACK_KEYS)
packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
if (create_info.options & HA_OPTION_NO_PACK_KEYS)
packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
if (share->db_create_options & HA_OPTION_STATS_PERSISTENT)
packet->append(STRING_WITH_LEN(" STATS_PERSISTENT=1"));
if (share->db_create_options & HA_OPTION_NO_STATS_PERSISTENT)
packet->append(STRING_WITH_LEN(" STATS_PERSISTENT=0"));
if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_ON)
packet->append(STRING_WITH_LEN(" STATS_AUTO_RECALC=1"));
else if (share->stats_auto_recalc == HA_STATS_AUTO_RECALC_OFF)
packet->append(STRING_WITH_LEN(" STATS_AUTO_RECALC=0"));
if (share->stats_sample_pages != 0)
{
char *end;
packet->append(STRING_WITH_LEN(" STATS_SAMPLE_PAGES="));
end= longlong10_to_str(share->stats_sample_pages, buff, 10);
packet->append(buff, (uint) (end - buff));
}
/* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
if (create_info.options & HA_OPTION_CHECKSUM)
packet->append(STRING_WITH_LEN(" CHECKSUM=1"));
if (create_info.page_checksum != HA_CHOICE_UNDEF)
{
packet->append(STRING_WITH_LEN(" PAGE_CHECKSUM="));
packet->append(ha_choice_values[create_info.page_checksum], 1);
}
if (create_info.options & HA_OPTION_DELAY_KEY_WRITE)
packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1"));
if (create_info.row_type != ROW_TYPE_DEFAULT)
{
packet->append(STRING_WITH_LEN(" ROW_FORMAT="));
packet->append(ha_row_type[(uint) create_info.row_type]);
}
if (share->transactional != HA_CHOICE_UNDEF)
{
packet->append(STRING_WITH_LEN(" TRANSACTIONAL="));
packet->append(ha_choice_values[(uint) share->transactional], 1);
}
if (table->s->key_block_size)
{
char *end;
packet->append(STRING_WITH_LEN(" KEY_BLOCK_SIZE="));
end= longlong10_to_str(table->s->key_block_size, buff, 10);
packet->append(buff, (uint) (end - buff));
}
table->file->append_create_info(packet);
if (share->comment.length)
{
packet->append(STRING_WITH_LEN(" COMMENT="));
append_unescaped(packet, share->comment.str, share->comment.length);
}
if (share->connect_string.length)
{
packet->append(STRING_WITH_LEN(" CONNECTION="));
append_unescaped(packet, share->connect_string.str, share->connect_string.length);
}
append_create_options(thd, packet, share->option_list, check_options,
hton->table_options);
append_directory(thd, packet, "DATA", create_info.data_file_name);
append_directory(thd, packet, "INDEX", create_info.index_file_name);
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
{
if (table->part_info &&
@ -2423,6 +2463,55 @@ static int show_create_view(THD *thd, TABLE_LIST *table, String *buff)
}
static int show_create_sequence(THD *thd, TABLE_LIST *table_list,
String *packet)
{
TABLE *table= table_list->table;
SEQUENCE *seq= table->s->sequence;
LEX_STRING alias;
sql_mode_t sql_mode= thd->variables.sql_mode;
bool foreign_db_mode= sql_mode & (MODE_POSTGRESQL | MODE_ORACLE |
MODE_MSSQL | MODE_DB2 |
MODE_MAXDB | MODE_ANSI);
bool show_table_options= !(sql_mode & MODE_NO_TABLE_OPTIONS) &&
!foreign_db_mode;
if (lower_case_table_names == 2)
{
alias.str= table->alias.c_ptr();
alias.length= table->alias.length();
}
else
alias= table->s->table_name;
packet->append(STRING_WITH_LEN("CREATE SEQUENCE "));
append_identifier(thd, packet, alias.str, alias.length);
packet->append(STRING_WITH_LEN(" start with "));
packet->append_longlong(seq->start);
packet->append(STRING_WITH_LEN(" minvalue "));
packet->append_longlong(seq->min_value);
packet->append(STRING_WITH_LEN(" maxvalue "));
packet->append_longlong(seq->max_value);
packet->append(STRING_WITH_LEN(" increment by "));
packet->append_longlong(seq->increment);
if (seq->cache)
{
packet->append(STRING_WITH_LEN(" cache "));
packet->append_longlong(seq->cache);
}
else
packet->append(STRING_WITH_LEN(" nocache"));
if (seq->cycle)
packet->append(STRING_WITH_LEN(" cycle"));
else
packet->append(STRING_WITH_LEN(" nocycle"));
if (show_table_options)
add_table_options(thd, table, 0, 0, 1, packet);
return 0;
}
/****************************************************************************
Return info about all processes
returns for each thread: thread id, user, host, db, command, info
@ -4143,7 +4232,8 @@ static void get_table_engine_for_i_s(THD *thd, char *buf, TABLE_LIST *tl,
char path[FN_REFLEN];
build_table_filename(path, sizeof(path) - 1,
db->str, table->str, reg_ext, 0);
if (dd_frm_type(thd, path, &engine_name) == FRMTYPE_TABLE)
bool is_sequence;
if (dd_frm_type(thd, path, &engine_name, &is_sequence) == TABLE_TYPE_NORMAL)
tl->option= engine_name.str;
}
}
@ -4360,10 +4450,14 @@ static int fill_schema_table_names(THD *thd, TABLE_LIST *tables,
{
CHARSET_INFO *cs= system_charset_info;
handlerton *hton;
if (ha_table_exists(thd, db_name->str, table_name->str, &hton))
bool is_sequence;
if (ha_table_exists(thd, db_name->str, table_name->str, &hton,
&is_sequence))
{
if (hton == view_pseudo_hton)
table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
else if (is_sequence)
table->field[3]->store(STRING_WITH_LEN("SEQUENCE"), cs);
else
table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
}
@ -5041,7 +5135,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
String str(option_buff,sizeof(option_buff), system_charset_info);
TABLE *show_table= tables->table;
TABLE_SHARE *share= show_table->s;
handler *file= show_table->file;
handler *file= show_table->db_stat ? show_table->file : 0;
handlerton *tmp_db_type= share->db_type();
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool is_partitioned= FALSE;
@ -5051,6 +5145,8 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
else if (share->tmp_table)
table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs);
else if (share->table_type == TABLE_TYPE_SEQUENCE)
table->field[3]->store(STRING_WITH_LEN("SEQUENCE"), cs);
else
table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);

View File

@ -546,6 +546,15 @@ bool String::append_ulonglong(ulonglong val)
return FALSE;
}
bool String::append_longlong(longlong val)
{
if (realloc(str_length+MAX_BIGINT_WIDTH+2))
return TRUE;
char *end= (char*) longlong10_to_str(val, (char*) Ptr + str_length, -10);
str_length= end - Ptr;
return FALSE;
}
/*
Append a string in the given charset to the string
with character set recoding

View File

@ -473,6 +473,7 @@ public:
bool append(const LEX_CSTRING *ls) { return append(ls->str, ls->length); }
bool append(const char *s, uint32 arg_length);
bool append(const char *s, uint32 arg_length, CHARSET_INFO *cs);
bool append_longlong(longlong val);
bool append_ulonglong(ulonglong val);
bool append(IO_CACHE* file, uint32 arg_length);
bool append_with_prefill(const char *s, uint32 arg_length,

View File

@ -54,7 +54,7 @@
#include "sql_show.h"
#include "transaction.h"
#include "sql_audit.h"
#include "sql_sequence.h"
#ifdef __WIN__
#include <io.h>
@ -1992,6 +1992,8 @@ int write_bin_log(THD *thd, bool clear_error,
thd Thread handle
tables List of tables to delete
if_exists If 1, don't give error if one table doesn't exists
drop_temporary 1 if DROP TEMPORARY
drop_seqeunce 1 if DROP SEQUENCE
NOTES
Will delete all tables that can be deleted and give a compact error
@ -2008,8 +2010,8 @@ int write_bin_log(THD *thd, bool clear_error,
*/
bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
my_bool drop_temporary)
bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists,
bool drop_temporary, bool drop_sequence)
{
bool error;
Drop_table_error_handler err_handler;
@ -2086,7 +2088,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
/* mark for close and remove all cached entries */
thd->push_internal_handler(&err_handler);
error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary,
false, false, false);
false, drop_sequence, false, false);
thd->pop_internal_handler();
if (error)
@ -2175,6 +2177,7 @@ static uint32 comment_length(THD *thd, uint32 comment_pos,
int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
bool drop_temporary, bool drop_view,
bool drop_sequence,
bool dont_log_query,
bool dont_free_locks)
{
@ -2189,7 +2192,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
bool non_tmp_table_deleted= 0;
bool is_drop_tmp_if_exists_added= 0;
bool was_view= 0;
bool was_view= 0, was_table, is_sequence;
String built_query;
String built_trans_tmp_query, built_non_trans_tmp_query;
DBUG_ENTER("mysql_rm_table_no_locks");
@ -2231,17 +2234,19 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
*/
if (!dont_log_query)
{
const char *object_to_drop= (drop_sequence) ? "SEQUENCE" : "TABLE";
if (!drop_temporary)
{
const char *comment_start;
uint32 comment_len;
built_query.set_charset(thd->charset());
built_query.append("DROP TABLE ");
if (if_exists)
built_query.append("DROP TABLE IF EXISTS ");
else
built_query.append("DROP TABLE ");
built_query.append("IF EXISTS ");
/* Preserve comment in original query */
if ((comment_len= comment_length(thd, if_exists ? 17:9, &comment_start)))
{
built_query.append(comment_start, comment_len);
@ -2249,21 +2254,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
}
}
built_trans_tmp_query.set_charset(system_charset_info);
built_trans_tmp_query.append("DROP TEMPORARY ");
built_trans_tmp_query.append(object_to_drop);
built_trans_tmp_query.append(' ');
if (thd->is_current_stmt_binlog_format_row() || if_exists)
{
is_drop_tmp_if_exists_added= true;
built_trans_tmp_query.set_charset(system_charset_info);
built_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
built_non_trans_tmp_query.set_charset(system_charset_info);
built_non_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
}
else
{
built_trans_tmp_query.set_charset(system_charset_info);
built_trans_tmp_query.append("DROP TEMPORARY TABLE ");
built_non_trans_tmp_query.set_charset(system_charset_info);
built_non_trans_tmp_query.append("DROP TEMPORARY TABLE ");
built_trans_tmp_query.append("IF EXISTS ");
}
built_non_trans_tmp_query.set_charset(system_charset_info);
built_non_trans_tmp_query.copy(built_trans_tmp_query);
}
for (table= tables; table; table= table->next_local)
@ -2288,7 +2289,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
thd->find_temporary_table(table) &&
table->mdl_request.ticket != NULL));
if (table->open_type == OT_BASE_ONLY || !is_temporary_table(table))
if (table->open_type == OT_BASE_ONLY || !is_temporary_table(table) ||
(drop_sequence && table->table->s->table_type != TABLE_TYPE_SEQUENCE))
error= 1;
else
{
@ -2396,26 +2398,31 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
error= 0;
if (drop_temporary ||
(ha_table_exists(thd, db, alias, &table_type) == 0 && table_type == 0) ||
(!drop_view && (was_view= (table_type == view_pseudo_hton))))
(ha_table_exists(thd, db, alias, &table_type, &is_sequence) == 0 &&
table_type == 0) ||
(!drop_view && (was_view= (table_type == view_pseudo_hton))) ||
(drop_sequence && !is_sequence))
{
/*
One of the following cases happened:
. "DROP TEMPORARY" but a temporary table was not found.
. "DROP" but table was not found
. "DROP TABLE" statement, but it's a view.
. "DROP SEQUENCE", but it's not a sequence
*/
was_table= drop_sequence && table_type;
if (if_exists)
{
char buff[FN_REFLEN];
int err= (drop_sequence ? ER_UNKNOWN_SEQUENCES :
ER_BAD_TABLE_ERROR);
String tbl_name(buff, sizeof(buff), system_charset_info);
tbl_name.length(0);
tbl_name.append(db);
tbl_name.append('.');
tbl_name.append(table->table_name);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_BAD_TABLE_ERROR,
ER_THD(thd, ER_BAD_TABLE_ERROR),
err, ER_THD(thd, err),
tbl_name.c_ptr_safe());
}
else
@ -2536,8 +2543,12 @@ err:
DBUG_ASSERT(errors);
if (errors == 1 && was_view)
my_error(ER_IT_IS_A_VIEW, MYF(0), wrong_tables.c_ptr_safe());
else if (errors == 1 && drop_sequence && was_table)
my_error(ER_NOT_SEQUENCE2, MYF(0), wrong_tables.c_ptr_safe());
else if (errors > 1 || !thd->is_error())
my_error(ER_BAD_TABLE_ERROR, MYF(0), wrong_tables.c_ptr_safe());
my_error((drop_sequence ? ER_UNKNOWN_SEQUENCES :
ER_BAD_TABLE_ERROR),
MYF(0), wrong_tables.c_ptr_safe());
error= 1;
}
@ -3181,11 +3192,26 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
bool tmp_table= create_table_mode == C_ALTER_TABLE;
DBUG_ENTER("mysql_prepare_create_table");
select_field_pos= alter_info->create_list.elements - select_field_count;
null_fields=blob_columns=0;
create_info->varchar= 0;
max_key_length= file->max_key_length();
/* Handle creation of sequences */
if (create_info->sequence)
{
if (!(file->ha_table_flags() & HA_CAN_TABLES_WITHOUT_ROLLBACK))
{
my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), file->engine_name()->str,
"SEQUENCE");
DBUG_RETURN(TRUE);
}
/* The user specified fields: check that structure is ok */
if (check_sequence_fields(thd->lex, &alter_info->create_list))
DBUG_RETURN(TRUE);
}
select_field_pos= alter_info->create_list.elements - select_field_count;
for (field_no=0; (sql_field=it++) ; field_no++)
{
CHARSET_INFO *save_cs;
@ -4655,7 +4681,7 @@ int create_table_impl(THD *thd,
*/
(void) trans_rollback_stmt(thd);
/* Remove normal table without logging. Keep tables locked */
if (mysql_rm_table_no_locks(thd, &table_list, 0, 0, 0, 1, 1))
if (mysql_rm_table_no_locks(thd, &table_list, 0, 0, 0, 0, 1, 1))
goto err;
/*
@ -4802,7 +4828,7 @@ int create_table_impl(THD *thd,
}
}
#endif
error= 0;
err:
THD_STAGE_INFO(thd, stage_after_create);
@ -4825,10 +4851,11 @@ warn:
*/
int mysql_create_table_no_lock(THD *thd,
const char *db, const char *table_name,
Table_specification_st *create_info,
Alter_info *alter_info, bool *is_trans,
int create_table_mode)
const char *db, const char *table_name,
Table_specification_st *create_info,
Alter_info *alter_info, bool *is_trans,
int create_table_mode,
TABLE_LIST *table_list)
{
KEY *not_used_1;
uint not_used_2;
@ -4857,6 +4884,17 @@ int mysql_create_table_no_lock(THD *thd,
alter_info, create_table_mode,
is_trans, &not_used_1, &not_used_2, &frm);
my_free(const_cast<uchar*>(frm.str));
if (!res && create_info->sequence)
{
/* Set create_info.table if temporary table */
if (create_info->tmp_table())
table_list->table= create_info->table;
else
table_list->table= 0;
res= sequence_insert(thd, thd->lex, table_list);
}
return res;
}
@ -4918,7 +4956,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
promote_first_timestamp_column(&alter_info->create_list);
if (mysql_create_table_no_lock(thd, db, table_name, create_info, alter_info,
&is_trans, create_table_mode) > 0)
&is_trans, create_table_mode,
create_table) > 0)
{
result= 1;
goto err;
@ -5305,7 +5344,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
res= ((create_res=
mysql_create_table_no_lock(thd, table->db, table->table_name,
&local_create_info, &local_alter_info,
&is_trans, C_ORDINARY_CREATE)) > 0);
&is_trans, C_ORDINARY_CREATE,
table)) > 0);
/* Remember to log if we deleted something */
do_logging= thd->log_current_statement;
if (res)
@ -5542,7 +5582,7 @@ int mysql_discard_or_import_tablespace(THD *thd,
table_list->mdl_request.set_type(MDL_EXCLUSIVE);
table_list->lock_type= TL_WRITE;
/* Do not open views. */
table_list->required_type= FRMTYPE_TABLE;
table_list->required_type= TABLE_TYPE_NORMAL;
if (open_and_lock_tables(thd, table_list, FALSE, 0,
&alter_prelocking_strategy))
@ -7442,6 +7482,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (!(used_fields & HA_CREATE_USED_CONNECTION))
create_info->connect_string= table->s->connect_string;
if (!(used_fields & HA_CREATE_USED_SEQUENCE))
create_info->sequence= table->s->table_type == TABLE_TYPE_SEQUENCE;
restore_record(table, s->default_values); // Empty record for DEFAULT
if ((create_info->fields_option_struct= (ha_field_option_struct**)
@ -8480,7 +8523,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Note that RENAME TABLE the only ALTER clause which is supported for views
has been already processed.
*/
table_list->required_type= FRMTYPE_TABLE;
table_list->required_type= TABLE_TYPE_NORMAL;
Alter_table_prelocking_strategy alter_prelocking_strategy;
@ -8587,7 +8630,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Table maybe does not exist, but we got an exclusive lock
on the name, now we can safely try to find out for sure.
*/
if (ha_table_exists(thd, alter_ctx.new_db, alter_ctx.new_name, 0))
if (ha_table_exists(thd, alter_ctx.new_db, alter_ctx.new_name))
{
/* Table will be closed in do_command() */
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias);
@ -9930,7 +9973,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
table->next_global= NULL;
table->lock_type= TL_READ;
/* Allow to open real tables only. */
table->required_type= FRMTYPE_TABLE;
table->required_type= TABLE_TYPE_NORMAL;
if (thd->open_temporary_tables(table) ||
open_and_lock_tables(thd, table, FALSE, 0))

View File

@ -196,7 +196,7 @@ int mysql_create_table_no_lock(THD *thd, const char *db,
const char *table_name,
Table_specification_st *create_info,
Alter_info *alter_info, bool *is_trans,
int create_table_mode);
int create_table_mode, TABLE_LIST *table);
handler *mysql_create_frm_image(THD *thd,
const char *db, const char *table_name,
@ -239,10 +239,11 @@ bool mysql_restore_table(THD* thd, TABLE_LIST* table_list);
bool mysql_checksum_table(THD* thd, TABLE_LIST* table_list,
HA_CHECK_OPT* check_opt);
bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
my_bool drop_temporary);
bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists,
bool drop_temporary, bool drop_sequence);
int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
bool drop_temporary, bool drop_view,
bool drop_sequence,
bool log_query, bool dont_free_locks);
bool log_drop_table(THD *thd, const char *db_name, size_t db_name_length,
const char *table_name, size_t table_name_length,

View File

@ -525,7 +525,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
}
/* We also don't allow creation of triggers on views. */
tables->required_type= FRMTYPE_TABLE;
tables->required_type= TABLE_TYPE_NORMAL;
/*
Also prevent DROP TRIGGER from opening temporary table which might
shadow the subject table on which trigger to be dropped is defined.

View File

@ -216,7 +216,7 @@ Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref,
or writing into the table. Yet, to open a write cursor we need
a thr_lock lock. Allow to open base tables only.
*/
table_ref->required_type= FRMTYPE_TABLE;
table_ref->required_type= TABLE_TYPE_NORMAL;
/*
Ignore pending FLUSH TABLES since we don't want to release
the MDL lock taken above and otherwise there is no way to
@ -248,8 +248,8 @@ Sql_cmd_truncate_table::handler_truncate(THD *thd, TABLE_LIST *table_ref,
table_ref->table->file->print_error(error, MYF(0));
/*
If truncate method is not implemented then we don't binlog the
statement. If truncation has failed in a transactional engine then also we
donot binlog the statment. Only in non transactional engine we binlog
statement. If truncation has failed in a transactional engine then also
we don't binlog the statment. Only in non transactional engine we binlog
inspite of errors.
*/
if (error == HA_ERR_WRONG_COMMAND ||
@ -311,14 +311,17 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref,
}
else
{
handlerton *hton;
bool is_sequence;
/* Acquire an exclusive lock. */
DBUG_ASSERT(table_ref->next_global == NULL);
if (lock_table_names(thd, table_ref, NULL,
thd->variables.lock_wait_timeout, 0))
DBUG_RETURN(TRUE);
handlerton *hton;
if (!ha_table_exists(thd, table_ref->db, table_ref->table_name, &hton) ||
if (!ha_table_exists(thd, table_ref->db, table_ref->table_name,
&hton, &is_sequence) ||
hton == view_pseudo_hton)
{
my_error(ER_NO_SUCH_TABLE, MYF(0), table_ref->db, table_ref->table_name);
@ -337,7 +340,7 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref,
*hton_can_recreate= false;
}
else
*hton_can_recreate= hton->flags & HTON_CAN_RECREATE;
*hton_can_recreate= !is_sequence && hton->flags & HTON_CAN_RECREATE;
}
/*

View File

@ -683,8 +683,14 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
buff.append(views->source.str, views->source.length);
int errcode= query_error_code(thd, TRUE);
/*
Don't log any unsafe warnings for CREATE VIEW as it's safely replicated
with statement based replication
*/
thd->reset_unsafe_warnings();
if (thd->binlog_query(THD::STMT_QUERY_TYPE,
buff.ptr(), buff.length(), FALSE, FALSE, FALSE, errcode))
buff.ptr(), buff.length(), FALSE, FALSE, FALSE,
errcode))
res= TRUE;
}
@ -1015,7 +1021,7 @@ loop_out:
fn_format(path_buff, file.str, dir.str, "", MY_UNPACK_FILENAME);
path.length= strlen(path_buff);
if (ha_table_exists(thd, view->db, view->table_name, NULL))
if (ha_table_exists(thd, view->db, view->table_name))
{
if (lex->create_info.if_not_exists())
{
@ -1153,7 +1159,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
DBUG_ENTER("mysql_make_view");
DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name));
if (table->required_type == FRMTYPE_TABLE)
if (table->required_type == TABLE_TYPE_NORMAL)
{
my_error(ER_WRONG_OBJECT, MYF(0), share->db.str, share->table_name.str,
"BASE TABLE");
@ -1541,7 +1547,9 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
*/
for (tbl= view_main_select_tables; tbl; tbl= tbl->next_local)
{
tbl->lock_type= table->lock_type;
/* We have to keep the lock type for sequence tables */
if (!tbl->sequence)
tbl->lock_type= table->lock_type;
tbl->mdl_request.set_type((tbl->lock_type >= TL_WRITE_ALLOW_WRITE) ?
MDL_SHARED_WRITE : MDL_SHARED_READ);
}
@ -1797,8 +1805,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
if (thd->lex->if_exists())
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_BAD_TABLE_ERROR,
ER_THD(thd, ER_BAD_TABLE_ERROR),
ER_UNKNOWN_VIEW,
ER_THD(thd, ER_UNKNOWN_VIEW),
name);
continue;
}
@ -1840,7 +1848,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
}
if (non_existant_views.length())
{
my_error(ER_BAD_TABLE_ERROR, MYF(0), non_existant_views.c_ptr_safe());
my_error(ER_UNKNOWN_VIEW, MYF(0), non_existant_views.c_ptr_safe());
}
something_wrong= error || wrong_object_name || non_existant_views.length();

Some files were not shown because too many files have changed in this diff Show More