Commit c5d09f73 authored by Nayuta Yanagisawa's avatar Nayuta Yanagisawa

MDEV-5271 Support engine-defined attributes per partition

Make it possible to specify engine-defined attributes on partitions
as well as tables.

If an engine-defined attribute is only specified at the table level,
it applies to all the partitions in the table.
This is a backward-compatible behavior.

If the same attribute is specified both at the table level and the
partition level, the per-partition one takes precedence.
So, we can consider per-table attributes as default values.

One cannot specify engine-defined attributes on subpartitions.

Implementation details:

* We store per-partition attributes in the partition_element class
  because we already have the part_comment field, which is for
  per-partition comments.

* In the case of ALTER TABLE statements, the partition_elements in
  table->part_info is set up by mysql_unpack_partition().
  So, we parse per-partition attributes after the call of the function.
parent 83dd7db6
...@@ -896,7 +896,7 @@ partitions 3 ...@@ -896,7 +896,7 @@ partitions 3
(partition tablespace ts1, (partition tablespace ts1,
partition x2 tablespace ts2, partition x2 tablespace ts2,
partition x3 tablespace ts3); partition x3 tablespace ts3);
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 'ts1, 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 '
partition x2 tablespace ts2, partition x2 tablespace ts2,
partition x3 tablespace ts3)' at line 8 partition x3 tablespace ts3)' at line 8
CREATE TABLE t1 ( CREATE TABLE t1 (
......
#
# MDEV-5271 Support engine-defined attributes per partition
#
# partitioned tables
CREATE TABLE `t1` (
`id` INT
) ENGINE=InnoDB ENCRYPTED="YES" PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="NO" ENCRYPTION_KEY_ID=1,
PARTITION pt2 VALUES LESS THAN MAXVALUE ENCRYPTED="DEFAULT" ENCRYPTION_KEY_ID=1
);
SHOW CREATE TABLE `t1`;
Table Create Table
t1 CREATE TABLE `t1` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `ENCRYPTED`='YES'
PARTITION BY RANGE (`id`)
(PARTITION `pt1` VALUES LESS THAN (100) ENGINE = InnoDB ENCRYPTED = 'NO' ENCRYPTION_KEY_ID = 1,
PARTITION `pt2` VALUES LESS THAN MAXVALUE ENGINE = InnoDB ENCRYPTED = 'DEFAULT' ENCRYPTION_KEY_ID = 1)
INSERT INTO t1 VALUES (1), (2), (3);
DELETE FROM t1 WHERE id = 1;
UPDATE t1 SET id = 4 WHERE id = 3;
SELECT * FROM t1 WHERE id IN (2, 3);
id
2
DROP TABLE `t1`;
CREATE TABLE `t2` (
`id` INT
) ENGINE=InnoDB ENCRYPTED="YES" ENCRYPTION_KEY_ID=2 PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100),
PARTITION pt2 VALUES LESS THAN MAXVALUE
);
ERROR HY000: Can't create table `test`.`t2` (errno: 140 "Wrong create options")
CREATE TABLE `t3` (
`id` INT
) ENGINE=InnoDB ENCRYPTED="NO" PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="YES" ENCRYPTION_KEY_ID=2,
PARTITION pt2 VALUES LESS THAN MAXVALUE
);
ERROR HY000: Can't create table `test`.`t3` (errno: 140 "Wrong create options")
CREATE TABLE `t4` (
`id` INT
) ENGINE=InnoDB ENCRYPTED="NO";
SHOW CREATE TABLE `t4`;
Table Create Table
t4 CREATE TABLE `t4` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `ENCRYPTED`='NO'
ALTER TABLE `t4` PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="NO",
PARTITION pt2 VALUES LESS THAN MAXVALUE ENCRYPTED="DEFAULT"
);
SHOW CREATE TABLE `t4`;
Table Create Table
t4 CREATE TABLE `t4` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `ENCRYPTED`='NO'
PARTITION BY RANGE (`id`)
(PARTITION `pt1` VALUES LESS THAN (100) ENGINE = InnoDB ENCRYPTED = 'NO',
PARTITION `pt2` VALUES LESS THAN MAXVALUE ENGINE = InnoDB ENCRYPTED = 'DEFAULT')
ALTER TABLE `t4` PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100),
PARTITION pt2 VALUES LESS THAN MAXVALUE
);
SHOW CREATE TABLE `t4`;
Table Create Table
t4 CREATE TABLE `t4` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `ENCRYPTED`='NO'
PARTITION BY RANGE (`id`)
(PARTITION `pt1` VALUES LESS THAN (100) ENGINE = InnoDB,
PARTITION `pt2` VALUES LESS THAN MAXVALUE ENGINE = InnoDB)
ALTER TABLE `t4` PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="YES" ENCRYPTION_KEY_ID=2,
PARTITION pt2 VALUES LESS THAN MAXVALUE ENCRYPTED="DEFAULT"
);
ERROR HY000: Can't create table `test`.`t4` (errno: 140 "Wrong create options")
DROP TABLE `t4`;
# subpartitioned tables
CREATE TABLE `t5` (
`id` INT
) ENGINE=InnoDB ENCRYPTED="NO" PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id)
SUBPARTITIONS 2 (
PARTITION pt1 VALUES LESS THAN (100),
PARTITION pt2 VALUES LESS THAN MAXVALUE
);
SHOW CREATE TABLE `t5`;
Table Create Table
t5 CREATE TABLE `t5` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `ENCRYPTED`='NO'
PARTITION BY RANGE (`id`)
SUBPARTITION BY HASH (`id`)
SUBPARTITIONS 2
(PARTITION `pt1` VALUES LESS THAN (100) ENGINE = InnoDB,
PARTITION `pt2` VALUES LESS THAN MAXVALUE ENGINE = InnoDB)
DROP TABLE `t5`;
CREATE TABLE `t6` (
`id` INT
) ENGINE=InnoDB PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id)
SUBPARTITIONS 2 (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="YES",
PARTITION pt2 VALUES LESS THAN MAXVALUE
);
ERROR HY000: Can't create table `test`.`t6` (errno: 140 "Wrong create options")
CREATE TABLE `t7` (
id INT
) ENGINE=InnoDB PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id) (
PARTITION pt1 VALUES LESS THAN (100)(
SUBPARTITION spt1 ENCRYPTED="NO",
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE (
SUBPARTITION spt3,
SUBPARTITION spt4
)
);
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 'ENCRYPTED="NO",
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE ...' at line 6
CREATE TABLE `t8` (
id INT
) ENGINE=InnoDB ENCRYPTED="NO" PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id) (
PARTITION pt1 VALUES LESS THAN (100) (
SUBPARTITION spt1,
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE (
SUBPARTITION spt3,
SUBPARTITION spt4
)
);
SHOW CREATE TABLE `t8`;
Table Create Table
t8 CREATE TABLE `t8` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `ENCRYPTED`='NO'
PARTITION BY RANGE (`id`)
SUBPARTITION BY HASH (`id`)
(PARTITION `pt1` VALUES LESS THAN (100)
(SUBPARTITION `spt1` ENGINE = InnoDB,
SUBPARTITION `spt2` ENGINE = InnoDB),
PARTITION `pt2` VALUES LESS THAN MAXVALUE
(SUBPARTITION `spt3` ENGINE = InnoDB,
SUBPARTITION `spt4` ENGINE = InnoDB))
DROP TABLE `t8`;
CREATE TABLE `t9` (
id INT
) ENGINE=InnoDB PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="NO" (
SUBPARTITION spt1,
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE (
SUBPARTITION spt3,
SUBPARTITION spt4
)
);
SHOW CREATE TABLE `t9`;
Table Create Table
t9 CREATE TABLE `t9` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
PARTITION BY RANGE (`id`)
SUBPARTITION BY HASH (`id`)
(PARTITION `pt1` VALUES LESS THAN (100)
(SUBPARTITION `spt1` ENGINE = InnoDB,
SUBPARTITION `spt2` ENGINE = InnoDB),
PARTITION `pt2` VALUES LESS THAN MAXVALUE
(SUBPARTITION `spt3` ENGINE = InnoDB,
SUBPARTITION `spt4` ENGINE = InnoDB))
DROP TABLE `t9`;
CREATE TABLE `t10` (
id INT
) ENGINE=InnoDB PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="YES" (
SUBPARTITION spt1,
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE (
SUBPARTITION spt3,
SUBPARTITION spt4
)
);
ERROR HY000: Can't create table `test`.`t10` (errno: 140 "Wrong create options")
CREATE TABLE `t11` (
id INT
) ENGINE=InnoDB ENCRYPTED="YES" PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="NO" (
SUBPARTITION spt1,
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE ENCRYPTED="NO" (
SUBPARTITION spt3,
SUBPARTITION spt4
)
);
SHOW CREATE TABLE `t11`;
Table Create Table
t11 CREATE TABLE `t11` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `ENCRYPTED`='YES'
PARTITION BY RANGE (`id`)
SUBPARTITION BY HASH (`id`)
(PARTITION `pt1` VALUES LESS THAN (100)
(SUBPARTITION `spt1` ENGINE = InnoDB,
SUBPARTITION `spt2` ENGINE = InnoDB),
PARTITION `pt2` VALUES LESS THAN MAXVALUE
(SUBPARTITION `spt3` ENGINE = InnoDB,
SUBPARTITION `spt4` ENGINE = InnoDB))
DROP TABLE `t11`;
--echo #
--echo # MDEV-5271 Support engine-defined attributes per partition
--echo #
--source include/have_partition.inc
--source include/have_innodb.inc
--echo # partitioned tables
CREATE TABLE `t1` (
`id` INT
) ENGINE=InnoDB ENCRYPTED="YES" PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="NO" ENCRYPTION_KEY_ID=1,
PARTITION pt2 VALUES LESS THAN MAXVALUE ENCRYPTED="DEFAULT" ENCRYPTION_KEY_ID=1
);
SHOW CREATE TABLE `t1`;
INSERT INTO t1 VALUES (1), (2), (3);
DELETE FROM t1 WHERE id = 1;
UPDATE t1 SET id = 4 WHERE id = 3;
SELECT * FROM t1 WHERE id IN (2, 3);
DROP TABLE `t1`;
--error ER_CANT_CREATE_TABLE
CREATE TABLE `t2` (
`id` INT
) ENGINE=InnoDB ENCRYPTED="YES" ENCRYPTION_KEY_ID=2 PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100),
PARTITION pt2 VALUES LESS THAN MAXVALUE
);
--error ER_CANT_CREATE_TABLE
CREATE TABLE `t3` (
`id` INT
) ENGINE=InnoDB ENCRYPTED="NO" PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="YES" ENCRYPTION_KEY_ID=2,
PARTITION pt2 VALUES LESS THAN MAXVALUE
);
CREATE TABLE `t4` (
`id` INT
) ENGINE=InnoDB ENCRYPTED="NO";
SHOW CREATE TABLE `t4`;
ALTER TABLE `t4` PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="NO",
PARTITION pt2 VALUES LESS THAN MAXVALUE ENCRYPTED="DEFAULT"
);
SHOW CREATE TABLE `t4`;
ALTER TABLE `t4` PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100),
PARTITION pt2 VALUES LESS THAN MAXVALUE
);
SHOW CREATE TABLE `t4`;
--error ER_CANT_CREATE_TABLE
ALTER TABLE `t4` PARTITION BY RANGE(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="YES" ENCRYPTION_KEY_ID=2,
PARTITION pt2 VALUES LESS THAN MAXVALUE ENCRYPTED="DEFAULT"
);
DROP TABLE `t4`;
--echo # subpartitioned tables
CREATE TABLE `t5` (
`id` INT
) ENGINE=InnoDB ENCRYPTED="NO" PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id)
SUBPARTITIONS 2 (
PARTITION pt1 VALUES LESS THAN (100),
PARTITION pt2 VALUES LESS THAN MAXVALUE
);
SHOW CREATE TABLE `t5`;
DROP TABLE `t5`;
--error ER_CANT_CREATE_TABLE
CREATE TABLE `t6` (
`id` INT
) ENGINE=InnoDB PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id)
SUBPARTITIONS 2 (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="YES",
PARTITION pt2 VALUES LESS THAN MAXVALUE
);
--error ER_PARSE_ERROR
CREATE TABLE `t7` (
id INT
) ENGINE=InnoDB PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id) (
PARTITION pt1 VALUES LESS THAN (100)(
SUBPARTITION spt1 ENCRYPTED="NO",
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE (
SUBPARTITION spt3,
SUBPARTITION spt4
)
);
CREATE TABLE `t8` (
id INT
) ENGINE=InnoDB ENCRYPTED="NO" PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id) (
PARTITION pt1 VALUES LESS THAN (100) (
SUBPARTITION spt1,
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE (
SUBPARTITION spt3,
SUBPARTITION spt4
)
);
SHOW CREATE TABLE `t8`;
DROP TABLE `t8`;
CREATE TABLE `t9` (
id INT
) ENGINE=InnoDB PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="NO" (
SUBPARTITION spt1,
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE (
SUBPARTITION spt3,
SUBPARTITION spt4
)
);
SHOW CREATE TABLE `t9`;
DROP TABLE `t9`;
--error ER_CANT_CREATE_TABLE
CREATE TABLE `t10` (
id INT
) ENGINE=InnoDB PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="YES" (
SUBPARTITION spt1,
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE (
SUBPARTITION spt3,
SUBPARTITION spt4
)
);
CREATE TABLE `t11` (
id INT
) ENGINE=InnoDB ENCRYPTED="YES" PARTITION BY RANGE(id)
SUBPARTITION BY HASH(id) (
PARTITION pt1 VALUES LESS THAN (100) ENCRYPTED="NO" (
SUBPARTITION spt1,
SUBPARTITION spt2
),
PARTITION pt2 VALUES LESS THAN MAXVALUE ENCRYPTED="NO" (
SUBPARTITION spt3,
SUBPARTITION spt4
)
);
SHOW CREATE TABLE `t11`;
DROP TABLE `t11`;
/* Copyright (C) 2010, 2020, MariaDB Corporation. /* Copyright (C) 2010, 2020, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "mariadb.h" #include "mariadb.h"
#include "create_options.h" #include "create_options.h"
#include "partition_info.h"
#include <my_getopt.h> #include <my_getopt.h>
#include "set_var.h" #include "set_var.h"
...@@ -339,8 +340,11 @@ bool parse_option_list(THD* thd, handlerton *hton, void *option_struct_arg, ...@@ -339,8 +340,11 @@ bool parse_option_list(THD* thd, handlerton *hton, void *option_struct_arg,
LEX_CSTRING name= { opt->name, opt->name_length }; LEX_CSTRING name= { opt->name, opt->name_length };
default_val.str= strmake_root(root, str->ptr(), str->length()); default_val.str= strmake_root(root, str->ptr(), str->length());
default_val.length= str->length(); default_val.length= str->length();
val= new (root) engine_option_value(name, default_val, val= new (root) engine_option_value(
opt->type != HA_OPTION_TYPE_ULL, option_list, &last); name, default_val, opt->type != HA_OPTION_TYPE_ULL);
if (!val)
DBUG_RETURN(TRUE);
val->link(option_list, &last);
val->parsed= true; val->parsed= true;
} }
} }
...@@ -497,6 +501,61 @@ bool parse_engine_table_options(THD *thd, handlerton *ht, TABLE_SHARE *share) ...@@ -497,6 +501,61 @@ bool parse_engine_table_options(THD *thd, handlerton *ht, TABLE_SHARE *share)
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
#ifdef WITH_PARTITION_STORAGE_ENGINE
/**
Parses engine-defined partition options
@param [in] thd thread handler
@parem [in] table table with part_info
@retval TRUE Error
@retval FALSE OK
In the case of ALTER TABLE statements, table->part_info is set up
by mysql_unpack_partition(). So, one should not call the present
function before the call of mysql_unpack_partition().
*/
bool parse_engine_part_options(THD *thd, TABLE *table)
{
MEM_ROOT *root= &table->mem_root;
TABLE_SHARE *share= table->s;
partition_info *part_info= table->part_info;
engine_option_value *tmp_option_list;
handlerton *ht;
DBUG_ENTER("parse_engine_part_options");
if (!part_info)
DBUG_RETURN(FALSE);
List_iterator<partition_element> it(part_info->partitions);
while (partition_element *part_elem= it++)
{
if (merge_engine_options(share->option_list, part_elem->option_list,
&tmp_option_list, root))
DBUG_RETURN(TRUE);
if (!part_info->is_sub_partitioned())
{
ht= part_elem->engine_type;
if (parse_option_list(thd, ht, &part_elem->option_struct,
&tmp_option_list, ht->table_options, TRUE, root))
DBUG_RETURN(TRUE);
}
else
{
List_iterator<partition_element> sub_it(part_elem->subpartitions);
while (partition_element *sub_part_elem= sub_it++)
{
ht= sub_part_elem->engine_type;
if (parse_option_list(thd, ht, &sub_part_elem->option_struct,
&tmp_option_list, ht->table_options, TRUE, root))
DBUG_RETURN(TRUE);
}
}
}
DBUG_RETURN(FALSE);
}
#endif
bool engine_options_differ(void *old_struct, void *new_struct, bool engine_options_differ(void *old_struct, void *new_struct,
ha_create_table_option *rules) ha_create_table_option *rules)
...@@ -694,10 +753,11 @@ uchar *engine_option_value::frm_read(const uchar *buff, const uchar *buff_end, ...@@ -694,10 +753,11 @@ uchar *engine_option_value::frm_read(const uchar *buff, const uchar *buff_end,
return NULL; return NULL;
buff+= value.length; buff+= value.length;
engine_option_value *ptr=new (root) engine_option_value *ptr=
engine_option_value(name, value, len & FRM_QUOTED_VALUE, start, end); new (root) engine_option_value(name, value, len & FRM_QUOTED_VALUE);
if (!ptr) if (!ptr)
return NULL; return NULL;
ptr->link(start, end);
return (uchar *)buff; return (uchar *)buff;
} }
...@@ -766,23 +826,40 @@ bool engine_table_options_frm_read(const uchar *buff, size_t length, ...@@ -766,23 +826,40 @@ bool engine_table_options_frm_read(const uchar *buff, size_t length,
/** /**
Merges two lists of engine_option_value's with duplicate removal. Merges two lists of engine_option_value's with duplicate removal.
*/
engine_option_value *merge_engine_table_options(engine_option_value *first, @param [in] source option list
engine_option_value *second, @param [in] changes option list whose options overwrite source's
MEM_ROOT *root) @param [out] out new option list created by merging given two
@param [in] root MEM_ROOT for allocating memory
@retval TRUE Error
@retval FALSE OK
*/
bool merge_engine_options(engine_option_value *source,
engine_option_value *changes,
engine_option_value **out, MEM_ROOT *root)
{ {
engine_option_value *UNINIT_VAR(end), *opt; engine_option_value *UNINIT_VAR(end), *opt, *opt_copy;
DBUG_ENTER("merge_engine_table_options"); *out= 0;
DBUG_ENTER("merge_engine_options");
/* Create copy of first list */ /* Create copy of source list */
for (opt= first, first= 0; opt; opt= opt->next) for (opt= source; opt; opt= opt->next)
new (root) engine_option_value(opt, &first, &end); {
opt_copy= new (root) engine_option_value(opt);
if (!opt_copy)
DBUG_RETURN(TRUE);
opt_copy->link(out, &end);
}
for (opt= second; opt; opt= opt->next) for (opt= changes; opt; opt= opt->next)
new (root) engine_option_value(opt->name, opt->value, opt->quoted_value, {
&first, &end); opt_copy= new (root) engine_option_value(opt);
DBUG_RETURN(first); if (!opt_copy)
DBUG_RETURN(TRUE);
opt_copy->link(out, &end);
}
DBUG_RETURN(FALSE);
} }
bool is_engine_option_known(engine_option_value *opt, bool is_engine_option_known(engine_option_value *opt,
......
/* Copyright (C) 2010 Monty Program Ab /* Copyright (C) 2010, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -35,30 +35,23 @@ class engine_option_value: public Sql_alloc ...@@ -35,30 +35,23 @@ class engine_option_value: public Sql_alloc
bool parsed; ///< to detect unrecognized options bool parsed; ///< to detect unrecognized options
bool quoted_value; ///< option=VAL vs. option='VAL' bool quoted_value; ///< option=VAL vs. option='VAL'
engine_option_value(engine_option_value *src, engine_option_value(engine_option_value *src) :
engine_option_value **start, engine_option_value **end) :
name(src->name), value(src->value), name(src->name), value(src->value),
next(NULL), parsed(src->parsed), quoted_value(src->quoted_value) next(NULL), parsed(src->parsed), quoted_value(src->quoted_value)
{ {
link(start, end);
} }
engine_option_value(LEX_CSTRING &name_arg, LEX_CSTRING &value_arg, engine_option_value(LEX_CSTRING &name_arg, LEX_CSTRING &value_arg,
bool quoted, bool quoted) :
engine_option_value **start, engine_option_value **end) :
name(name_arg), value(value_arg), name(name_arg), value(value_arg),
next(NULL), parsed(false), quoted_value(quoted) next(NULL), parsed(false), quoted_value(quoted)
{ {
link(start, end);
} }
engine_option_value(LEX_CSTRING &name_arg, engine_option_value(LEX_CSTRING &name_arg):
engine_option_value **start, engine_option_value **end) :
name(name_arg), value(null_clex_str), name(name_arg), value(null_clex_str),
next(NULL), parsed(false), quoted_value(false) next(NULL), parsed(false), quoted_value(false)
{ {
link(start, end);
} }
engine_option_value(LEX_CSTRING &name_arg, ulonglong value_arg, engine_option_value(LEX_CSTRING &name_arg, ulonglong value_arg,
engine_option_value **start, engine_option_value **end,
MEM_ROOT *root) : MEM_ROOT *root) :
name(name_arg), next(NULL), parsed(false), quoted_value(false) name(name_arg), next(NULL), parsed(false), quoted_value(false)
{ {
...@@ -66,7 +59,6 @@ class engine_option_value: public Sql_alloc ...@@ -66,7 +59,6 @@ class engine_option_value: public Sql_alloc
if (likely((value.str= str= (char *)alloc_root(root, 22)))) if (likely((value.str= str= (char *)alloc_root(root, 22))))
{ {
value.length= longlong10_to_str(value_arg, str, 10) - str; value.length= longlong10_to_str(value_arg, str, 10) - str;
link(start, end);
} }
} }
static uchar *frm_read(const uchar *buff, const uchar *buff_end, static uchar *frm_read(const uchar *buff, const uchar *buff_end,
...@@ -83,15 +75,18 @@ class Create_field; ...@@ -83,15 +75,18 @@ class Create_field;
bool resolve_sysvar_table_options(handlerton *hton); bool resolve_sysvar_table_options(handlerton *hton);
void free_sysvar_table_options(handlerton *hton); void free_sysvar_table_options(handlerton *hton);
bool parse_engine_table_options(THD *thd, handlerton *ht, TABLE_SHARE *share); bool parse_engine_table_options(THD *thd, handlerton *ht, TABLE_SHARE *share);
#ifdef WITH_PARTITION_STORAGE_ENGINE
bool parse_engine_part_options(THD *thd, TABLE *table);
#endif
bool parse_option_list(THD* thd, handlerton *hton, void *option_struct, bool parse_option_list(THD* thd, handlerton *hton, void *option_struct,
engine_option_value **option_list, engine_option_value **option_list,
ha_create_table_option *rules, ha_create_table_option *rules,
bool suppress_warning, MEM_ROOT *root); bool suppress_warning, MEM_ROOT *root);
bool engine_table_options_frm_read(const uchar *buff, size_t length, bool engine_table_options_frm_read(const uchar *buff, size_t length,
TABLE_SHARE *share); TABLE_SHARE *share);
engine_option_value *merge_engine_table_options(engine_option_value *source, bool merge_engine_options(engine_option_value *source,
engine_option_value *changes, engine_option_value *changes,
MEM_ROOT *root); engine_option_value **out, MEM_ROOT *root);
uint engine_table_options_frm_length(engine_option_value *table_option_list, uint engine_table_options_frm_length(engine_option_value *table_option_list,
List<Create_field> &create_fields, List<Create_field> &create_fields,
......
...@@ -2716,6 +2716,7 @@ register_query_cache_dependant_tables(THD *thd, ...@@ -2716,6 +2716,7 @@ register_query_cache_dependant_tables(THD *thd,
2) MAX_ROWS, MIN_ROWS on partition 2) MAX_ROWS, MIN_ROWS on partition
3) Index file name on partition 3) Index file name on partition
4) Data file name on partition 4) Data file name on partition
5) Engine-defined attributes on partition
*/ */
int ha_partition::set_up_table_before_create(TABLE *tbl, int ha_partition::set_up_table_before_create(TABLE *tbl,
...@@ -2753,6 +2754,10 @@ int ha_partition::set_up_table_before_create(TABLE *tbl, ...@@ -2753,6 +2754,10 @@ int ha_partition::set_up_table_before_create(TABLE *tbl,
if (info->connect_string.length) if (info->connect_string.length)
info->used_fields|= HA_CREATE_USED_CONNECTION; info->used_fields|= HA_CREATE_USED_CONNECTION;
tbl->s->connect_string= part_elem->connect_string; tbl->s->connect_string= part_elem->connect_string;
if (part_elem->option_list)
tbl->s->option_list= part_elem->option_list;
if (part_elem->option_struct)
tbl->s->option_struct= part_elem->option_struct;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define PARTITION_ELEMENT_INCLUDED #define PARTITION_ELEMENT_INCLUDED
/* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. /* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -126,6 +127,9 @@ class partition_element :public Sql_alloc ...@@ -126,6 +127,9 @@ class partition_element :public Sql_alloc
bool empty; bool empty;
elem_type_enum type; elem_type_enum type;
engine_option_value *option_list; // create options for partition
ha_table_option_struct *option_struct; // structure with parsed options
partition_element() partition_element()
: part_max_rows(0), part_min_rows(0), range_value(0), : part_max_rows(0), part_min_rows(0), range_value(0),
partition_name(NULL), partition_name(NULL),
...@@ -136,7 +140,8 @@ class partition_element :public Sql_alloc ...@@ -136,7 +140,8 @@ class partition_element :public Sql_alloc
signed_flag(FALSE), max_value(FALSE), signed_flag(FALSE), max_value(FALSE),
id(UINT_MAX32), id(UINT_MAX32),
empty(true), empty(true),
type(CONVENTIONAL) type(CONVENTIONAL),
option_list(NULL), option_struct(NULL)
{} {}
partition_element(partition_element *part_elem) partition_element(partition_element *part_elem)
: part_max_rows(part_elem->part_max_rows), : part_max_rows(part_elem->part_max_rows),
...@@ -155,7 +160,9 @@ class partition_element :public Sql_alloc ...@@ -155,7 +160,9 @@ class partition_element :public Sql_alloc
max_value(part_elem->max_value), max_value(part_elem->max_value),
id(part_elem->id), id(part_elem->id),
empty(part_elem->empty), empty(part_elem->empty),
type(CONVENTIONAL) type(CONVENTIONAL),
option_list(part_elem->option_list),
option_struct(part_elem->option_struct)
{} {}
~partition_element() {} ~partition_element() {}
......
/* Copyright (c) 2005, 2017, Oracle and/or its affiliates. /* Copyright (c) 2005, 2017, Oracle and/or its affiliates.
Copyright (c) 2009, 2020, MariaDB Copyright (c) 2009, 2020, 2021, MariaDB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
#include "sql_select.h" #include "sql_select.h"
#include "ddl_log.h" #include "ddl_log.h"
#include "tztime.h" // my_tz_OFFSET0 #include "tztime.h" // my_tz_OFFSET0
#include "create_options.h" // engine_option_value
#include <algorithm> #include <algorithm>
using std::max; using std::max;
...@@ -2205,7 +2206,7 @@ static int add_keyword_int(String *str, const char *keyword, longlong num) ...@@ -2205,7 +2206,7 @@ static int add_keyword_int(String *str, const char *keyword, longlong num)
return err + str->append_longlong(num); return err + str->append_longlong(num);
} }
static int add_partition_options(String *str, partition_element *p_elem) static int add_server_part_options(String *str, partition_element *p_elem)
{ {
int err= 0; int err= 0;
...@@ -2232,6 +2233,20 @@ static int add_partition_options(String *str, partition_element *p_elem) ...@@ -2232,6 +2233,20 @@ static int add_partition_options(String *str, partition_element *p_elem)
return err; return err;
} }
static int add_engine_part_options(String *str, partition_element *p_elem)
{
engine_option_value *opt= p_elem->option_list;
for (; opt; opt= opt->next)
{
if (!opt->value.str)
continue;
if ((add_keyword_string(str, opt->name.str, opt->quoted_value,
opt->value.str)))
return 1;
}
return 0;
}
/* /*
Find the given field's Create_field object using name of field Find the given field's Create_field object using name of field
...@@ -2655,7 +2670,10 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info, ...@@ -2655,7 +2670,10 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info,
part_info->use_default_subpartitions) part_info->use_default_subpartitions)
{ {
if (show_partition_options) if (show_partition_options)
err+= add_partition_options(&str, part_elem); {
err+= add_server_part_options(&str, part_elem);
err+= add_engine_part_options(&str, part_elem);
}
} }
else else
{ {
...@@ -2669,7 +2687,7 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info, ...@@ -2669,7 +2687,7 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info,
err+= append_identifier(thd, &str, part_elem->partition_name, err+= append_identifier(thd, &str, part_elem->partition_name,
strlen(part_elem->partition_name)); strlen(part_elem->partition_name));
if (show_partition_options) if (show_partition_options)
err+= add_partition_options(&str, part_elem); err+= add_server_part_options(&str, part_elem);
if (j != (num_subparts-1)) if (j != (num_subparts-1))
err+= str.append(STRING_WITH_LEN(",\n ")); err+= str.append(STRING_WITH_LEN(",\n "));
else else
......
...@@ -7863,8 +7863,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, ...@@ -7863,8 +7863,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
thd->calloc(sizeof(void*) * table->s->keys)) == NULL) thd->calloc(sizeof(void*) * table->s->keys)) == NULL)
DBUG_RETURN(1); DBUG_RETURN(1);
create_info->option_list= merge_engine_table_options(table->s->option_list, if (merge_engine_options(table->s->option_list, create_info->option_list,
create_info->option_list, thd->mem_root); &create_info->option_list, thd->mem_root))
DBUG_RETURN(1);
/* /*
First collect all fields from table which isn't in drop_list First collect all fields from table which isn't in drop_list
......
/* /*
Copyright (c) 2000, 2015, Oracle and/or its affiliates. Copyright (c) 2000, 2015, Oracle and/or its affiliates.
Copyright (c) 2010, 2021, MariaDB Copyright (c) 2010, 2020, 2021, MariaDB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -301,6 +301,7 @@ void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)() ...@@ -301,6 +301,7 @@ void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)()
class With_element_head *with_element_head; class With_element_head *with_element_head;
class With_clause *with_clause; class With_clause *with_clause;
class Virtual_column_info *virtual_column; class Virtual_column_info *virtual_column;
engine_option_value *engine_option_value_ptr;
handlerton *db_type; handlerton *db_type;
st_select_lex *select_lex; st_select_lex *select_lex;
...@@ -1802,6 +1803,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); ...@@ -1802,6 +1803,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <vers_range_unit> opt_history_unit %type <vers_range_unit> opt_history_unit
%type <vers_history_point> history_point %type <vers_history_point> history_point
%type <vers_column_versioning> with_or_without_system %type <vers_column_versioning> with_or_without_system
%type <engine_option_value_ptr> engine_defined_option;
%ifdef MARIADB %ifdef MARIADB
%type <NONE> sp_tail_standalone %type <NONE> sp_tail_standalone
...@@ -5040,7 +5042,7 @@ sub_part_definition: ...@@ -5040,7 +5042,7 @@ sub_part_definition:
part_info->use_default_num_subpartitions= FALSE; part_info->use_default_num_subpartitions= FALSE;
part_info->count_curr_subparts++; part_info->count_curr_subparts++;
} }
sub_name opt_part_options {} sub_name opt_subpart_options {}
; ;
sub_name: sub_name:
...@@ -5054,15 +5056,34 @@ sub_name: ...@@ -5054,15 +5056,34 @@ sub_name:
opt_part_options: opt_part_options:
/* empty */ {} /* empty */ {}
| opt_part_option_list {} | part_option_list {}
; ;
opt_part_option_list: part_option_list:
opt_part_option_list opt_part_option {} part_option_list part_option {}
| opt_part_option {} | part_option {}
; ;
opt_part_option: part_option:
server_part_option {}
| engine_defined_option
{
$1->link(&Lex->part_info->curr_part_elem->option_list,
&Lex->option_list_last);
}
;
opt_subpart_options:
/* empty */ {}
| subpart_option_list {}
;
subpart_option_list:
subpart_option_list server_part_option {}
| server_part_option {}
;
server_part_option:
TABLESPACE opt_equal ident_or_text TABLESPACE opt_equal ident_or_text
{ /* Compatibility with MySQL */ } { /* Compatibility with MySQL */ }
| opt_storage ENGINE_SYM opt_equal storage_engines | opt_storage ENGINE_SYM opt_equal storage_engines
...@@ -5424,42 +5445,43 @@ create_table_option: ...@@ -5424,42 +5445,43 @@ create_table_option:
Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL; Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL;
Lex->create_info.transactional= $3; Lex->create_info.transactional= $3;
} }
| IDENT_sys equal TEXT_STRING_sys | engine_defined_option
{
$1->link(&Lex->create_info.option_list, &Lex->option_list_last);
}
| SEQUENCE_SYM opt_equal choice
{
Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE;
Lex->create_info.sequence= ($3 == HA_CHOICE_YES);
}
| versioning_option
;
engine_defined_option:
IDENT_sys equal TEXT_STRING_sys
{ {
if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH)) if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
(void) new (thd->mem_root) $$= new (thd->mem_root) engine_option_value($1, $3, true);
engine_option_value($1, $3, true, MYSQL_YYABORT_UNLESS($$);
&Lex->create_info.option_list,
&Lex->option_list_last);
} }
| IDENT_sys equal ident | IDENT_sys equal ident
{ {
if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH)) if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
(void) new (thd->mem_root) $$= new (thd->mem_root) engine_option_value($1, $3, false);
engine_option_value($1, $3, false, MYSQL_YYABORT_UNLESS($$);
&Lex->create_info.option_list,
&Lex->option_list_last);
} }
| IDENT_sys equal real_ulonglong_num | IDENT_sys equal real_ulonglong_num
{ {
(void) new (thd->mem_root) $$= new (thd->mem_root) engine_option_value($1, $3, thd->mem_root);
engine_option_value($1, $3, &Lex->create_info.option_list, MYSQL_YYABORT_UNLESS($$);
&Lex->option_list_last, thd->mem_root);
} }
| IDENT_sys equal DEFAULT | IDENT_sys equal DEFAULT
{ {
(void) new (thd->mem_root) $$= new (thd->mem_root) engine_option_value($1);
engine_option_value($1, &Lex->create_info.option_list, MYSQL_YYABORT_UNLESS($$);
&Lex->option_list_last);
} }
| SEQUENCE_SYM opt_equal choice
{
Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE;
Lex->create_info.sequence= ($3 == HA_CHOICE_YES);
}
| versioning_option
; ;
opt_versioning_option: opt_versioning_option:
...@@ -6350,35 +6372,9 @@ asrow_attribute: ...@@ -6350,35 +6372,9 @@ asrow_attribute:
serial_attribute: serial_attribute:
asrow_attribute asrow_attribute
| IDENT_sys equal TEXT_STRING_sys | engine_defined_option
{
if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
(void) new (thd->mem_root)
engine_option_value($1, $3, true,
&Lex->last_field->option_list,
&Lex->option_list_last);
}
| IDENT_sys equal ident
{ {
if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH)) $1->link(&Lex->last_field->option_list, &Lex->option_list_last);
my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
(void) new (thd->mem_root)
engine_option_value($1, $3, false,
&Lex->last_field->option_list,
&Lex->option_list_last);
}
| IDENT_sys equal real_ulonglong_num
{
(void) new (thd->mem_root)
engine_option_value($1, $3, &Lex->last_field->option_list,
&Lex->option_list_last, thd->mem_root);
}
| IDENT_sys equal DEFAULT
{
(void) new (thd->mem_root)
engine_option_value($1, &Lex->last_field->option_list,
&Lex->option_list_last);
} }
| with_or_without_system VERSIONING_SYM | with_or_without_system VERSIONING_SYM
{ {
...@@ -6781,33 +6777,9 @@ all_key_opt: ...@@ -6781,33 +6777,9 @@ all_key_opt:
{ {
Lex->last_key->key_create_info.is_ignored= $1; Lex->last_key->key_create_info.is_ignored= $1;
} }
| IDENT_sys equal TEXT_STRING_sys | engine_defined_option
{
if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
(void) new (thd->mem_root)
engine_option_value($1, $3, true, &Lex->option_list,
&Lex->option_list_last);
}
| IDENT_sys equal ident
{
if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH))
my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str));
(void) new (thd->mem_root)
engine_option_value($1, $3, false, &Lex->option_list,
&Lex->option_list_last);
}
| IDENT_sys equal real_ulonglong_num
{
(void) new (thd->mem_root)
engine_option_value($1, $3, &Lex->option_list,
&Lex->option_list_last, thd->mem_root);
}
| IDENT_sys equal DEFAULT
{ {
(void) new (thd->mem_root) $1->link(&Lex->option_list, &Lex->option_list_last);
engine_option_value($1, &Lex->option_list,
&Lex->option_list_last);
} }
; ;
......
...@@ -4244,6 +4244,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, ...@@ -4244,6 +4244,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
thd->restore_active_arena(&part_func_arena, &backup_arena); thd->restore_active_arena(&part_func_arena, &backup_arena);
goto partititon_err; goto partititon_err;
} }
if (parse_engine_part_options(thd, outparam))
goto err;
outparam->part_info->is_auto_partitioned= share->auto_partitioned; outparam->part_info->is_auto_partitioned= share->auto_partitioned;
DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned)); DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned));
/* /*
......
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