Commit 4e02c2fe authored by Jan Lindström's avatar Jan Lindström

MDEV-5335: Force PK option. Added a new dynamic configuration variable

innodb_force_primary_key default off. If option is true, create table without 
primary key or unique key where all keyparts are NOT NULL is not
accepted. Instead an error message is printed. Variable value can
be changed with set global innodb_force_primary_key = <value>.
parent fc86a1f4
CREATE TABLE T1(A INTEGER) ENGINE=INNODB;
ERROR 42000: This table type requires a primary key
SHOW WARNINGS;
Level Code Message
Error 1173 This table type requires a primary key
CREATE TABLE T1(A INTEGER UNIQUE KEY) ENGINE=INNODB;
ERROR 42000: This table type requires a primary key
SHOW WARNINGS;
Level Code Message
Error 1173 This table type requires a primary key
CREATE TABLE T1(A INTEGER NOT NULL PRIMARY KEY) ENGINE=INNODB;
SHOW CREATE TABLE T1;
Table Create Table
T1 CREATE TABLE `T1` (
`A` int(11) NOT NULL,
PRIMARY KEY (`A`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SHOW WARNINGS;
Level Code Message
DROP TABLE T1;
CREATE TABLE T1(A INTEGER NOT NULL UNIQUE KEY) ENGINE=INNODB;
SHOW CREATE TABLE T1;
Table Create Table
T1 CREATE TABLE `T1` (
`A` int(11) NOT NULL,
UNIQUE KEY `A` (`A`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SHOW WARNINGS;
Level Code Message
DROP TABLE T1;
set global innodb_force_primary_key = 0;
CREATE TABLE T1(A INTEGER) ENGINE=INNODB;
SHOW WARNINGS;
Level Code Message
INSERT INTO T1 VALUES (1),(2),(3);
set global innodb_force_primary_key = 1;
SELECT * FROM T1;
A
1
2
3
CREATE TABLE T2(A INTEGER) ENGINE=INNODB;
ERROR 42000: This table type requires a primary key
SHOW WARNINGS;
Level Code Message
Error 1173 This table type requires a primary key
DROP TABLE T1;
-- source include/have_innodb.inc
let $force_pk=`select @@innodb_force_primary_key`;
-- error 1173
CREATE TABLE T1(A INTEGER) ENGINE=INNODB;
SHOW WARNINGS;
-- error 1173
CREATE TABLE T1(A INTEGER UNIQUE KEY) ENGINE=INNODB;
SHOW WARNINGS;
CREATE TABLE T1(A INTEGER NOT NULL PRIMARY KEY) ENGINE=INNODB;
SHOW CREATE TABLE T1;
SHOW WARNINGS;
DROP TABLE T1;
CREATE TABLE T1(A INTEGER NOT NULL UNIQUE KEY) ENGINE=INNODB;
SHOW CREATE TABLE T1;
SHOW WARNINGS;
DROP TABLE T1;
set global innodb_force_primary_key = 0;
CREATE TABLE T1(A INTEGER) ENGINE=INNODB;
SHOW WARNINGS;
INSERT INTO T1 VALUES (1),(2),(3);
set global innodb_force_primary_key = 1;
SELECT * FROM T1;
-- error 1173
CREATE TABLE T2(A INTEGER) ENGINE=INNODB;
SHOW WARNINGS;
DROP TABLE T1;
--disable_query_log
eval set global innodb_force_primary_key=$force_pk;
--enable_query_log
SELECT COUNT(@@GLOBAL.innodb_force_primary_key);
COUNT(@@GLOBAL.innodb_force_primary_key)
1
1 Expected
SET @@GLOBAL.innodb_force_primary_key=1;
Expected ok
SELECT COUNT(@@GLOBAL.innodb_force_primary_key);
COUNT(@@GLOBAL.innodb_force_primary_key)
1
1 Expected
SELECT IF(@@GLOBAL.innodb_force_primary_key, 'ON', 'OFF') = VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='innodb_force_primary_key';
IF(@@GLOBAL.innodb_force_primary_key, 'ON', 'OFF') = VARIABLE_VALUE
1
1 Expected
SELECT COUNT(@@GLOBAL.innodb_force_primary_key);
COUNT(@@GLOBAL.innodb_force_primary_key)
1
1 Expected
SELECT COUNT(VARIABLE_VALUE)
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='innodb_force_primary_key';
COUNT(VARIABLE_VALUE)
1
1 Expected
SELECT @@innodb_force_primary_key = @@GLOBAL.innodb_force_primary_key;
@@innodb_force_primary_key = @@GLOBAL.innodb_force_primary_key
1
1 Expected
SELECT COUNT(@@innodb_force_primary_key);
COUNT(@@innodb_force_primary_key)
1
1 Expected
SELECT COUNT(@@local.innodb_force_primary_key);
ERROR HY000: Variable 'innodb_force_primary_key' is a GLOBAL variable
Expected Variable 'innodb_force_primary_key' is a GLOBAL variable
SELECT COUNT(@@SESSION.innodb_force_primary_key);
ERROR HY000: Variable 'innodb_force_primary_key' is a GLOBAL variable
Expected Variable 'innodb_force_primary_key' is a GLOBAL variable
SELECT COUNT(@@GLOBAL.innodb_force_primary_key);
COUNT(@@GLOBAL.innodb_force_primary_key)
1
1 Expected
--source include/have_innodb.inc
let $force_pk=`select @@innodb_force_primary_key`;
SELECT COUNT(@@GLOBAL.innodb_force_primary_key);
--echo 1 Expected
####################################################################
# Check if Value can set #
####################################################################
SET @@GLOBAL.innodb_force_primary_key=1;
--echo Expected ok
SELECT COUNT(@@GLOBAL.innodb_force_primary_key);
--echo 1 Expected
#################################################################
# Check if the value in GLOBAL Table matches value in variable #
#################################################################
SELECT IF(@@GLOBAL.innodb_force_primary_key, 'ON', 'OFF') = VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='innodb_force_primary_key';
--echo 1 Expected
SELECT COUNT(@@GLOBAL.innodb_force_primary_key);
--echo 1 Expected
SELECT COUNT(VARIABLE_VALUE)
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='innodb_force_primary_key';
--echo 1 Expected
################################################################################
# Check if accessing variable with and without GLOBAL point to same variable #
################################################################################
SELECT @@innodb_force_primary_key = @@GLOBAL.innodb_force_primary_key;
--echo 1 Expected
SELECT COUNT(@@innodb_force_primary_key);
--echo 1 Expected
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
SELECT COUNT(@@local.innodb_force_primary_key);
--echo Expected Variable 'innodb_force_primary_key' is a GLOBAL variable
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
SELECT COUNT(@@SESSION.innodb_force_primary_key);
--echo Expected Variable 'innodb_force_primary_key' is a GLOBAL variable
SELECT COUNT(@@GLOBAL.innodb_force_primary_key);
--echo 1 Expected
--disable_query_log
eval set global innodb_force_primary_key=$force_pk;
--enable_query_log
......@@ -2252,6 +2252,7 @@ ha_innobase::ha_innobase(
HA_BINLOG_ROW_CAPABLE |
HA_CAN_GEOMETRY | HA_PARTIAL_COLUMN_READ |
HA_TABLE_SCAN_ON_INDEX | HA_CAN_FULLTEXT |
(srv_force_primary_key ? HA_REQUIRE_PRIMARY_KEY : 0 ) |
HA_CAN_FULLTEXT_EXT | HA_CAN_EXPORT),
start_of_scan(0),
num_write_row(0)
......@@ -4227,12 +4228,19 @@ ha_innobase::table_flags() const
/* Need to use tx_isolation here since table flags is (also)
called before prebuilt is inited. */
ulong const tx_isolation = thd_tx_isolation(ha_thd());
handler::Table_flags flags = int_table_flags;
if (srv_force_primary_key) {
flags |= HA_REQUIRE_PRIMARY_KEY;
} else {
flags &= ~HA_REQUIRE_PRIMARY_KEY;
}
if (tx_isolation <= ISO_READ_COMMITTED) {
return(int_table_flags);
return(flags);
}
return(int_table_flags | HA_BINLOG_STMT_CAPABLE);
return(flags | HA_BINLOG_STMT_CAPABLE);
}
/****************************************************************//**
......@@ -16622,6 +16630,12 @@ static MYSQL_SYSVAR_BOOL(trx_purge_view_update_only_debug,
NULL, NULL, FALSE);
#endif /* UNIV_DEBUG */
static MYSQL_SYSVAR_BOOL(force_primary_key,
srv_force_primary_key,
PLUGIN_VAR_OPCMDARG,
"Do not allow to create table without primary key (off by default)",
NULL, NULL, FALSE);
static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(additional_mem_pool_size),
MYSQL_SYSVAR(api_trx_level),
......@@ -16774,6 +16788,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(limit_optimistic_insert_debug),
MYSQL_SYSVAR(trx_purge_view_update_only_debug),
#endif /* UNIV_DEBUG */
MYSQL_SYSVAR(force_primary_key),
NULL
};
......
......@@ -353,6 +353,8 @@ extern ibool srv_use_atomic_writes;
extern ibool srv_use_posix_fallocate;
#endif
extern my_bool srv_force_primary_key;
extern ulong srv_max_buf_pool_modified_pct;
extern ulong srv_max_purge_lag;
extern ulong srv_max_purge_lag_delay;
......
......@@ -383,6 +383,9 @@ UNIV_INTERN ibool srv_print_innodb_lock_monitor = FALSE;
UNIV_INTERN ibool srv_print_innodb_tablespace_monitor = FALSE;
UNIV_INTERN ibool srv_print_innodb_table_monitor = FALSE;
/** If this flag is set tables without primary key are not allowed */
UNIV_INTERN my_bool srv_force_primary_key = FALSE;
/* Array of English strings describing the current state of an
i/o handler thread */
......
......@@ -2544,6 +2544,7 @@ ha_innobase::ha_innobase(
HA_BINLOG_ROW_CAPABLE |
HA_CAN_GEOMETRY | HA_PARTIAL_COLUMN_READ |
HA_TABLE_SCAN_ON_INDEX | HA_CAN_FULLTEXT |
(srv_force_primary_key ? HA_REQUIRE_PRIMARY_KEY : 0 ) |
HA_CAN_FULLTEXT_EXT | HA_CAN_EXPORT),
start_of_scan(0),
num_write_row(0)
......@@ -4624,12 +4625,19 @@ ha_innobase::table_flags() const
/* Need to use tx_isolation here since table flags is (also)
called before prebuilt is inited. */
ulong const tx_isolation = thd_tx_isolation(ha_thd());
handler::Table_flags flags = int_table_flags;
if (srv_force_primary_key) {
flags |= HA_REQUIRE_PRIMARY_KEY;
} else {
flags &= ~HA_REQUIRE_PRIMARY_KEY;
}
if (tx_isolation <= ISO_READ_COMMITTED) {
return(int_table_flags);
return(flags);
}
return(int_table_flags | HA_BINLOG_STMT_CAPABLE);
return(flags | HA_BINLOG_STMT_CAPABLE);
}
/****************************************************************//**
......@@ -17729,6 +17737,12 @@ static MYSQL_SYSVAR_BOOL(trx_purge_view_update_only_debug,
NULL, NULL, FALSE);
#endif /* UNIV_DEBUG */
static MYSQL_SYSVAR_BOOL(force_primary_key,
srv_force_primary_key,
PLUGIN_VAR_OPCMDARG,
"Do not allow to create table without primary key (off by default)",
NULL, NULL, FALSE);
const char *corrupt_table_action_names[]=
{
"assert", /* 0 */
......@@ -17951,6 +17965,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(fake_changes),
MYSQL_SYSVAR(locking_fake_changes),
MYSQL_SYSVAR(use_stacktrace),
MYSQL_SYSVAR(force_primary_key),
NULL
};
......
......@@ -431,6 +431,8 @@ extern ulong srv_pass_corrupt_table;
extern ulong srv_log_checksum_algorithm;
extern my_bool srv_force_primary_key;
/* Helper macro to support srv_pass_corrupt_table checks. If 'cond' is FALSE,
execute 'code' if srv_pass_corrupt_table is non-zero, or trigger a fatal error
otherwise. The break statement in 'code' will obviously not work as
......
......@@ -515,6 +515,9 @@ UNIV_INTERN ibool srv_print_innodb_lock_monitor = FALSE;
UNIV_INTERN ibool srv_print_innodb_tablespace_monitor = FALSE;
UNIV_INTERN ibool srv_print_innodb_table_monitor = FALSE;
/** If this flag is set tables without primary key are not allowed */
UNIV_INTERN my_bool srv_force_primary_key = FALSE;
/* Array of English strings describing the current state of an
i/o handler thread */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment