← Back to team overview

maria-developers team mailing list archive

Re: Rev 2740: options for CREATE TABLE (MWL#43) (version after first review). in file:///home/bell/maria/bzr/work-maria-5.2-createoptions/

 

sanja@xxxxxxxxxxxx wrote:
> At file:///home/bell/maria/bzr/work-maria-5.2-createoptions/
>
> ------------------------------------------------------------
> revno: 2740
> revision-id: sanja@xxxxxxxxxxxx-20100205170316-gg4nio1p81cpmjop
> parent: knielsen@xxxxxxxxxxxxxxx-20100201190519-b9uktnn90rwwiile
> committer: sanja@xxxxxxxxxxxx
> branch nick: work-maria-5.2-createoptions
> timestamp: Fri 2010-02-05 19:03:16 +0200
> message:
>   options for CREATE TABLE (MWL#43) (version after first review).
>   
Here is diff which was missed.
=== modified file 'include/my_base.h'
--- include/my_base.h	2009-09-07 20:50:10 +0000
+++ include/my_base.h	2010-02-05 09:42:27 +0000
@@ -314,6 +314,8 @@
 #define HA_OPTION_RELIES_ON_SQL_LAYER   512
 #define HA_OPTION_NULL_FIELDS		1024
 #define HA_OPTION_PAGE_CHECKSUM		2048
+/* .frm has extra create options in linked-list format */
+#define HA_OPTION_TEXT_CREATE_OPTIONS   (1L << 14)
 #define HA_OPTION_TEMP_COMPRESS_RECORD  (1L << 15)      /* set by isamchk */
 #define HA_OPTION_READ_ONLY_DATA        (1L << 16)      /* Set by isamchk */
 #define HA_OPTION_NO_CHECKSUM           (1L << 17)

=== modified file 'libmysqld/CMakeLists.txt'
--- libmysqld/CMakeLists.txt	2009-12-03 11:19:05 +0000
+++ libmysqld/CMakeLists.txt	2010-02-05 09:42:27 +0000
@@ -139,7 +139,8 @@
            ../sql/strfunc.cc ../sql/table.cc ../sql/thr_malloc.cc
            ../sql/time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc
            ../sql/partition_info.cc ../sql/sql_connect.cc 
-           ../sql/scheduler.cc ../sql/event_parse_data.cc
+           ../sql/scheduler.cc ../sql/event_parse_data.cc 
+	   ../sql/sql_create_options.cc
            ${GEN_SOURCES}
            ${LIB_SOURCES})
 

=== modified file 'libmysqld/Makefile.am'
--- libmysqld/Makefile.am	2009-12-03 11:19:05 +0000
+++ libmysqld/Makefile.am	2010-02-05 09:42:27 +0000
@@ -75,7 +75,7 @@
 	parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
 	rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
 	debug_sync.cc \
-	sql_tablespace.cc \
+	sql_tablespace.cc sql_create_options.cc \
 	rpl_injector.cc my_user.c partition_info.cc \
 	sql_servers.cc event_parse_data.cc opt_table_elimination.cc
 

=== added file 'mysql-test/r/create_options.result'
--- mysql-test/r/create_options.result	1970-01-01 00:00:00 +0000
+++ mysql-test/r/create_options.result	2010-02-05 11:52:21 +0000
@@ -0,0 +1,197 @@
+drop table if exists t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 TKEY1=NULL tkey1=1v2 tkey2=2v1 tkey3=3v1;
+Warnings:
+Warning	1650	Unused option 'tkey1'='1v2'
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v1' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1=NULL tkey1=1v1 tkey1=1v2  tkey2=2v1 tkey3=3v1;
+Warnings:
+Warning	1650	Unused option 'tkey1'='1v2'
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v1' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1='NULL' tkey2=2v1 tkey3=3v1;
+Warnings:
+Warning	1650	Unused option 'TKEY1'='NULL'
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v1' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1=NULL tkey2=2v1 tkey3=3v1;
+Warnings:
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v1' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 TKEY1=DEFAULT tkey1=1v2 tkey2=2v1 tkey3=3v1;
+Warnings:
+Warning	1650	Unused option 'tkey1'='1v2'
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v1' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1=DEFAULT tkey1=1v1 tkey1=1v2  tkey2=2v1 tkey3=3v1;
+Warnings:
+Warning	1650	Unused option 'tkey1'='1v2'
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v1' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1='DEFAULT' tkey2=2v1 tkey3=3v1;
+Warnings:
+Warning	1650	Unused option 'TKEY1'='DEFAULT'
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v1' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1=DEFAULT tkey2=2v1 tkey3=3v1;
+Warnings:
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v1' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+alter table t1 change a a int `fkey1`='v1';
+alter table t1 change a a int fkey1=v2;
+Warnings:
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v2' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+alter table t1 add column b int;
+Warnings:
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v2' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL `fkey1`='v2',
+  `b` int(11) DEFAULT NULL,
+  KEY `akey` (`a`) `kkey1`='v1'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 `tkey2`='2v1' `tkey3`='3v1'
+alter table t1 add key bkey (b) kkey2=v1;
+Warnings:
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v2' of field 'a'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+Warning	1652	Unused option 'kkey2'='v1' of key 'bkey'
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL `fkey1`='v2',
+  `b` int(11) DEFAULT NULL,
+  KEY `akey` (`a`) `kkey1`='v1',
+  KEY `bkey` (`b`) `kkey2`='v1'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 `tkey2`='2v1' `tkey3`='3v1'
+alter table t1 add column c int fkey1=v1 fkey2=v2;
+Warnings:
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v2' of field 'a'
+Warning	1651	Unused option 'fkey1'='v1' of field 'c'
+Warning	1651	Unused option 'fkey2'='v2' of field 'c'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+Warning	1652	Unused option 'kkey2'='v1' of key 'bkey'
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL `fkey1`='v2',
+  `b` int(11) DEFAULT NULL,
+  `c` int(11) DEFAULT NULL `fkey1`='v1' `fkey2`='v2',
+  KEY `akey` (`a`) `kkey1`='v1',
+  KEY `bkey` (`b`) `kkey2`='v1'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 `tkey2`='2v1' `tkey3`='3v1'
+alter table t1 add key ckey (c) kkey3=v1 kkey4=v1;
+Warnings:
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v2' of field 'a'
+Warning	1651	Unused option 'fkey1'='v1' of field 'c'
+Warning	1651	Unused option 'fkey2'='v2' of field 'c'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+Warning	1652	Unused option 'kkey2'='v1' of key 'bkey'
+Warning	1652	Unused option 'kkey3'='v1' of key 'ckey'
+Warning	1652	Unused option 'kkey4'='v1' of key 'ckey'
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL `fkey1`='v2',
+  `b` int(11) DEFAULT NULL,
+  `c` int(11) DEFAULT NULL `fkey1`='v1' `fkey2`='v2',
+  KEY `akey` (`a`) `kkey1`='v1',
+  KEY `bkey` (`b`) `kkey2`='v1',
+  KEY `ckey` (`c`) `kkey3`='v1' `kkey4`='v1'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 `tkey2`='2v1' `tkey3`='3v1'
+alter table t1 drop b;
+Warnings:
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v2' of field 'a'
+Warning	1651	Unused option 'fkey1'='v1' of field 'c'
+Warning	1651	Unused option 'fkey2'='v2' of field 'c'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+Warning	1652	Unused option 'kkey3'='v1' of key 'ckey'
+Warning	1652	Unused option 'kkey4'='v1' of key 'ckey'
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL `fkey1`='v2',
+  `c` int(11) DEFAULT NULL `fkey1`='v1' `fkey2`='v2',
+  KEY `akey` (`a`) `kkey1`='v1',
+  KEY `ckey` (`c`) `kkey3`='v1' `kkey4`='v1'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 `tkey2`='2v1' `tkey3`='3v1'
+alter table t1 add column b int fkey2=v1;
+Warnings:
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v2' of field 'a'
+Warning	1651	Unused option 'fkey1'='v1' of field 'c'
+Warning	1651	Unused option 'fkey2'='v2' of field 'c'
+Warning	1651	Unused option 'fkey2'='v1' of field 'b'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+Warning	1652	Unused option 'kkey3'='v1' of key 'ckey'
+Warning	1652	Unused option 'kkey4'='v1' of key 'ckey'
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL `fkey1`='v2',
+  `c` int(11) DEFAULT NULL `fkey1`='v1' `fkey2`='v2',
+  `b` int(11) DEFAULT NULL `fkey2`='v1',
+  KEY `akey` (`a`) `kkey1`='v1',
+  KEY `ckey` (`c`) `kkey3`='v1' `kkey4`='v1'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 `tkey2`='2v1' `tkey3`='3v1'
+alter table t1 add key bkey (b) kkey2=v2;
+Warnings:
+Warning	1650	Unused option 'tkey2'='2v1'
+Warning	1650	Unused option 'tkey3'='3v1'
+Warning	1651	Unused option 'fkey1'='v2' of field 'a'
+Warning	1651	Unused option 'fkey1'='v1' of field 'c'
+Warning	1651	Unused option 'fkey2'='v2' of field 'c'
+Warning	1651	Unused option 'fkey2'='v1' of field 'b'
+Warning	1652	Unused option 'kkey1'='v1' of key 'akey'
+Warning	1652	Unused option 'kkey3'='v1' of key 'ckey'
+Warning	1652	Unused option 'kkey4'='v1' of key 'ckey'
+Warning	1652	Unused option 'kkey2'='v2' of key 'bkey'
+show create table t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL `fkey1`='v2',
+  `c` int(11) DEFAULT NULL `fkey1`='v1' `fkey2`='v2',
+  `b` int(11) DEFAULT NULL `fkey2`='v1',
+  KEY `akey` (`a`) `kkey1`='v1',
+  KEY `ckey` (`c`) `kkey3`='v1' `kkey4`='v1',
+  KEY `bkey` (`b`) `kkey2`='v2'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 `tkey2`='2v1' `tkey3`='3v1'
+drop table t1;

=== added file 'mysql-test/r/create_options_example.result'
--- mysql-test/r/create_options_example.result	1970-01-01 00:00:00 +0000
+++ mysql-test/r/create_options_example.result	2010-02-05 12:29:41 +0000
@@ -0,0 +1,16 @@
+drop table if exists t1;
+create table t1 (a int ttt=xxx E=1, key akey (a) kkk=xxx ) E=1 ttt=xxx ttt=yyy TTT=DEFAULT mmm=CCC zzz=MMM;
+Warnings:
+Warning	1650	Unused option 'E'='1'
+Warning	1650	Unused option 'mmm'='CCC'
+Warning	1650	Unused option 'zzz'='MMM'
+Warning	1651	Unused option 'ttt'='xxx' of field 'a'
+Warning	1651	Unused option 'E'='1' of field 'a'
+Warning	1652	Unused option 'kkk'='xxx' of key 'akey'
+drop table t1;
+create table t1 (a int ttt=xxx E=1) ENGINE=EXAMPLE E=1 ttt=xxx ttt=yyy TTT=DEFAULT mmm=CCC zzz=MMM;
+Warnings:
+Warning	1650	Unused option 'mmm'='CCC'
+Warning	1650	Unused option 'zzz'='MMM'
+Warning	1651	Unused option 'ttt'='xxx' of field 'a'
+drop table t1;

=== added file 'mysql-test/t/create_options.test'
--- mysql-test/t/create_options.test	1970-01-01 00:00:00 +0000
+++ mysql-test/t/create_options.test	2010-02-05 09:42:27 +0000
@@ -0,0 +1,39 @@
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 TKEY1=NULL tkey1=1v2 tkey2=2v1 tkey3=3v1;
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1=NULL tkey1=1v1 tkey1=1v2  tkey2=2v1 tkey3=3v1;
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1='NULL' tkey2=2v1 tkey3=3v1;
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1=NULL tkey2=2v1 tkey3=3v1;
+drop table t1;
+
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 TKEY1=DEFAULT tkey1=1v2 tkey2=2v1 tkey3=3v1;
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1=DEFAULT tkey1=1v1 tkey1=1v2  tkey2=2v1 tkey3=3v1;
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1='DEFAULT' tkey2=2v1 tkey3=3v1;
+drop table t1;
+create table t1 (a int fkey1=v1, key akey (a) kkey1=v1) tkey1=1v1 tkey1=1v2 TKEY1=DEFAULT tkey2=2v1 tkey3=3v1;
+# the same value so no warnings (no changes)
+alter table t1 change a a int `fkey1`='v1';
+alter table t1 change a a int fkey1=v2;
+alter table t1 add column b int;
+show create table t1;
+alter table t1 add key bkey (b) kkey2=v1;
+show create table t1;
+alter table t1 add column c int fkey1=v1 fkey2=v2;
+show create table t1;
+alter table t1 add key ckey (c) kkey3=v1 kkey4=v1;
+show create table t1;
+alter table t1 drop b;
+show create table t1;
+alter table t1 add column b int fkey2=v1;
+show create table t1;
+alter table t1 add key bkey (b) kkey2=v2;
+show create table t1;
+drop table t1;

=== added file 'mysql-test/t/create_options_example-master.opt'
--- mysql-test/t/create_options_example-master.opt	1970-01-01 00:00:00 +0000
+++ mysql-test/t/create_options_example-master.opt	2010-02-05 09:42:27 +0000
@@ -0,0 +1,2 @@
+$EXAMPLE_PLUGIN_OPT
+$EXAMPLE_PLUGIN_LOAD

=== added file 'mysql-test/t/create_options_example.test'
--- mysql-test/t/create_options_example.test	1970-01-01 00:00:00 +0000
+++ mysql-test/t/create_options_example.test	2010-02-05 09:42:27 +0000
@@ -0,0 +1,16 @@
+--source include/have_example_plugin.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+#All vaues with warnings
+create table t1 (a int ttt=xxx E=1, key akey (a) kkk=xxx ) E=1 ttt=xxx ttt=yyy TTT=DEFAULT mmm=CCC zzz=MMM;
+
+drop table t1;
+
+# E=1 accepted by engine
+create table t1 (a int ttt=xxx E=1) ENGINE=EXAMPLE E=1 ttt=xxx ttt=yyy TTT=DEFAULT mmm=CCC zzz=MMM;
+
+drop table t1;
+

=== modified file 'sql/CMakeLists.txt'
--- sql/CMakeLists.txt	2010-01-29 18:42:22 +0000
+++ sql/CMakeLists.txt	2010-02-05 09:42:27 +0000
@@ -77,6 +77,7 @@
                rpl_rli.cc rpl_mi.cc sql_servers.cc
                sql_connect.cc scheduler.cc 
                sql_profile.cc event_parse_data.cc opt_table_elimination.cc
+	       sql_create_options.cc
                ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
                ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
                ${PROJECT_SOURCE_DIR}/include/mysqld_error.h

=== modified file 'sql/Makefile.am'
--- sql/Makefile.am	2009-12-03 11:19:05 +0000
+++ sql/Makefile.am	2010-02-05 09:42:27 +0000
@@ -78,7 +78,7 @@
 			sql_plugin.h authors.h event_parse_data.h \
 			event_data_objects.h event_scheduler.h \
 			sql_partition.h partition_info.h partition_element.h \
-			contributors.h sql_servers.h
+			contributors.h sql_servers.h sql_create_options.h
 
 mysqld_SOURCES =	sql_lex.cc sql_handler.cc sql_partition.cc \
 			item.cc item_sum.cc item_buff.cc item_func.cc \
@@ -124,7 +124,7 @@
 			sql_plugin.cc sql_binlog.cc \
 			sql_builtin.cc sql_tablespace.cc partition_info.cc \
 			sql_servers.cc event_parse_data.cc \
-                        opt_table_elimination.cc
+                        opt_table_elimination.cc sql_create_options.cc
 
 nodist_mysqld_SOURCES =	mini_client_errors.c pack.c client.c my_time.c my_user.c 
 

=== modified file 'sql/field.cc'
--- sql/field.cc	2010-02-01 06:14:12 +0000
+++ sql/field.cc	2010-02-05 10:17:32 +0000
@@ -9568,7 +9568,8 @@
                         Item *fld_on_update_value, LEX_STRING *fld_comment,
                         char *fld_change, List<String> *fld_interval_list,
                         CHARSET_INFO *fld_charset, uint fld_geom_type,
-			Virtual_column_info *fld_vcol_info)
+			Virtual_column_info *fld_vcol_info,
+                        CREATE_OPTION_LIST *create_opt)
 {
   uint sign_len, allowed_type_modifier= 0;
   ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
@@ -9579,6 +9580,10 @@
   field_name= fld_name;
   def= fld_default_value;
   flags= fld_type_modifier;
+  if (create_opt)
+    create_options= *create_opt;
+  else
+    create_options.empty();
   unireg_check= (fld_type_modifier & AUTO_INCREMENT_FLAG ?
                  Field::NEXT_NUMBER : Field::NONE);
   decimals= fld_decimals ? (uint)atoi(fld_decimals) : 0;
@@ -10220,6 +10225,7 @@
   decimals=   old_field->decimals();
   vcol_info=  old_field->vcol_info;
   stored_in_db= old_field->stored_in_db;
+  create_options= old_field->create_options;
 
   /* Fix if the original table had 4 byte pointer blobs */
   if (flags & BLOB_FLAG)
@@ -10294,6 +10300,24 @@
 
 
 /**
+  Makes a clone of this object for ALTER/CREATE TABLE
+
+  @note: We need to do the clone of the list because in
+  ALTER TABLE we may change the list for the cloned field
+
+  @param mem_root        MEM_ROOT where to clone the field
+*/
+
+Create_field *Create_field::clone(MEM_ROOT *mem_root) const
+{
+  Create_field *res= new (mem_root) Create_field(*this);
+  if (res && create_options_clone(mem_root, &res->create_options))
+    return NULL;
+  return res;
+}
+
+
+/**
   maximum possible display length for blob.
 
   @return

=== modified file 'sql/field.h'
--- sql/field.h	2010-02-01 06:14:12 +0000
+++ sql/field.h	2010-02-05 09:58:35 +0000
@@ -137,6 +137,8 @@
   struct st_table *table;		// Pointer for table
   struct st_table *orig_table;		// Pointer to original table
   const char	**table_name, *field_name;
+  /** reference to the list of options or NULL */
+  CREATE_OPTION_LIST create_options;
   LEX_STRING	comment;
   /* Field is part of the following keys */
   key_map	key_start, part_of_key, part_of_key_not_clustered;
@@ -2140,6 +2142,7 @@
   CHARSET_INFO *charset;
   Field::geometry_type geom_type;
   Field *field;				// For alter table
+  CREATE_OPTION_LIST create_options;
 
   uint8 row,col,sc_length,interval_id;	// For rea_create_table
   uint	offset,pack_flag;
@@ -2160,8 +2163,7 @@
   Create_field() :after(0) {}
   Create_field(Field *field, Field *orig_field);
   /* Used to make a clone of this object for ALTER/CREATE TABLE */
-  Create_field *clone(MEM_ROOT *mem_root) const
-    { return new (mem_root) Create_field(*this); }
+  Create_field *clone(MEM_ROOT *mem_root) const;
   void create_length_to_internal_length(void);
 
   /* Init for a tmp table field. To be extended if need be. */
@@ -2173,8 +2175,8 @@
             char *decimals, uint type_modifier, Item *default_value,
             Item *on_update_value, LEX_STRING *comment, char *change,
             List<String> *interval_list, CHARSET_INFO *cs,
-            uint uint_geom_type,
-	    Virtual_column_info *vcol_info);
+            uint uint_geom_type, Virtual_column_info *vcol_info,
+            CREATE_OPTION_LIST *create_opt);
 
   bool field_flags_are_binary()
   {

=== modified file 'sql/handler.cc'
--- sql/handler.cc	2010-02-01 06:14:12 +0000
+++ sql/handler.cc	2010-02-05 09:42:27 +0000
@@ -3716,12 +3716,18 @@
                             TRUE))
     goto err;
 
+  /* Use options which we just have read */
+  create_info->create_table_options= table.s->create_table_options;
+
   if (update_create_info)
     update_create_info_from_table(create_info, &table);
 
   name= get_canonical_filename(table.file, share.path.str, name_buff);
 
   error= table.file->ha_create(name, &table, create_info);
+
+  create_options_check_unused(thd, create_info->create_table_options);
+
   VOID(closefrm(&table, 0));
   if (error)
   {

=== modified file 'sql/handler.h'
--- sql/handler.h	2010-02-01 06:14:12 +0000
+++ sql/handler.h	2010-02-05 09:42:27 +0000
@@ -919,6 +919,12 @@
   LEX_STRING connect_string;
   const char *password, *tablespace;
   LEX_STRING comment;
+  TABLE_OPTIONS create_table_options_orig;
+  /**
+    Originally create_table_options points on above field, but during ALTER
+    TABLE of the options it points on new built parameters
+  */
+  TABLE_OPTIONS *create_table_options;
   const char *data_file_name, *index_file_name;
   const char *alias;
   ulonglong max_rows,min_rows;

=== modified file 'sql/mysql_priv.h'
--- sql/mysql_priv.h	2010-01-04 17:54:42 +0000
+++ sql/mysql_priv.h	2010-02-05 09:42:27 +0000
@@ -44,6 +44,7 @@
 #include "sql_plugin.h"
 #include "scheduler.h"
 #include "log_slow.h"
+#include "sql_create_options.h"
 
 class Parser_state;
 
@@ -1484,7 +1485,8 @@
 		       char *change, List<String> *interval_list,
 		       CHARSET_INFO *cs,
 		       uint uint_geom_type,
-                       Virtual_column_info *vcol_info);
+                       Virtual_column_info *vcol_info,
+                       CREATE_OPTION_LIST *create_options);
 Create_field * new_create_field(THD *thd, char *field_name, enum_field_types type,
 				char *length, char *decimals,
 				uint type_modifier, 

=== modified file 'sql/share/errmsg.txt'
--- sql/share/errmsg.txt	2010-01-04 17:54:42 +0000
+++ sql/share/errmsg.txt	2010-02-05 09:42:27 +0000
@@ -6240,3 +6240,13 @@
 ER_DEBUG_SYNC_HIT_LIMIT
   eng "debug sync point hit limit reached"
   ger "Debug Sync Point Hit Limit erreicht"
+
+WARN_UNUSED_TABLE_OPTION
+        eng "Unused option '%-.64s'='%-.64s'"
+
+WARN_UNUSED_FIELD_OPTION
+        eng "Unused option '%-.64s'='%-.64s' of field '%-.64s'"
+
+WARN_UNUSED_KEY_OPTION
+        eng "Unused option '%-.64s'='%-.64s' of key '%-.64s'"
+

=== modified file 'sql/sp_head.cc'
--- sql/sp_head.cc	2010-02-01 06:14:12 +0000
+++ sql/sp_head.cc	2010-02-05 09:42:27 +0000
@@ -2215,7 +2215,7 @@
                       lex->charset ? lex->charset :
                                      thd->variables.collation_database,
                       lex->uint_geom_type,
-		      lex->vcol_info))
+		      lex->vcol_info, &lex->create_opt))
     return TRUE;
 
   if (field_def->interval_list.elements)

=== modified file 'sql/sql_class.cc'
--- sql/sql_class.cc	2010-02-01 06:14:12 +0000
+++ sql/sql_class.cc	2010-02-05 09:42:27 +0000
@@ -109,6 +109,8 @@
   generated(rhs.generated)
 {
   list_copy_and_replace_each_value(columns, mem_root);
+  create_options= rhs.create_options;
+  create_options_clone(mem_root, &create_options);
 }
 
 /**
@@ -775,6 +777,7 @@
 
 void THD::push_internal_handler(Internal_error_handler *handler)
 {
+  DBUG_ENTER("THD::push_internal_handler");
   if (m_internal_handler)
   {
     handler->m_prev_internal_handler= m_internal_handler;
@@ -784,6 +787,7 @@
   {
     m_internal_handler= handler;
   }
+  DBUG_VOID_RETURN;
 }
 
 
@@ -803,8 +807,10 @@
 
 void THD::pop_internal_handler()
 {
+  DBUG_ENTER("THD::pop_internal_handler");
   DBUG_ASSERT(m_internal_handler != NULL);
   m_internal_handler= m_internal_handler->m_prev_internal_handler;
+  DBUG_VOID_RETURN;
 }
 
 extern "C"

=== modified file 'sql/sql_class.h'
--- sql/sql_class.h	2010-01-04 17:54:42 +0000
+++ sql/sql_class.h	2010-02-05 12:15:23 +0000
@@ -204,14 +204,19 @@
   KEY_CREATE_INFO key_create_info;
   List<Key_part_spec> columns;
   const char *name;
+  CREATE_OPTION_LIST create_options;
   bool generated;
 
   Key(enum Keytype type_par, const char *name_arg,
       KEY_CREATE_INFO *key_info_arg,
-      bool generated_arg, List<Key_part_spec> &cols)
+      bool generated_arg, List<Key_part_spec> &cols,
+      CREATE_OPTION_LIST *create_opt)
     :type(type_par), key_create_info(*key_info_arg), columns(cols),
     name(name_arg), generated(generated_arg)
-  {}
+  {
+    if (create_opt)
+      create_options= *create_opt;
+  }
   Key(const Key &rhs, MEM_ROOT *mem_root);
   virtual ~Key() {}
   /* Equality comparison of keys (ignoring name) */
@@ -239,7 +244,7 @@
   Foreign_key(const char *name_arg, List<Key_part_spec> &cols,
 	      Table_ident *table,   List<Key_part_spec> &ref_cols,
 	      uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg)
-    :Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols),
+    :Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols, NULL),
     ref_table(table), ref_columns(ref_cols),
     delete_opt(delete_opt_arg), update_opt(update_opt_arg),
     match_opt(match_opt_arg)

=== added file 'sql/sql_create_options.cc'
--- sql/sql_create_options.cc	1970-01-01 00:00:00 +0000
+++ sql/sql_create_options.cc	2010-02-05 11:44:17 +0000
@@ -0,0 +1,646 @@
+
+#include "mysql_priv.h"
+
+/* Additional length of index for CREATE_OPTION_XXX types */
+static uint create_options_len[3]= {0, 2, 2};
+
+
+/**
+  Adds new option to this list
+
+  @param options         pointer to the list
+  @param root            memroot to allocate option
+  @param str_key         key
+  @param str_val         value
+  @param changed         pointer to variable to report changed data
+
+  @retval TRUE  error
+  @retval FALSE OK
+*/
+
+my_bool create_option_add(CREATE_OPTION_LIST *options, MEM_ROOT *root,
+                          const LEX_STRING *str_key,
+                          const LEX_STRING *str_val,
+                          my_bool *changed)
+{
+  CREATE_OPTION *cur_option, **option;
+  char *key, *val;
+  my_bool not_used;
+  my_bool copy= FALSE;
+  my_bool replace= FALSE;
+  DBUG_ENTER("create_option_add");
+  DBUG_PRINT("enter", ("key: '%s'  value: '%s'",
+                       str_key->str, str_val->str));
+  if (changed)
+    copy= TRUE;
+  else
+    changed= &not_used;
+
+  DBUG_ASSERT(options->first ||
+              (!options->first && options->last == &options->first));
+  *changed= FALSE;
+
+  /* try to find the option first */
+  for (option= &(options->first);
+       *option && my_strcasecmp(system_charset_info,
+                                str_key->str, (*option)->key.str);
+       option= &((*option)->next)) ;
+  if (str_val->str)
+  {
+    /* add / replace */
+    if (*option)
+    {
+      /* replace */
+      cur_option= *option;
+      if (!(*changed) &&
+          (cur_option->val.length != str_val->length ||
+           memcmp(cur_option->val.str, str_val->str, str_val->length)))
+      {
+        *changed= TRUE;
+      }
+      replace= TRUE;
+    }
+    else
+    {
+      /* add */
+      if (!(cur_option= (CREATE_OPTION *)alloc_root(root,
+                                                    sizeof(CREATE_OPTION))))
+        DBUG_RETURN(TRUE);
+      bzero(cur_option, sizeof(CREATE_OPTION));
+      *(options->last)= cur_option;
+      options->last= &(cur_option->next);
+      *changed= TRUE;
+    }
+    if (changed || replace)
+    {
+      /*
+        In case of replace we use new key in case it differ only in case
+        like 'key' and 'KEY'
+      */
+      if (!multi_alloc_root(root, &key, str_key->length + 1,
+                            &val, str_val->length + 1, NULL))
+        DBUG_RETURN(TRUE);
+      cur_option->key.str=
+        (char *)memcpy(key, str_key->str,
+                       (cur_option->key.length= str_key->length));
+      key[str_key->length]= '\0';
+      cur_option->val.str=
+        (char *)memcpy(val, str_val->str,
+                       (cur_option->val.length= str_val->length));
+      val[str_val->length]= '\0';
+      cur_option->used= FALSE;
+      cur_option->owner= NULL;
+    }
+    DBUG_ASSERT(options->first ||
+                (!options->first && options->last == &options->first));
+  }
+  else
+  {
+    /* remove */
+    if (*option)
+    {
+      if (options->last == &((*option)->next))
+        options->last= option; /* we deleted last option */
+      *option= (*option)->next;
+      *changed= TRUE;
+      DBUG_ASSERT(options->first ||
+                  (!options->first && options->last == &options->first));
+    }
+  }
+  DBUG_RETURN(FALSE);
+}
+
+
+/**
+  Creates empty fields/keys array for table create options structure
+
+  @param root            memroot where to allocate memory for this structure
+  @param n               number of fields/keys
+
+  @return pointer to array or NULL in case of error.
+*/
+
+CREATE_OPTION_LIST *create_create_options_array(MEM_ROOT *root, uint n)
+{
+  uint i;
+  DBUG_ENTER("create_create_options_array");
+  DBUG_PRINT("enter", ("Number: %u", n));
+
+  CREATE_OPTION_LIST *res=
+    (CREATE_OPTION_LIST *) alloc_root(root,
+                                  sizeof(CREATE_OPTION_LIST) * (n + 1));
+  bzero(res, sizeof(CREATE_OPTION_LIST) * (n + 1));
+  if (!res)
+    DBUG_RETURN(NULL);
+  for (i= 0; i < n; i++)
+    res[i].last= &res[i].first;
+  /* We do not do above for res[n]. It is sign of array end */
+  DBUG_RETURN(res);
+}
+
+
+/**
+  Creates empty table create options structure
+
+  @param root            memroot where to allocate memory for this structure
+  @param fields          number of fields
+  @param keys            number of keys
+
+  @return pointer to prepared structure or NULL in case of error.
+*/
+
+TABLE_OPTIONS *create_create_options(MEM_ROOT *root, uint fields, uint keys)
+{
+  TABLE_OPTIONS *res;
+  DBUG_ENTER("create_create_options");
+  DBUG_PRINT("enter", ("fields: %u  keys: %u", fields, keys));
+
+  if (!(res= (TABLE_OPTIONS *)alloc_root(root, sizeof(TABLE_OPTIONS))))
+    DBUG_RETURN(NULL);
+
+  /*bzero(res, sizeof(TABLE_OPTIONS));*/
+  res->table_opt.empty();
+  if (!(res->field_opt= create_create_options_array(root, fields)) ||
+      !(res->key_opt= create_create_options_array(root, keys)))
+    DBUG_RETURN(NULL);
+
+  DBUG_RETURN(res);
+}
+
+
+/**
+  Reads options from this buffer
+
+  @param buffer          the buffer to read from
+  @param mem_root        memroot for allocating
+  @param opt             parametes to write to
+
+  @retval TRUE  Error
+  @retval FALSE OK
+*/
+
+my_bool create_options_read(const uchar *buff, uint length, MEM_ROOT *root,
+                            TABLE_OPTIONS *opt)
+{
+  const uchar *buff_end= buff + length;
+  DBUG_ENTER("create_options_read");
+  while (buff < buff_end)
+  {
+    CREATE_OPTION *option;
+    CREATE_OPTION_TYPES type;
+    uint index= 0;
+
+    if (!(option= (CREATE_OPTION *) alloc_root(root, sizeof(CREATE_OPTION))))
+      DBUG_RETURN(TRUE);
+
+    DBUG_ASSERT(buff + 4 <= buff_end);
+    option->val.length= uint2korr(buff);
+    option->key.length= buff[2];
+    option->next= NULL;
+    type= (CREATE_OPTION_TYPES)buff[3];
+    buff+= 4;
+    switch (type) {
+    case CREATE_OPTION_FIELD:
+      index= uint2korr(buff);
+      buff+= 2;
+      *(opt->field_opt[index].last)= option;
+      opt->field_opt[index].last= &option->next;
+      break;
+    case CREATE_OPTION_KEY:
+      index= uint2korr(buff);
+      buff+= 2;
+      *(opt->key_opt[index].last)= option;
+      opt->key_opt[index].last= &option->next;
+      break;
+    case CREATE_OPTION_TABLE:
+      /* table */
+      *(opt->table_opt.last)= option;
+      opt->table_opt.last= &option->next;
+      break;
+    default:
+      DBUG_ASSERT(0);
+    }
+    if (!(option->key.str= strmake_root(root, (const char*)buff,
+                                        option->key.length)))
+      DBUG_RETURN(TRUE);
+    buff+= option->key.length;
+    if (!(option->val.str= strmake_root(root, (const char*)buff,
+                                        option->val.length)))
+      DBUG_RETURN(TRUE);
+    buff+= option->val.length;
+    option->used= FALSE;
+    option->owner= NULL;
+    DBUG_PRINT("info", ("type: %u index: %u  key: '%s'  value: '%s'",
+			(uint) type, (uint) index,
+                        option->key.str, option->val.str));
+  }
+  DBUG_RETURN(FALSE);
+}
+
+/**
+  Calculates length of saved image of the option lists
+
+  @param opt             list of options
+  @param extra_length    type of the record
+
+  @return length
+*/
+
+static ulong create_options_list_length(CREATE_OPTION_LIST *opts, int extra_length)
+{
+  CREATE_OPTION *opt;
+  ulong res= 0;
+  DBUG_ENTER("create_options_list_length");
+  for (opt= opts->first; opt != NULL; opt= opt->next)
+  {
+    DBUG_PRINT("info", ("key: '%s'  value: '%s'",
+			(opt->key.str ? opt->key.str : "<NULL>"),
+			(opt->val.str ? opt->val.str : "<NULL>")));
+    DBUG_ASSERT(opt->key.length);
+    /*
+      length of disk for every record:
+      2 bytes - value length
+      1 byte  - key length
+      1 byte  - record type
+      0/2 bytes - none/key number/field number
+    */
+    res+= 2 + 1 + 1 + extra_length + opt->key.length + opt->val.length;
+  }
+  DBUG_RETURN(res);
+}
+
+/**
+  Calculates length of saved image of the all options of the table
+
+  @param opts            table of options
+
+  @return length
+*/
+
+ulong create_options_length(TABLE_OPTIONS *opt)
+{
+  CREATE_OPTION_LIST *opts;
+  ulong res;
+  DBUG_ENTER("create_options_length");
+
+  res=
+    (opt->table_opt.first ?
+     create_options_list_length(&opt->table_opt,
+                                create_options_len[CREATE_OPTION_TABLE]):
+     0);
+  if (opt->field_opt)
+  {
+    for (opts= opt->field_opt; !opts->last_opt(); opts++)
+      res+=
+        create_options_list_length(opts,
+                                   create_options_len[CREATE_OPTION_FIELD]);
+  }
+  if (opt->key_opt)
+  {
+    for (opts= opt->key_opt; !opts->last_opt(); opts++)
+      res+=
+        create_options_list_length(opts,
+                                   create_options_len[CREATE_OPTION_KEY]);
+  }
+  DBUG_RETURN(res);
+}
+
+
+/**
+  Writes list of options of given type and index to the given file
+
+  @param buff            buffer for storing options
+  @param opts            list of options
+  @param record_type     type of options (table, field, key)
+  @param index           index of option (used by fields and keys)
+
+  @return pointer on next byte after written ones
+*/
+
+static uchar *create_options_list_store(uchar *buff, CREATE_OPTION_LIST *opts,
+                                         CREATE_OPTION_TYPES record_type,
+                                         uint index)
+{
+  CREATE_OPTION *opt;
+  DBUG_ENTER("create_options_list_store");
+
+  for (opt= opts->first; opt != NULL; opt= opt->next)
+  {
+    DBUG_PRINT("info", ("type: %u index: %u  key: '%s'  value: '%s'",
+			(uint) record_type, (uint) index,
+                        opt->key.str, opt->val.str));
+    int2store(buff, opt->val.length);
+    buff[2]= opt->key.length;
+    buff[3]= record_type;
+    buff+= 4;
+    switch (record_type) {
+    case CREATE_OPTION_FIELD:
+    case CREATE_OPTION_KEY:
+      DBUG_ASSERT(index <= 0xffff);
+      int2store(buff, index);
+      buff+= 2;
+      break;
+    case CREATE_OPTION_TABLE:
+      break;
+    default:
+      DBUG_ASSERT(0); /* impossible */
+    }
+    memcpy(buff, opt->key.str, opt->key.length);
+    buff+= opt->key.length;
+    memcpy(buff, opt->val.str, opt->val.length);
+    buff+= opt->val.length;
+  }
+  DBUG_RETURN(buff);
+}
+
+
+/**
+  Writes options of the table to the given buffer
+
+  @param buff            buffer for storing options
+  @param opt             table options structure
+*/
+
+void create_options_store(uchar *buff, TABLE_OPTIONS *opt)
+{
+  CREATE_OPTION_LIST *opts;
+  uint index;
+  DBUG_ENTER("create_options_store");
+  if (opt->table_opt.first)
+    buff= create_options_list_store(buff, &opt->table_opt,
+                                    CREATE_OPTION_TABLE, 0 /*not used here*/);
+  if (opt->field_opt)
+  {
+    for (opts= opt->field_opt, index= 0; !opts->last_opt(); opts++, index++)
+      buff= create_options_list_store(buff, opts, CREATE_OPTION_FIELD, index);
+  }
+  if (opt->key_opt)
+  {
+    for (opts= opt->key_opt, index= 0; !opts->last_opt(); opts++, index++)
+      buff= create_options_list_store(buff, opts, CREATE_OPTION_KEY, index);
+  }
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Issue warnings about unused options
+
+  @param thd             thread handler
+  @param options         table options structure
+*/
+
+void create_options_check_unused(THD *thd,
+                                 TABLE_OPTIONS *options)
+{
+  CREATE_OPTION *opt;
+  CREATE_OPTION_LIST *opts;
+  uint index;
+  DBUG_ENTER("create_options_check_unused");
+
+  if (!options)
+    DBUG_VOID_RETURN;
+  /* Check option usage for table */
+  for (opt= options->table_opt.first; opt != NULL; opt= opt->next)
+  {
+    if (!opt->used)
+    {
+      push_warning_printf(thd,
+			  MYSQL_ERROR::WARN_LEVEL_WARN,
+			  WARN_UNUSED_TABLE_OPTION,
+			  ER(WARN_UNUSED_TABLE_OPTION),
+			  (const char *) opt->key.str,
+			  (const char *) opt->val.str);
+
+    }
+  }
+  /* Check option usage for fields */
+  if (options->field_opt)
+  {
+    for (opts= options->field_opt, index= 0;
+         !opts->last_opt();
+         opts++, index++)
+    {
+      for (opt= opts->first; opt != NULL; opt= opt->next)
+      {
+        if (!opt->used)
+        {
+          Field *field= (Field *) opt->owner;
+          push_warning_printf(thd,
+                              MYSQL_ERROR::WARN_LEVEL_WARN,
+                              WARN_UNUSED_FIELD_OPTION,
+                              ER(WARN_UNUSED_FIELD_OPTION),
+                              (const char *) opt->key.str,
+                              (const char *) opt->val.str,
+                              field->field_name);
+
+        }
+      }
+    }
+  }
+  /* Check option usage for keys */
+  if (options->key_opt)
+  {
+    for (opts= options->key_opt, index= 0;
+         !opts->last_opt();
+         opts++, index++)
+    {
+      for (opt= opts->first; opt != NULL; opt= opt->next)
+      {
+        if (!opt->used)
+        {
+          KEY *key= (KEY *) opt->owner;
+          push_warning_printf(thd,
+                              MYSQL_ERROR::WARN_LEVEL_WARN,
+                              WARN_UNUSED_KEY_OPTION,
+                              ER(WARN_UNUSED_KEY_OPTION),
+                              (const char *) opt->key.str,
+                              (const char *) opt->val.str,
+                              key->name);
+
+        }
+      }
+    }
+  }
+
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Adds references from Fields and KEYs objects to options
+
+  @param share           TABLE_SHARE object.
+*/
+
+void create_options_binding(TABLE_SHARE *share)
+{
+  TABLE_OPTIONS *options= share->create_table_options;
+  CREATE_OPTION *opt;
+  CREATE_OPTION_LIST *opts;
+  Field **fld;
+  KEY *keyinfo;
+  DBUG_ENTER("create_options_binding");
+
+  if (!options)
+    DBUG_VOID_RETURN;
+
+  if (options->field_opt)
+  {
+    for (opts= options->field_opt, fld= share->field;
+         !opts->last_opt();
+         opts++, fld++)
+    {
+      (*fld)->create_options= *opts;
+      for (opt= opts->first; opt != NULL; opt= opt->next)
+      {
+        opt->owner= (void *)(*fld);
+        DBUG_PRINT("info", ("key: '%s'  value: '%s'  field: '%s'",
+                            opt->key.str, opt->val.str, (*fld)->field_name));
+
+      }
+    }
+  }
+  if (options->key_opt)
+  {
+    for (opts= options->key_opt, keyinfo= share->key_info;
+         !opts->last_opt();
+         opts++, keyinfo++)
+    {
+      keyinfo->create_options= *opts;
+      for (opt= opts->first; opt != NULL; opt= opt->next)
+      {
+        opt->owner= (void *)keyinfo;
+        DBUG_PRINT("info", ("key: '%s'  value: '%s'  key: '%s'",
+                            opt->key.str, opt->val.str, keyinfo->name));
+      }
+    }
+  }
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  clones options
+
+  @param root            mem_root where to clone the options
+  @param opt             options list to clone
+
+  @retval FALSE OK
+  @retval TRUE  Error
+*/
+
+my_bool create_options_clone(MEM_ROOT *root, CREATE_OPTION_LIST *opts)
+{
+  CREATE_OPTION *opt;
+  CREATE_OPTION *clone;
+  char *key, *val;
+  DBUG_ENTER("create_options_clone");
+
+  opt= opts->first;
+  opts->empty();
+
+  if (opt == NULL)
+    DBUG_RETURN(FALSE);
+
+  for (; opt != NULL; opt= opt->next)
+  {
+    if (!multi_alloc_root(root, &clone, sizeof(CREATE_OPTION),
+                          &key, opt->key.length + 1,
+                          &val, opt->val.length + 1, NULL))
+      DBUG_RETURN(TRUE);
+    clone->key.str= (char *)memcpy(key, opt->key.str,
+                                   (clone->key.length= opt->key.length) + 1);
+    clone->val.str= (char *)memcpy(val, opt->val.str,
+                                   (clone->val.length= opt->val.length) + 1);
+    clone->used= opt->used;
+    clone->owner= opt->owner;
+
+    *opts->last= clone;
+    opts->last= &clone->next;
+  }
+  clone->next= NULL;
+
+  DBUG_RETURN(FALSE);
+}
+
+
+/**
+  Merges source and changes lists checking for real changes
+
+  @param source          source list to merge
+  @param changes         changes in the list
+  @param root            memroot to allocate option
+  @param changed         pointer to variable to report changed data or NULL
+
+  @return merged list
+*/
+
+CREATE_OPTION_LIST *create_table_list_merge(CREATE_OPTION_LIST *source,
+                                            CREATE_OPTION_LIST *changes,
+                                            MEM_ROOT *root,
+                                            my_bool *changed)
+{
+  CREATE_OPTION *opt;
+  my_bool unused;
+  DBUG_ENTER("create_table_list_merge");
+  if (!changed)
+    changed= &unused;
+
+  for (opt= changes->first; opt; opt= opt->next)
+  {
+    if (create_option_add(source, root, &opt->key, &opt->val,
+                          changed))
+      DBUG_RETURN(NULL);
+  }
+
+  DBUG_RETURN(source);
+}
+
+
+/**
+  Compare 2 option lists
+
+  @param opt1            first options list
+  @param opt2            second options list
+
+  @retval TRUE  lists are equal
+  @retval FALSE lists are different
+*/
+
+my_bool is_equal_create_options(CREATE_OPTION *opt1, CREATE_OPTION *opt2)
+{
+  uint n1= 0, n2= 0;
+  CREATE_OPTION *i, *j;
+  DBUG_ENTER("is_equal_create_options");
+
+  /* check length first */
+  for (i= opt1; i; i= i->next) n1++;
+  for (i= opt2; i; i= i->next) n2++;
+
+  if (n1 != n2)
+  {
+    DBUG_PRINT("info", ("length mismatch (%u != %u)", n1, n2));
+    DBUG_RETURN(FALSE);
+  }
+  for (i= opt1; i; i= i->next)
+  {
+    for (j= opt2;
+         j && my_strcasecmp(system_charset_info,
+                            i->key.str, j->key.str);
+         j= j->next) ;
+    if (!j)
+    {
+      DBUG_PRINT("info", ("Key '%s' not found in second list", i->key.str));
+      DBUG_RETURN(FALSE);
+    }
+    if (i->val.length != j->val.length ||
+        memcmp(i->val.str, j->val.str, i->val.length))
+    {
+      DBUG_PRINT("info", ("Values of key '%s' mismatch ('%s' != '%s')",
+                          i->key.str, i->val.str, j->val.str));
+      DBUG_RETURN(FALSE);
+    }
+  }
+  DBUG_RETURN(TRUE);
+}

=== added file 'sql/sql_create_options.h'
--- sql/sql_create_options.h	1970-01-01 00:00:00 +0000
+++ sql/sql_create_options.h	2010-02-05 11:17:48 +0000
@@ -0,0 +1,102 @@
+
+#ifndef _SQL_CREATE_OPTIONS_H
+#define _SQL_CREATE_OPTIONS_H
+
+
+/* types of cretate options records on disk, also it is length of extra data */
+typedef enum enum_create_options_type {
+  CREATE_OPTION_TABLE= 0,
+  CREATE_OPTION_KEY= 1,
+  CREATE_OPTION_FIELD= 2
+} CREATE_OPTION_TYPES;
+
+typedef struct st_create_option {
+  /* pointer to the next option or NULL */
+  struct st_create_option *next;
+  /* pointer to Field or KEY or NULL */
+  void *owner;
+  /* key and value of the option (\0 terminated)*/
+  LEX_STRING key, val;
+  /* used to issue warnings about unused options */
+  my_bool used;
+} CREATE_OPTION;
+
+struct st_table_options;
+
+
+class st_create_option_list {
+public:
+  /**
+    pointer on the first list element
+  */
+  CREATE_OPTION *first;
+  /**
+    pointer on last list '.next' or beginning of the list in case of empty list
+
+    @note:
+    If it is NULL then it is just sign of array of list end
+  */
+private:
+  CREATE_OPTION **last;
+public:
+  void empty() {first= NULL; last= &first;}
+  st_create_option_list() {empty();}
+  st_create_option_list(const st_create_option_list &o)
+  {
+    if ((first= o.first))
+      last= o.last;
+    else
+      last= &first;
+  }
+  my_bool last_opt() { return last == NULL; }
+  friend my_bool create_option_add(st_create_option_list *options,
+                                   MEM_ROOT *root,
+                                   const LEX_STRING *str_key,
+                                   const LEX_STRING *str_val,
+                                   my_bool *changed);
+  friend st_create_option_list *create_create_options_array(MEM_ROOT *root,
+                                                            uint n);
+  friend my_bool create_options_read(const uchar *buff, uint length,
+                                     MEM_ROOT *root,
+                                     st_table_options *opt);
+  friend my_bool create_options_clone(MEM_ROOT *root,
+                                       st_create_option_list *opts);
+};
+typedef class st_create_option_list CREATE_OPTION_LIST;
+
+
+typedef struct st_table_options {
+  CREATE_OPTION_LIST table_opt;  /* table options list */
+  CREATE_OPTION_LIST *field_opt; /* fields options array */
+  CREATE_OPTION_LIST *key_opt;   /* keys options array */
+} TABLE_OPTIONS;
+
+CREATE_OPTION_LIST *create_create_options_array(MEM_ROOT *root, uint n);
+TABLE_OPTIONS *create_create_options(MEM_ROOT *root, uint fields, uint keys);
+
+my_bool create_options_read(const uchar *buff, uint length, MEM_ROOT *root,
+                            TABLE_OPTIONS *opt);
+
+my_bool create_option_add(CREATE_OPTION_LIST *options, MEM_ROOT *root,
+                          const LEX_STRING *k, const LEX_STRING *v,
+                          my_bool *chanes);
+
+ulong create_options_length(TABLE_OPTIONS *opt);
+
+void create_options_store(uchar *buff, TABLE_OPTIONS *opt);
+
+void create_options_check_unused(THD *thd,
+                                 TABLE_OPTIONS *options);
+
+struct st_table_share;
+void create_options_binding(struct st_table_share *share);
+
+my_bool create_options_clone(MEM_ROOT *root, CREATE_OPTION_LIST *opt);
+
+CREATE_OPTION_LIST *create_table_list_merge(CREATE_OPTION_LIST *source,
+                                            CREATE_OPTION_LIST *changes,
+                                            MEM_ROOT *root,
+                                            my_bool *changed);
+my_bool is_equal_create_options(CREATE_OPTION *opt1, CREATE_OPTION *opt2);
+
+#endif

=== modified file 'sql/sql_lex.h'
--- sql/sql_lex.h	2010-01-04 17:54:42 +0000
+++ sql/sql_lex.h	2010-02-05 09:42:27 +0000
@@ -869,6 +869,7 @@
 #define ALTER_ALL_PARTITION      (1L << 21)
 #define ALTER_REMOVE_PARTITIONING (1L << 22)
 #define ALTER_FOREIGN_KEY        (1L << 23)
+#define ALTER_CREATE_OPT         (1L << 24)
 
 enum enum_alter_table_change_level
 {
@@ -1747,6 +1748,11 @@
   const char *stmt_definition_end;
 
   /**
+    Collects create options for Field and KEY
+  */
+  CREATE_OPTION_LIST create_opt;
+
+  /**
     During name resolution search only in the table list given by 
     Name_resolution_context::first_name_resolution_table and
     Name_resolution_context::last_name_resolution_table

=== modified file 'sql/sql_parse.cc'
--- sql/sql_parse.cc	2010-02-01 06:14:12 +0000
+++ sql/sql_parse.cc	2010-02-05 09:42:27 +0000
@@ -6153,7 +6153,8 @@
 		       char *change,
                        List<String> *interval_list, CHARSET_INFO *cs,
 		       uint uint_geom_type,
-		       Virtual_column_info *vcol_info)
+		       Virtual_column_info *vcol_info,
+                       CREATE_OPTION_LIST *create_options)
 {
   register Create_field *new_field;
   LEX  *lex= thd->lex;
@@ -6171,7 +6172,7 @@
     lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
     key= new Key(Key::PRIMARY, NullS,
                       &default_key_create_info,
-                      0, lex->col_list);
+                      0, lex->col_list, NULL);
     lex->alter_info.key_list.push_back(key);
     lex->col_list.empty();
   }
@@ -6181,7 +6182,7 @@
     lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
     key= new Key(Key::UNIQUE, NullS,
                  &default_key_create_info, 0,
-                 lex->col_list);
+                 lex->col_list, NULL);
     lex->alter_info.key_list.push_back(key);
     lex->col_list.empty();
   }
@@ -6239,7 +6240,8 @@
   if (!(new_field= new Create_field()) ||
       new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
                       default_value, on_update_value, comment, change,
-                      interval_list, cs, uint_geom_type, vcol_info))
+                      interval_list, cs, uint_geom_type, vcol_info,
+                      create_options))
     DBUG_RETURN(1);
 
   lex->alter_info.create_list.push_back(new_field);

=== modified file 'sql/sql_show.cc'
--- sql/sql_show.cc	2010-02-01 06:14:12 +0000
+++ sql/sql_show.cc	2010-02-05 09:42:27 +0000
@@ -1174,6 +1174,26 @@
   return has_default;
 }
 
+
+/**
+  Appends list of options to string
+
+  @param thd             thread handler
+  @param packet          string to append
+  @param opt             list of options
+*/
+
+static void append_create_options(THD *thd, String *packet, CREATE_OPTION *opt)
+{
+  for(; opt; opt= opt->next)
+  {
+    packet->append(' ');
+    append_identifier(thd, packet, opt->key.str, opt->key.length);
+    packet->append('=');
+    append_unescaped(packet, opt->val.str, opt->val.length);
+  }
+}
+
 /*
   Build a CREATE TABLE statement for a table.
 
@@ -1356,6 +1376,8 @@
       packet->append(STRING_WITH_LEN(" COMMENT "));
       append_unescaped(packet, field->comment.str, field->comment.length);
     }
+    if (field->create_options.first)
+      append_create_options(thd, packet, field->create_options.first);
   }
 
   key_info= table->key_info;
@@ -1427,6 +1449,8 @@
       append_identifier(thd, packet, parser_name->str, parser_name->length);
       packet->append(STRING_WITH_LEN(" */ "));
     }
+    if (key_info->create_options.first)
+      append_create_options(thd, packet, key_info->create_options.first);
   }
 
   /*
@@ -1586,6 +1610,11 @@
       packet->append(STRING_WITH_LEN(" CONNECTION="));
       append_unescaped(packet, share->connect_string.str, share->connect_string.length);
     }
+    /* create_table_options can be NULL for temporary tables */
+    if (share->create_table_options &&
+        share->create_table_options->table_opt.first)
+      append_create_options(thd, packet,
+                            share->create_table_options->table_opt.first);
     append_directory(thd, packet, "DATA",  create_info.data_file_name);
     append_directory(thd, packet, "INDEX", create_info.index_file_name);
   }

=== modified file 'sql/sql_table.cc'
--- sql/sql_table.cc	2010-02-01 06:14:12 +0000
+++ sql/sql_table.cc	2010-02-05 11:04:23 +0000
@@ -3040,6 +3040,7 @@
     key_info->key_part=key_part_info;
     key_info->usable_key_parts= key_number;
     key_info->algorithm= key->key_create_info.algorithm;
+    key_info->create_options= key->create_options;
 
     if (key->type == Key::FULLTEXT)
     {
@@ -5732,7 +5733,8 @@
       create_info->used_fields & HA_CREATE_USED_TRANSACTIONAL ||
       create_info->used_fields & HA_CREATE_USED_PACK_KEYS ||
       create_info->used_fields & HA_CREATE_USED_MAX_ROWS ||
-      (alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
+      (alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY |
+                            ALTER_CREATE_OPT)) ||
       order_num ||
       !table->s->mysql_version ||
       (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
@@ -5785,6 +5787,15 @@
       DBUG_RETURN(0);
     }
 
+    if (!is_equal_create_options(tmp_new_field->create_options.first,
+                                 field->create_options.first))
+    {
+      DBUG_PRINT("info", ("Options difference in field '%s'",
+                          new_field->field_name));
+      *need_copy_table= ALTER_TABLE_DATA_CHANGED;
+      DBUG_RETURN(0);
+    }
+
     /* Don't pack rows in old tables if the user has requested this. */
       if (create_info->row_type == ROW_TYPE_DYNAMIC ||
           (tmp_new_field->flags & BLOB_FLAG) ||
@@ -5869,7 +5880,9 @@
     if ((table_key->algorithm != new_key->algorithm) ||
 	((table_key->flags & HA_KEYFLAG_MASK) !=
          (new_key->flags & HA_KEYFLAG_MASK)) ||
-        (table_key->key_parts != new_key->key_parts))
+        (table_key->key_parts != new_key->key_parts) ||
+        !is_equal_create_options(table_key->create_options.first,
+                                 new_key->create_options.first))
       goto index_changed;
 
     /*
@@ -6108,6 +6121,41 @@
   }
   restore_record(table, s->default_values);     // Empty record for DEFAULT
 
+  if (create_info->create_table_options_orig.table_opt.first)
+  {
+    CREATE_OPTION_LIST *res;
+    my_bool changed= FALSE;
+    if (!table->s->create_table_options &&
+        !(table->s->create_table_options=
+          create_create_options(&table->s->mem_root,
+                                table->s->fields, table->s->keys)))
+      goto err;
+
+    if (!(res=
+          create_table_list_merge(&table->s->create_table_options->table_opt,
+                                  &create_info->
+                                  create_table_options_orig.table_opt,
+                                  thd->mem_root,
+                                  &changed)))
+      goto err;
+    DBUG_ASSERT(res->first);
+    create_info->create_table_options_orig.table_opt= *res;
+
+    if (changed)
+      alter_info->change_level= ALTER_TABLE_DATA_CHANGED;
+    else
+    {
+      alter_info->flags&= ~ALTER_CREATE_OPT;
+      DBUG_PRINT("info", ("Table options was not changed"));
+    }
+  }
+  else
+    if (table->s->create_table_options)
+      create_info->create_table_options_orig.table_opt=
+        table->s->create_table_options->table_opt;
+    else
+      create_info->create_table_options_orig.table_opt.empty();
+
   /*
     First collect all fields from table which isn't in drop_list
   */
@@ -6360,7 +6408,7 @@
       key= new Key(key_type, key_name,
                    &key_create_info,
                    test(key_info->flags & HA_GENERATED_KEY),
-                   key_parts);
+                   key_parts, &key_info->create_options);
       new_key_list.push_back(key);
     }
   }

=== modified file 'sql/sql_yacc.yy'
--- sql/sql_yacc.yy	2010-02-01 06:14:12 +0000
+++ sql/sql_yacc.yy	2010-02-05 10:41:23 +0000
@@ -1276,6 +1276,7 @@
         IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
         NCHAR_STRING opt_component key_cache_name
         sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
+        plugin_option_value
 
 %type <lex_str_ptr>
         opt_table_alias
@@ -1826,6 +1827,7 @@
             lex->create_info.default_table_charset= NULL;
             lex->name.str= 0;
             lex->name.length= 0;
+            lex->create_info.create_table_options_orig.table_opt.empty();
           }
           create2
           {
@@ -1854,6 +1856,7 @@
             lex->alter_info.flags= ALTER_ADD_INDEX;
             lex->col_list.empty();
             lex->change=NullS;
+            lex->create_opt.empty();
           }
           '(' key_list ')' key_options
           {
@@ -1865,7 +1868,7 @@
               MYSQL_YYABORT;
             }
             key= new Key($2, $4.str, &lex->key_create_info, 0,
-                         lex->col_list);
+                         lex->col_list, &lex->create_opt);
             if (key == NULL)
               MYSQL_YYABORT;
             lex->alter_info.key_list.push_back(key);
@@ -2306,6 +2309,7 @@
 
             lex->interval_list.empty();
             lex->uint_geom_type= 0;
+            lex->create_opt.empty();
           }
         ;
 
@@ -4714,6 +4718,16 @@
 	    Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL;
             Lex->create_info.transactional= $3;
           }
+        | IDENT_sys equal plugin_option_value
+          {
+            LEX *lex= Lex;
+            create_option_add(&(lex->
+                                create_info.
+                                create_table_options_orig.table_opt),
+                              YYTHD->mem_root, &$1, &$3,
+                              NULL);
+            lex->alter_info.flags|= ALTER_CREATE_OPT;
+          }
         ;
 
 default_charset:
@@ -4835,7 +4849,11 @@
         ;
 
 key_def:
-          key_type opt_ident key_alg '(' key_list ')' key_options
+          key_type opt_ident key_alg '(' key_list ')'
+          {
+            Lex->create_opt.empty();
+          }
+          key_options
           {
             LEX *lex=Lex;
             if ($1 != Key::FULLTEXT && lex->key_create_info.parser_name.str)
@@ -4844,19 +4862,23 @@
               MYSQL_YYABORT;
             }
             Key *key= new Key($1, $2, &lex->key_create_info, 0,
-                              lex->col_list);
+                              lex->col_list, &lex->create_opt);
             if (key == NULL)
               MYSQL_YYABORT;
             lex->alter_info.key_list.push_back(key);
             lex->col_list.empty(); /* Alloced by sql_alloc */
           }
         | opt_constraint constraint_key_type opt_ident key_alg
-          '(' key_list ')' key_options
+          '(' key_list ')'
+          {
+            Lex->create_opt.empty();
+          }
+          key_options
           {
             LEX *lex=Lex;
             const char *key_name= $3 ? $3 : $1;
             Key *key= new Key($2, key_name, &lex->key_create_info, 0,
-                              lex->col_list);
+                              lex->col_list, &lex->create_opt);
             if (key == NULL)
               MYSQL_YYABORT;
             lex->alter_info.key_list.push_back(key);
@@ -4878,7 +4900,7 @@
             lex->alter_info.key_list.push_back(key);
             key= new Key(Key::MULTIPLE, key_name,
                          &default_key_create_info, 1,
-                         lex->col_list);
+                         lex->col_list, NULL);
             if (key == NULL)
               MYSQL_YYABORT;
             lex->alter_info.key_list.push_back(key);
@@ -4924,6 +4946,7 @@
             lex->comment=null_lex_str;
             lex->charset=NULL;
 	    lex->vcol_info= 0;
+            lex->create_opt.empty();
           }
           field_def
           {
@@ -4934,7 +4957,7 @@
                                   &lex->comment,
                                   lex->change,&lex->interval_list,lex->charset,
                                   lex->uint_geom_type,
-                                  lex->vcol_info))
+                                  lex->vcol_info, &lex->create_opt))
               MYSQL_YYABORT;
           }
         ;
@@ -5354,6 +5377,13 @@
               Lex->charset=$2;
             }
           }
+        | IDENT_sys equal plugin_option_value
+          {
+            create_option_add(&(Lex->create_opt),
+                              YYTHD->mem_root, &$1, &$3,
+                              NULL);
+          }
+
         ;
 
 now_or_signed_literal:
@@ -5639,6 +5669,13 @@
               MYSQL_YYABORT;
             }
           }
+        | IDENT_sys equal plugin_option_value
+          {
+            my_bool unused;
+            create_option_add(&(Lex->create_opt),
+                              YYTHD->mem_root, &$1, &$3,
+                              &unused);
+          }
         ;
 
 btree_or_rtree:
@@ -6105,6 +6142,7 @@
             LEX *lex=Lex;
             lex->change= $3.str;
             lex->alter_info.flags|= ALTER_CHANGE_COLUMN;
+            lex->create_opt.empty();
           }
           field_spec opt_place
         | MODIFY_SYM opt_column field_ident
@@ -6116,6 +6154,7 @@
             lex->charset= NULL;
             lex->alter_info.flags|= ALTER_CHANGE_COLUMN;
 	    lex->vcol_info= 0;
+            lex->create_opt.empty();
           }
           field_def
           {
@@ -6127,7 +6166,7 @@
                                   &lex->comment,
                                   $3.str, &lex->interval_list, lex->charset,
                                   lex->uint_geom_type,
-                                  lex->vcol_info))
+                                  lex->vcol_info, &lex->create_opt))
               MYSQL_YYABORT;
           }
           opt_place
@@ -13577,6 +13616,7 @@
             lex->interval_list.empty();
             lex->type= 0;
             lex->vcol_info= 0;
+            lex->create_opt.empty();
           }
           type /* $11 */
           { /* $12 */
@@ -13827,6 +13867,32 @@
           }
         ;
 
+/**************************************************************************
+
+ Create options
+
+**************************************************************************/
+
+plugin_option_value:
+  DEFAULT
+    {
+      $$.str= NULL; /* We are going to remove the option */
+      $$.length= 0;
+    }
+  | NULL_SYM
+    {
+      $$.str= NULL; /* We are going to remove the option */
+      $$.length= 0;
+    }
+  | IDENT_sys { $$ = $1; }
+  | TEXT_STRING_sys { $$ = $1; }
+  | DECIMAL_NUM { $$ = $1; }
+  | FLOAT_NUM { $$ = $1; }
+  | NUM { $$ = $1; }
+  | LONG_NUM { $$ = $1; }
+  | HEX_NUM { $$ = $1; }
+
+
 /**
   @} (end of group Parser)
 */

=== modified file 'sql/structs.h'
--- sql/structs.h	2010-02-01 06:14:12 +0000
+++ sql/structs.h	2010-02-05 09:42:27 +0000
@@ -101,6 +101,8 @@
     int  bdb_return_if_eq;
   } handler;
   struct st_table *table;
+  /** reference to the list of options or NULL */
+  CREATE_OPTION_LIST create_options;
 } KEY;
 
 

=== modified file 'sql/table.cc'
--- sql/table.cc	2010-02-01 06:14:12 +0000
+++ sql/table.cc	2010-02-05 09:42:27 +0000
@@ -670,12 +670,13 @@
   uint db_create_options, keys, key_parts, n_length;
   uint key_info_length, com_length, null_bit_pos;
   uint vcol_screen_length;
-  uint extra_rec_buf_length;
+  uint extra_rec_buf_length, options_len;
   uint i,j;
   bool use_hash;
   char *keynames, *names, *comment_pos, *vcol_screen_pos;
   uchar *record;
-  uchar *disk_buff, *strpos, *null_flags, *null_pos;
+  uchar *disk_buff, *strpos, *null_flags, *null_pos, *options;
+  uchar *buff= 0;
   ulong pos, record_offset, *rec_per_key, rec_buff_length;
   handler *handler_file= 0;
   KEY	*keyinfo;
@@ -791,7 +792,6 @@
 
   for (i=0 ; i < keys ; i++, keyinfo++)
   {
-    keyinfo->table= 0;                           // Updated in open_frm
     if (new_frm_ver >= 3)
     {
       keyinfo->flags=	   (uint) uint2korr(strpos) ^ HA_NOSAME;
@@ -861,15 +861,14 @@
   if ((n_length= uint4korr(head+55)))
   {
     /* Read extra data segment */
-    uchar *buff, *next_chunk, *buff_end;
+    uchar *next_chunk, *buff_end;
     DBUG_PRINT("info", ("extra segment size is %u bytes", n_length));
     if (!(next_chunk= buff= (uchar*) my_malloc(n_length, MYF(MY_WME))))
       goto err;
     if (my_pread(file, buff, n_length, record_offset + share->reclength,
                  MYF(MY_NABP)))
     {
-      my_free(buff, MYF(0));
-      goto err;
+      goto free_and_err;
     }
     share->connect_string.length= uint2korr(buff);
     if (!(share->connect_string.str= strmake_root(&share->mem_root,
@@ -877,8 +876,7 @@
                                                   share->connect_string.
                                                   length)))
     {
-      my_free(buff, MYF(0));
-      goto err;
+      goto free_and_err;
     }
     next_chunk+= share->connect_string.length + 2;
     buff_end= buff + n_length;
@@ -898,8 +896,7 @@
                 plugin_data(tmp_plugin, handlerton *)))
         {
           /* bad file, legacy_db_type did not match the name */
-          my_free(buff, MYF(0));
-          goto err;
+          goto free_and_err;
         }
         /*
           tmp_plugin is locked with a local lock.
@@ -928,8 +925,7 @@
           error= 8;
           my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
                    "--skip-partition");
-          my_free(buff, MYF(0));
-          goto err;
+          goto free_and_err;
         }
         plugin_unlock(NULL, share->db_plugin);
         share->db_plugin= ha_lock_engine(NULL, partition_hton);
@@ -943,8 +939,7 @@
         /* purecov: begin inspected */
         error= 8;
         my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), name.str);
-        my_free(buff, MYF(0));
-        goto err;
+        goto free_and_err;
         /* purecov: end */
       }
       next_chunk+= str_db_type_length + 2;
@@ -960,16 +955,14 @@
               memdup_root(&share->mem_root, next_chunk + 4,
                           partition_info_len + 1)))
         {
-          my_free(buff, MYF(0));
-          goto err;
+          goto free_and_err;
         }
       }
 #else
       if (partition_info_len)
       {
         DBUG_PRINT("info", ("WITH_PARTITION_STORAGE_ENGINE is not defined"));
-        my_free(buff, MYF(0));
-        goto err;
+        goto free_and_err;
       }
 #endif
       next_chunk+= 5 + partition_info_len;
@@ -995,6 +988,17 @@
 #endif
       next_chunk++;
     }
+    if (share->db_create_options & HA_OPTION_TEXT_CREATE_OPTIONS)
+    {
+      /*
+        store options position, but skip till the time we will
+        know number of fields
+      */
+      options_len= uint4korr(next_chunk);
+      options= next_chunk + 4;
+      next_chunk+= options_len;
+      options_len-= 4;
+    }
     keyinfo= share->key_info;
     for (i= 0; i < keys; i++, keyinfo++)
     {
@@ -1005,8 +1009,7 @@
         {
           DBUG_PRINT("error",
                      ("fulltext key uses parser that is not defined in .frm"));
-          my_free(buff, MYF(0));
-          goto err;
+          goto free_and_err;
         }
         parser_name.str= (char*) next_chunk;
         parser_name.length= strlen((char*) next_chunk);
@@ -1016,12 +1019,10 @@
         if (! keyinfo->parser)
         {
           my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), parser_name.str);
-          my_free(buff, MYF(0));
-          goto err;
+          goto free_and_err;
         }
       }
     }
-    my_free(buff, MYF(0));
   }
   share->key_block_size= uint2korr(head+62);
 
@@ -1031,21 +1032,21 @@
   share->rec_buff_length= rec_buff_length;
   if (!(record= (uchar *) alloc_root(&share->mem_root,
                                      rec_buff_length)))
-    goto err;                                   /* purecov: inspected */
+    goto free_and_err;                          /* purecov: inspected */
   share->default_values= record;
   if (my_pread(file, record, (size_t) share->reclength,
                record_offset, MYF(MY_NABP)))
-    goto err;                                   /* purecov: inspected */
+    goto free_and_err;                          /* purecov: inspected */
 
   VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
   if (my_read(file, head,288,MYF(MY_NABP)))
-    goto err;
+    goto free_and_err;
 #ifdef HAVE_CRYPTED_FRM
   if (crypted)
   {
     crypted->decode((char*) head+256,288-256);
     if (sint2korr(head+284) != 0)		// Should be 0
-      goto err;                                 // Wrong password
+      goto free_and_err;                        // Wrong password
   }
 #endif
 
@@ -1065,6 +1066,20 @@
                                    share->comment.length);
 
   DBUG_PRINT("info",("i_count: %d  i_parts: %d  index: %d  n_length: %d  int_length: %d  com_length: %d  vcol_screen_length: %d", interval_count,interval_parts, share->keys,n_length,int_length, com_length, vcol_screen_length));
+
+  if (share->db_create_options & HA_OPTION_TEXT_CREATE_OPTIONS)
+  {
+    if (!(share->create_table_options=
+          create_create_options(&share->mem_root, share->fields, keys)) ||
+        create_options_read(options, options_len, &share->mem_root,
+                            share->create_table_options))
+    {
+      goto free_and_err;
+    }
+  }
+  my_free(buff, MYF(MY_ALLOW_ZERO_PTR));
+
+
   if (!(field_ptr = (Field **)
 	alloc_root(&share->mem_root,
 		   (uint) ((share->fields+1)*sizeof(Field*)+
@@ -1681,6 +1696,8 @@
   bitmap_init(&share->all_set, bitmaps, share->fields, FALSE);
   bitmap_set_all(&share->all_set);
 
+  create_options_binding(share);
+
   delete handler_file;
 #ifndef DBUG_OFF
   if (use_hash)
@@ -1688,6 +1705,8 @@
 #endif
   DBUG_RETURN (0);
 
+ free_and_err:
+  my_free(buff, MYF(MY_ALLOW_ZERO_PTR));
  err:
   share->error= error;
   share->open_errno= my_errno;
@@ -2880,6 +2899,7 @@
   ulong length;
   uchar fill[IO_SIZE];
   int create_flags= O_RDWR | O_TRUNC;
+  DBUG_ENTER("create_frm");
 
   if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
     create_flags|= O_EXCL | O_NOFOLLOW;
@@ -2961,7 +2981,7 @@
       {
 	VOID(my_close(file,MYF(0)));
 	VOID(my_delete(name,MYF(0)));
-	return(-1);
+	DBUG_RETURN(-1);
       }
     }
   }
@@ -2972,7 +2992,7 @@
     else
       my_error(ER_CANT_CREATE_TABLE,MYF(0),table,my_errno);
   }
-  return (file);
+  DBUG_RETURN(file);
 } /* create_frm */
 
 

=== modified file 'sql/table.h'
--- sql/table.h	2010-02-01 06:14:12 +0000
+++ sql/table.h	2010-02-05 09:42:27 +0000
@@ -340,6 +340,7 @@
 #ifdef NOT_YET
   struct st_table *open_tables;		/* link to open tables */
 #endif
+  TABLE_OPTIONS *create_table_options;  /* text options for table */
 
   /* The following is copied to each TABLE on OPEN */
   Field **field;

=== modified file 'sql/unireg.cc'
--- sql/unireg.cc	2010-01-04 17:54:42 +0000
+++ sql/unireg.cc	2010-02-05 10:43:05 +0000
@@ -75,6 +75,94 @@
   return is_handled;
 }
 
+
+/**
+  Collects information about fields text create options into one array
+
+  @param thd                  Thread handler
+  @param create_fields        List of fields
+  @param create_table_options Table create options information
+                              structure to store result in it
+
+  @retval FALSE OK
+  @retval TRUE  Error
+*/
+
+static my_bool
+collect_fields_create_options(THD *thd, List<Create_field> &create_fields,
+                              TABLE_OPTIONS *create_table_options)
+{
+  List_iterator<Create_field> it(create_fields);
+  Create_field *field;
+  uint index;
+  uint fields= create_fields.elements;
+  bool is_allocated= create_table_options->field_opt;
+  DBUG_ENTER("collect_fields_create_options");
+
+  for (index= 0; (field= it++); index++)
+  {
+    if (field->create_options.first)
+    {
+      if (!is_allocated)
+      {
+        is_allocated= TRUE;
+        if (!(create_table_options->field_opt=
+              create_create_options_array(thd->mem_root,
+                                          fields)))
+        {
+          DBUG_RETURN(TRUE);
+        }
+      }
+      DBUG_ASSERT(field->create_options.first);
+      create_table_options->field_opt[index]= field->create_options;
+    }
+  }
+  DBUG_RETURN(FALSE);
+}
+
+/**
+  Collects information about keys text create options into one array
+
+  @param thd                  Thread handler
+  @param keys                 Number of keys
+  @param key_info             Array of key descriptors
+  @param create_table_options Table create options information
+                              structure to store result in it
+
+  @retval FALSE OK
+  @retval TRUE  Error
+*/
+
+static my_bool
+collect_keys_create_options(THD *thd, uint keys, KEY *key_info,
+                            TABLE_OPTIONS *create_table_options)
+{
+  uint index;
+  bool is_allocated= create_table_options->key_opt;
+  DBUG_ENTER("collect_keys_create_options");
+
+  for (index= 0; index < keys; index++, key_info++)
+  {
+    if (key_info->create_options.first)
+    {
+      if (!is_allocated)
+      {
+        is_allocated= TRUE;
+        if (!(create_table_options->key_opt=
+              create_create_options_array(thd->mem_root,
+                                          keys)))
+        {
+          DBUG_RETURN(TRUE);
+        }
+      }
+      DBUG_ASSERT(key_info->create_options.first);
+      create_table_options->key_opt[index]= key_info->create_options;
+    }
+  }
+  DBUG_RETURN(FALSE);
+}
+
+
 /*
   Create a frm (table definition) file
 
@@ -107,6 +195,7 @@
   ulong key_buff_length;
   File file;
   ulong filepos, data_offset;
+  uint options_len= 0;
   uchar fileinfo[64],forminfo[288],*keybuff;
   TYPELIB formnames;
   uchar *screen_buff;
@@ -124,6 +213,7 @@
     DBUG_RETURN(1);
   DBUG_ASSERT(db_file != NULL);
 
+  create_info->create_table_options= &create_info->create_table_options_orig;
  /* If fixed row records, we need one bit to check for deleted rows */
   if (!(create_info->table_options & HA_OPTION_PACK_RECORD))
     create_info->null_bits++;
@@ -183,6 +273,25 @@
       create_info->extra_size+= key_info[i].parser_name->length + 1;
   }
 
+  if (collect_fields_create_options(thd, create_fields,
+                                    create_info->create_table_options) ||
+      collect_keys_create_options(thd, keys, key_info,
+                                  create_info->create_table_options))
+  {
+    my_free(screen_buff, MYF(0));
+    DBUG_RETURN(1);
+  }
+  if (create_info->create_table_options &&
+      (create_info->create_table_options->table_opt.first ||
+       create_info->create_table_options->field_opt ||
+       create_info->create_table_options->key_opt))
+  {
+    create_info->table_options|= HA_OPTION_TEXT_CREATE_OPTIONS;
+    create_info->extra_size+=
+      (options_len= 4 +
+       create_options_length(create_info->create_table_options));
+  }
+
   if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
 		       create_info, keys)) < 0)
   {
@@ -294,6 +403,22 @@
     if (my_write(file, (uchar*) buff, 6, MYF_RW))
       goto err;
   }
+
+  if (options_len)
+  {
+    uchar *optbuff= (uchar *)my_malloc(options_len, MYF(0));
+    my_bool error;
+    DBUG_PRINT("info", ("Create options length: %u", options_len));
+    if (!optbuff)
+      goto err;
+    int4store(optbuff, options_len);
+    create_options_store(optbuff + 4, create_info->create_table_options);
+    error= my_write(file, optbuff, options_len, MYF_RW);
+    my_free(optbuff, MYF(0));
+    if (error)
+      goto err;
+  }
+
   for (i= 0; i < keys; i++)
   {
     if (key_info[i].parser_name)

=== modified file 'storage/example/ha_example.cc'
--- storage/example/ha_example.cc	2008-02-24 13:12:17 +0000
+++ storage/example/ha_example.cc	2010-02-05 12:34:16 +0000
@@ -836,11 +836,43 @@
 int ha_example::create(const char *name, TABLE *table_arg,
                        HA_CREATE_INFO *create_info)
 {
+  CREATE_OPTION *opt;
   DBUG_ENTER("ha_example::create");
   /*
     This is not implemented but we want someone to be able to see that it
     works.
   */
+  /* Example of checking parameters for table*/
+  if (!create_info->create_table_options)
+    DBUG_RETURN(0);
+  for (opt= create_info->create_table_options->table_opt.first;
+       opt;
+       opt= opt->next)
+  {
+    /* check for legal options and its legal values */
+    if (opt->key.length == 1 &&
+        (opt->key.str[0] == 'e' || opt->key.str[0] == 'E') &&
+        opt->val.length == 1 &&
+        opt->val.str[0] == '1')
+      opt->used= 1; /* tell MariaDB that we used the only legal parameter */
+  }
+  /* Example of checking parameters for fields*/
+  for (Field **field= table_arg->s->field; *field; field++)
+  {
+    if ((*field)->create_options.first)
+    {
+      for (opt= (*field)->create_options.first; opt; opt= opt->next)
+      {
+        /* check for legal options and its legal values */
+        if (opt->key.length == 1 &&
+            (opt->key.str[0] == 'e' || opt->key.str[0] == 'E') &&
+            opt->val.length == 1 &&
+            opt->val.str[0] == '1')
+          opt->used= 1; /* tell MariaDB that we used the only legal parameter */
+      }
+    }
+  }
+
   DBUG_RETURN(0);
 }
 

=== modified file 'storage/pbxt/src/discover_xt.cc'
--- storage/pbxt/src/discover_xt.cc	2010-02-01 06:14:12 +0000
+++ storage/pbxt/src/discover_xt.cc	2010-02-05 09:42:27 +0000
@@ -1623,7 +1623,7 @@
 #endif
 		       NULL /*default_value*/, NULL /*on_update_value*/, &comment, NULL /*change*/, 
 		       NULL /*interval_list*/, info->field_charset, 0 /*uint_geom_type*/, 
-		       NULL /*vcol_info*/)) 
+                       NULL /*vcol_info*/, NULL /* create options */))
 #endif
 			goto error;
 


References