diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 3c3facae34f..6c83fffa8fb 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -116,6 +116,7 @@ valgrind_flags="$valgrind_flags -DMYSQL_SERVER_SUFFIX=-valgrind-max" # Used in -debug builds debug_cflags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS " debug_cflags="$debug_cflags -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC -DSAFE_MUTEX" +error_inject="--with-error-inject " # # Base C++ flags for all builds base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti" diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max index d799311526b..adb9b7899a5 100755 --- a/BUILD/compile-pentium-debug-max +++ b/BUILD/compile-pentium-debug-max @@ -4,6 +4,6 @@ path=`dirname $0` . "$path/SETUP.sh" "$@" --with-debug=full extra_flags="$pentium_cflags $debug_cflags" -extra_configs="$pentium_configs $debug_configs $max_configs" +extra_configs="$pentium_configs $debug_configs $max_configs $error_inject" . "$path/FINISH.sh" diff --git a/client/mysql.cc b/client/mysql.cc index 900bdec067a..01308055ac0 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2241,8 +2241,10 @@ print_table_data(MYSQL_RES *result) MYSQL_ROW cur; MYSQL_FIELD *field; bool *num_flag; + bool *not_null_flag; num_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result)); + not_null_flag=(bool*) my_alloca(sizeof(bool)*mysql_num_fields(result)); if (info_flag) { print_field_types(result); @@ -2260,7 +2262,7 @@ print_table_data(MYSQL_RES *result) length=max(length,field->max_length); if (length < 4 && !IS_NOT_NULL(field->flags)) length=4; // Room for "NULL" - field->max_length=length+1; + field->max_length=length; separator.fill(separator.length()+length+2,'-'); separator.append('+'); } @@ -2272,10 +2274,11 @@ print_table_data(MYSQL_RES *result) (void) tee_fputs("|", PAGER); for (uint off=0; (field = mysql_fetch_field(result)) ; off++) { - tee_fprintf(PAGER, " %-*s|",(int) min(field->max_length, + tee_fprintf(PAGER, " %-*s |",(int) min(field->max_length, MAX_COLUMN_LENGTH), field->name); num_flag[off]= IS_NUM(field->type); + not_null_flag[off]= IS_NOT_NULL(field->flags); } (void) tee_fputs("\n", PAGER); tee_puts((char*) separator.ptr(), PAGER); @@ -2295,7 +2298,8 @@ print_table_data(MYSQL_RES *result) uint visible_length; uint extra_padding; - if (lengths[off] == 0) + /* If this column may have a null value, use "NULL" for empty. */ + if (! not_null_flag[off] && (lengths[off] == 0)) { buffer= "NULL"; data_length= 4; @@ -2335,6 +2339,7 @@ print_table_data(MYSQL_RES *result) } tee_puts((char*) separator.ptr(), PAGER); my_afree((gptr) num_flag); + my_afree((gptr) not_null_flag); } @@ -2349,11 +2354,8 @@ tee_print_sized_data(const char *data, unsigned int data_length, unsigned int to unsigned int i; const char *p; - total_bytes_to_send -= 1; - /* Off by one, perhaps mistakenly accounting for a terminating NUL. */ - if (right_justified) - for (i= 0; i < (total_bytes_to_send - data_length); i++) + for (i= data_length; i < total_bytes_to_send; i++) tee_putc((int)' ', PAGER); for (i= 0, p= data; i < data_length; i+= 1, p+= 1) @@ -2365,7 +2367,7 @@ tee_print_sized_data(const char *data, unsigned int data_length, unsigned int to } if (! right_justified) - for (i= 0; i < (total_bytes_to_send - data_length); i++) + for (i= data_length; i < total_bytes_to_send; i++) tee_putc((int)' ', PAGER); } diff --git a/client/mysqldump.c b/client/mysqldump.c index f268ca5b468..23d78a588a7 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -50,6 +50,7 @@ #include "mysql.h" #include "mysql_version.h" #include "mysqld_error.h" +#include "sql/ha_ndbcluster_tables.h" /* Exit codes */ @@ -134,7 +135,6 @@ static CHARSET_INFO *charset_info= &my_charset_latin1; const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace"; /* do we met VIEWs during tables scaning */ my_bool was_views= 0; - const char *compatible_mode_names[]= { "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2", @@ -2937,6 +2937,8 @@ static int dump_all_tables_in_db(char *database) afterdot= strmov(hash_key, database); *afterdot++= '.'; + if (!strcmp(database, NDB_REP_DB)) /* Skip cluster internal database */ + return 0; if (init_dumping(database)) return 1; if (opt_xml) diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4 index 5346b81fb03..d8199f5970e 100644 --- a/config/ac-macros/misc.m4 +++ b/config/ac-macros/misc.m4 @@ -361,7 +361,8 @@ AC_CACHE_VAL(mysql_cv_termcap_lib, [AC_CHECK_LIB(ncurses, tgetent, mysql_cv_termcap_lib=libncurses, [AC_CHECK_LIB(curses, tgetent, mysql_cv_termcap_lib=libcurses, [AC_CHECK_LIB(termcap, tgetent, mysql_cv_termcap_lib=libtermcap, - mysql_cv_termcap_lib=NOT_FOUND)])])]) + [AC_CHECK_LIB(tinfo, tgetent, mysql_cv_termcap_lib=libtinfo, + mysql_cv_termcap_lib=NOT_FOUND)])])])]) AC_MSG_CHECKING(for termcap functions library) if test "$mysql_cv_termcap_lib" = "NOT_FOUND"; then AC_MSG_ERROR([No curses/termcap library found]) @@ -369,6 +370,8 @@ elif test "$mysql_cv_termcap_lib" = "libtermcap"; then TERMCAP_LIB=-ltermcap elif test "$mysql_cv_termcap_lib" = "libncurses"; then TERMCAP_LIB=-lncurses +elif test "$mysql_cv_termcap_lib" = "libtinfo"; then +TERMCAP_LIB=-ltinfo else TERMCAP_LIB=-lcurses fi diff --git a/configure.in b/configure.in index 6984f5b5f89..2fde26d5930 100644 --- a/configure.in +++ b/configure.in @@ -666,6 +666,7 @@ else AC_MSG_RESULT([no]) fi + MYSQL_SYS_LARGEFILE # Types that must be checked AFTER large file support is checked @@ -774,6 +775,9 @@ AC_SUBST(WRAPLIBS) if test "$TARGET_LINUX" = "true"; then AC_MSG_CHECKING([for atomic operations]) + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + atom_ops= AC_TRY_RUN([ #include @@ -809,6 +813,8 @@ int main() if test -z "$atom_ops"; then atom_ops="no"; fi AC_MSG_RESULT($atom_ops) + AC_LANG_RESTORE + AC_ARG_WITH(pstack, [ --with-pstack Use the pstack backtrace library], [ USE_PSTACK=$withval ], @@ -1608,6 +1614,21 @@ else CXXFLAGS="$OPTIMIZE_CXXFLAGS -DDBUG_OFF $CXXFLAGS" fi +# If we should allow error injection tests +AC_ARG_WITH(error-inject, + [ --with-error-inject Enable error injection in MySQL Server], + [ with_error_inject=$withval ], + [ with_error_inject=no ]) + +if test $with_debug != "no" +then + if test "$with_error_inject" = "yes" + then + AC_DEFINE([ERROR_INJECT_SUPPORT], [1], + [Enable error injection in MySQL Server]) + fi +fi + AC_ARG_WITH([fast-mutexes], AC_HELP_STRING([--with-fast-mutexes], [Compile with fast mutexes (default is disabled)]), diff --git a/include/my_sys.h b/include/my_sys.h index 51883e8d6f9..41851b91cbd 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -559,7 +559,7 @@ extern File my_register_filename(File fd, const char *FileName, enum file_type type_of_file, uint error_message_number, myf MyFlags); extern File my_create(const char *FileName,int CreateFlags, - int AccsesFlags, myf MyFlags); + int AccessFlags, myf MyFlags); extern int my_close(File Filedes,myf MyFlags); extern File my_dup(File file, myf MyFlags); extern int my_mkdir(const char *dir, int Flags, myf MyFlags); diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 8ddf7668844..5aaddf36aa3 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -43,6 +43,8 @@ dist-hook: $(distdir)/r \ $(distdir)/include \ $(distdir)/std_data \ + $(distdir)/std_data/ndb_backup50 \ + $(distdir)/std_data/ndb_backup51 \ $(distdir)/lib -$(INSTALL_DATA) $(srcdir)/t/*.def $(distdir)/t $(INSTALL_DATA) $(srcdir)/t/*.test $(distdir)/t @@ -63,6 +65,8 @@ dist-hook: $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(distdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50/BACKUP* $(distdir)/std_data/ndb_backup50 + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51/BACKUP* $(distdir)/std_data/ndb_backup51 $(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(distdir)/lib $(INSTALL_DATA) $(srcdir)/lib/*.pl $(distdir)/lib @@ -74,6 +78,8 @@ install-data-local: $(DESTDIR)$(testdir)/r \ $(DESTDIR)$(testdir)/include \ $(DESTDIR)$(testdir)/std_data \ + $(DESTDIR)$(testdir)/std_data/ndb_backup50 \ + $(DESTDIR)$(testdir)/std_data/ndb_backup51 \ $(DESTDIR)$(testdir)/lib $(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(testdir) -$(INSTALL_DATA) $(srcdir)/t/*.def $(DESTDIR)$(testdir)/t @@ -98,6 +104,8 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.frm $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(DESTDIR)$(testdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup50/BACKUP* $(DESTDIR)$(testdir)/std_data/ndb_backup50 + $(INSTALL_DATA) $(srcdir)/std_data/ndb_backup51/BACKUP* $(DESTDIR)$(testdir)/std_data/ndb_backup51 $(INSTALL_DATA) $(srcdir)/lib/init_db.sql $(DESTDIR)$(testdir)/lib $(INSTALL_DATA) $(srcdir)/lib/*.pl $(DESTDIR)$(testdir)/lib diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 18ee70aa2e0..a095b4535fe 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1524,6 +1524,7 @@ sub ndbcluster_start ($) { if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", ["--port=$opt_ndbcluster_port", "--data-dir=$opt_vardir", + "--character-sets-dir=$path_charsetsdir", "--verbose=2", "--core"], "", "/dev/null", "", "") ) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index aad71f89ef2..54c5ce20047 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -1230,7 +1230,7 @@ start_ndbcluster() then NDBCLUSTER_EXTRA_OPTS="--small" fi - OPTS="$NDBCLUSTER_OPTS $NDBCLUSTER_EXTRA_OPTS --verbose=$NDB_VERBOSE --initial --relative-config-data-dir --core" + OPTS="$NDBCLUSTER_OPTS $NDBCLUSTER_EXTRA_OPTS --character-sets-dir=$CHARSETSDIR --verbose=$NDB_VERBOSE --initial --relative-config-data-dir --core" if [ "x$NDB_VERBOSE" != "x0" ] ; then echo "Starting master ndbcluster " $OPTS fi diff --git a/mysql-test/ndb/ndbcluster.sh b/mysql-test/ndb/ndbcluster.sh index 6812067a8ed..d55b53da2ae 100644 --- a/mysql-test/ndb/ndbcluster.sh +++ b/mysql-test/ndb/ndbcluster.sh @@ -66,6 +66,7 @@ VERBOSE=100 NDB_MGM_EXTRA_OPTS= NDB_MGMD_EXTRA_OPTS= NDBD_EXTRA_OPTS= +CHARSETSDIR= while test $# -gt 0; do case "$1" in @@ -119,6 +120,9 @@ while test $# -gt 0; do --ndbd-extra-opts=*) NDBD_EXTRA_OPTS=`echo "$1" | sed -e "s;--ndbd-extra-opts=;;"` ;; + --character-sets-dir=*) + CHARSETSDIR=`echo "$1" | sed -e "s;--character-sets-dir=;;"` + ;; --core) opt_core="--core" ;; @@ -159,7 +163,7 @@ fi exec_mgmtclient="$exec_mgmtclient --no-defaults $opt_core $NDB_MGM_EXTRA_OPTS" exec_mgmtsrvr="$exec_mgmtsrvr --no-defaults $opt_core $NDB_MGMD_EXTRA_OPTS" -exec_ndb="$exec_ndb --no-defaults $opt_core $NDBD_EXTRA_OPTS" +exec_ndb="$exec_ndb --no-defaults $opt_core $NDBD_EXTRA_OPTS --character-sets-dir=$CHARSETSDIR" exec_waiter="$exec_waiter --no-defaults $opt_core" ndb_host="localhost" diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index e58aaa4554f..62e2085ae09 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -674,6 +674,18 @@ Warnings: Warning 1264 Out of range value for column 'Field1' at row 1 DROP TABLE t1; SET NAMES latin1; +SELECT CONVERT(103, CHAR(50) UNICODE); +CONVERT(103, CHAR(50) UNICODE) +103 +SELECT CONVERT(103.0, CHAR(50) UNICODE); +CONVERT(103.0, CHAR(50) UNICODE) +103.0 +SELECT CONVERT(-103, CHAR(50) UNICODE); +CONVERT(-103, CHAR(50) UNICODE) +-103 +SELECT CONVERT(-103.0, CHAR(50) UNICODE); +CONVERT(-103.0, CHAR(50) UNICODE) +-103.0 CREATE TABLE t1 ( a varchar(255) NOT NULL default '', KEY a (a) diff --git a/mysql-test/r/func_op.result b/mysql-test/r/func_op.result index 61b29e9380d..24685d07f3d 100644 --- a/mysql-test/r/func_op.result +++ b/mysql-test/r/func_op.result @@ -35,3 +35,14 @@ select -1 >> 0, -1 << 0; select -1 >> 1, -1 << 1; -1 >> 1 -1 << 1 9223372036854775807 18446744073709551614 +drop table if exists t1,t2; +create table t1(a int); +create table t2(a int, b int); +insert into t1 values (1), (2), (3); +insert into t2 values (1, 7), (3, 7); +select t1.a, t2.a, t2.b, bit_count(t2.b) from t1 left join t2 on t1.a=t2.a; +a a b bit_count(t2.b) +1 1 7 3 +2 NULL NULL NULL +3 3 7 3 +drop table t1, t2; diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 46c37795531..0b706b24488 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1030,3 +1030,13 @@ c res y,abc abc y,abc abc drop table t1; +select cast(rtrim(' 20.06 ') as decimal(19,2)); +cast(rtrim(' 20.06 ') as decimal(19,2)) +20.06 +select cast(ltrim(' 20.06 ') as decimal(19,2)); +cast(ltrim(' 20.06 ') as decimal(19,2)) +20.06 +select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2)); +cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2)) +20.06 +End of 5.0 tests diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index a003ed14c77..f32d7ee264a 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1306,13 +1306,13 @@ insert into t1 (a) select b from t2; select count(*) from t1; count(*) 29267 -explain select * from t1 where c between 1 and 10000; +explain select * from t1 where c between 1 and 2500; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range c c 5 NULL # Using where update t1 set c=a; -explain select * from t1 where c between 1 and 10000; +explain select * from t1 where c between 1 and 2500; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL c NULL NULL NULL # Using where +1 SIMPLE t1 range c c 5 NULL # Using where drop table t1,t2; create table t1 (id int primary key auto_increment, fk int, index index_fk (fk)) engine=innodb; insert into t1 (id) values (null),(null),(null),(null),(null); @@ -3233,15 +3233,6 @@ drop trigger t2t; drop trigger t3t; drop trigger t4t; drop table t1, t2, t3, t4, t5; -create table t1(a date) engine=innodb; -create table t2(a date, key(a)) engine=innodb; -insert into t1 values('2005-10-01'); -insert into t2 values('2005-10-01'); -select * from t1, t2 -where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; -a a -2005-10-01 2005-10-01 -drop table t1, t2; CREATE TABLE t1 ( field1 varchar(8) NOT NULL DEFAULT '', field2 varchar(8) NOT NULL DEFAULT '', @@ -3291,3 +3282,176 @@ t1 CREATE TABLE `t1` ( UNIQUE KEY `c2` (`c2`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 drop table t1, t2; +create table t1(a date) engine=innodb; +create table t2(a date, key(a)) engine=innodb; +insert into t1 values('2005-10-01'); +insert into t2 values('2005-10-01'); +select * from t1, t2 +where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; +a a +2005-10-01 2005-10-01 +drop table t1, t2; +create table t1 (id int not null, f_id int not null, f int not null, +primary key(f_id, id)) engine=innodb; +create table t2 (id int not null,s_id int not null,s varchar(200), +primary key(id)) engine=innodb; +INSERT INTO t1 VALUES (8, 1, 3); +INSERT INTO t1 VALUES (1, 2, 1); +INSERT INTO t2 VALUES (1, 0, ''); +INSERT INTO t2 VALUES (8, 1, ''); +commit; +DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id) +WHERE mm.id IS NULL; +select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id) +where mm.id is null lock in share mode; +id f_id f +drop table t1,t2; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); +commit; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t1 set b = 5 where b = 1; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +select * from t1 where a = 7 and b = 3 for update; +a b +7 3 +commit; +commit; +drop table t1; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +commit; +set autocommit = 0; +select * from t1 lock in share mode; +a b +1 1 +2 2 +3 1 +4 2 +5 1 +6 2 +update t1 set b = 5 where b = 1; +set autocommit = 0; +select * from t1 where a = 2 and b = 2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +commit; +drop table t1; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(d int not null, e int, primary key(d)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +d e +3 1 +8 6 +12 1 +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t1 select * from t2; +update t1 set b = (select e from t2 where a = d); +create table t3(d int not null, e int, primary key(d)) engine=innodb +select * from t2; +commit; +commit; +drop table t1, t2, t3; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(a int not null, b int, primary key(a)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +create table t3(d int not null, b int, primary key(d)) engine=innodb; +insert into t3 values (8,6),(12,1),(3,1); +create table t5(a int not null, b int, primary key(a)) engine=innodb; +insert into t5 values (1,2),(5,3),(4,2); +create table t6(d int not null, e int, primary key(d)) engine=innodb; +insert into t6 values (8,6),(12,1),(3,1); +create table t8(a int not null, b int, primary key(a)) engine=innodb; +insert into t8 values (1,2),(5,3),(4,2); +create table t9(d int not null, e int, primary key(d)) engine=innodb; +insert into t9 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +a b +3 1 +8 6 +12 1 +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +insert into t1 select * from t2; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +update t3 set b = (select b from t2 where a = d); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t5 (select * from t2 lock in share mode); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t6 set e = (select b from t2 where a = d lock in share mode); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t8 (select * from t2 for update); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t9 set e = (select b from t2 where a = d for update); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +drop table t1, t2, t3, t5, t6, t8, t9; +CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; +ERROR HY000: Can't create table 'test.t1' (errno: -1) +CREATE TABLE t1 ( +a BIGINT(20) NOT NULL, +PRIMARY KEY (a) +) ENGINE=INNODB DEFAULT CHARSET=UTF8; +CREATE TABLE t2 ( +a BIGINT(20) NOT NULL, +b VARCHAR(128) NOT NULL, +c TEXT NOT NULL, +PRIMARY KEY (a,b), +KEY idx_t2_b_c (b,c(200)), +CONSTRAINT t_fk FOREIGN KEY (a) REFERENCES t1 (a) +ON DELETE CASCADE +) ENGINE=INNODB DEFAULT CHARSET=UTF8; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1, 'bar', 'vbar'); +INSERT INTO t2 VALUES (1, 'BAR2', 'VBAR'); +INSERT INTO t2 VALUES (1, 'bar_bar', 'bibi'); +INSERT INTO t2 VALUES (1, 'customer_over', '1'); +SELECT * FROM t2 WHERE b = 'customer_over'; +a b c +1 customer_over 1 +SELECT * FROM t2 WHERE BINARY b = 'customer_over'; +a b c +1 customer_over 1 +SELECT DISTINCT p0.a FROM t2 p0 WHERE p0.b = 'customer_over'; +a +1 +/* Bang: Empty result set, above was expected: */ +SELECT DISTINCT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; +a +1 +SELECT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; +a +1 +drop table t2, t1; diff --git a/mysql-test/r/innodb_unsafe_binlog.result b/mysql-test/r/innodb_unsafe_binlog.result index e741fbb75a4..38f0c2a12fa 100644 --- a/mysql-test/r/innodb_unsafe_binlog.result +++ b/mysql-test/r/innodb_unsafe_binlog.result @@ -15,7 +15,7 @@ where mm.id is null lock in share mode; id f_id f drop table t1,t2; create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); commit; set autocommit = 0; select * from t1 lock in share mode; @@ -26,6 +26,7 @@ a b 4 2 5 1 6 2 +7 3 update t1 set b = 5 where b = 1; set autocommit = 0; select * from t1 where a = 2 and b = 2 for update; @@ -33,3 +34,87 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction commit; commit; drop table t1; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); +commit; +set autocommit = 0; +update t1 set b = 5 where b = 1; +set autocommit = 0; +select * from t1 where a = 7 and b = 3 for update; +a b +7 3 +commit; +commit; +drop table t1; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(d int not null, e int, primary key(d)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +d e +3 1 +8 6 +12 1 +set autocommit = 0; +insert into t1 select * from t2; +update t1 set b = (select e from t2 where a = d); +create table t3(d int not null, e int, primary key(d)) engine=innodb +select * from t2; +commit; +commit; +drop table t1, t2, t3; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(a int not null, b int, primary key(a)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +create table t3(d int not null, b int, primary key(d)) engine=innodb; +insert into t3 values (8,6),(12,1),(3,1); +create table t5(a int not null, b int, primary key(a)) engine=innodb; +insert into t5 values (1,2),(5,3),(4,2); +create table t6(d int not null, e int, primary key(d)) engine=innodb; +insert into t6 values (8,6),(12,1),(3,1); +create table t8(a int not null, b int, primary key(a)) engine=innodb; +insert into t8 values (1,2),(5,3),(4,2); +create table t9(d int not null, e int, primary key(d)) engine=innodb; +insert into t9 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +a b +3 1 +8 6 +12 1 +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +insert into t1 select * from t2; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +update t3 set b = (select b from t2 where a = d); +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; +set autocommit = 0; +insert into t5 (select * from t2 lock in share mode); +set autocommit = 0; +update t6 set e = (select b from t2 where a = d lock in share mode); +set autocommit = 0; +create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; +set autocommit = 0; +insert into t8 (select * from t2 for update); +set autocommit = 0; +update t9 set e = (select b from t2 where a = d for update); +set autocommit = 0; +create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +commit; +drop table t1, t2, t3, t5, t6, t8, t9; diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index ae50c714bba..a067d3ad0f8 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -85,3 +85,15 @@ c_cp932 | NULL | NULL | Τη γλώσσα | | NULL | NULL | ᛖᚴ ᚷᛖᛏ | +------+------+---------------------------+ ++------+---+------+ +| i | j | k | ++------+---+------+ +| NULL | 1 | NULL | ++------+---+------+ ++-------+---------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-------+---------+------+-----+---------+-------+ +| i | int(11) | YES | | NULL | | +| j | int(11) | NO | | NULL | | +| k | int(11) | YES | | NULL | | ++-------+---------+------+-----+---------+-------+ diff --git a/mysql-test/r/ndb_partition_key.result b/mysql-test/r/ndb_partition_key.result index 8225fca7a54..503283df532 100644 --- a/mysql-test/r/ndb_partition_key.result +++ b/mysql-test/r/ndb_partition_key.result @@ -165,6 +165,20 @@ ENGINE=NDB PARTITION BY KEY(c3) PARTITIONS 5; ALTER TABLE t1 COALESCE PARTITION 4; DROP TABLE t1; +CREATE TABLE t1 (a int primary key) +ENGINE=NDB +PARTITION BY KEY(a); +ALTER TABLE t1 OPTIMIZE PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 CHECK PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 REPAIR PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 ANALYZE PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +ALTER TABLE t1 REBUILD PARTITION p0; +ERROR HY000: Table storage engine for 't1' doesn't have this option +DROP TABLE t1; CREATE TABLE t1 ( c1 MEDIUMINT NOT NULL AUTO_INCREMENT, c2 TEXT NOT NULL, diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index 5461e4dd563..ca21b333a6a 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -23,3 +23,23 @@ select 1; show status like 'last_query_cost'; Variable_name Value Last_query_cost 0.000000 +FLUSH STATUS; +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 1 +SET @save_thread_cache_size=@@thread_cache_size; +SET GLOBAL thread_cache_size=3; +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 3 +FLUSH STATUS; +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 2 +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 3 +SHOW STATUS LIKE 'max_used_connections'; +Variable_name Value +Max_used_connections 4 +SET GLOBAL thread_cache_size=@save_thread_cache_size; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index ac451c5c34d..7cc3a954cd6 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -952,3 +952,16 @@ load data infile '../std_data_ln/words.dat' into table t1 (a) set b:= f1(); drop table t1; drop function f1; drop function f2; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +conn_id INT, +trigger_conn_id INT +); +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +SET NEW.trigger_conn_id = CONNECTION_ID(); +INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1); +INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1); +SELECT * FROM t1 WHERE conn_id != trigger_conn_id; +conn_id trigger_conn_id +DROP TRIGGER t1_bi; +DROP TABLE t1; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 0b6ebe9dd89..fd6a6dbd3d3 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2600,3 +2600,26 @@ id td 5 2005-01-04 DROP VIEW v1; DROP TABLE t1; +create table t1 (a int); +create view v1 as select * from t1; +create view v2 as select * from v1; +drop table t1; +rename table v2 to t1; +select * from v1; +ERROR HY000: `test`.`v1` contain view recursion +drop view t1, v1; +create table t1 (a int); +create function f1() returns int +begin +declare mx int; +select max(a) from t1 into mx; +return mx; +end// +create view v1 as select f1() as a; +create view v2 as select * from v1; +drop table t1; +rename table v2 to t1; +select * from v1; +ERROR HY000: Recursive stored functions and triggers are not allowed. +drop function f1; +drop view t1, v1; diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index af46b9c385a..c7662f4f85a 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -409,6 +409,14 @@ INSERT INTO t1 VALUES ('-1'); DROP TABLE t1; SET NAMES latin1; +# +# Bug#18691 Converting number to UNICODE string returns invalid result +# +SELECT CONVERT(103, CHAR(50) UNICODE); +SELECT CONVERT(103.0, CHAR(50) UNICODE); +SELECT CONVERT(-103, CHAR(50) UNICODE); +SELECT CONVERT(-103.0, CHAR(50) UNICODE); + # # Bug#9557 MyISAM utf8 table crash # diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index cec913ac320..8766e9f3f6a 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -24,13 +24,12 @@ rpl_deadlock_innodb : BUG#16920 2006-04-12 kent fails in show slave stat rpl_ndb_2innodb : BUG#19227 2006-04-20 pekka pk delete apparently not replicated rpl_ndb_2myisam : BUG#19227 2006-04-20 pekka pk delete apparently not replicated rpl_ndb_auto_inc : BUG#17086 2006-02-16 jmiller CR: auto_increment_increment and auto_increment_offset produce duplicate key er -rpl_ndb_ddl : result file needs update + test needs to checked +rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on solaris +rpl_ndb_ddl : BUG#18946 result file needs update + test needs to checked rpl_ndb_innodb2ndb : BUG#17400 2006-04-19 tomas Cluster Replication: delete & update of rows in table without pk fails on slave. rpl_ndb_log : BUG#18947 2006-03-21 tomas CRBR: order in binlog of create table and insert (on different table) not determ rpl_ndb_myisam2ndb : BUG#17400 2006-04-19 tomas Cluster Replication: delete & update of rows in table without pk fails on slave. -#rpl_ndb_relay_space : BUG#16993 2006-02-16 jmiller RBR: ALTER TABLE ZEROFILL AUTO_INCREMENT is not replicated correctly rpl_switch_stm_row_mixed : BUG#18590 2006-03-28 brian -#rpl_row_basic_7ndb : BUG#17400 2006-04-09 brian Cluster Replication: delete & update of rows in table without pk fails on slave. rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly rpl_row_func003 : BUG#19074 2006-13-04 andrei test failed rpl_row_inexist_tbl : BUG#18948 2006-03-09 mats Disabled since patch makes this test wait forever @@ -42,15 +41,3 @@ udf : BUG#18564 2006-03-27 ian (Permission by Brian) # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open #ndb_binlog_ddl_multi : BUG#18976 2006-04-10 kent CRBR: multiple binlog, second binlog may miss schema log events - -# the below ndb failures have not been objerved for > 5 push builds, close bugs -#ndb_gis : BUG#18600 2006-03-28 brian ndb_gis test failure -#ndb_load : BUG#17233 2006-02-16 jmiller failed load data from infile causes mysqld dbug_assert, binlog not flushed -#rpl_ndb_basic : BUG#18592 2006-03-28 brian rpl_ndb_basic failure -#rpl_ndb_dd_advance : BUG#18924 2006-04-09 brian rpl_ndb_dd_advance failure -rpl_ndb_dd_partitions : fails on solaris -#rpl_ndb_dd_basic : BUG#18569 2006-03-28 brian rpl_ndb_dd_basic failure -#rpl_ndb_insert_ignore : BUG#18567 2006-03-28 brian rpl_ndb_insert_ignore failure -#rpl_ndb_multi_update2 : BUG#18928 2006-04-09 brian rpl_ndb_multi_update2 failed -#rpl_ndb_multi_update3 : BUG#18627 2006-03-29 monty Cluster Replication: rpl_ndb_multi_update3 fails on Intel 64 bit -#rpl_ndb_trig004 : BUG#18977 2006-04-10 kent Test fails randomly diff --git a/mysql-test/t/func_op.test b/mysql-test/t/func_op.test index 24266150e4c..0a4f5034f4c 100644 --- a/mysql-test/t/func_op.test +++ b/mysql-test/t/func_op.test @@ -17,4 +17,18 @@ select 0 | -1, 0 ^ -1, 0 & -1; select -1 >> 0, -1 << 0; select -1 >> 1, -1 << 1; +# +# Bug 13044: wrong bit_count() results +# + +--disable_warnings +drop table if exists t1,t2; +--enable_warnings +create table t1(a int); +create table t2(a int, b int); +insert into t1 values (1), (2), (3); +insert into t2 values (1, 7), (3, 7); +select t1.a, t2.a, t2.b, bit_count(t2.b) from t1 left join t2 on t1.a=t2.a; +drop table t1, t2; + # End of 4.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index ef20d766bce..85cedee0f4a 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -684,4 +684,11 @@ insert into t1 values ('y,abc'),('y,abc'); select c, substring_index(lcase(c), @q:=',', -1) as res from t1; drop table t1; -# End of 5.0 tests +# +# Bug #17043: Casting trimmed string to decimal loses precision +# +select cast(rtrim(' 20.06 ') as decimal(19,2)); +select cast(ltrim(' 20.06 ') as decimal(19,2)); +select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2)); + +--echo End of 5.0 tests diff --git a/mysql-test/t/innodb-master.opt b/mysql-test/t/innodb-master.opt index 4cb927540bf..4901efb416c 100644 --- a/mysql-test/t/innodb-master.opt +++ b/mysql-test/t/innodb-master.opt @@ -1 +1 @@ ---binlog_cache_size=32768 +--binlog_cache_size=32768 --innodb_lock_wait_timeout=1 diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index ab408e9b4a5..d44f554f200 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -901,10 +901,10 @@ insert into t2 (a) select b from t1; insert into t1 (a) select b from t2; select count(*) from t1; --replace_column 9 # -explain select * from t1 where c between 1 and 10000; +explain select * from t1 where c between 1 and 2500; update t1 set c=a; --replace_column 9 # -explain select * from t1 where c between 1 and 10000; +explain select * from t1 where c between 1 and 2500; drop table t1,t2; # @@ -2129,18 +2129,6 @@ connection default; disconnect a; disconnect b; -# -# Bug #14360: problem with intervals -# - -create table t1(a date) engine=innodb; -create table t2(a date, key(a)) engine=innodb; -insert into t1 values('2005-10-01'); -insert into t2 values('2005-10-01'); -select * from t1, t2 - where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; -drop table t1, t2; - # # Test that cascading updates leading to duplicate keys give the correct # error message (bug #9680) @@ -2193,3 +2181,303 @@ alter table t1 drop foreign key c2_fk; show create table t1; # drop table t1, t2; + +# +# Bug #14360: problem with intervals +# + +create table t1(a date) engine=innodb; +create table t2(a date, key(a)) engine=innodb; +insert into t1 values('2005-10-01'); +insert into t2 values('2005-10-01'); +select * from t1, t2 + where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; +drop table t1, t2; + +create table t1 (id int not null, f_id int not null, f int not null, +primary key(f_id, id)) engine=innodb; +create table t2 (id int not null,s_id int not null,s varchar(200), +primary key(id)) engine=innodb; +INSERT INTO t1 VALUES (8, 1, 3); +INSERT INTO t1 VALUES (1, 2, 1); +INSERT INTO t2 VALUES (1, 0, ''); +INSERT INTO t2 VALUES (8, 1, ''); +commit; +DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id) +WHERE mm.id IS NULL; +select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id) +where mm.id is null lock in share mode; +drop table t1,t2; + +# +# Test case where X-locks on unused rows should be released in a +# update (because READ COMMITTED isolation level) +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); +commit; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +update t1 set b = 5 where b = 1; +connection b; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +# +# X-lock to record (7,3) should be released in a update +# +select * from t1 where a = 7 and b = 3 for update; +connection a; +commit; +connection b; +commit; +drop table t1; +connection default; +disconnect a; +disconnect b; + +# +# Test case where no locks should be released (because we are not +# using READ COMMITTED isolation level) +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +commit; +set autocommit = 0; +select * from t1 lock in share mode; +update t1 set b = 5 where b = 1; +connection b; +set autocommit = 0; +# +# S-lock to records (2,2),(4,2), and (6,2) should not be released in a update +# +--error 1205 +select * from t1 where a = 2 and b = 2 for update; +# +# X-lock to record (1,1),(3,1),(5,1) should not be released in a update +# +--error 1205 +connection a; +commit; +connection b; +commit; +connection default; +disconnect a; +disconnect b; +drop table t1; + +# +# Consistent read should be used in following selects +# +# 1) INSERT INTO ... SELECT +# 2) UPDATE ... = ( SELECT ...) +# 3) CREATE ... SELECT + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(d int not null, e int, primary key(d)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +connection b; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +insert into t1 select * from t2; +update t1 set b = (select e from t2 where a = d); +create table t3(d int not null, e int, primary key(d)) engine=innodb +select * from t2; +commit; +connection a; +commit; +connection default; +disconnect a; +disconnect b; +drop table t1, t2, t3; + +# +# Consistent read should not be used if +# +# (a) isolation level is serializable OR +# (b) select ... lock in share mode OR +# (c) select ... for update +# +# in following queries: +# +# 1) INSERT INTO ... SELECT +# 2) UPDATE ... = ( SELECT ...) +# 3) CREATE ... SELECT + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connect (c,localhost,root,,); +connect (d,localhost,root,,); +connect (e,localhost,root,,); +connect (f,localhost,root,,); +connect (g,localhost,root,,); +connect (h,localhost,root,,); +connect (i,localhost,root,,); +connect (j,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(a int not null, b int, primary key(a)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +create table t3(d int not null, b int, primary key(d)) engine=innodb; +insert into t3 values (8,6),(12,1),(3,1); +create table t5(a int not null, b int, primary key(a)) engine=innodb; +insert into t5 values (1,2),(5,3),(4,2); +create table t6(d int not null, e int, primary key(d)) engine=innodb; +insert into t6 values (8,6),(12,1),(3,1); +create table t8(a int not null, b int, primary key(a)) engine=innodb; +insert into t8 values (1,2),(5,3),(4,2); +create table t9(d int not null, e int, primary key(d)) engine=innodb; +insert into t9 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +connection b; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +insert into t1 select * from t2; +connection c; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +update t3 set b = (select b from t2 where a = d); +connection d; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; +connection e; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +insert into t5 (select * from t2 lock in share mode); +connection f; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +update t6 set e = (select b from t2 where a = d lock in share mode); +connection g; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; +connection h; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +insert into t8 (select * from t2 for update); +connection i; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +update t9 set e = (select b from t2 where a = d for update); +connection j; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +--send +create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; + +connection b; +--error 1205 +reap; + +connection c; +--error 1205 +reap; + +connection d; +--error 1205 +reap; + +connection e; +--error 1205 +reap; + +connection f; +--error 1205 +reap; + +connection g; +--error 1205 +reap; + +connection h; +--error 1205 +reap; + +connection i; +--error 1205 +reap; + +connection j; +--error 1205 +reap; + +connection a; +commit; + +connection default; +disconnect a; +disconnect b; +disconnect c; +disconnect d; +disconnect e; +disconnect f; +disconnect g; +disconnect h; +disconnect i; +disconnect j; +drop table t1, t2, t3, t5, t6, t8, t9; + +# bug 18934, "InnoDB crashes when table uses column names like DB_ROW_ID" +--error 1005 +CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; + +# +# Bug #17152: Wrong result with BINARY comparison on aliased column +# + +CREATE TABLE t1 ( + a BIGINT(20) NOT NULL, + PRIMARY KEY (a) + ) ENGINE=INNODB DEFAULT CHARSET=UTF8; + +CREATE TABLE t2 ( + a BIGINT(20) NOT NULL, + b VARCHAR(128) NOT NULL, + c TEXT NOT NULL, + PRIMARY KEY (a,b), + KEY idx_t2_b_c (b,c(200)), + CONSTRAINT t_fk FOREIGN KEY (a) REFERENCES t1 (a) + ON DELETE CASCADE + ) ENGINE=INNODB DEFAULT CHARSET=UTF8; + +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1, 'bar', 'vbar'); +INSERT INTO t2 VALUES (1, 'BAR2', 'VBAR'); +INSERT INTO t2 VALUES (1, 'bar_bar', 'bibi'); +INSERT INTO t2 VALUES (1, 'customer_over', '1'); + +SELECT * FROM t2 WHERE b = 'customer_over'; +SELECT * FROM t2 WHERE BINARY b = 'customer_over'; +SELECT DISTINCT p0.a FROM t2 p0 WHERE p0.b = 'customer_over'; +/* Bang: Empty result set, above was expected: */ +SELECT DISTINCT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; +SELECT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; + +drop table t2, t1; diff --git a/mysql-test/t/innodb_unsafe_binlog-master.opt b/mysql-test/t/innodb_unsafe_binlog-master.opt index 503c8457b2c..9581c225d6d 100644 --- a/mysql-test/t/innodb_unsafe_binlog-master.opt +++ b/mysql-test/t/innodb_unsafe_binlog-master.opt @@ -1 +1 @@ ---innodb_locks_unsafe_for_binlog=true +--innodb_locks_unsafe_for_binlog=true --innodb_lock_wait_timeout=1 diff --git a/mysql-test/t/innodb_unsafe_binlog.test b/mysql-test/t/innodb_unsafe_binlog.test index e4cb683e59d..af1091e4421 100644 --- a/mysql-test/t/innodb_unsafe_binlog.test +++ b/mysql-test/t/innodb_unsafe_binlog.test @@ -1,7 +1,9 @@ -- source include/have_innodb.inc # -# Note that these tests uses a innodb_locks_unsafe_for_binlog option. -# +# Note that these tests uses options +# innodb_locks_unsafe_for_binlog = true +# innodb_lock_timeout = 5 + # # Test cases for a bug #15650 # @@ -33,7 +35,7 @@ connect (a,localhost,root,,); connect (b,localhost,root,,); connection a; create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); commit; set autocommit = 0; select * from t1 lock in share mode; @@ -50,6 +52,197 @@ commit; connection b; commit; drop table t1; +connection default; disconnect a; disconnect b; +# +# unlock row test +# + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); +commit; +set autocommit = 0; +update t1 set b = 5 where b = 1; +connection b; +set autocommit = 0; +# +# X-lock to record (7,3) should be released in a update +# +select * from t1 where a = 7 and b = 3 for update; +commit; +connection a; +commit; +drop table t1; +connection default; +disconnect a; +disconnect b; + + +# +# Consistent read should be used in following selects +# +# 1) INSERT INTO ... SELECT +# 2) UPDATE ... = ( SELECT ...) +# 3) CREATE ... SELECT + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(d int not null, e int, primary key(d)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +connection b; +set autocommit = 0; +insert into t1 select * from t2; +update t1 set b = (select e from t2 where a = d); +create table t3(d int not null, e int, primary key(d)) engine=innodb +select * from t2; +commit; +connection a; +commit; +connection default; +disconnect a; +disconnect b; +drop table t1, t2, t3; + +# +# Consistent read should not be used if +# +# (a) isolation level is serializable OR +# (b) select ... lock in share mode OR +# (c) select ... for update +# +# in following queries: +# +# 1) INSERT INTO ... SELECT +# 2) UPDATE ... = ( SELECT ...) +# 3) CREATE ... SELECT + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connect (c,localhost,root,,); +connect (d,localhost,root,,); +connect (e,localhost,root,,); +connect (f,localhost,root,,); +connect (g,localhost,root,,); +connect (h,localhost,root,,); +connect (i,localhost,root,,); +connect (j,localhost,root,,); +connection a; +create table t1(a int not null, b int, primary key(a)) engine=innodb; +insert into t1 values (1,2),(5,3),(4,2); +create table t2(a int not null, b int, primary key(a)) engine=innodb; +insert into t2 values (8,6),(12,1),(3,1); +create table t3(d int not null, b int, primary key(d)) engine=innodb; +insert into t3 values (8,6),(12,1),(3,1); +create table t5(a int not null, b int, primary key(a)) engine=innodb; +insert into t5 values (1,2),(5,3),(4,2); +create table t6(d int not null, e int, primary key(d)) engine=innodb; +insert into t6 values (8,6),(12,1),(3,1); +create table t8(a int not null, b int, primary key(a)) engine=innodb; +insert into t8 values (1,2),(5,3),(4,2); +create table t9(d int not null, e int, primary key(d)) engine=innodb; +insert into t9 values (8,6),(12,1),(3,1); +commit; +set autocommit = 0; +select * from t2 for update; +connection b; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +insert into t1 select * from t2; +connection c; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +update t3 set b = (select b from t2 where a = d); +connection d; +set autocommit = 0; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +--send +create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; +connection e; +set autocommit = 0; +--send +insert into t5 (select * from t2 lock in share mode); +connection f; +set autocommit = 0; +--send +update t6 set e = (select b from t2 where a = d lock in share mode); +connection g; +set autocommit = 0; +--send +create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; +connection h; +set autocommit = 0; +--send +insert into t8 (select * from t2 for update); +connection i; +set autocommit = 0; +--send +update t9 set e = (select b from t2 where a = d for update); +connection j; +set autocommit = 0; +--send +create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; + +connection b; +--error 1205 +reap; + +connection c; +--error 1205 +reap; + +connection d; +--error 1205 +reap; + +connection e; +--error 1205 +reap; + +connection f; +--error 1205 +reap; + +connection g; +--error 1205 +reap; + +connection h; +--error 1205 +reap; + +connection i; +--error 1205 +reap; + +connection j; +--error 1205 +reap; + +connection a; +commit; + +connection default; +disconnect a; +disconnect b; +disconnect c; +disconnect d; +disconnect e; +disconnect f; +disconnect g; +disconnect h; +disconnect i; +disconnect j; +drop table t1, t2, t3, t5, t6, t8, t9; diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 95cba2743da..e76553f42e7 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -67,3 +67,8 @@ drop table t1; # --exec $MYSQL -t --default-character-set utf8 test -e "create table t1 (i int, j int, k char(25) charset utf8); insert into t1 (i) values (1); insert into t1 (k) values ('<----------------------->'); insert into t1 (k) values ('<-----'); insert into t1 (k) values ('Τη γλώσσα'); insert into t1 (k) values ('ᛖᚴ ᚷᛖᛏ'); select * from t1; DROP TABLE t1;" +# +# "DESCRIBE" commands may return strange NULLness flags. +# +--exec $MYSQL -t --default-character-set utf8 test -e "create table t1 (i int, j int not null, k int); insert into t1 values (null, 1, null); select * from t1; describe t1; drop table t1;" + diff --git a/mysql-test/t/ndb_partition_key.test b/mysql-test/t/ndb_partition_key.test index 87933671529..ce939663ab8 100644 --- a/mysql-test/t/ndb_partition_key.test +++ b/mysql-test/t/ndb_partition_key.test @@ -154,6 +154,24 @@ ALTER TABLE t1 COALESCE PARTITION 4; DROP TABLE t1; +# +# Bug 16822: OPTIMIZE TABLE hangs test +# +CREATE TABLE t1 (a int primary key) +ENGINE=NDB +PARTITION BY KEY(a); +--error 1031 +ALTER TABLE t1 OPTIMIZE PARTITION p0; +--error 1031 +ALTER TABLE t1 CHECK PARTITION p0; +--error 1031 +ALTER TABLE t1 REPAIR PARTITION p0; +--error 1031 +ALTER TABLE t1 ANALYZE PARTITION p0; +--error 1031 +ALTER TABLE t1 REBUILD PARTITION p0; +DROP TABLE t1; + # # BUG 16806: ALTER TABLE fails # diff --git a/mysql-test/t/rpl_view-slave.opt b/mysql-test/t/rpl_view-slave.opt new file mode 100644 index 00000000000..79b3bf6174b --- /dev/null +++ b/mysql-test/t/rpl_view-slave.opt @@ -0,0 +1 @@ +--replicate-ignore-table=test.foo diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 929a0cb5877..1a71425d2a7 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -36,11 +36,111 @@ reap; show status like 'Table_lock%'; drop table t1; +disconnect con2; +disconnect con1; +connection default; + # End of 4.1 tests # -# lost_query_cost +# last_query_cost # select 1; show status like 'last_query_cost'; + +# +# Test for Bug #15933 max_used_connections is wrong after FLUSH STATUS +# if connections are cached +# +# +# The first suggested fix from the bug report was chosen +# (see http://bugs.mysql.com/bug.php?id=15933): +# +# a) On flushing the status, set max_used_connections to +# threads_connected, not to 0. +# +# b) Check if it is necessary to increment max_used_connections when +# taking a thread from the cache as well as when creating new threads +# + +# Wait for at most $disconnect_timeout seconds for disconnects to finish. +let $disconnect_timeout = 10; + +# Wait for any previous disconnects to finish. +FLUSH STATUS; +--disable_query_log +--disable_result_log +eval SET @wait_left = $disconnect_timeout; +let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; +eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; +let $wait_more = `SELECT @max_used_connections != 1 && @wait_left > 0`; +while ($wait_more) +{ + sleep 1; + FLUSH STATUS; + SET @wait_left = @wait_left - 1; + let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; + eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; + let $wait_more = `SELECT @max_used_connections != 1 && @wait_left > 0`; +} +--enable_query_log +--enable_result_log + +# Prerequisite. +SHOW STATUS LIKE 'max_used_connections'; + +# Save original setting. +SET @save_thread_cache_size=@@thread_cache_size; +SET GLOBAL thread_cache_size=3; + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +connection con1; +disconnect con2; + +# Check that max_used_connections still reflects maximum value. +SHOW STATUS LIKE 'max_used_connections'; + +# Check that after flush max_used_connections equals to current number +# of connections. First wait for previous disconnect to finish. +FLUSH STATUS; +--disable_query_log +--disable_result_log +eval SET @wait_left = $disconnect_timeout; +let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; +eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; +let $wait_more = `SELECT @max_used_connections != 2 && @wait_left > 0`; +while ($wait_more) +{ + sleep 1; + FLUSH STATUS; + SET @wait_left = @wait_left - 1; + let $max_used_connections = `SHOW STATUS LIKE 'max_used_connections'`; + eval SET @max_used_connections = SUBSTRING('$max_used_connections', 21)+0; + let $wait_more = `SELECT @max_used_connections != 2 && @wait_left > 0`; +} +--enable_query_log +--enable_result_log +# Check that we don't count disconnected thread any longer. +SHOW STATUS LIKE 'max_used_connections'; + +# Check that max_used_connections is updated when cached thread is +# reused... +connect (con2,localhost,root,,); +SHOW STATUS LIKE 'max_used_connections'; + +# ...and when new thread is created. +connect (con3,localhost,root,,); +SHOW STATUS LIKE 'max_used_connections'; + +# Restore original setting. +connection default; +SET GLOBAL thread_cache_size=@save_thread_cache_size; + +disconnect con3; +disconnect con2; +disconnect con1; + +# End of 5.0 tests diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index c5925bbd9d5..a0b67b2204d 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -1114,3 +1114,31 @@ load data infile '../std_data_ln/words.dat' into table t1 (a) set b:= f1(); drop table t1; drop function f1; drop function f2; + +# +# Test for Bug #16461 connection_id() does not work properly inside trigger +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 ( + conn_id INT, + trigger_conn_id INT +); +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + SET NEW.trigger_conn_id = CONNECTION_ID(); + +INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1); + +connect (con1,localhost,root,,); +INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1); +connection default; +disconnect con1; + +SELECT * FROM t1 WHERE conn_id != trigger_conn_id; + +DROP TRIGGER t1_bi; +DROP TABLE t1; + +# End of 5.0 tests diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 82f053fb223..04b41ca4a71 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2459,3 +2459,34 @@ SELECT * FROM v1 WHERE td BETWEEN '2005.01.02' AND '2005.01.04'; DROP VIEW v1; DROP TABLE t1; + +# +# BUG#14308: Recursive view definitions +# +# using view only +create table t1 (a int); +create view v1 as select * from t1; +create view v2 as select * from v1; +drop table t1; +rename table v2 to t1; +-- error ER_VIEW_RECURSIVE +select * from v1; +drop view t1, v1; +# using SP function +create table t1 (a int); +delimiter //; +create function f1() returns int +begin + declare mx int; + select max(a) from t1 into mx; + return mx; +end// +delimiter ;// +create view v1 as select f1() as a; +create view v2 as select * from v1; +drop table t1; +rename table v2 to t1; +-- error ER_SP_NO_RECURSION +select * from v1; +drop function f1; +drop view t1, v1; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 1b0f4c34acc..42def845174 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -132,6 +132,7 @@ extern "C" { #include "../storage/innobase/include/sync0sync.h" #include "../storage/innobase/include/fil0fil.h" #include "../storage/innobase/include/trx0xa.h" +#include "../storage/innobase/include/thr0loc.h" } #define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */ @@ -237,7 +238,7 @@ handlerton innobase_hton = { NULL, /* Fill FILES table */ HTON_NO_FLAGS, NULL, /* binlog_func */ - NULL, /* binlog_log_query */ + NULL, /* binlog_log_query */ innobase_release_temporary_latches }; @@ -535,18 +536,18 @@ convert_error_code_to_mysql( } else if (error == (int) DB_CORRUPTION) { - return(HA_ERR_CRASHED); - } else if (error == (int) DB_NO_SAVEPOINT) { + return(HA_ERR_CRASHED); + } else if (error == (int) DB_NO_SAVEPOINT) { - return(HA_ERR_NO_SAVEPOINT); - } else if (error == (int) DB_LOCK_TABLE_FULL) { - /* Since we rolled back the whole transaction, we must - tell it also to MySQL so that MySQL knows to empty the - cached binlog for this transaction */ + return(HA_ERR_NO_SAVEPOINT); + } else if (error == (int) DB_LOCK_TABLE_FULL) { + /* Since we rolled back the whole transaction, we must + tell it also to MySQL so that MySQL knows to empty the + cached binlog for this transaction */ - if (thd) { - ha_rollback(thd); - } + if (thd) { + ha_rollback(thd); + } return(HA_ERR_LOCK_TABLE_FULL); } else { @@ -1014,7 +1015,6 @@ innobase_query_caching_of_table_permitted( mutex_enter_noninline(&kernel_mutex); trx_print(stderr, trx, 1024); mutex_exit_noninline(&kernel_mutex); - ut_error; } innobase_release_stat_resources(trx); @@ -1769,25 +1769,6 @@ innobase_report_binlog_offset_and_commit( trx->mysql_log_file_name = log_file_name; trx->mysql_log_offset = (ib_longlong)end_offset; -#ifdef HAVE_REPLICATION - if (thd->variables.sync_replication) { - /* Let us store the binlog file name and the position, so that - we know how long to wait for the binlog to the replicated to - the slave in synchronous replication. */ - - if (trx->repl_wait_binlog_name == NULL) { - - trx->repl_wait_binlog_name = - (char*)mem_alloc_noninline(FN_REFLEN + 100); - } - - ut_a(strlen(log_file_name) < FN_REFLEN + 100); - - strcpy(trx->repl_wait_binlog_name, log_file_name); - - trx->repl_wait_binlog_pos = (ib_longlong)end_offset; - } -#endif /* HAVE_REPLICATION */ trx->flush_log_later = TRUE; innobase_commit(thd, TRUE); @@ -1856,121 +1837,9 @@ innobase_commit_complete( trx_commit_complete_for_mysql(trx); } -#ifdef HAVE_REPLICATION - if (thd->variables.sync_replication - && trx->repl_wait_binlog_name - && innobase_repl_state != 0) { - - struct timespec abstime; - int cmp; - int ret; - - /* In synchronous replication, let us wait until the MySQL - replication has sent the relevant binlog segment to the - replication slave. */ - - pthread_mutex_lock(&innobase_repl_cond_mutex); -try_again: - if (innobase_repl_state == 0) { - - pthread_mutex_unlock(&innobase_repl_cond_mutex); - - return(0); - } - - cmp = strcmp(innobase_repl_file_name, - trx->repl_wait_binlog_name); - if (cmp > 0 - || (cmp == 0 && innobase_repl_pos - >= (my_off_t)trx->repl_wait_binlog_pos)) { - /* We have already sent the relevant binlog to the - slave: no need to wait here */ - - pthread_mutex_unlock(&innobase_repl_cond_mutex); - -/* printf("Binlog now sent\n"); */ - - return(0); - } - - /* Let us update the info about the minimum binlog position - of waiting threads in the innobase_repl_... variables */ - - if (innobase_repl_wait_file_name_inited != 0) { - cmp = strcmp(trx->repl_wait_binlog_name, - innobase_repl_wait_file_name); - if (cmp < 0 - || (cmp == 0 - && (my_off_t)trx->repl_wait_binlog_pos - <= innobase_repl_wait_pos)) { - /* This thd has an even lower position, let - us update the minimum info */ - - strcpy(innobase_repl_wait_file_name, - trx->repl_wait_binlog_name); - - innobase_repl_wait_pos = - trx->repl_wait_binlog_pos; - } - } else { - strcpy(innobase_repl_wait_file_name, - trx->repl_wait_binlog_name); - - innobase_repl_wait_pos = trx->repl_wait_binlog_pos; - - innobase_repl_wait_file_name_inited = 1; - } - set_timespec(abstime, thd->variables.sync_replication_timeout); - - /* Let us suspend this thread to wait on the condition; - when replication has progressed far enough, we will release - these waiting threads. The following call - pthread_cond_timedwait also atomically unlocks - innobase_repl_cond_mutex. */ - - innobase_repl_n_wait_threads++; - -/* printf("Waiting for binlog to be sent\n"); */ - - ret = pthread_cond_timedwait(&innobase_repl_cond, - &innobase_repl_cond_mutex, &abstime); - innobase_repl_n_wait_threads--; - - if (ret != 0) { - ut_print_timestamp(stderr); - - sql_print_error("MySQL synchronous replication was " - "not able to send the binlog to the " - "slave within the timeout %lu. We " - "assume that the slave has become " - "inaccessible, and switch off " - "synchronous replication until the " - "communication to the slave works " - "again. MySQL synchronous replication " - "has sent binlog to the slave up to " - "file %s, position %lu. This " - "transaction needs it to be sent up " - "to file %s, position %lu.", - thd->variables.sync_replication_timeout, - innobase_repl_file_name, - (ulong) innobase_repl_pos, - trx->repl_wait_binlog_name, - (ulong) trx->repl_wait_binlog_pos); - - innobase_repl_state = 0; - - pthread_mutex_unlock(&innobase_repl_cond_mutex); - - return(0); - } - - goto try_again; - } -#endif // HAVE_REPLICATION return(0); } - /********************************************************************* Rolls back a transaction or the latest SQL statement. */ @@ -2196,6 +2065,7 @@ innobase_close_connection( innobase_rollback_trx(trx); + thr_local_free(trx->mysql_thread_id); trx_free_for_mysql(trx); return(0); @@ -2216,7 +2086,7 @@ ha_innobase::get_row_type() const row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; if (prebuilt && prebuilt->table) { - if (innodb_dict_table_is_comp(prebuilt->table)) { + if (dict_table_is_comp_noninline(prebuilt->table)) { return(ROW_TYPE_COMPACT); } else { return(ROW_TYPE_REDUNDANT); @@ -3609,7 +3479,8 @@ calc_row_difference( TRUE, new_mysql_row_col, col_pack_len, - innodb_dict_table_is_comp(prebuilt->table)); + dict_table_is_comp_noninline( + prebuilt->table)); ufield->new_val.data = dfield.data; ufield->new_val.len = dfield.len; } else { @@ -3769,9 +3640,17 @@ ha_innobase::unlock_row(void) ut_error; } + /* Consistent read does not take any locks, thus there is + nothing to unlock. */ + + if (prebuilt->select_lock_type == LOCK_NONE) { + DBUG_VOID_RETURN; + } + switch (prebuilt->row_read_type) { case ROW_READ_WITH_LOCKS: - if (!srv_locks_unsafe_for_binlog) { + if (!srv_locks_unsafe_for_binlog + || prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED) { break; } /* fall through */ @@ -3803,7 +3682,13 @@ ha_innobase::try_semi_consistent_read(bool yes) { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; - if (yes && srv_locks_unsafe_for_binlog) { + /* Row read type is set to semi consistent read if this was + requested by the MySQL and either innodb_locks_unsafe_for_binlog + option is used or this session is using READ COMMITTED isolation + level. */ + + if (yes && (srv_locks_unsafe_for_binlog + || prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) { prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT; } else { prebuilt->row_read_type = ROW_READ_WITH_LOCKS; @@ -6286,12 +6171,6 @@ ha_innobase::external_lock( trx->n_mysql_tables_in_use++; prebuilt->mysql_has_locked = TRUE; - if (trx->n_mysql_tables_in_use == 1) { - trx->isolation_level = innobase_map_isolation_level( - (enum_tx_isolation) - thd->variables.tx_isolation); - } - if (trx->isolation_level == TRX_ISO_SERIALIZABLE && prebuilt->select_lock_type == LOCK_NONE && (thd->options @@ -6765,11 +6644,22 @@ ha_innobase::store_lock( TL_IGNORE */ { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; + trx_t* trx = prebuilt->trx; /* NOTE: MySQL can call this function with lock 'type' TL_IGNORE! Be careful to ignore TL_IGNORE if we are going to do something with only 'real' locks! */ + /* If no MySQL tables is use we need to set isolation level + of the transaction. */ + + if (lock_type != TL_IGNORE + && trx->n_mysql_tables_in_use == 0) { + trx->isolation_level = innobase_map_isolation_level( + (enum_tx_isolation) + thd->variables.tx_isolation); + } + if ((lock_type == TL_READ && thd->in_lock_tables) || (lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) || lock_type == TL_READ_WITH_SHARED_LOCKS || @@ -6794,18 +6684,26 @@ ha_innobase::store_lock( unexpected if an obsolete consistent read view would be used. */ - if (srv_locks_unsafe_for_binlog && - prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE && - (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) && - (thd->lex->sql_command == SQLCOM_INSERT_SELECT || - thd->lex->sql_command == SQLCOM_UPDATE)) { + ulint isolation_level; - /* In case we have innobase_locks_unsafe_for_binlog - option set and isolation level of the transaction + isolation_level = trx->isolation_level; + + if ((srv_locks_unsafe_for_binlog + || isolation_level == TRX_ISO_READ_COMMITTED) + && isolation_level != TRX_ISO_SERIALIZABLE + && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) + && (thd->lex->sql_command == SQLCOM_INSERT_SELECT + || thd->lex->sql_command == SQLCOM_UPDATE + || thd->lex->sql_command == SQLCOM_CREATE_TABLE)) { + + /* If we either have innobase_locks_unsafe_for_binlog + option set or this session is using READ COMMITTED + isolation level and isolation level of the transaction is not set to serializable and MySQL is doing - INSERT INTO...SELECT or UPDATE ... = (SELECT ...) - without FOR UPDATE or IN SHARE MODE in select, then - we use consistent read for select. */ + INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or + CREATE ... SELECT... without FOR UPDATE or + IN SHARE MODE in select, then we use consistent + read for select. */ prebuilt->select_lock_type = LOCK_NONE; prebuilt->stored_select_lock_type = LOCK_NONE; @@ -6854,25 +6752,26 @@ ha_innobase::store_lock( } /* If we are not doing a LOCK TABLE, DISCARD/IMPORT - TABLESPACE or TRUNCATE TABLE then allow multiple + TABLESPACE or TRUNCATE TABLE then allow multiple writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ < TL_WRITE_CONCURRENT_INSERT. - We especially allow multiple writers if MySQL is at the - start of a stored procedure call (SQLCOM_CALL) - (MySQL does have thd->in_lock_tables TRUE there). */ + We especially allow multiple writers if MySQL is at the + start of a stored procedure call (SQLCOM_CALL) or a + stored function call (MySQL does have thd->in_lock_tables + TRUE there). */ - if ((lock_type >= TL_WRITE_CONCURRENT_INSERT - && lock_type <= TL_WRITE) - && !(thd->in_lock_tables - && thd->lex->sql_command == SQLCOM_LOCK_TABLES) - && !thd->tablespace_op - && thd->lex->sql_command != SQLCOM_TRUNCATE - && thd->lex->sql_command != SQLCOM_OPTIMIZE - && thd->lex->sql_command != SQLCOM_CREATE_TABLE) { + if ((lock_type >= TL_WRITE_CONCURRENT_INSERT + && lock_type <= TL_WRITE) + && !(thd->in_lock_tables + && thd->lex->sql_command == SQLCOM_LOCK_TABLES) + && !thd->tablespace_op + && thd->lex->sql_command != SQLCOM_TRUNCATE + && thd->lex->sql_command != SQLCOM_OPTIMIZE + && thd->lex->sql_command != SQLCOM_CREATE_TABLE) { lock_type = TL_WRITE_ALLOW_WRITE; - } + } /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ... MySQL would use the lock TL_READ_NO_INSERT on t2, and that diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 6bbe3a562d7..4f0c9eb151b 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -316,9 +316,6 @@ int innobase_rollback_by_xid( XID *xid); /* in : X/Open XA Transaction Identification */ -int innobase_repl_report_sent_binlog(THD *thd, char *log_file_name, - my_off_t end_offset); - /*********************************************************************** Create a consistent view for a cursor based on current transaction which is created if the corresponding MySQL thread still lacks one. diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 3d0e6df2831..aa555e310cb 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -384,14 +384,14 @@ Thd_ndb::get_open_table(THD *thd, const void *key) thd_ndb_share->key= key; thd_ndb_share->stat.last_count= count; thd_ndb_share->stat.no_uncommitted_rows_count= 0; - thd_ndb_share->stat.records == ~(ha_rows)0; + thd_ndb_share->stat.records= ~(ha_rows)0; my_hash_insert(&open_tables, (byte *)thd_ndb_share); } else if (thd_ndb_share->stat.last_count != count) { thd_ndb_share->stat.last_count= count; thd_ndb_share->stat.no_uncommitted_rows_count= 0; - thd_ndb_share->stat.records == ~(ha_rows)0; + thd_ndb_share->stat.records= ~(ha_rows)0; } DBUG_PRINT("exit", ("thd_ndb_share: 0x%x key: 0x%x", thd_ndb_share, key)); DBUG_RETURN(thd_ndb_share); @@ -4764,7 +4764,10 @@ int ha_ndbcluster::create(const char *name, DBUG_RETURN(my_errno); } -int ha_ndbcluster::create_handler_files(const char *file, HA_CREATE_INFO *info) +int ha_ndbcluster::create_handler_files(const char *file, + const char *old_name, + int action_flag, + HA_CREATE_INFO *info) { char path[FN_REFLEN]; const char *name; @@ -4776,6 +4779,10 @@ int ha_ndbcluster::create_handler_files(const char *file, HA_CREATE_INFO *info) DBUG_ENTER("create_handler_files"); + if (action_flag != CHF_INDEX_FLAG) + { + DBUG_RETURN(FALSE); + } DBUG_PRINT("enter", ("file: %s", file)); if (!(ndb= get_ndb())) DBUG_RETURN(HA_ERR_NO_CONNECTION); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 75b6b302e8c..0af65a373bd 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -626,7 +626,8 @@ class ha_ndbcluster: public handler int rename_table(const char *from, const char *to); int delete_table(const char *name); int create(const char *name, TABLE *form, HA_CREATE_INFO *info); - int create_handler_files(const char *file, HA_CREATE_INFO *info); + int create_handler_files(const char *file, const char *old_name, + int action_flag, HA_CREATE_INFO *info); int get_default_no_partitions(ulonglong max_rows); bool get_no_parts(const char *name, uint *no_parts); void set_auto_partitions(partition_info *part_info); diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index c2b95d27aef..a39d92ae7a5 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -3095,6 +3095,9 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) Thd_ndb *thd_ndb=0; int ndb_update_binlog_index= 1; injector *inj= injector::instance(); +#ifdef RUN_NDB_BINLOG_TIMER + Timer main_timer; +#endif pthread_mutex_lock(&injector_mutex); /* @@ -3233,9 +3236,6 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) thd->db= db; } -#ifdef RUN_NDB_BINLOG_TIMER - Timer main_timer; -#endif for ( ; !((abort_loop || do_ndbcluster_binlog_close_connection) && ndb_latest_handled_binlog_epoch >= g_latest_trans_gci); ) { @@ -3316,15 +3316,16 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) if (res > 0) { DBUG_PRINT("info", ("pollEvents res: %d", res)); -#ifdef RUN_NDB_BINLOG_TIMER - Timer gci_timer, write_timer; - int event_count= 0; -#endif thd->proc_info= "Processing events"; NdbEventOperation *pOp= i_ndb->nextEvent(); Binlog_index_row row; while (pOp != NULL) { +#ifdef RUN_NDB_BINLOG_TIMER + Timer gci_timer, write_timer; + int event_count= 0; + gci_timer.start(); +#endif gci= pOp->getGCI(); DBUG_PRINT("info", ("Handling gci: %d", (unsigned)gci)); // sometimes get TE_ALTER with invalid table @@ -3503,6 +3504,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) DBUG_PRINT("info", ("COMMIT gci: %lld", gci)); if (ndb_update_binlog_index) ndb_add_binlog_index(thd, &row); + ndb_latest_applied_binlog_epoch= gci; } ndb_latest_handled_binlog_epoch= gci; #ifdef RUN_NDB_BINLOG_TIMER diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 3ee9a2954eb..1ab2c4270fd 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -403,88 +403,6 @@ int ha_partition::ha_initialise() /**************************************************************************** MODULE meta data changes ****************************************************************************/ -/* - Create partition names - - SYNOPSIS - create_partition_name() - out:out Created partition name string - in1 First part - in2 Second part - name_variant Normal, temporary or renamed partition name - - RETURN VALUE - NONE - - DESCRIPTION - This method is used to calculate the partition name, service routine to - the del_ren_cre_table method. -*/ - -#define NORMAL_PART_NAME 0 -#define TEMP_PART_NAME 1 -#define RENAMED_PART_NAME 2 -static void create_partition_name(char *out, const char *in1, - const char *in2, uint name_variant, - bool translate) -{ - char transl_part_name[FN_REFLEN]; - const char *transl_part; - - if (translate) - { - tablename_to_filename(in2, transl_part_name, FN_REFLEN); - transl_part= transl_part_name; - } - else - transl_part= in2; - if (name_variant == NORMAL_PART_NAME) - strxmov(out, in1, "#P#", transl_part, NullS); - else if (name_variant == TEMP_PART_NAME) - strxmov(out, in1, "#P#", transl_part, "#TMP#", NullS); - else if (name_variant == RENAMED_PART_NAME) - strxmov(out, in1, "#P#", transl_part, "#REN#", NullS); -} - -/* - Create subpartition name - - SYNOPSIS - create_subpartition_name() - out:out Created partition name string - in1 First part - in2 Second part - in3 Third part - name_variant Normal, temporary or renamed partition name - - RETURN VALUE - NONE - - DESCRIPTION - This method is used to calculate the subpartition name, service routine to - the del_ren_cre_table method. -*/ - -static void create_subpartition_name(char *out, const char *in1, - const char *in2, const char *in3, - uint name_variant) -{ - char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN]; - - tablename_to_filename(in2, transl_part_name, FN_REFLEN); - tablename_to_filename(in3, transl_subpart_name, FN_REFLEN); - if (name_variant == NORMAL_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, NullS); - else if (name_variant == TEMP_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, "#TMP#", NullS); - else if (name_variant == RENAMED_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, - "#SP#", transl_subpart_name, "#REN#", NullS); -} - - /* Delete a table @@ -576,7 +494,9 @@ int ha_partition::rename_table(const char *from, const char *to) and types of engines in the partitions. */ -int ha_partition::create_handler_files(const char *name, +int ha_partition::create_handler_files(const char *path, + const char *old_path, + int action_flag, HA_CREATE_INFO *create_info) { DBUG_ENTER("ha_partition::create_handler_files()"); @@ -585,10 +505,29 @@ int ha_partition::create_handler_files(const char *name, We need to update total number of parts since we might write the handler file as part of a partition management command */ - if (create_handler_file(name)) + if (action_flag == CHF_DELETE_FLAG || + action_flag == CHF_RENAME_FLAG) { - my_error(ER_CANT_CREATE_HANDLER_FILE, MYF(0)); - DBUG_RETURN(1); + char name[FN_REFLEN]; + char old_name[FN_REFLEN]; + + strxmov(name, path, ha_par_ext, NullS); + strxmov(old_name, old_path, ha_par_ext, NullS); + if ((action_flag == CHF_DELETE_FLAG && + my_delete(name, MYF(MY_WME))) || + (action_flag == CHF_RENAME_FLAG && + my_rename(old_name, name, MYF(MY_WME)))) + { + DBUG_RETURN(TRUE); + } + } + else if (action_flag == CHF_CREATE_FLAG) + { + if (create_handler_file(path)) + { + my_error(ER_CANT_CREATE_HANDLER_FILE, MYF(0)); + DBUG_RETURN(1); + } } DBUG_RETURN(0); } @@ -654,45 +593,26 @@ int ha_partition::create(const char *name, TABLE *table_arg, int ha_partition::drop_partitions(const char *path) { List_iterator part_it(m_part_info->partitions); - List_iterator temp_it(m_part_info->temp_partitions); char part_name_buff[FN_REFLEN]; uint no_parts= m_part_info->partitions.elements; uint part_count= 0; uint no_subparts= m_part_info->no_subparts; uint i= 0; uint name_variant; - int error= 1; - bool reorged_parts= (m_reorged_parts > 0); - bool temp_partitions= (m_part_info->temp_partitions.elements > 0); + int ret_error; + int error= 0; DBUG_ENTER("ha_partition::drop_partitions"); - if (temp_partitions) - no_parts= m_part_info->temp_partitions.elements; do { - partition_element *part_elem; - if (temp_partitions) - { - /* - We need to remove the reorganised partitions that were put in the - temp_partitions-list. - */ - part_elem= temp_it++; - DBUG_ASSERT(part_elem->part_state == PART_TO_BE_DROPPED); - } - else - part_elem= part_it++; - if (part_elem->part_state == PART_TO_BE_DROPPED || - part_elem->part_state == PART_IS_CHANGED) + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_TO_BE_DROPPED) { handler *file; /* This part is to be dropped, meaning the part or all its subparts. */ name_variant= NORMAL_PART_NAME; - if (part_elem->part_state == PART_IS_CHANGED || - (part_elem->part_state == PART_TO_BE_DROPPED && temp_partitions)) - name_variant= RENAMED_PART_NAME; if (m_is_sub_partitioned) { List_iterator sub_it(part_elem->subpartitions); @@ -704,12 +624,10 @@ int ha_partition::drop_partitions(const char *path) create_subpartition_name(part_name_buff, path, part_elem->partition_name, sub_elem->partition_name, name_variant); - if (reorged_parts) - file= m_reorged_file[part_count++]; - else - file= m_file[part]; + file= m_file[part]; DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); - error= file->delete_table((const char *) part_name_buff); + if ((ret_error= file->delete_table((const char *) part_name_buff))) + error= ret_error; } while (++j < no_subparts); } else @@ -717,12 +635,10 @@ int ha_partition::drop_partitions(const char *path) create_partition_name(part_name_buff, path, part_elem->partition_name, name_variant, TRUE); - if (reorged_parts) - file= m_reorged_file[part_count++]; - else - file= m_file[i]; + file= m_file[i]; DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); - error= file->delete_table((const char *) part_name_buff); + if ((ret_error= file->delete_table((const char *) part_name_buff))) + error= ret_error; } if (part_elem->part_state == PART_IS_CHANGED) part_elem->part_state= PART_NORMAL; @@ -764,7 +680,8 @@ int ha_partition::rename_partitions(const char *path) uint no_subparts= m_part_info->no_subparts; uint i= 0; uint j= 0; - int error= 1; + int error= 0; + int ret_error; uint temp_partitions= m_part_info->temp_partitions.elements; handler *file; partition_element *part_elem, *sub_elem; @@ -772,6 +689,14 @@ int ha_partition::rename_partitions(const char *path) if (temp_partitions) { + /* + These are the reorganised partitions that have already been copied. + We delete the partitions and log the delete by inactivating the + delete log entry in the table log. We only need to synchronise + these writes before moving to the next loop since there is no + interaction among reorganised partitions, they cannot have the + same name. + */ do { part_elem= temp_it++; @@ -782,39 +707,59 @@ int ha_partition::rename_partitions(const char *path) { sub_elem= sub_it++; file= m_reorged_file[part_count++]; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - RENAMED_PART_NAME); create_subpartition_name(norm_name_buff, path, part_elem->partition_name, sub_elem->partition_name, NORMAL_PART_NAME); - DBUG_PRINT("info", ("Rename subpartition from %s to %s", - norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + else + sub_elem->log_entry= NULL; /* Indicate success */ } while (++j < no_subparts); } else { file= m_reorged_file[part_count++]; - create_partition_name(part_name_buff, path, - part_elem->partition_name, RENAMED_PART_NAME, - TRUE); create_partition_name(norm_name_buff, path, part_elem->partition_name, NORMAL_PART_NAME, TRUE); - DBUG_PRINT("info", ("Rename partition from %s to %s", - norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + else + part_elem->log_entry= NULL; /* Indicate success */ } } while (++i < temp_partitions); + VOID(sync_ddl_log()); } i= 0; do { + /* + When state is PART_IS_CHANGED it means that we have created a new + TEMP partition that is to be renamed to normal partition name and + we are to delete the old partition with currently the normal name. + + We perform this operation by + 1) Delete old partition with normal partition name + 2) Signal this in table log entry + 3) Synch table log to ensure we have consistency in crashes + 4) Rename temporary partition name to normal partition name + 5) Signal this to table log entry + It is not necessary to synch the last state since a new rename + should not corrupt things if there was no temporary partition. + + The only other parts we need to cater for are new parts that + replace reorganised parts. The reorganised parts were deleted + by the code above that goes through the temp_partitions list. + Thus the synch above makes it safe to simply perform step 4 and 5 + for those entries. + */ part_elem= part_it++; if (part_elem->part_state == PART_IS_CHANGED || (part_elem->part_state == PART_IS_ADDED && temp_partitions)) @@ -836,14 +781,12 @@ int ha_partition::rename_partitions(const char *path) if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - RENAMED_PART_NAME); - DBUG_PRINT("info", ("Rename subpartition from %s to %s", - norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + VOID(sync_ddl_log()); } file= m_new_file[part]; create_subpartition_name(part_name_buff, path, @@ -852,8 +795,13 @@ int ha_partition::rename_partitions(const char *path) TEMP_PART_NAME); DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); - error= file->rename_table((const char *) part_name_buff, - (const char *) norm_name_buff); + if ((ret_error= file->rename_table((const char *) part_name_buff, + (const char *) norm_name_buff))) + error= ret_error; + else if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; + else + sub_elem->log_entry= NULL; } while (++j < no_subparts); } else @@ -864,13 +812,12 @@ int ha_partition::rename_partitions(const char *path) if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; - create_partition_name(part_name_buff, path, - part_elem->partition_name, RENAMED_PART_NAME, - TRUE); - DBUG_PRINT("info", ("Rename partition from %s to %s", - norm_name_buff, part_name_buff)); - error= file->rename_table((const char *) norm_name_buff, - (const char *) part_name_buff); + DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); + if ((ret_error= file->delete_table((const char *) norm_name_buff))) + error= ret_error; + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + VOID(sync_ddl_log()); } file= m_new_file[i]; create_partition_name(part_name_buff, path, @@ -878,11 +825,17 @@ int ha_partition::rename_partitions(const char *path) TRUE); DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); - error= file->rename_table((const char *) part_name_buff, - (const char *) norm_name_buff); + if ((ret_error= file->rename_table((const char *) part_name_buff, + (const char *) norm_name_buff))) + error= ret_error; + else if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) + error= 1; + else + part_elem->log_entry= NULL; } } } while (++i < no_parts); + VOID(sync_ddl_log()); DBUG_RETURN(error); } @@ -1204,7 +1157,6 @@ int ha_partition::prepare_new_partition(TABLE *table, error: if (create_flag) VOID(file->delete_table(part_name)); - print_error(error, MYF(0)); DBUG_RETURN(error); } @@ -1331,7 +1283,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (m_reorged_parts + 1)))) { mem_alloc_error(sizeof(partition_element*)*(m_reorged_parts+1)); - DBUG_RETURN(TRUE); + DBUG_RETURN(ER_OUTOFMEMORY); } /* @@ -1363,7 +1315,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (2*(no_remain_partitions + 1))))) { mem_alloc_error(sizeof(handler*)*2*(no_remain_partitions+1)); - DBUG_RETURN(TRUE); + DBUG_RETURN(ER_OUTOFMEMORY); } m_added_file= &new_file_array[no_remain_partitions + 1]; @@ -1435,7 +1387,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->engine_type))) { mem_alloc_error(sizeof(handler)); - DBUG_RETURN(TRUE); + DBUG_RETURN(ER_OUTOFMEMORY); } } while (++j < no_subparts); } @@ -1483,7 +1435,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (const char *)part_name_buff))) { cleanup_new_partition(part_count); - DBUG_RETURN(TRUE); + DBUG_RETURN(error); } m_added_file[part_count++]= new_file_array[part]; } while (++j < no_subparts); @@ -1499,7 +1451,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, (const char *)part_name_buff))) { cleanup_new_partition(part_count); - DBUG_RETURN(TRUE); + DBUG_RETURN(error); } m_added_file[part_count++]= new_file_array[i]; } @@ -1605,8 +1557,7 @@ int ha_partition::copy_partitions(ulonglong *copied, ulonglong *deleted) } DBUG_RETURN(FALSE); error: - print_error(result, MYF(0)); - DBUG_RETURN(TRUE); + DBUG_RETURN(result); } @@ -1873,8 +1824,8 @@ bool ha_partition::create_handler_file(const char *name) { part_elem= part_it++; if (part_elem->part_state != PART_NORMAL && - part_elem->part_state != PART_IS_ADDED && - part_elem->part_state != PART_IS_CHANGED) + part_elem->part_state != PART_TO_BE_ADDED && + part_elem->part_state != PART_CHANGED) continue; tablename_to_filename(part_elem->partition_name, part_name, FN_REFLEN); @@ -1925,8 +1876,8 @@ bool ha_partition::create_handler_file(const char *name) { part_elem= part_it++; if (part_elem->part_state != PART_NORMAL && - part_elem->part_state != PART_IS_ADDED && - part_elem->part_state != PART_IS_CHANGED) + part_elem->part_state != PART_TO_BE_ADDED && + part_elem->part_state != PART_CHANGED) continue; if (!m_is_sub_partitioned) { diff --git a/sql/ha_partition.h b/sql/ha_partition.h index ecaa7e1e8fa..b31b9af28a3 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -179,7 +179,8 @@ public: virtual int rename_table(const char *from, const char *to); virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); - virtual int create_handler_files(const char *name, + virtual int create_handler_files(const char *name, + const char *old_name, int action_flag, HA_CREATE_INFO *create_info); virtual void update_create_info(HA_CREATE_INFO *create_info); virtual char *update_table_comment(const char *comment); diff --git a/sql/handler.h b/sql/handler.h index e93fdfe67e3..c7c3aa54c3b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -632,6 +632,7 @@ typedef struct { #define UNDEF_NODEGROUP 65535 class Item; +struct st_table_log_memory_entry; class partition_info; @@ -639,7 +640,6 @@ struct st_partition_iter; #define NOT_A_PARTITION_ID ((uint32)-1) - typedef struct st_ha_create_information { CHARSET_INFO *table_charset, *default_table_charset; @@ -1379,8 +1379,15 @@ public: virtual void drop_table(const char *name); virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0; - virtual int create_handler_files(const char *name, HA_CREATE_INFO *info) - { return FALSE;} + +#define CHF_CREATE_FLAG 0 +#define CHF_DELETE_FLAG 1 +#define CHF_RENAME_FLAG 2 +#define CHF_INDEX_FLAG 3 + + virtual int create_handler_files(const char *name, const char *old_name, + int action_flag, HA_CREATE_INFO *info) + { return FALSE; } virtual int change_partitions(HA_CREATE_INFO *create_info, const char *path, diff --git a/sql/item.cc b/sql/item.cc index 787dc22365e..6c79bb39369 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -644,22 +644,6 @@ Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs) } -Item *Item_static_int_func::safe_charset_converter(CHARSET_INFO *tocs) -{ - Item_string *conv; - char buf[64]; - String *s, tmp(buf, sizeof(buf), &my_charset_bin); - s= val_str(&tmp); - if ((conv= new Item_static_string_func(func_name, s->ptr(), s->length(), - s->charset()))) - { - conv->str_value.copy(); - conv->str_value.mark_as_const(); - } - return conv; -} - - Item *Item_static_float_func::safe_charset_converter(CHARSET_INFO *tocs) { Item_string *conv; diff --git a/sql/item.h b/sql/item.h index 6c7a0976df1..ffa3e09fc6e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1431,18 +1431,6 @@ public: }; -class Item_static_int_func :public Item_int -{ - const char *func_name; -public: - Item_static_int_func(const char *str_arg, longlong i, uint length) - :Item_int(NullS, i, length), func_name(str_arg) - {} - Item *safe_charset_converter(CHARSET_INFO *tocs); - void print(String *str) { str->append(func_name); } -}; - - class Item_uint :public Item_int { public: diff --git a/sql/item_create.cc b/sql/item_create.cc index fb1ef0ee9bc..6eca6209438 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -71,14 +71,8 @@ Item *create_func_ceiling(Item* a) Item *create_func_connection_id(void) { - THD *thd=current_thd; - thd->lex->safe_to_cache_query= 0; - return new Item_static_int_func("connection_id()", - (longlong) - ((thd->slave_thread) ? - thd->variables.pseudo_thread_id : - thd->thread_id), - 10); + current_thd->lex->safe_to_cache_query= 0; + return new Item_func_connection_id(); } Item *create_func_conv(Item* a, Item *b, Item *c) diff --git a/sql/item_func.cc b/sql/item_func.cc index 99b49d5686e..efaf4071066 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -561,6 +561,31 @@ String *Item_int_func::val_str(String *str) } +void Item_func_connection_id::fix_length_and_dec() +{ + Item_int_func::fix_length_and_dec(); + max_length= 10; +} + + +bool Item_func_connection_id::fix_fields(THD *thd, Item **ref) +{ + if (Item_int_func::fix_fields(thd, ref)) + return TRUE; + + /* + To replicate CONNECTION_ID() properly we should use + pseudo_thread_id on slave, which contains the value of thread_id + on master. + */ + value= ((thd->slave_thread) ? + thd->variables.pseudo_thread_id : + thd->thread_id); + + return FALSE; +} + + /* Check arguments here to determine result's type for a numeric function of two arguments. @@ -2464,11 +2489,8 @@ longlong Item_func_bit_count::val_int() { DBUG_ASSERT(fixed == 1); ulonglong value= (ulonglong) args[0]->val_int(); - if (args[0]->null_value) - { - null_value=1; /* purecov: inspected */ + if ((null_value= args[0]->null_value)) return 0; /* purecov: inspected */ - } return (longlong) my_count_bits(value); } diff --git a/sql/item_func.h b/sql/item_func.h index ccbbbab1df4..ed5924e8fe1 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -279,6 +279,18 @@ public: }; +class Item_func_connection_id :public Item_int_func +{ + longlong value; + +public: + const char *func_name() const { return "connection_id"; } + void fix_length_and_dec(); + bool fix_fields(THD *thd, Item **ref); + longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } +}; + + class Item_func_signed :public Item_int_func { public: diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index dc14bd93136..cbdfdeef05f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -80,6 +80,20 @@ String *Item_str_func::check_well_formed_result(String *str) } +my_decimal *Item_str_func::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + char buff[64]; + String *res, tmp(buff,sizeof(buff), &my_charset_bin); + res= val_str(&tmp); + if (!res) + return 0; + (void)str2my_decimal(E_DEC_FATAL_ERROR, (char*) res->ptr(), + res->length(), res->charset(), decimal_value); + return decimal_value; +} + + double Item_str_func::val_real() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 6a95a9e5d1f..7d7b62df0dc 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -33,6 +33,7 @@ public: Item_str_func(List &list) :Item_func(list) {decimals=NOT_FIXED_DEC; } longlong val_int(); double val_real(); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return STRING_RESULT; } void left_right_max_length(); String *check_well_formed_result(String *str); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 6fbd6db1a89..34e8b585dcc 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2255,8 +2255,8 @@ String *Item_char_typecast::val_str(String *str) // Convert character set if differ uint dummy_errors; if (!(res= args[0]->val_str(&tmp_value)) || - str->copy(res->ptr(), res->length(), res->charset(), - cast_cs, &dummy_errors)) + str->copy(res->ptr(), res->length(), from_cs, + cast_cs, &dummy_errors)) { null_value= 1; return 0; @@ -2311,21 +2311,40 @@ String *Item_char_typecast::val_str(String *str) void Item_char_typecast::fix_length_and_dec() { uint32 char_length; - /* - We always force character set conversion if cast_cs is a - multi-byte character set. It garantees that the result of CAST is - a well-formed string. For single-byte character sets we allow - just to copy from the argument. A single-byte character sets - string is always well-formed. + /* + We always force character set conversion if cast_cs + is a multi-byte character set. It garantees that the + result of CAST is a well-formed string. + For single-byte character sets we allow just to copy + from the argument. A single-byte character sets string + is always well-formed. + + There is a special trick to convert form a number to ucs2. + As numbers have my_charset_bin as their character set, + it wouldn't do conversion to ucs2 without an additional action. + To force conversion, we should pretend to be non-binary. + Let's choose from_cs this way: + - If the argument in a number and cast_cs is ucs2 (i.e. mbminlen > 1), + then from_cs is set to latin1, to perform latin1 -> ucs2 conversion. + - If the argument is a number and cast_cs is ASCII-compatible + (i.e. mbminlen == 1), then from_cs is set to cast_cs, + which allows just to take over the args[0]->val_str() result + and thus avoid unnecessary character set conversion. + - If the argument is not a number, then from_cs is set to + the argument's charset. */ - charset_conversion= ((cast_cs->mbmaxlen > 1) || - !my_charset_same(args[0]->collation.collation, - cast_cs) && - args[0]->collation.collation != &my_charset_bin && - cast_cs != &my_charset_bin); + from_cs= (args[0]->result_type() == INT_RESULT || + args[0]->result_type() == DECIMAL_RESULT || + args[0]->result_type() == REAL_RESULT) ? + (cast_cs->mbminlen == 1 ? cast_cs : &my_charset_latin1) : + args[0]->collation.collation; + charset_conversion= (cast_cs->mbmaxlen > 1) || + !my_charset_same(from_cs, cast_cs) && + from_cs != &my_charset_bin && + cast_cs != &my_charset_bin; collation.set(cast_cs, DERIVATION_IMPLICIT); char_length= (cast_length >= 0) ? cast_length : - args[0]->max_length/args[0]->collation.collation->mbmaxlen; + args[0]->max_length/from_cs->mbmaxlen; max_length= char_length * cast_cs->mbmaxlen; } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index c5ea618dafe..ae0ca1a0445 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -708,7 +708,7 @@ public: class Item_char_typecast :public Item_typecast { int cast_length; - CHARSET_INFO *cast_cs; + CHARSET_INFO *cast_cs, *from_cs; bool charset_conversion; String tmp_value; public: diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 5773f0476a9..bc398b3d20a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -613,6 +613,100 @@ struct Query_cache_query_flags #define query_cache_invalidate_by_MyISAM_filename_ref NULL #endif /*HAVE_QUERY_CACHE*/ +/* + Error injector Macros to enable easy testing of recovery after failures + in various error cases. +*/ +#ifndef ERROR_INJECT_SUPPORT + +#define ERROR_INJECT(x) 0 +#define ERROR_INJECT_ACTION(x,action) 0 +#define ERROR_INJECT_CRASH(x) 0 +#define ERROR_INJECT_VALUE(x) 0 +#define ERROR_INJECT_VALUE_ACTION(x,action) 0 +#define ERROR_INJECT_VALUE_CRASH(x) 0 +#define SET_ERROR_INJECT_VALUE(x) + +#else + +inline bool check_and_unset_keyword(const char *dbug_str) +{ + const char *extra_str= "-d,"; + char total_str[200]; + if (_db_strict_keyword_ (dbug_str)) + { + strxmov(total_str, extra_str, dbug_str, NullS); + DBUG_SET(total_str); + return 1; + } + return 0; +} + + +inline bool +check_and_unset_inject_value(int value) +{ + THD *thd= current_thd; + if (thd->error_inject_value == (uint)value) + { + thd->error_inject_value= 0; + return 1; + } + return 0; +} + +/* + ERROR INJECT MODULE: + -------------------- + These macros are used to insert macros from the application code. + The event that activates those error injections can be activated + from SQL by using: + SET SESSION dbug=+d,code; + + After the error has been injected, the macros will automatically + remove the debug code, thus similar to using: + SET SESSION dbug=-d,code + from SQL. + + ERROR_INJECT_CRASH will inject a crash of the MySQL Server if code + is set when macro is called. ERROR_INJECT_CRASH can be used in + if-statements, it will always return FALSE unless of course it + crashes in which case it doesn't return at all. + + ERROR_INJECT_ACTION will inject the action specified in the action + parameter of the macro, before performing the action the code will + be removed such that no more events occur. ERROR_INJECT_ACTION + can also be used in if-statements and always returns FALSE. + ERROR_INJECT can be used in a normal if-statement, where the action + part is performed in the if-block. The macro returns TRUE if the + error was activated and otherwise returns FALSE. If activated the + code is removed. + + Sometimes it is necessary to perform error inject actions as a serie + of events. In this case one can use one variable on the THD object. + Thus one sets this value by using e.g. SET_ERROR_INJECT_VALUE(100). + Then one can later test for it by using ERROR_INJECT_CRASH_VALUE, + ERROR_INJECT_ACTION_VALUE and ERROR_INJECT_VALUE. This have the same + behaviour as the above described macros except that they use the + error inject value instead of a code used by DBUG macros. +*/ +#define SET_ERROR_INJECT_VALUE(x) \ + current_thd->error_inject_value= (x) +#define ERROR_INJECT_CRASH(code) \ + DBUG_EVALUATE_IF(code, (abort(), 0), 0) +#define ERROR_INJECT_ACTION(code, action) \ + (check_and_unset_keyword(code) ? ((action), 0) : 0) +#define ERROR_INJECT(code) \ + check_and_unset_keyword(code) +#define ERROR_INJECT_VALUE(value) \ + check_and_unset_inject_value(value) +#define ERROR_INJECT_VALUE_ACTION(value,action) \ + (check_and_unset_inject_value(value) ? (action) : 0) +#define ERROR_INJECT_VALUE_CRASH(value) \ + ERROR_INJECT_VALUE_ACTION(value, (abort(), 0)) + +#endif + uint build_table_path(char *buff, size_t bufflen, const char *db, const char *table, const char *ext); void write_bin_log(THD *thd, bool clear_error, @@ -1090,6 +1184,16 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info, bool remove_table_from_cache(THD *thd, const char *db, const char *table, uint flags); +#define NORMAL_PART_NAME 0 +#define TEMP_PART_NAME 1 +#define RENAMED_PART_NAME 2 +void create_partition_name(char *out, const char *in1, + const char *in2, uint name_variant, + bool translate); +void create_subpartition_name(char *out, const char *in1, + const char *in2, const char *in3, + uint name_variant); + typedef struct st_lock_param_type { ulonglong copied; @@ -1109,14 +1213,94 @@ typedef struct st_lock_param_type uint key_count; uint db_options; uint pack_frm_len; + partition_info *part_info; } ALTER_PARTITION_PARAM_TYPE; void mem_alloc_error(size_t size); -#define WFRM_INITIAL_WRITE 1 -#define WFRM_CREATE_HANDLER_FILES 2 + +enum ddl_log_entry_code +{ + /* + DDL_LOG_EXECUTE_CODE: + This is a code that indicates that this is a log entry to + be executed, from this entry a linked list of log entries + can be found and executed. + DDL_LOG_ENTRY_CODE: + An entry to be executed in a linked list from an execute log + entry. + DDL_IGNORE_LOG_ENTRY_CODE: + An entry that is to be ignored + */ + DDL_LOG_EXECUTE_CODE = 'e', + DDL_LOG_ENTRY_CODE = 'l', + DDL_IGNORE_LOG_ENTRY_CODE = 'i' +}; + +enum ddl_log_action_code +{ + /* + The type of action that a DDL_LOG_ENTRY_CODE entry is to + perform. + DDL_LOG_DELETE_ACTION: + Delete an entity + DDL_LOG_RENAME_ACTION: + Rename an entity + DDL_LOG_REPLACE_ACTION: + Rename an entity after removing the previous entry with the + new name, that is replace this entry. + */ + DDL_LOG_DELETE_ACTION = 'd', + DDL_LOG_RENAME_ACTION = 'r', + DDL_LOG_REPLACE_ACTION = 's' +}; + + +typedef struct st_ddl_log_entry +{ + const char *name; + const char *from_name; + const char *handler_name; + uint next_entry; + uint entry_pos; + enum ddl_log_entry_code entry_type; + enum ddl_log_action_code action_type; + /* + Most actions have only one phase. REPLACE does however have two + phases. The first phase removes the file with the new name if + there was one there before and the second phase renames the + old name to the new name. + */ + char phase; +} DDL_LOG_ENTRY; + +typedef struct st_ddl_log_memory_entry +{ + uint entry_pos; + struct st_ddl_log_memory_entry *next_log_entry; + struct st_ddl_log_memory_entry *prev_log_entry; + struct st_ddl_log_memory_entry *next_active_log_entry; +} DDL_LOG_MEMORY_ENTRY; + + +bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, + DDL_LOG_MEMORY_ENTRY **active_entry); +bool write_execute_ddl_log_entry(uint first_entry, + bool complete, + DDL_LOG_MEMORY_ENTRY **active_entry); +bool deactivate_ddl_log_entry(uint entry_no); +void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry); +bool sync_ddl_log(); +void release_ddl_log(); +void execute_ddl_log_recovery(); +bool execute_ddl_log_entry(THD *thd, uint first_entry); + +extern pthread_mutex_t LOCK_gdl; + +#define WFRM_WRITE_SHADOW 1 +#define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM 4 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); -bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); +int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table); @@ -1224,6 +1408,7 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, /* mysqld.cc */ extern void MYSQLerror(const char*); +void refresh_status(THD *thd); /* item_func.cc */ extern bool check_reserved_words(LEX_STRING *name); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 73bd0d57eb3..4de1e95d0f3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1755,17 +1755,6 @@ void end_thread(THD *thd, bool put_in_cache) } -/* Start a cached thread. LOCK_thread_count is locked on entry */ - -static void start_cached_thread(THD *thd) -{ - thread_cache.append(thd); - wake_thread++; - thread_count++; - pthread_cond_signal(&COND_thread_cache); -} - - void flush_thread_cache() { (void) pthread_mutex_lock(&LOCK_thread_count); @@ -3605,6 +3594,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); unireg_abort(1); } } + execute_ddl_log_recovery(); create_shutdown_thread(); create_maintenance_thread(); @@ -3656,6 +3646,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); pthread_cond_wait(&COND_thread_count,&LOCK_thread_count); (void) pthread_mutex_unlock(&LOCK_thread_count); + release_ddl_log(); #if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) if (Service.IsNT() && start_mode) Service.Stop(); @@ -3927,6 +3918,25 @@ static bool read_init_file(char *file_name) #ifndef EMBEDDED_LIBRARY +/* + Create new thread to handle incoming connection. + + SYNOPSIS + create_new_thread() + thd in/out Thread handle of future thread. + + DESCRIPTION + This function will create new thread to handle the incoming + connection. If there are idle cached threads one will be used. + 'thd' will be pushed into 'threads'. + + In single-threaded mode (#define ONE_THREAD) connection will be + handled inside this function. + + RETURN VALUE + none +*/ + static void create_new_thread(THD *thd) { DBUG_ENTER("create_new_thread"); @@ -3950,11 +3960,12 @@ static void create_new_thread(THD *thd) thd->real_id=pthread_self(); // Keep purify happy /* Start a new thread to handle connection */ + thread_count++; + #ifdef ONE_THREAD if (test_flags & TEST_NO_THREADS) // For debugging under Linux { thread_cache_size=0; // Safety - thread_count++; threads.append(thd); thd->real_id=pthread_self(); (void) pthread_mutex_unlock(&LOCK_thread_count); @@ -3963,18 +3974,20 @@ static void create_new_thread(THD *thd) else #endif { + if (thread_count-delayed_insert_threads > max_used_connections) + max_used_connections=thread_count-delayed_insert_threads; + if (cached_thread_count > wake_thread) { - start_cached_thread(thd); + thread_cache.append(thd); + wake_thread++; + pthread_cond_signal(&COND_thread_cache); } else { int error; - thread_count++; thread_created++; threads.append(thd); - if (thread_count-delayed_insert_threads > max_used_connections) - max_used_connections=thread_count-delayed_insert_threads; DBUG_PRINT("info",(("creating thread %d"), thd->thread_id)); thd->connect_time = time(NULL); if ((error=pthread_create(&thd->real_id,&connection_attrib, @@ -5918,7 +5931,7 @@ The minimum value for this variable is 4096.", (gptr*) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG, REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0}, {"max_prepared_stmt_count", OPT_MAX_PREPARED_STMT_COUNT, - "Maximum numbrer of prepared statements in the server.", + "Maximum number of prepared statements in the server.", (gptr*) &max_prepared_stmt_count, (gptr*) &max_prepared_stmt_count, 0, GET_ULONG, REQUIRED_ARG, 16382, 0, 1*1024*1024, 0, 1, 0}, {"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE, @@ -6160,23 +6173,6 @@ The minimum value for this variable is 4096.", {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.", (gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, -#ifdef HAVE_REPLICATION - {"sync-replication", OPT_SYNC_REPLICATION, - "Enable synchronous replication.", - (gptr*) &global_system_variables.sync_replication, - (gptr*) &global_system_variables.sync_replication, - 0, GET_ULONG, REQUIRED_ARG, 0, 0, 1, 0, 1, 0}, - {"sync-replication-slave-id", OPT_SYNC_REPLICATION_SLAVE_ID, - "Synchronous replication is wished for this slave.", - (gptr*) &global_system_variables.sync_replication_slave_id, - (gptr*) &global_system_variables.sync_replication_slave_id, - 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0}, - {"sync-replication-timeout", OPT_SYNC_REPLICATION_TIMEOUT, - "Synchronous replication timeout.", - (gptr*) &global_system_variables.sync_replication_timeout, - (gptr*) &global_system_variables.sync_replication_timeout, - 0, GET_ULONG, REQUIRED_ARG, 10, 0, ~0L, 0, 1, 0}, -#endif /* HAVE_REPLICATION */ {"table_cache", OPT_TABLE_OPEN_CACHE, "Deprecated; use --table_open_cache instead.", (gptr*) &table_cache_size, (gptr*) &table_cache_size, 0, GET_ULONG, @@ -8062,7 +8058,38 @@ static void create_pid_file() (void) my_close(file, MYF(0)); } sql_perror("Can't start server: can't create PID file"); - exit(1); + exit(1); +} + + +/* Clear most status variables */ +void refresh_status(THD *thd) +{ + pthread_mutex_lock(&LOCK_status); + + /* We must update the global status before cleaning up the thread */ + add_to_status(&global_status_var, &thd->status_var); + bzero((char*) &thd->status_var, sizeof(thd->status_var)); + + for (SHOW_VAR *ptr= status_vars; ptr->name; ptr++) + { + /* Note that SHOW_LONG_NOFLUSH variables are not reset */ + if (ptr->type == SHOW_LONG) + *(ulong*) ptr->value= 0; + } + /* Reset the counters of all key caches (default and named). */ + process_key_caches(reset_key_cache_counters); + pthread_mutex_unlock(&LOCK_status); + + /* + Set max_used_connections to the number of currently open + connections. Lock LOCK_thread_count out of LOCK_status to avoid + deadlocks. Status reset becomes not atomic, but status data is + not exact anyway. + */ + pthread_mutex_lock(&LOCK_thread_count); + max_used_connections= thread_count-delayed_insert_threads; + pthread_mutex_unlock(&LOCK_thread_count); } diff --git a/sql/partition_element.h b/sql/partition_element.h index d20715d2408..13693934c0f 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -36,6 +36,8 @@ enum partition_state { PART_IS_ADDED= 8 }; +struct st_ddl_log_memory_entry; + class partition_element :public Sql_alloc { public: List subpartitions; @@ -44,6 +46,7 @@ public: ulonglong part_min_rows; char *partition_name; char *tablespace_name; + struct st_ddl_log_memory_entry *log_entry; longlong range_value; char* part_comment; char* data_file_name; @@ -55,7 +58,8 @@ public: partition_element() : part_max_rows(0), part_min_rows(0), partition_name(NULL), - tablespace_name(NULL), range_value(0), part_comment(NULL), + tablespace_name(NULL), log_entry(NULL), + range_value(0), part_comment(NULL), data_file_name(NULL), index_file_name(NULL), engine_type(NULL),part_state(PART_NORMAL), nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE) diff --git a/sql/partition_info.h b/sql/partition_info.h index ae95b4a339f..3a1e6be4050 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -28,7 +28,7 @@ typedef int (*get_part_id_func)(partition_info *part_info, longlong *func_value); typedef uint32 (*get_subpart_id_func)(partition_info *part_info); - +struct st_ddl_log_memory_entry; class partition_info : public Sql_alloc { @@ -76,7 +76,11 @@ public: Item *subpart_expr; Item *item_free_list; - + + struct st_ddl_log_memory_entry *first_log_entry; + struct st_ddl_log_memory_entry *exec_log_entry; + struct st_ddl_log_memory_entry *frm_log_entry; + /* A bitmap of partitions used by the current query. Usage pattern: @@ -191,6 +195,7 @@ public: part_field_array(NULL), subpart_field_array(NULL), full_part_field_array(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), + first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL), list_array(NULL), part_info_string(NULL), part_func_string(NULL), subpart_func_string(NULL), diff --git a/sql/set_var.cc b/sql/set_var.cc index 59e0c7b6ff7..16a0c752639 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -436,14 +436,6 @@ sys_var_thd_storage_engine sys_storage_engine("storage_engine", &SV::table_type); #ifdef HAVE_REPLICATION sys_var_sync_binlog_period sys_sync_binlog_period("sync_binlog", &sync_binlog_period); -sys_var_thd_ulong sys_sync_replication("sync_replication", - &SV::sync_replication); -sys_var_thd_ulong sys_sync_replication_slave_id( - "sync_replication_slave_id", - &SV::sync_replication_slave_id); -sys_var_thd_ulong sys_sync_replication_timeout( - "sync_replication_timeout", - &SV::sync_replication_timeout); #endif sys_var_bool_ptr sys_sync_frm("sync_frm", &opt_sync_frm); sys_var_long_ptr sys_table_def_size("table_definition_cache", @@ -966,11 +958,6 @@ SHOW_VAR init_vars[]= { {sys_sync_binlog_period.name,(char*) &sys_sync_binlog_period, SHOW_SYS}, #endif {sys_sync_frm.name, (char*) &sys_sync_frm, SHOW_SYS}, -#ifdef HAVE_REPLICATION - {sys_sync_replication.name, (char*) &sys_sync_replication, SHOW_SYS}, - {sys_sync_replication_slave_id.name, (char*) &sys_sync_replication_slave_id,SHOW_SYS}, - {sys_sync_replication_timeout.name, (char*) &sys_sync_replication_timeout,SHOW_SYS}, -#endif #ifdef HAVE_TZNAME {"system_time_zone", system_time_zone, SHOW_CHAR}, #endif diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index d836bd4ff6c..c63c5f21a54 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5826,6 +5826,8 @@ ER_NDB_CANT_SWITCH_BINLOG_FORMAT eng "The NDB cluster engine does not support changing the binlog format on the fly yet" ER_PARTITION_NO_TEMPORARY eng "Cannot create temporary table with partitions" +ER_DDL_LOG_ERROR + eng "Error in DDL log" ER_NULL_IN_VALUES_LESS_THAN eng "Not allowed to use NULL value in VALUES LESS THAN" swe "Det r inte tilltet att anvnda NULL-vrden i VALUES LESS THAN" @@ -5834,3 +5836,5 @@ ER_WRONG_PARTITION_NAME swe "Felaktigt partitionsnamn" ER_MAX_PREPARED_STMT_COUNT_REACHED 42000 eng "Can't create more than max_prepared_stmt_count statements (current value: %lu)" +ER_VIEW_RECURSIVE + eng "`%-.64s`.`%-.64s` contain view recursion" diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 47d4326d780..5a421d00186 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1229,7 +1229,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, DBUG_PRINT("info", ("function %s", m_name.str)); LINT_INIT(binlog_save_options); - params = m_pcont->context_pvars(); + params= m_pcont->context_var_count(); /* Check that the function is called with all specified arguments. @@ -1412,7 +1412,7 @@ bool sp_head::execute_procedure(THD *thd, List *args) { bool err_status= FALSE; - uint params = m_pcont->context_pvars(); + uint params = m_pcont->context_var_count(); sp_rcontext *save_spcont, *octx; sp_rcontext *nctx = NULL; bool save_enable_slow_log= false; @@ -1466,15 +1466,15 @@ sp_head::execute_procedure(THD *thd, List *args) for (uint i= 0 ; i < params ; i++) { Item *arg_item= it_args++; - sp_pvar_t *pvar= m_pcont->find_pvar(i); + sp_variable_t *spvar= m_pcont->find_variable(i); if (!arg_item) break; - if (!pvar) + if (!spvar) continue; - if (pvar->mode != sp_param_in) + if (spvar->mode != sp_param_in) { if (!arg_item->is_splocal() && !item_is_user_var(arg_item)) { @@ -1484,7 +1484,7 @@ sp_head::execute_procedure(THD *thd, List *args) } } - if (pvar->mode == sp_param_out) + if (spvar->mode == sp_param_out) { Item_null *null_item= new Item_null(); @@ -1560,9 +1560,9 @@ sp_head::execute_procedure(THD *thd, List *args) if (!arg_item) break; - sp_pvar_t *pvar= m_pcont->find_pvar(i); + sp_variable_t *spvar= m_pcont->find_variable(i); - if (pvar->mode == sp_param_in) + if (spvar->mode == sp_param_in) continue; if (arg_item->is_splocal()) @@ -2432,7 +2432,7 @@ sp_instr_set::print(String *str) { /* set name@offset ... */ int rsrv = SP_INSTR_UINT_MAXLEN+6; - sp_pvar_t *var = m_ctx->find_pvar(m_offset); + sp_variable_t *var = m_ctx->find_variable(m_offset); /* 'var' should always be non-null, but just in case... */ if (var) @@ -3048,8 +3048,8 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) void sp_instr_cfetch::print(String *str) { - List_iterator_fast li(m_varlist); - sp_pvar_t *pv; + List_iterator_fast li(m_varlist); + sp_variable_t *pv; LEX_STRING n; my_bool found= m_ctx->find_cursor(m_cursor, &n); /* cfetch name@offset vars... */ diff --git a/sql/sp_head.h b/sql/sp_head.h index 66e0a5856f4..08d503f7415 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -44,7 +44,7 @@ class sp_instr; class sp_instr_opt_meta; class sp_instr_jump_if_not; struct sp_cond_type; -struct sp_pvar; +struct sp_variable; class sp_name : public Sql_alloc { @@ -1075,7 +1075,7 @@ public: virtual void print(String *str); - void add_to_varlist(struct sp_pvar *var) + void add_to_varlist(struct sp_variable *var) { m_varlist.push_back(var); } @@ -1083,7 +1083,7 @@ public: private: uint m_cursor; - List m_varlist; + List m_varlist; }; // class sp_instr_cfetch : public sp_instr diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index f69053a7c88..448df908a32 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -27,10 +27,10 @@ #include "sp_head.h" /* - * Sanity check for SQLSTATEs. Will not check if it's really an existing - * state (there are just too many), but will check length and bad characters. - * Returns TRUE if it's ok, FALSE if it's bad. - */ + Sanity check for SQLSTATEs. Will not check if it's really an existing + state (there are just too many), but will check length and bad characters. + Returns TRUE if it's ok, FALSE if it's bad. +*/ bool sp_cond_check(LEX_STRING *sqlstate) { @@ -51,25 +51,25 @@ sp_cond_check(LEX_STRING *sqlstate) } sp_pcontext::sp_pcontext(sp_pcontext *prev) - :Sql_alloc(), m_total_pvars(0), m_csubsize(0), m_hsubsize(0), - m_handlers(0), m_parent(prev), m_pboundary(0) + :Sql_alloc(), m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0), + m_context_handlers(0), m_parent(prev), m_pboundary(0) { - VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8)); + VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *), 16, 8)); VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int), 16, 8)); - VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8)); - VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8)); - VOID(my_init_dynamic_array(&m_handler, sizeof(sp_cond_type_t *), 16, 8)); + VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *), 16, 8)); + VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING), 16, 8)); + VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *), 16, 8)); m_label.empty(); m_children.empty(); if (!prev) { - m_poffset= m_coffset= 0; + m_var_offset= m_cursor_offset= 0; m_num_case_exprs= 0; } else { - m_poffset= prev->m_poffset + prev->m_total_pvars; - m_coffset= prev->current_cursors(); + m_var_offset= prev->m_var_offset + prev->m_max_var_index; + m_cursor_offset= prev->current_cursor_count(); m_num_case_exprs= prev->get_num_case_exprs(); } } @@ -85,11 +85,11 @@ sp_pcontext::destroy() m_children.empty(); m_label.empty(); - delete_dynamic(&m_pvar); + delete_dynamic(&m_vars); delete_dynamic(&m_case_expr_id_lst); - delete_dynamic(&m_cond); - delete_dynamic(&m_cursor); - delete_dynamic(&m_handler); + delete_dynamic(&m_conds); + delete_dynamic(&m_cursors); + delete_dynamic(&m_handlers); } sp_pcontext * @@ -105,15 +105,15 @@ sp_pcontext::push_context() sp_pcontext * sp_pcontext::pop_context() { - m_parent->m_total_pvars= m_parent->m_total_pvars + m_total_pvars; + m_parent->m_max_var_index+= m_max_var_index; - uint submax= max_handlers(); - if (submax > m_parent->m_hsubsize) - m_parent->m_hsubsize= submax; + uint submax= max_handler_index(); + if (submax > m_parent->m_max_handler_index) + m_parent->m_max_handler_index= submax; - submax= max_cursors(); - if (submax > m_parent->m_csubsize) - m_parent->m_csubsize= submax; + submax= max_cursor_index(); + if (submax > m_parent->m_max_cursor_index) + m_parent->m_max_cursor_index= submax; if (m_num_case_exprs > m_parent->m_num_case_exprs) m_parent->m_num_case_exprs= m_num_case_exprs; @@ -130,12 +130,12 @@ sp_pcontext::diff_handlers(sp_pcontext *ctx, bool exclusive) while (pctx && pctx != ctx) { - n+= pctx->m_handlers; + n+= pctx->m_context_handlers; last_ctx= pctx; pctx= pctx->parent_context(); } if (pctx) - return (exclusive && last_ctx ? n - last_ctx->m_handlers : n); + return (exclusive && last_ctx ? n - last_ctx->m_context_handlers : n); return 0; // Didn't find ctx } @@ -148,32 +148,33 @@ sp_pcontext::diff_cursors(sp_pcontext *ctx, bool exclusive) while (pctx && pctx != ctx) { - n+= pctx->m_cursor.elements; + n+= pctx->m_cursors.elements; last_ctx= pctx; pctx= pctx->parent_context(); } if (pctx) - return (exclusive && last_ctx ? n - last_ctx->m_cursor.elements : n); + return (exclusive && last_ctx ? n - last_ctx->m_cursors.elements : n); return 0; // Didn't find ctx } -/* This does a linear search (from newer to older variables, in case -** we have shadowed names). -** It's possible to have a more efficient allocation and search method, -** but it might not be worth it. The typical number of parameters and -** variables will in most cases be low (a handfull). -** ...and, this is only called during parsing. +/* + This does a linear search (from newer to older variables, in case + we have shadowed names). + It's possible to have a more efficient allocation and search method, + but it might not be worth it. The typical number of parameters and + variables will in most cases be low (a handfull). + ...and, this is only called during parsing. */ -sp_pvar_t * -sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped) +sp_variable_t * +sp_pcontext::find_variable(LEX_STRING *name, my_bool scoped) { - uint i= m_pvar.elements - m_pboundary; + uint i= m_vars.elements - m_pboundary; while (i--) { - sp_pvar_t *p; + sp_variable_t *p; - get_dynamic(&m_pvar, (gptr)&p, i); + get_dynamic(&m_vars, (gptr)&p, i); if (my_strnncoll(system_charset_info, (const uchar *)name->str, name->length, (const uchar *)p->name.str, p->name.length) == 0) @@ -182,7 +183,7 @@ sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped) } } if (!scoped && m_parent) - return m_parent->find_pvar(name, scoped); + return m_parent->find_variable(name, scoped); return NULL; } @@ -192,40 +193,40 @@ sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped) - When evaluating parameters at the beginning, and setting out parameters at the end, of invokation. (Top frame only, so no recursion then.) - For printing of sp_instr_set. (Debug mode only.) - */ -sp_pvar_t * -sp_pcontext::find_pvar(uint offset) +*/ +sp_variable_t * +sp_pcontext::find_variable(uint offset) { - if (m_poffset <= offset && offset < m_poffset + m_pvar.elements) + if (m_var_offset <= offset && offset < m_var_offset + m_vars.elements) { // This frame - sp_pvar_t *p; + sp_variable_t *p; - get_dynamic(&m_pvar, (gptr)&p, offset - m_poffset); + get_dynamic(&m_vars, (gptr)&p, offset - m_var_offset); return p; } if (m_parent) - return m_parent->find_pvar(offset); // Some previous frame + return m_parent->find_variable(offset); // Some previous frame return NULL; // index out of bounds } -sp_pvar_t * -sp_pcontext::push_pvar(LEX_STRING *name, enum enum_field_types type, - sp_param_mode_t mode) +sp_variable_t * +sp_pcontext::push_variable(LEX_STRING *name, enum enum_field_types type, + sp_param_mode_t mode) { - sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t)); + sp_variable_t *p= (sp_variable_t *)sql_alloc(sizeof(sp_variable_t)); if (!p) return NULL; - ++m_total_pvars; + ++m_max_var_index; p->name.str= name->str; p->name.length= name->length; p->type= type; p->mode= mode; - p->offset= current_pvars(); + p->offset= current_var_count(); p->dflt= NULL; - insert_dynamic(&m_pvar, (gptr)&p); + insert_dynamic(&m_vars, (gptr)&p); return p; } @@ -272,23 +273,23 @@ sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val) p->name.str= name->str; p->name.length= name->length; p->val= val; - insert_dynamic(&m_cond, (gptr)&p); + insert_dynamic(&m_conds, (gptr)&p); } } /* - * See comment for find_pvar() above - */ + See comment for find_variable() above +*/ sp_cond_type_t * sp_pcontext::find_cond(LEX_STRING *name, my_bool scoped) { - uint i= m_cond.elements; + uint i= m_conds.elements; while (i--) { sp_cond_t *p; - get_dynamic(&m_cond, (gptr)&p, i); + get_dynamic(&m_conds, (gptr)&p, i); if (my_strnncoll(system_charset_info, (const uchar *)name->str, name->length, (const uchar *)p->name.str, p->name.length) == 0) @@ -302,20 +303,20 @@ sp_pcontext::find_cond(LEX_STRING *name, my_bool scoped) } /* - * This only searches the current context, for error checking of - * duplicates. - * Returns TRUE if found. - */ + This only searches the current context, for error checking of + duplicates. + Returns TRUE if found. +*/ bool sp_pcontext::find_handler(sp_cond_type_t *cond) { - uint i= m_handler.elements; + uint i= m_handlers.elements; while (i--) { sp_cond_type_t *p; - get_dynamic(&m_handler, (gptr)&p, i); + get_dynamic(&m_handlers, (gptr)&p, i); if (cond->type == p->type) { switch (p->type) @@ -341,31 +342,31 @@ sp_pcontext::push_cursor(LEX_STRING *name) { LEX_STRING n; - if (m_cursor.elements == m_csubsize) - m_csubsize+= 1; + if (m_cursors.elements == m_max_cursor_index) + m_max_cursor_index+= 1; n.str= name->str; n.length= name->length; - insert_dynamic(&m_cursor, (gptr)&n); + insert_dynamic(&m_cursors, (gptr)&n); } /* - * See comment for find_pvar() above - */ + See comment for find_variable() above +*/ my_bool sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped) { - uint i= m_cursor.elements; + uint i= m_cursors.elements; while (i--) { LEX_STRING n; - get_dynamic(&m_cursor, (gptr)&n, i); + get_dynamic(&m_cursors, (gptr)&n, i); if (my_strnncoll(system_charset_info, (const uchar *)name->str, name->length, (const uchar *)n.str, n.length) == 0) { - *poff= m_coffset + i; + *poff= m_cursor_offset + i; return TRUE; } } @@ -380,10 +381,10 @@ sp_pcontext::retrieve_field_definitions(List *field_def_lst) { /* Put local/context fields in the result list. */ - for (uint i = 0; i < m_pvar.elements; ++i) + for (uint i = 0; i < m_vars.elements; ++i) { - sp_pvar_t *var_def; - get_dynamic(&m_pvar, (gptr) &var_def, i); + sp_variable_t *var_def; + get_dynamic(&m_vars, (gptr) &var_def, i); field_def_lst->push_back(&var_def->field_def); } @@ -400,17 +401,17 @@ sp_pcontext::retrieve_field_definitions(List *field_def_lst) /* Find a cursor by offset from the top. This is only used for debugging. - */ +*/ my_bool sp_pcontext::find_cursor(uint offset, LEX_STRING *n) { - if (m_coffset <= offset && offset < m_coffset + m_cursor.elements) + if (m_cursor_offset <= offset && + offset < m_cursor_offset + m_cursors.elements) { // This frame - get_dynamic(&m_cursor, (gptr)n, offset - m_coffset); + get_dynamic(&m_cursors, (gptr)n, offset - m_cursor_offset); return TRUE; } if (m_parent) return m_parent->find_cursor(offset, n); // Some previous frame return FALSE; // index out of bounds } - diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 872c7c1d505..e61057537da 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -29,22 +29,23 @@ typedef enum sp_param_inout } sp_param_mode_t; -typedef struct sp_pvar +typedef struct sp_variable { LEX_STRING name; enum enum_field_types type; sp_param_mode_t mode; /* - offset -- basically, this is an index of variable in the scope of root - parsing context. This means, that all variables in a stored routine - have distinct indexes/offsets. + offset -- this the index to the variable's value in the runtime frame. + This is calculated during parsing and used when creating sp_instr_set + instructions and Item_splocal items. + I.e. values are set/referred by array indexing in runtime. */ uint offset; Item *dflt; create_field field_def; -} sp_pvar_t; +} sp_variable_t; #define SP_LAB_REF 0 // Unresolved reference (for goto) @@ -76,9 +77,10 @@ typedef struct sp_cond_type uint mysqlerr; } sp_cond_type_t; -/* Sanity check for SQLSTATEs. Will not check if it's really an existing - * state (there are just too many), but will check length bad characters. - */ +/* + Sanity check for SQLSTATEs. Will not check if it's really an existing + state (there are just too many), but will check length bad characters. +*/ extern bool sp_cond_check(LEX_STRING *sqlstate); @@ -90,7 +92,17 @@ typedef struct sp_cond /* - This seems to be an "SP parsing context" or something. + The parse-time context, used to keep track on declared variables/parameters, + conditions, handlers, cursors and labels, during parsing. + sp_contexts are organized as a tree, with one object for each begin-end + block, plus a root-context for the parameters. + This is used during parsing for looking up defined names (e.g. declared + variables and visible labels), for error checking, and to calculate offsets + to be used at runtime. (During execution variable values, active handlers + and cursors, etc, are referred to by an index in a stack.) + The pcontext tree is also kept during execution and is used for error + checking (e.g. correct number of parameters), and in the future, used by + the debugger. */ class sp_pcontext : public Sql_alloc @@ -134,50 +146,64 @@ class sp_pcontext : public Sql_alloc // Parameters and variables // + /* + The maximum number of variables used in this and all child contexts + In the root, this gives us the number of slots needed for variables + during execution. + */ inline uint - total_pvars() + max_var_index() { - return m_total_pvars; + return m_max_var_index; } + /* + The current number of variables used in the parents (from the root), + including this context. + */ inline uint - current_pvars() + current_var_count() { - return m_poffset + m_pvar.elements; + return m_var_offset + m_vars.elements; } + /* The number of variables in this context alone */ inline uint - context_pvars() + context_var_count() { - return m_pvar.elements; + return m_vars.elements; } + /* Map index in this pcontext to runtime offset */ inline uint - pvar_context2index(uint i) + var_context2runtime(uint i) { - return m_poffset + i; + return m_var_offset + i; } + /* Set type of variable. 'i' is the offset from the top */ inline void set_type(uint i, enum enum_field_types type) { - sp_pvar_t *p= find_pvar(i); + sp_variable_t *p= find_variable(i); if (p) p->type= type; } + /* Set default value of variable. 'i' is the offset from the top */ inline void set_default(uint i, Item *it) { - sp_pvar_t *p= find_pvar(i); + sp_variable_t *p= find_variable(i); if (p) p->dflt= it; } - sp_pvar_t * - push_pvar(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode); + sp_variable_t * + push_variable(LEX_STRING *name, enum enum_field_types type, + sp_param_mode_t mode); /* Retrieve definitions of fields from the current context and its @@ -187,12 +213,12 @@ class sp_pcontext : public Sql_alloc retrieve_field_definitions(List *field_def_lst); // Find by name - sp_pvar_t * - find_pvar(LEX_STRING *name, my_bool scoped=0); + sp_variable_t * + find_variable(LEX_STRING *name, my_bool scoped=0); - // Find by offset - sp_pvar_t * - find_pvar(uint offset); + // Find by offset (from the top) + sp_variable_t * + find_variable(uint offset); /* Set the current scope boundary (for default values). @@ -280,7 +306,7 @@ class sp_pcontext : public Sql_alloc pop_cond(uint num) { while (num--) - pop_dynamic(&m_cond); + pop_dynamic(&m_conds); } sp_cond_type_t * @@ -293,22 +319,22 @@ class sp_pcontext : public Sql_alloc inline void push_handler(sp_cond_type_t *cond) { - insert_dynamic(&m_handler, (gptr)&cond); + insert_dynamic(&m_handlers, (gptr)&cond); } bool find_handler(sp_cond_type *cond); inline uint - max_handlers() + max_handler_index() { - return m_hsubsize + m_handlers; + return m_max_handler_index + m_context_handlers; } inline void add_handlers(uint n) { - m_handlers+= n; + m_context_handlers+= n; } // @@ -326,51 +352,51 @@ class sp_pcontext : public Sql_alloc find_cursor(uint offset, LEX_STRING *n); inline uint - max_cursors() + max_cursor_index() { - return m_csubsize + m_cursor.elements; + return m_max_cursor_index + m_cursors.elements; } inline uint - current_cursors() + current_cursor_count() { - return m_coffset + m_cursor.elements; + return m_cursor_offset + m_cursors.elements; } protected: /* - m_total_pvars -- number of variables (including all types of arguments) + m_max_var_index -- number of variables (including all types of arguments) in this context including all children contexts. - m_total_pvars >= m_pvar.elements. + m_max_var_index >= m_vars.elements. - m_total_pvars of the root parsing context contains number of all + m_max_var_index of the root parsing context contains number of all variables (including arguments) in all enclosed contexts. */ - uint m_total_pvars; + uint m_max_var_index; // The maximum sub context's framesizes - uint m_csubsize; - uint m_hsubsize; - uint m_handlers; // No. of handlers in this context + uint m_max_cursor_index; + uint m_max_handler_index; + uint m_context_handlers; // No. of handlers in this context private: sp_pcontext *m_parent; // Parent context /* - m_poffset -- basically, this is an index of the first variable in this - parsing context. + m_var_offset -- this is an index of the first variable in this + parsing context. - m_poffset is 0 for root context. + m_var_offset is 0 for root context. Since now each variable is stored in separate place, no reuse is done, - so m_poffset is different for all enclosed contexts. + so m_var_offset is different for all enclosed contexts. */ - uint m_poffset; + uint m_var_offset; - uint m_coffset; // Cursor offset for this context + uint m_cursor_offset; // Cursor offset for this context /* Boundary for finding variables in this context. This is the number @@ -382,11 +408,11 @@ private: int m_num_case_exprs; - DYNAMIC_ARRAY m_pvar; // Parameters/variables + DYNAMIC_ARRAY m_vars; // Parameters/variables DYNAMIC_ARRAY m_case_expr_id_lst; /* Stack of CASE expression ids. */ - DYNAMIC_ARRAY m_cond; // Conditions - DYNAMIC_ARRAY m_cursor; // Cursors - DYNAMIC_ARRAY m_handler; // Handlers, for checking of duplicates + DYNAMIC_ARRAY m_conds; // Conditions + DYNAMIC_ARRAY m_cursors; // Cursors + DYNAMIC_ARRAY m_handlers; // Handlers, for checking for duplicates List m_label; // The label list diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index af4e41c29be..38b6de0e75a 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -73,16 +73,16 @@ bool sp_rcontext::init(THD *thd) return !(m_handler= - (sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handlers() * + (sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handler_index() * sizeof(sp_handler_t))) || !(m_hstack= - (uint*)thd->alloc(m_root_parsing_ctx->max_handlers() * + (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() * sizeof(uint))) || !(m_in_handler= - (uint*)thd->alloc(m_root_parsing_ctx->max_handlers() * + (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() * sizeof(uint))) || !(m_cstack= - (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursors() * + (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursor_index() * sizeof(sp_cursor*))) || !(m_case_expr_holders= (Item_cache**)thd->calloc(m_root_parsing_ctx->get_num_case_exprs() * @@ -105,12 +105,12 @@ sp_rcontext::init_var_table(THD *thd) { List field_def_lst; - if (!m_root_parsing_ctx->total_pvars()) + if (!m_root_parsing_ctx->max_var_index()) return FALSE; m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst); - DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->total_pvars()); + DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->max_var_index()); if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst))) return TRUE; @@ -134,7 +134,7 @@ bool sp_rcontext::init_var_items() { uint idx; - uint num_vars= m_root_parsing_ctx->total_pvars(); + uint num_vars= m_root_parsing_ctx->max_var_index(); if (!(m_var_items= (Item**) sql_alloc(num_vars * sizeof (Item *)))) return TRUE; @@ -381,7 +381,7 @@ sp_cursor::destroy() int -sp_cursor::fetch(THD *thd, List *vars) +sp_cursor::fetch(THD *thd, List *vars) { if (! server_side_cursor) { @@ -528,9 +528,9 @@ int Select_fetch_into_spvars::prepare(List &fields, SELECT_LEX_UNIT *u) bool Select_fetch_into_spvars::send_data(List &items) { - List_iterator_fast pv_iter(*spvar_list); + List_iterator_fast spvar_iter(*spvar_list); List_iterator_fast item_iter(items); - sp_pvar_t *pv; + sp_variable_t *spvar; Item *item; /* Must be ensured by the caller */ @@ -540,9 +540,9 @@ bool Select_fetch_into_spvars::send_data(List &items) Assign the row fetched from a server side cursor to stored procedure variables. */ - for (; pv= pv_iter++, item= item_iter++; ) + for (; spvar= spvar_iter++, item= item_iter++; ) { - if (thd->spcont->set_variable(thd, pv->offset, item)) + if (thd->spcont->set_variable(thd, spvar->offset, item)) return TRUE; } return FALSE; diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index e7393902e72..20aaea3b7c1 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -24,7 +24,7 @@ struct sp_cond_type; class sp_cursor; -struct sp_pvar; +struct sp_variable; class sp_lex_keeper; class sp_instr_cpush; @@ -265,12 +265,12 @@ private: class Select_fetch_into_spvars: public select_result_interceptor { - List *spvar_list; + List *spvar_list; uint field_count; public: Select_fetch_into_spvars() {} /* Remove gcc warning */ uint get_field_count() { return field_count; } - void set_spvar_list(List *vars) { spvar_list= vars; } + void set_spvar_list(List *vars) { spvar_list= vars; } virtual bool send_eof() { return FALSE; } virtual bool send_data(List &items); @@ -307,7 +307,7 @@ public: } int - fetch(THD *, List *vars); + fetch(THD *, List *vars); inline sp_instr_cpush * get_instr() diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e09fed180ba..94b7ce1f3cc 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6140,9 +6140,8 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) abort_and_upgrade_lock() lpt Parameter passing struct All parameters passed through the ALTER_PARTITION_PARAM_TYPE object - RETURN VALUES - TRUE Failure - FALSE Success + RETURN VALUE + 0 DESCRIPTION Remember old lock level (for possible downgrade later on), abort all waiting threads and ensure that all keeping locks currently are @@ -6156,23 +6155,17 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b) old_lock_level Old lock level */ -bool abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) +int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) { uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG; - int error= FALSE; DBUG_ENTER("abort_and_upgrade_locks"); lpt->old_lock_type= lpt->table->reginfo.lock_type; VOID(pthread_mutex_lock(&LOCK_open)); mysql_lock_abort(lpt->thd, lpt->table, TRUE); VOID(remove_table_from_cache(lpt->thd, lpt->db, lpt->table_name, flags)); - if (lpt->thd->killed) - { - lpt->thd->no_warnings_for_error= 0; - error= TRUE; - } VOID(pthread_mutex_unlock(&LOCK_open)); - DBUG_RETURN(error); + DBUG_RETURN(0); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 63d3b053529..ac03585f0a4 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -223,6 +223,9 @@ THD::THD() cuted_fields= sent_row_count= 0L; limit_found_rows= 0; statement_id_counter= 0UL; +#ifdef ERROR_INJECT_SUPPORT + error_inject_value= 0UL; +#endif // Must be reset to handle error with THD's created for init of mysqld lex->current_select= 0; start_time=(time_t) 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index 53712aaf69e..fdb70b6c991 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -241,11 +241,6 @@ struct system_variables my_bool new_mode; my_bool query_cache_wlock_invalidate; my_bool engine_condition_pushdown; -#ifdef HAVE_REPLICATION - ulong sync_replication; - ulong sync_replication_slave_id; - ulong sync_replication_timeout; -#endif /* HAVE_REPLICATION */ my_bool innodb_table_locks; my_bool innodb_support_xa; my_bool ndb_force_send; @@ -1099,6 +1094,9 @@ public: query_id_t query_id, warn_id; ulong thread_id, col_access; +#ifdef ERROR_INJECT_SUPPORT + ulong error_inject_value; +#endif /* Statement id is thread-wide. This counter is used to generate ids */ ulong statement_id_counter; ulong rand_saved_seed1, rand_saved_seed2; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c63a5c23d60..9037a6a1d32 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -68,7 +68,6 @@ static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_multi_update_lock(THD *thd); static void remove_escape(char *name); -static void refresh_status(THD *thd); const char *any_db="*any*"; // Special symbol for check_access @@ -6905,26 +6904,6 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query) } -/* Clear most status variables */ - -static void refresh_status(THD *thd) -{ - pthread_mutex_lock(&LOCK_status); - - /* We must update the global status before cleaning up the thread */ - add_to_status(&global_status_var, &thd->status_var); - bzero((char*) &thd->status_var, sizeof(thd->status_var)); - - for (SHOW_VAR *ptr= status_vars; ptr->name; ptr++) - if (ptr->type == SHOW_LONG) // note that SHOW_LONG_NOFLUSH variables are not reset - *(ulong*) ptr->value= 0; - - /* Reset the counters of all key caches (default and named). */ - process_key_caches(reset_key_cache_counters); - pthread_mutex_unlock(&LOCK_status); -} - - /* If pointer is not a null pointer, append filename to it */ bool append_file_to_dir(THD *thd, const char **filename_ptr, diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index aae80f07b71..0442ad724d2 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1792,15 +1792,10 @@ char *generate_partition_syntax(partition_info *part_info, char path[FN_REFLEN]; int err= 0; List_iterator part_it(part_info->partitions); - List_iterator temp_it(part_info->temp_partitions); File fptr; char *buf= NULL; //Return buffer - uint use_temp= 0; - uint no_temp_parts= part_info->temp_partitions.elements; - bool write_part_state; DBUG_ENTER("generate_partition_syntax"); - write_part_state= (part_info->part_state && !part_info->part_state_len); if (unlikely(((fptr= create_temp_file(path,mysql_tmpdir,"psy", O_RDWR | O_BINARY | O_TRUNC | O_TEMPORARY, MYF(MY_WME)))) < 0)) @@ -1865,67 +1860,26 @@ char *generate_partition_syntax(partition_info *part_info, err+= add_space(fptr); } } - no_parts= part_info->no_parts; - tot_no_parts= no_parts + no_temp_parts; + tot_no_parts= part_info->partitions.elements; no_subparts= part_info->no_subparts; if (write_all || (!part_info->use_default_partitions)) { + bool first= TRUE; err+= add_begin_parenthesis(fptr); i= 0; do { - /* - We need to do some clever list manipulation here since we have two - different needs for our list processing and here we take some of the - cost of using a simpler list processing for the other parts of the - code. - - ALTER TABLE REORGANIZE PARTITIONS has the list of partitions to be - the final list as the main list and the reorganised partitions is in - the temporary partition list. Thus when finding the first part added - we insert the temporary list if there is such a list. If there is no - temporary list we are performing an ADD PARTITION. - */ - if (use_temp && use_temp <= no_temp_parts) + part_elem= part_it++; + if (part_elem->part_state != PART_TO_BE_DROPPED && + part_elem->part_state != PART_REORGED_DROPPED) { - part_elem= temp_it++; - DBUG_ASSERT(no_temp_parts); - no_temp_parts--; - } - else if (use_temp) - { - DBUG_ASSERT(no_parts); - part_elem= save_part_elem; - use_temp= 0; - no_parts--; - } - else - { - part_elem= part_it++; - if ((part_elem->part_state == PART_TO_BE_ADDED || - part_elem->part_state == PART_IS_ADDED) && no_temp_parts) + if (!first) { - save_part_elem= part_elem; - part_elem= temp_it++; - no_temp_parts--; - use_temp= 1; - } - else - { - DBUG_ASSERT(no_parts); - no_parts--; - } - } - - if (part_elem->part_state != PART_IS_DROPPED) - { - if (write_part_state) - { - uint32 part_state_id= part_info->part_state_len; - part_info->part_state[part_state_id]= (uchar)part_elem->part_state; - part_info->part_state_len= part_state_id+1; + err+= add_comma(fptr); + err+= add_space(fptr); } + first= FALSE; err+= add_partition(fptr); err+= add_name_string(fptr, part_elem->partition_name); err+= add_space(fptr); @@ -1955,16 +1909,10 @@ char *generate_partition_syntax(partition_info *part_info, err+= add_end_parenthesis(fptr); } while (++j < no_subparts); } - if (i != (tot_no_parts-1)) - { - err+= add_comma(fptr); - err+= add_space(fptr); - } } if (i == (tot_no_parts-1)) err+= add_end_parenthesis(fptr); } while (++i < tot_no_parts); - DBUG_ASSERT(!no_parts && !no_temp_parts); } if (err) goto close_file; @@ -3525,27 +3473,6 @@ set_engine_all_partitions(partition_info *part_info, } } while (++i < part_info->no_parts); } -/* - SYNOPSIS - fast_alter_partition_error_handler() - lpt Container for parameters - - RETURN VALUES - None - - DESCRIPTION - Support routine to clean up after failures of on-line ALTER TABLE - for partition management. -*/ - -static void fast_alter_partition_error_handler(ALTER_PARTITION_PARAM_TYPE *lpt) -{ - DBUG_ENTER("fast_alter_partition_error_handler"); - /* TODO: WL 2826 Error handling */ - DBUG_VOID_RETURN; -} - - /* SYNOPSIS fast_end_partition() @@ -3567,6 +3494,7 @@ static void fast_alter_partition_error_handler(ALTER_PARTITION_PARAM_TYPE *lpt) static int fast_end_partition(THD *thd, ulonglong copied, ulonglong deleted, + TABLE *table, TABLE_LIST *table_list, bool is_empty, ALTER_PARTITION_PARAM_TYPE *lpt, bool written_bin_log) @@ -3594,7 +3522,7 @@ static int fast_end_partition(THD *thd, ulonglong copied, send_ok(thd,copied+deleted,0L,tmp_name); DBUG_RETURN(FALSE); } - fast_alter_partition_error_handler(lpt); + table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); } @@ -3843,7 +3771,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info, after the change as before. Thus we can reply ok immediately without any changes at all. */ - DBUG_RETURN(fast_end_partition(thd, ULL(0), ULL(0), NULL, + DBUG_RETURN(fast_end_partition(thd, ULL(0), ULL(0), + table, NULL, TRUE, NULL, FALSE)); } else if (new_part_no > curr_part_no) @@ -4195,6 +4124,7 @@ that are reorganised. my_error(ER_ROW_IS_REFERENCED, MYF(0)); DBUG_RETURN(TRUE); } + tab_part_info->no_parts-= no_parts_dropped; } else if ((alter_info->flags & ALTER_OPTIMIZE_PARTITION) || (alter_info->flags & ALTER_ANALYZE_PARTITION) || @@ -4239,6 +4169,11 @@ that are reorganised. my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), ptr); DBUG_RETURN(TRUE); } + if (!(*fast_alter_partition)) + { + table->file->print_error(HA_ERR_WRONG_COMMAND, MYF(0)); + DBUG_RETURN(TRUE); + } } else if (alter_info->flags & ALTER_COALESCE_PARTITION) { @@ -4597,6 +4532,7 @@ the generated partition syntax in a correct manner. /* Make sure change of engine happens to all partitions. */ + DBUG_PRINT("info", ("partition changed")); set_engine_all_partitions(thd->work_part_info, create_info->db_type); *partition_changed= TRUE; } @@ -4611,7 +4547,10 @@ the generated partition syntax in a correct manner. using the partition handler. */ if (thd->work_part_info != table->part_info) + { + DBUG_PRINT("info", ("partition changed")); *partition_changed= TRUE; + } if (create_info->db_type == &partition_hton) part_info->default_engine_type= table->part_info->default_engine_type; else @@ -4663,14 +4602,22 @@ the generated partition syntax in a correct manner. static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) { char path[FN_REFLEN+1]; + int error; + handler *file= lpt->table->file; DBUG_ENTER("mysql_change_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - DBUG_RETURN(lpt->table->file->change_partitions(lpt->create_info, path, - &lpt->copied, - &lpt->deleted, - lpt->pack_frm_data, - lpt->pack_frm_len)); + if ((error= file->change_partitions(lpt->create_info, path, &lpt->copied, + &lpt->deleted, lpt->pack_frm_data, + lpt->pack_frm_len))) + { + if (error != ER_OUTOFMEMORY) + file->print_error(error, MYF(0)); + else + lpt->thd->fatal_error(); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); } @@ -4696,10 +4643,17 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) { char path[FN_REFLEN+1]; + int error; DBUG_ENTER("mysql_rename_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - DBUG_RETURN(lpt->table->file->rename_partitions(path)); + if ((error= lpt->table->file->rename_partitions(path))) + { + if (error != 1) + lpt->table->file->print_error(error, MYF(0)); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); } @@ -4730,11 +4684,13 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) List_iterator part_it(part_info->partitions); uint i= 0; uint remove_count= 0; + int error; DBUG_ENTER("mysql_drop_partitions"); build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - if (lpt->table->file->drop_partitions(path)) + if ((error= lpt->table->file->drop_partitions(path))) { + lpt->table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); } do @@ -4751,6 +4707,767 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) } +/* + Insert log entry into list + SYNOPSIS + insert_part_info_log_entry_list() + log_entry + RETURN VALUES + NONE +*/ + +static void insert_part_info_log_entry_list(partition_info *part_info, + DDL_LOG_MEMORY_ENTRY *log_entry) +{ + log_entry->next_active_log_entry= part_info->first_log_entry; + part_info->first_log_entry= log_entry; +} + + +/* + Release all log entries for this partition info struct + SYNOPSIS + release_part_info_log_entries() + first_log_entry First log entry in list to release + RETURN VALUES + NONE +*/ + +static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY *log_entry) +{ + DBUG_ENTER("release_part_info_log_entries"); + + while (log_entry) + { + release_ddl_log_memory_entry(log_entry); + log_entry= log_entry->next_active_log_entry; + } + DBUG_VOID_RETURN; +} + + +/* + Log an delete/rename frm file + SYNOPSIS + write_log_replace_delete_frm() + lpt Struct for parameters + next_entry Next reference to use in log record + from_path Name to rename from + to_path Name to rename to + replace_flag TRUE if replace, else delete + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Support routine that writes a replace or delete of an frm file into the + ddl log. It also inserts an entry that keeps track of used space into + the partition info object +*/ + +static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt, + uint next_entry, + const char *from_path, + const char *to_path, + bool replace_flag) +{ + DDL_LOG_ENTRY ddl_log_entry; + DDL_LOG_MEMORY_ENTRY *log_entry; + DBUG_ENTER("write_log_replace_delete_frm"); + + if (replace_flag) + ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; + else + ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; + ddl_log_entry.next_entry= next_entry; + ddl_log_entry.handler_name= reg_ext; + ddl_log_entry.name= to_path; + if (replace_flag) + ddl_log_entry.from_name= from_path; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + insert_part_info_log_entry_list(lpt->part_info, log_entry); + DBUG_RETURN(FALSE); +} + + +/* + Log final partition changes in change partition + SYNOPSIS + write_log_changed_partitions() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + This code is used to perform safe ADD PARTITION for HASH partitions + and COALESCE for HASH partitions and REORGANIZE for any type of + partitions. + We prepare entries for all partitions except the reorganised partitions + in REORGANIZE partition, those are handled by + write_log_dropped_partitions. For those partitions that are replaced + special care is needed to ensure that this is performed correctly and + this requires a two-phased approach with this log as a helper for this. + + This code is closely intertwined with the code in rename_partitions in + the partition handler. +*/ + +static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, + uint *next_entry, const char *path) +{ + DDL_LOG_ENTRY ddl_log_entry; + partition_info *part_info= lpt->part_info; + DDL_LOG_MEMORY_ENTRY *log_entry; + char tmp_path[FN_LEN]; + char normal_path[FN_LEN]; + List_iterator part_it(part_info->partitions); + uint temp_partitions= part_info->temp_partitions.elements; + uint no_elements= part_info->partitions.elements; + uint i= 0; + DBUG_ENTER("write_log_changed_partitions"); + + do + { + partition_element *part_elem= part_it++; + if (part_elem->part_state == PART_IS_CHANGED || + (part_elem->part_state == PART_IS_ADDED && temp_partitions)) + { + if (part_info->is_sub_partitioned()) + { + List_iterator sub_it(part_elem->subpartitions); + uint no_subparts= part_info->no_subparts; + uint j= 0; + do + { + partition_element *sub_elem= sub_it++; + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= + ha_resolve_storage_engine_name(sub_elem->engine_type); + create_subpartition_name(tmp_path, path, + part_elem->partition_name, + sub_elem->partition_name, + TEMP_PART_NAME); + create_subpartition_name(normal_path, path, + part_elem->partition_name, + sub_elem->partition_name, + NORMAL_PART_NAME); + ddl_log_entry.name= normal_path; + ddl_log_entry.from_name= tmp_path; + if (part_elem->part_state == PART_IS_CHANGED) + ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; + else + ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + sub_elem->log_entry= log_entry; + insert_part_info_log_entry_list(part_info, log_entry); + } while (++j < no_subparts); + } + else + { + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= + ha_resolve_storage_engine_name(part_elem->engine_type); + create_partition_name(tmp_path, path, + part_elem->partition_name, + TEMP_PART_NAME, TRUE); + create_partition_name(normal_path, path, + part_elem->partition_name, + NORMAL_PART_NAME, TRUE); + ddl_log_entry.name= normal_path; + ddl_log_entry.from_name= tmp_path; + if (part_elem->part_state == PART_IS_CHANGED) + ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION; + else + ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + part_elem->log_entry= log_entry; + insert_part_info_log_entry_list(part_info, log_entry); + } + } + } while (++i < no_elements); + DBUG_RETURN(FALSE); +} + + +/* + Log dropped partitions + SYNOPSIS + write_log_dropped_partitions() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, + uint *next_entry, + const char *path, + bool temp_list) +{ + DDL_LOG_ENTRY ddl_log_entry; + partition_info *part_info= lpt->part_info; + DDL_LOG_MEMORY_ENTRY *log_entry; + char tmp_path[FN_LEN]; + List_iterator part_it(part_info->partitions); + List_iterator temp_it(part_info->temp_partitions); + uint no_temp_partitions= part_info->temp_partitions.elements; + uint no_elements= part_info->partitions.elements; + uint i= 0; + DBUG_ENTER("write_log_dropped_partitions"); + + ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; + if (temp_list) + no_elements= no_temp_partitions; + while (no_elements--) + { + partition_element *part_elem; + if (temp_list) + part_elem= temp_it++; + else + part_elem= part_it++; + if (part_elem->part_state == PART_TO_BE_DROPPED || + part_elem->part_state == PART_TO_BE_ADDED || + part_elem->part_state == PART_CHANGED) + { + uint name_variant; + if (part_elem->part_state == PART_CHANGED || + (part_elem->part_state == PART_TO_BE_ADDED && + no_temp_partitions)) + name_variant= TEMP_PART_NAME; + else + name_variant= NORMAL_PART_NAME; + if (part_info->is_sub_partitioned()) + { + List_iterator sub_it(part_elem->subpartitions); + uint no_subparts= part_info->no_subparts; + uint j= 0; + do + { + partition_element *sub_elem= sub_it++; + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= + ha_resolve_storage_engine_name(sub_elem->engine_type); + create_subpartition_name(tmp_path, path, + part_elem->partition_name, + sub_elem->partition_name, + name_variant); + ddl_log_entry.name= tmp_path; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + if (temp_list) + sub_elem->log_entry= log_entry; + insert_part_info_log_entry_list(part_info, log_entry); + } while (++j < no_subparts); + } + else + { + ddl_log_entry.next_entry= *next_entry; + ddl_log_entry.handler_name= + ha_resolve_storage_engine_name(part_elem->engine_type); + create_partition_name(tmp_path, path, + part_elem->partition_name, + name_variant, TRUE); + ddl_log_entry.name= tmp_path; + if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) + { + DBUG_RETURN(TRUE); + } + *next_entry= log_entry->entry_pos; + if (temp_list) + part_elem->log_entry= log_entry; + insert_part_info_log_entry_list(part_info, log_entry); + } + } + } + DBUG_RETURN(FALSE); +} + + +/* + Set execute log entry in ddl log for this partitioned table + SYNOPSIS + set_part_info_exec_log_entry() + part_info Partition info object + exec_log_entry Log entry + RETURN VALUES + NONE +*/ + +static void set_part_info_exec_log_entry(partition_info *part_info, + DDL_LOG_MEMORY_ENTRY *exec_log_entry) +{ + part_info->exec_log_entry= exec_log_entry; + exec_log_entry->next_active_log_entry= NULL; +} + + +/* + Write the log entry to ensure that the shadow frm file is removed at + crash. + SYNOPSIS + write_log_drop_shadow_frm() + lpt Struct containing parameters + install_frm Should we log action to install shadow frm or should + the action be to remove the shadow frm file. + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare an entry to the ddl log indicating a drop/install of the shadow frm + file and its corresponding handler file. +*/ + +static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DDL_LOG_ENTRY ddl_log_entry; + partition_info *part_info= lpt->part_info; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL; + char shadow_path[FN_LEN]; + DBUG_ENTER("write_log_drop_shadow_frm"); + + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + pthread_mutex_lock(&LOCK_gdl); + if (write_log_replace_delete_frm(lpt, 0UL, NULL, + (const char*)shadow_path, FALSE)) + goto error; + log_entry= part_info->first_log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + pthread_mutex_unlock(&LOCK_gdl); + set_part_info_exec_log_entry(part_info, exec_log_entry); + DBUG_RETURN(FALSE); + +error: + release_part_info_log_entries(part_info->first_log_entry); + pthread_mutex_unlock(&LOCK_gdl); + part_info->first_log_entry= NULL; + my_error(ER_DDL_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); +} + + +/* + Log renaming of shadow frm to real frm name and dropping of old frm + SYNOPSIS + write_log_rename_frm() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare an entry to ensure that we complete the renaming of the frm + file if failure occurs in the middle of the rename process. +*/ + +static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DDL_LOG_ENTRY ddl_log_entry; + partition_info *part_info= lpt->part_info; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char path[FN_LEN]; + char shadow_path[FN_LEN]; + DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + DBUG_ENTER("write_log_rename_frm"); + + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + pthread_mutex_lock(&LOCK_gdl); + if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE)) + goto error; + log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + release_part_info_log_entries(old_first_log_entry); + pthread_mutex_unlock(&LOCK_gdl); + DBUG_RETURN(FALSE); + +error: + release_part_info_log_entries(part_info->first_log_entry); + pthread_mutex_unlock(&LOCK_gdl); + part_info->first_log_entry= old_first_log_entry; + part_info->frm_log_entry= NULL; + my_error(ER_DDL_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); +} + + +/* + Write the log entries to ensure that the drop partition command is completed + even in the presence of a crash. + + SYNOPSIS + write_log_drop_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare entries to the ddl log indicating all partitions to drop and to + install the shadow frm file and remove the old frm file. +*/ + +static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DDL_LOG_ENTRY ddl_log_entry; + partition_info *part_info= lpt->part_info; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char tmp_path[FN_LEN]; + char path[FN_LEN]; + uint next_entry= 0; + DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + DBUG_ENTER("write_log_drop_partition"); + + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, + lpt->table_name, "#"); + pthread_mutex_lock(&LOCK_gdl); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + FALSE)) + goto error; + if (write_log_replace_delete_frm(lpt, next_entry, (const char*)tmp_path, + (const char*)path, TRUE)) + goto error; + log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + release_part_info_log_entries(old_first_log_entry); + pthread_mutex_unlock(&LOCK_gdl); + DBUG_RETURN(FALSE); + +error: + release_part_info_log_entries(part_info->first_log_entry); + pthread_mutex_unlock(&LOCK_gdl); + part_info->first_log_entry= old_first_log_entry; + part_info->frm_log_entry= NULL; + my_error(ER_DDL_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); +} + + +/* + Write the log entries to ensure that the add partition command is not + executed at all if a crash before it has completed + + SYNOPSIS + write_log_add_change_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Prepare entries to the ddl log indicating all partitions to drop and to + remove the shadow frm file. + We always inject entries backwards in the list in the ddl log since we + don't know the entry position until we have written it. +*/ + +static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + partition_info *part_info= lpt->part_info; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL; + char tmp_path[FN_LEN]; + char path[FN_LEN]; + uint next_entry= 0; + DBUG_ENTER("write_log_add_change_partition"); + + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, + lpt->table_name, "#"); + pthread_mutex_lock(&LOCK_gdl); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + FALSE)) + goto error; + if (write_log_replace_delete_frm(lpt, next_entry, NULL, tmp_path, + FALSE)) + goto error; + log_entry= part_info->first_log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + pthread_mutex_unlock(&LOCK_gdl); + set_part_info_exec_log_entry(part_info, exec_log_entry); + DBUG_RETURN(FALSE); + +error: + release_part_info_log_entries(part_info->first_log_entry); + pthread_mutex_unlock(&LOCK_gdl); + part_info->first_log_entry= NULL; + my_error(ER_DDL_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); +} + + +/* + Write description of how to complete the operation after first phase of + change partitions. + + SYNOPSIS + write_log_final_change_partition() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + We will write log entries that specify to remove all partitions reorganised, + to rename others to reflect the new naming scheme and to install the shadow + frm file. +*/ + +static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DDL_LOG_ENTRY ddl_log_entry; + partition_info *part_info= lpt->part_info; + DDL_LOG_MEMORY_ENTRY *log_entry; + DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry; + char path[FN_LEN]; + char shadow_path[FN_LEN]; + DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry; + uint next_entry= 0; + DBUG_ENTER("write_log_final_change_partition"); + + part_info->first_log_entry= NULL; + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + pthread_mutex_lock(&LOCK_gdl); + if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, + TRUE)) + goto error; + if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) + goto error; + if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE)) + goto error; + log_entry= part_info->first_log_entry; + part_info->frm_log_entry= log_entry; + if (write_execute_ddl_log_entry(log_entry->entry_pos, + FALSE, &exec_log_entry)) + goto error; + release_part_info_log_entries(old_first_log_entry); + pthread_mutex_unlock(&LOCK_gdl); + DBUG_RETURN(FALSE); + +error: + release_part_info_log_entries(part_info->first_log_entry); + pthread_mutex_unlock(&LOCK_gdl); + part_info->first_log_entry= old_first_log_entry; + part_info->frm_log_entry= NULL; + my_error(ER_DDL_LOG_ERROR, MYF(0)); + DBUG_RETURN(TRUE); +} + + +/* + Remove entry from ddl log and release resources for others to use + + SYNOPSIS + write_log_completed() + lpt Struct containing parameters + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt, + bool dont_crash) +{ + partition_info *part_info= lpt->part_info; + uint count_loop= 0; + bool not_success; + DDL_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry; + DBUG_ENTER("write_log_completed"); + + DBUG_ASSERT(log_entry); + pthread_mutex_lock(&LOCK_gdl); + if (write_execute_ddl_log_entry(0UL, TRUE, &log_entry)) + { + /* + Failed to write, Bad... + We have completed the operation but have log records to REMOVE + stuff that shouldn't be removed. What clever things could one do + here? An error output was written to the error output by the + above method so we don't do anything here. + */ + ; + } + release_part_info_log_entries(part_info->first_log_entry); + release_part_info_log_entries(part_info->exec_log_entry); + pthread_mutex_unlock(&LOCK_gdl); + part_info->exec_log_entry= NULL; + part_info->first_log_entry= NULL; + DBUG_VOID_RETURN; +} + + +/* + Release all log entries + SYNOPSIS + release_log_entries() + part_info Partition info struct + RETURN VALUES + NONE +*/ + +static void release_log_entries(partition_info *part_info) +{ + pthread_mutex_lock(&LOCK_gdl); + release_part_info_log_entries(part_info->first_log_entry); + release_part_info_log_entries(part_info->exec_log_entry); + pthread_mutex_unlock(&LOCK_gdl); + part_info->first_log_entry= NULL; + part_info->exec_log_entry= NULL; +} + + +/* + Handle errors for ALTER TABLE for partitioning + SYNOPSIS + handle_alter_part_error() + lpt Struct carrying parameters + not_completed Was request in complete phase when error occurred + RETURN VALUES + NONE +*/ + +void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, + bool not_completed, + bool drop_partition, + bool frm_install) +{ + partition_info *part_info= lpt->part_info; + DBUG_ENTER("handle_alter_part_error"); + + if (!part_info->first_log_entry && + execute_ddl_log_entry(current_thd, + part_info->first_log_entry->entry_pos)) + { + /* + We couldn't recover from error, most likely manual interaction + is required. + */ + write_log_completed(lpt, FALSE); + release_log_entries(part_info); + if (not_completed) + { + if (drop_partition) + { + /* Table is still ok, but we left a shadow frm file behind. */ + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s %s", + "Operation was unsuccessful, table is still intact,", + "but it is possible that a shadow frm file was left behind"); + } + else + { + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s %s %s %s", + "Operation was unsuccessful, table is still intact,", + "but it is possible that a shadow frm file was left behind.", + "It is also possible that temporary partitions are left behind,", + "these could be empty or more or less filled with records"); + } + } + else + { + if (frm_install) + { + /* + Failed during install of shadow frm file, table isn't intact + and dropped partitions are still there + */ + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s %s %s", + "Failed during alter of partitions, table is no longer intact.", + "The frm file is in an unknown state, and a backup", + "is required."); + } + else if (drop_partition) + { + /* + Table is ok, we have switched to new table but left dropped + partitions still in their places. We remove the log records and + ask the user to perform the action manually. We remove the log + records and ask the user to perform the action manually. + */ + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s %s", + "Failed during drop of partitions, table is intact.", + "Manual drop of remaining partitions is required"); + } + else + { + /* + We failed during renaming of partitions. The table is most + certainly in a very bad state so we give user warning and disable + the table by writing an ancient frm version into it. + */ + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1, + "%s %s %s", + "Failed during renaming of partitions. We are now in a position", + "where table is not reusable", + "Table is disabled by writing ancient frm file version into it"); + } + } + } + else + { + release_log_entries(part_info); + if (not_completed) + { + /* + We hit an error before things were completed but managed + to recover from the error. An error occurred and we have + restored things to original so no need for further action. + */ + ; + } + else + { + /* + We hit an error after we had completed most of the operation + and were successful in a second attempt so the operation + actually is successful now. We need to issue a warning that + even though we reported an error the operation was successfully + completed. + */ + push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1,"%s %s", + "Operation was successfully completed by failure handling,", + "after failure of normal operation"); + } + } + DBUG_VOID_RETURN; +} + + /* Actually perform the change requested by ALTER TABLE of partitions previously prepared. @@ -4792,9 +5509,12 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ALTER_PARTITION_PARAM_TYPE lpt_obj; ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj; bool written_bin_log= TRUE; + bool not_completed= TRUE; + bool frm_install= FALSE; DBUG_ENTER("fast_alter_partition_table"); lpt->thd= thd; + lpt->part_info= part_info; lpt->create_info= create_info; lpt->create_list= create_list; lpt->key_list= key_list; @@ -4826,17 +5546,18 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, In this case it is enough to call optimise_partitions, there is no need to change frm files or anything else. */ + int error; written_bin_log= FALSE; if (((alter_info->flags & ALTER_OPTIMIZE_PARTITION) && - (table->file->optimize_partitions(thd))) || + (error= table->file->optimize_partitions(thd))) || ((alter_info->flags & ALTER_ANALYZE_PARTITION) && - (table->file->analyze_partitions(thd))) || + (error= table->file->analyze_partitions(thd))) || ((alter_info->flags & ALTER_CHECK_PARTITION) && - (table->file->check_partitions(thd))) || + (error= table->file->check_partitions(thd))) || ((alter_info->flags & ALTER_REPAIR_PARTITION) && - (table->file->repair_partitions(thd)))) + (error= table->file->repair_partitions(thd)))) { - fast_alter_partition_error_handler(lpt); + table->file->print_error(error, MYF(0)); DBUG_RETURN(TRUE); } } @@ -4881,10 +5602,9 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 1) Write the new frm, pack it and then delete it 2) Perform the change within the handler */ - if ((mysql_write_frm(lpt, WFRM_INITIAL_WRITE | WFRM_PACK_FRM)) || - (mysql_change_partitions(lpt))) + if (mysql_write_frm(lpt, WFRM_WRITE_SHADOW | WFRM_PACK_FRM) || + mysql_change_partitions(lpt)) { - fast_alter_partition_error_handler(lpt); DBUG_RETURN(TRUE); } } @@ -4912,32 +5632,62 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, after a DROP PARTITION) if one ensured that failed accesses to the dropped partitions was aborted for sure (thus only possible for transactional engines). - - 1) Lock the table in TL_WRITE_ONLY to ensure all other accesses to + + 0) Write an entry that removes the shadow frm file if crash occurs + 1) Write the new frm file as a shadow frm + 2) Write the ddl log to ensure that the operation is completed + even in the presence of a MySQL Server crash + 3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to the table have completed - 2) Write the new frm file where the partitions have changed but are - still remaining with the state PART_TO_BE_DROPPED - 3) Write the bin log - 4) Prepare MyISAM handlers for drop of partitions - 5) Ensure that any users that has opened the table but not yet + 4) Write the bin log + Unfortunately the writing of the binlog is not synchronised with + other logging activities. So no matter in which order the binlog + is written compared to other activities there will always be cases + where crashes make strange things occur. In this placement it can + happen that the ALTER TABLE DROP PARTITION gets performed in the + master but not in the slaves if we have a crash, after writing the + ddl log but before writing the binlog. A solution to this would + require writing the statement first in the ddl log and then + when recovering from the crash read the binlog and insert it into + the binlog if not written already. + 5) Install the previously written shadow frm file + 6) Ensure that any users that has opened the table but not yet reached the abort lock do that before downgrading the lock. - 6) Drop the partitions - 7) Write the frm file that the partition has been dropped - 8) Wait until all accesses using the old frm file has completed - 9) Complete query + 7) Prepare MyISAM handlers for drop of partitions + 8) Drop the partitions + 9) Remove entries from ddl log + 10) Wait until all accesses using the old frm file has completed + 11) Complete query + + We insert Error injections at all places where it could be interesting + to test if recovery is properly done. */ - if ((abort_and_upgrade_lock(lpt)) || - (mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || + if (write_log_drop_shadow_frm(lpt) || + ERROR_INJECT_CRASH("crash_drop_partition_1") || + mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || + ERROR_INJECT_CRASH("crash_drop_partition_2") || + write_log_drop_partition(lpt) || + ERROR_INJECT_CRASH("crash_drop_partition_3") || + (not_completed= FALSE) || + abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE)) || - (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE)) || + thd->query, thd->query_length), FALSE)) || + ERROR_INJECT_CRASH("crash_drop_partition_4") || + (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || + ERROR_INJECT_CRASH("crash_drop_partition_5") || + ((frm_install= TRUE), FALSE) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ((frm_install= FALSE), FALSE) || (close_open_tables_and_downgrade(lpt), FALSE) || - (mysql_drop_partitions(lpt)) || - (mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || + ERROR_INJECT_CRASH("crash_drop_partition_6") || + mysql_drop_partitions(lpt) || + ERROR_INJECT_CRASH("crash_drop_partition_7") || + (write_log_completed(lpt, FALSE), FALSE) || + ERROR_INJECT_CRASH("crash_drop_partition_8") || (mysql_wait_completed_table(lpt, table), FALSE)) { - fast_alter_partition_error_handler(lpt); + handle_alter_part_error(lpt, not_completed, TRUE, frm_install); DBUG_RETURN(TRUE); } } @@ -4954,28 +5704,45 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, miss updates made by a transaction serialised before it that are inserted into the new partition. - 1) Write the new frm file where state of added partitions is - changed to PART_TO_BE_ADDED + 0) Write an entry that removes the shadow frm file if crash occurs + 1) Write the new frm file as a shadow frm file + 2) Log the changes to happen in ddl log 2) Add the new partitions 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users are still using the old partitioning scheme. Wait until all ongoing users have completed before progressing. - 4) Write a new frm file of the table where the partitions are added - to the table. - 5) Write binlog - 6) Wait until all accesses using the old frm file has completed - 7) Complete query + 4) Write binlog + 5) Now the change is completed except for the installation of the + new frm file. We thus write an action in the log to change to + the shadow frm file + 6) Install the new frm file of the table where the partitions are + added to the table. + 7) Wait until all accesses using the old frm file has completed + 8) Remove entries from ddl log + 9) Complete query */ - if ((mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || - (mysql_change_partitions(lpt)) || - (abort_and_upgrade_lock(lpt)) || - (mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || + if (write_log_add_change_partition(lpt) || + ERROR_INJECT_CRASH("crash_add_partition_1") || + mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || + ERROR_INJECT_CRASH("crash_add_partition_2") || + mysql_change_partitions(lpt) || + ERROR_INJECT_CRASH("crash_add_partition_3") || + abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - (close_open_tables_and_downgrade(lpt), FALSE)) + ERROR_INJECT_CRASH("crash_add_partition_4") || + write_log_rename_frm(lpt) || + (not_completed= FALSE) || + ERROR_INJECT_CRASH("crash_add_partition_5") || + ((frm_install= TRUE), FALSE) || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ERROR_INJECT_CRASH("crash_add_partition_6") || + (close_open_tables_and_downgrade(lpt), FALSE) || + (write_log_completed(lpt, FALSE), FALSE) || + ERROR_INJECT_CRASH("crash_add_partition_7")) { - fast_alter_partition_error_handler(lpt); + handle_alter_part_error(lpt, not_completed, FALSE, frm_install); DBUG_RETURN(TRUE); } } @@ -5012,44 +5779,57 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, use a lower lock level. This can be handled inside store_lock in the respective handler. - 1) Write the new frm file where state of added partitions is - changed to PART_TO_BE_ADDED and the reorganised partitions - are set in state PART_TO_BE_REORGED. - 2) Add the new partitions + 0) Write an entry that removes the shadow frm file if crash occurs + 1) Write the shadow frm file of new partitioning + 2) Log such that temporary partitions added in change phase are + removed in a crash situation + 3) Add the new partitions Copy from the reorganised partitions to the new partitions - 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users + 4) Log that operation is completed and log all complete actions + needed to complete operation from here + 5) Lock all partitions in TL_WRITE_ONLY to ensure that no users are still using the old partitioning scheme. Wait until all ongoing users have completed before progressing. - 4) Prepare MyISAM handlers for rename and delete of partitions - 5) Write a new frm file of the table where the partitions are - reorganised. - 6) Rename the reorged partitions such that they are no longer + 6) Prepare MyISAM handlers for rename and delete of partitions + 7) Rename the reorged partitions such that they are no longer used and rename those added to their real new names. - 7) Write bin log - 8) Wait until all accesses using the old frm file has completed - 9) Drop the reorganised partitions - 10)Write a new frm file of the table where the partitions are - reorganised. - 11)Wait until all accesses using the old frm file has completed - 12)Complete query + 8) Write bin log + 9) Install the shadow frm file + 10) Wait until all accesses using the old frm file has completed + 11) Drop the reorganised partitions + 12) Remove log entry + 13)Wait until all accesses using the old frm file has completed + 14)Complete query */ - - if ((mysql_write_frm(lpt, WFRM_INITIAL_WRITE)) || - (mysql_change_partitions(lpt)) || - (abort_and_upgrade_lock(lpt)) || - (mysql_write_frm(lpt, WFRM_CREATE_HANDLER_FILES)) || - (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE)) || - (mysql_rename_partitions(lpt)) || + if (write_log_add_change_partition(lpt) || + ERROR_INJECT_CRASH("crash_change_partition_1") || + mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || + ERROR_INJECT_CRASH("crash_change_partition_2") || + mysql_change_partitions(lpt) || + ERROR_INJECT_CRASH("crash_change_partition_3") || + write_log_final_change_partition(lpt) || + ERROR_INJECT_CRASH("crash_change_partition_4") || + (not_completed= FALSE) || + abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || + ERROR_INJECT_CRASH("crash_change_partition_5") || + (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || + ERROR_INJECT_CRASH("crash_change_partition_6") || + mysql_rename_partitions(lpt) || + ((frm_install= TRUE), FALSE) || + ERROR_INJECT_CRASH("crash_change_partition_7") || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ERROR_INJECT_CRASH("crash_change_partition_8") || (close_open_tables_and_downgrade(lpt), FALSE) || - (mysql_drop_partitions(lpt)) || - (mysql_write_frm(lpt, 0UL)) || + ERROR_INJECT_CRASH("crash_change_partition_9") || + (write_log_completed(lpt, FALSE), FALSE) || + ERROR_INJECT_CRASH("crash_change_partition_10") || (mysql_wait_completed_table(lpt, table), FALSE)) { - fast_alter_partition_error_handler(lpt); - DBUG_RETURN(TRUE); + handle_alter_part_error(lpt, not_completed, FALSE, frm_install); + DBUG_RETURN(TRUE); } } /* @@ -5057,7 +5837,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, user */ DBUG_RETURN(fast_end_partition(thd, lpt->copied, lpt->deleted, - table_list, FALSE, lpt, + table, table_list, FALSE, lpt, written_bin_log)); } #endif @@ -5709,5 +6489,85 @@ static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter) field->store(part_iter->field_vals.cur++, FALSE); return part_iter->part_info->get_subpartition_id(part_iter->part_info); } + + +/* + Create partition names + + SYNOPSIS + create_partition_name() + out:out Created partition name string + in1 First part + in2 Second part + name_variant Normal, temporary or renamed partition name + + RETURN VALUE + NONE + + DESCRIPTION + This method is used to calculate the partition name, service routine to + the del_ren_cre_table method. +*/ + +void create_partition_name(char *out, const char *in1, + const char *in2, uint name_variant, + bool translate) +{ + char transl_part_name[FN_REFLEN]; + const char *transl_part; + + if (translate) + { + tablename_to_filename(in2, transl_part_name, FN_REFLEN); + transl_part= transl_part_name; + } + else + transl_part= in2; + if (name_variant == NORMAL_PART_NAME) + strxmov(out, in1, "#P#", transl_part, NullS); + else if (name_variant == TEMP_PART_NAME) + strxmov(out, in1, "#P#", transl_part, "#TMP#", NullS); + else if (name_variant == RENAMED_PART_NAME) + strxmov(out, in1, "#P#", transl_part, "#REN#", NullS); +} + + +/* + Create subpartition name + + SYNOPSIS + create_subpartition_name() + out:out Created partition name string + in1 First part + in2 Second part + in3 Third part + name_variant Normal, temporary or renamed partition name + + RETURN VALUE + NONE + + DESCRIPTION + This method is used to calculate the subpartition name, service routine to + the del_ren_cre_table method. +*/ + +void create_subpartition_name(char *out, const char *in1, + const char *in2, const char *in3, + uint name_variant) +{ + char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN]; + + tablename_to_filename(in2, transl_part_name, FN_REFLEN); + tablename_to_filename(in3, transl_subpart_name, FN_REFLEN); + if (name_variant == NORMAL_PART_NAME) + strxmov(out, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, NullS); + else if (name_variant == TEMP_PART_NAME) + strxmov(out, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, "#TMP#", NullS); + else if (name_variant == RENAMED_PART_NAME) + strxmov(out, in1, "#P#", transl_part_name, + "#SP#", transl_subpart_name, "#REN#", NullS); +} #endif diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 6ec010b8a44..918c9f507e2 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -694,7 +694,7 @@ impossible position"; if (loop_breaker) break; - + end_io_cache(&log); (void) my_close(file, MYF(MY_WME)); @@ -834,7 +834,7 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) /* Issuing warning then started without --skip-slave-start */ if (!opt_skip_slave_start) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_MISSING_SKIP_SLAVE, + ER_MISSING_SKIP_SLAVE, ER(ER_MISSING_SKIP_SLAVE)); } @@ -860,7 +860,7 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_WAS_RUNNING, ER(ER_SLAVE_WAS_RUNNING)); } - + unlock_slave_threads(mi); if (slave_errno) @@ -1023,7 +1023,7 @@ err: slave_server_id the slave's server id */ - + void kill_zombie_dump_threads(uint32 slave_server_id) { @@ -1088,9 +1088,9 @@ bool change_master(THD* thd, MASTER_INFO* mi) */ /* - If the user specified host or port without binlog or position, + If the user specified host or port without binlog or position, reset binlog's name to FIRST and position to 4. - */ + */ if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos) { @@ -1117,7 +1117,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) mi->port = lex_mi->port; if (lex_mi->connect_retry) mi->connect_retry = lex_mi->connect_retry; - + if (lex_mi->ssl != LEX_MASTER_INFO::SSL_UNCHANGED) mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::SSL_ENABLE); if (lex_mi->ssl_ca) @@ -1133,7 +1133,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) #ifndef HAVE_OPENSSL if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath || lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key ) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_IGNORED_SSL_PARAMS, ER(ER_SLAVE_IGNORED_SSL_PARAMS)); #endif @@ -1500,7 +1500,7 @@ bool show_binlogs(THD* thd) } field_list.push_back(new Item_empty_string("Log_name", 255)); - field_list.push_back(new Item_return_int("File_size", 20, + field_list.push_back(new Item_return_int("File_size", 20, MYSQL_TYPE_LONGLONG)); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6cc2ad266e5..ca13fb27f96 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -248,6 +248,904 @@ static int mysql_copy_key_list(List *orig_key, DBUG_RETURN(FALSE); } +/* +-------------------------------------------------------------------------- + + MODULE: DDL log + ----------------- + + This module is used to ensure that we can recover from crashes that occur + in the middle of a meta-data operation in MySQL. E.g. DROP TABLE t1, t2; + We need to ensure that both t1 and t2 are dropped and not only t1 and + also that each table drop is entirely done and not "half-baked". + + To support this we create log entries for each meta-data statement in the + ddl log while we are executing. These entries are dropped when the + operation is completed. + + At recovery those entries that were not completed will be executed. + + There is only one ddl log in the system and it is protected by a mutex + and there is a global struct that contains information about its current + state. + + History: + First version written in 2006 by Mikael Ronstrom +-------------------------------------------------------------------------- +*/ + + +typedef struct st_global_ddl_log +{ + /* + We need to adjust buffer size to be able to handle downgrades/upgrades + where IO_SIZE has changed. We'll set the buffer size such that we can + handle that the buffer size was upto 4 times bigger in the version + that wrote the DDL log. + */ + char file_entry_buf[4*IO_SIZE]; + char file_name_str[FN_REFLEN]; + char *file_name; + DDL_LOG_MEMORY_ENTRY *first_free; + DDL_LOG_MEMORY_ENTRY *first_used; + uint num_entries; + File file_id; + uint name_len; + uint io_size; + bool inited; + bool recovery_phase; +} GLOBAL_DDL_LOG; + +GLOBAL_DDL_LOG global_ddl_log; + +pthread_mutex_t LOCK_gdl; + +#define DDL_LOG_ENTRY_TYPE_POS 0 +#define DDL_LOG_ACTION_TYPE_POS 1 +#define DDL_LOG_PHASE_POS 2 +#define DDL_LOG_NEXT_ENTRY_POS 4 +#define DDL_LOG_NAME_POS 8 + +#define DDL_LOG_NUM_ENTRY_POS 0 +#define DDL_LOG_NAME_LEN_POS 4 +#define DDL_LOG_IO_SIZE_POS 8 + +/* + Read one entry from ddl log file + SYNOPSIS + read_ddl_log_file_entry() + entry_no Entry number to read + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static bool read_ddl_log_file_entry(uint entry_no) +{ + bool error= FALSE; + File file_id= global_ddl_log.file_id; + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + uint io_size= global_ddl_log.io_size; + DBUG_ENTER("read_ddl_log_file_entry"); + + if (my_pread(file_id, (byte*)file_entry_buf, io_size, io_size * entry_no, + MYF(MY_WME)) != io_size) + error= TRUE; + DBUG_RETURN(error); +} + + +/* + Write one entry from ddl log file + SYNOPSIS + write_ddl_log_file_entry() + entry_no Entry number to read + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static bool write_ddl_log_file_entry(uint entry_no) +{ + bool error= FALSE; + File file_id= global_ddl_log.file_id; + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + DBUG_ENTER("write_ddl_log_file_entry"); + + if (my_pwrite(file_id, (byte*)file_entry_buf, + IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE) + error= TRUE; + DBUG_RETURN(error); +} + + +/* + Write ddl log header + SYNOPSIS + write_ddl_log_header() + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static bool write_ddl_log_header() +{ + uint16 const_var; + bool error= FALSE; + DBUG_ENTER("write_ddl_log_header"); + + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NUM_ENTRY_POS], + global_ddl_log.num_entries); + const_var= FN_LEN; + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS], + const_var); + const_var= IO_SIZE; + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS], + const_var); + if (write_ddl_log_file_entry(0UL)) + { + sql_print_error("Error writing ddl log header"); + DBUG_RETURN(TRUE); + } + VOID(sync_ddl_log()); + DBUG_RETURN(error); +} + + +/* + Create ddl log file name + SYNOPSIS + create_ddl_log_file_name() + file_name Filename setup + RETURN VALUES + NONE +*/ + +static inline void create_ddl_log_file_name(char *file_name) +{ + strxmov(file_name, mysql_data_home, "/", "ddl_log.log", NullS); +} + + +/* + Read header of ddl log file + SYNOPSIS + read_ddl_log_header() + RETURN VALUES + > 0 Last entry in ddl log + 0 No entries in ddl log + DESCRIPTION + When we read the ddl log header we get information about maximum sizes + of names in the ddl log and we also get information about the number + of entries in the ddl log. +*/ + +static uint read_ddl_log_header() +{ + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + char file_name[FN_REFLEN]; + uint entry_no; + bool successful_open= FALSE; + DBUG_ENTER("read_ddl_log_header"); + + bzero(file_entry_buf, sizeof(global_ddl_log.file_entry_buf)); + global_ddl_log.inited= FALSE; + global_ddl_log.recovery_phase= TRUE; + global_ddl_log.io_size= IO_SIZE; + create_ddl_log_file_name(file_name); + if ((global_ddl_log.file_id= my_open(file_name, + O_RDWR | O_BINARY, MYF(MY_WME))) >= 0) + { + if (read_ddl_log_file_entry(0UL)) + { + /* Write message into error log */ + sql_print_error("Failed to read ddl log file in recovery"); + } + else + successful_open= TRUE; + } + entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]); + global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]); + if (successful_open) + { + global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]); + DBUG_ASSERT(global_ddl_log.io_size <= + sizeof(global_ddl_log.file_entry_buf)); + } + else + { + entry_no= 0; + } + global_ddl_log.first_free= NULL; + global_ddl_log.first_used= NULL; + global_ddl_log.num_entries= 0; + VOID(pthread_mutex_init(&LOCK_gdl, MY_MUTEX_INIT_FAST)); + DBUG_RETURN(entry_no); +} + + +/* + Read a ddl log entry + SYNOPSIS + read_ddl_log_entry() + read_entry Number of entry to read + out:entry_info Information from entry + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Read a specified entry in the ddl log +*/ + +bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry) +{ + char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf; + uint inx; + uchar single_char; + DBUG_ENTER("read_ddl_log_entry"); + + if (read_ddl_log_file_entry(read_entry)) + { + DBUG_RETURN(TRUE); + } + ddl_log_entry->entry_pos= read_entry; + single_char= file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]; + ddl_log_entry->entry_type= (enum ddl_log_entry_code)single_char; + single_char= file_entry_buf[DDL_LOG_ACTION_TYPE_POS]; + ddl_log_entry->action_type= (enum ddl_log_action_code)single_char; + ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS]; + ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]); + ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS]; + inx= DDL_LOG_NAME_POS + global_ddl_log.name_len; + ddl_log_entry->from_name= &file_entry_buf[inx]; + inx+= global_ddl_log.name_len; + ddl_log_entry->handler_name= &file_entry_buf[inx]; + DBUG_RETURN(FALSE); +} + + +/* + Initialise ddl log + SYNOPSIS + init_ddl_log() + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Write the header of the ddl log file and length of names. Also set + number of entries to zero. +*/ + +static bool init_ddl_log() +{ + bool error= FALSE; + char file_name[FN_REFLEN]; + DBUG_ENTER("init_ddl_log"); + + if (global_ddl_log.inited) + { + DBUG_RETURN(FALSE); + } + global_ddl_log.io_size= IO_SIZE; + create_ddl_log_file_name(file_name); + if ((global_ddl_log.file_id= my_create(file_name, + CREATE_MODE, + O_RDWR | O_TRUNC | O_BINARY, + MYF(MY_WME))) < 0) + { + /* Couldn't create ddl log file, this is serious error */ + sql_print_error("Failed to open ddl log file"); + DBUG_RETURN(TRUE); + } + global_ddl_log.inited= TRUE; + if (write_ddl_log_header()) + { + global_ddl_log.inited= FALSE; + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + + +/* + Execute one action in a ddl log entry + SYNOPSIS + execute_ddl_log_action() + ddl_log_entry Information in action entry to execute + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry) +{ + bool frm_action= FALSE; + LEX_STRING handler_name; + handler *file= NULL; + MEM_ROOT mem_root; + int error= TRUE; + char to_path[FN_REFLEN]; + char from_path[FN_REFLEN]; + char *par_ext= (char*)".par"; + handlerton *hton; + DBUG_ENTER("execute_ddl_log_action"); + + if (ddl_log_entry->entry_type == DDL_IGNORE_LOG_ENTRY_CODE) + { + DBUG_RETURN(FALSE); + } + handler_name.str= (char*)ddl_log_entry->handler_name; + handler_name.length= strlen(ddl_log_entry->handler_name); + init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); + if (!strcmp(ddl_log_entry->handler_name, reg_ext)) + frm_action= TRUE; + else + { + TABLE_SHARE dummy; + + hton= ha_resolve_by_name(thd, &handler_name); + if (!hton) + { + my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name); + goto error; + } + bzero(&dummy, sizeof(TABLE_SHARE)); + file= get_new_handler(&dummy, &mem_root, hton); + if (!file) + { + mem_alloc_error(sizeof(handler)); + goto error; + } + } + switch (ddl_log_entry->action_type) + { + case DDL_LOG_REPLACE_ACTION: + case DDL_LOG_DELETE_ACTION: + { + if (ddl_log_entry->phase == 0) + { + if (frm_action) + { + strxmov(to_path, ddl_log_entry->name, reg_ext, NullS); + if ((error= my_delete(to_path, MYF(MY_WME)))) + { + if (my_errno != ENOENT) + break; + } +#ifdef WITH_PARTITION_STORAGE_ENGINE + strxmov(to_path, ddl_log_entry->name, par_ext, NullS); + VOID(my_delete(to_path, MYF(MY_WME))); +#endif + } + else + { + if ((error= file->delete_table(ddl_log_entry->name))) + { + if (error != ENOENT && error != HA_ERR_NO_SUCH_TABLE) + break; + } + } + if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) + break; + VOID(sync_ddl_log()); + error= FALSE; + if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION) + break; + } + DBUG_ASSERT(ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION); + /* + Fall through and perform the rename action of the replace + action. We have already indicated the success of the delete + action in the log entry by stepping up the phase. + */ + } + case DDL_LOG_RENAME_ACTION: + { + error= TRUE; + if (frm_action) + { + strxmov(to_path, ddl_log_entry->name, reg_ext, NullS); + strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS); + if (my_rename(from_path, to_path, MYF(MY_WME))) + break; +#ifdef WITH_PARTITION_STORAGE_ENGINE + strxmov(to_path, ddl_log_entry->name, par_ext, NullS); + strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS); + VOID(my_rename(from_path, to_path, MYF(MY_WME))); +#endif + } + else + { + if (file->rename_table(ddl_log_entry->from_name, + ddl_log_entry->name)) + break; + } + if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos))) + break; + VOID(sync_ddl_log()); + error= FALSE; + break; + } + default: + DBUG_ASSERT(0); + break; + } + delete file; +error: + free_root(&mem_root, MYF(0)); + DBUG_RETURN(error); +} + + +/* + Get a free entry in the ddl log + SYNOPSIS + get_free_ddl_log_entry() + out:active_entry A ddl log memory entry returned + RETURN VALUES + TRUE Error + FALSE Success +*/ + +static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry, + bool *write_header) +{ + DDL_LOG_MEMORY_ENTRY *used_entry; + DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used; + DBUG_ENTER("get_free_ddl_log_entry"); + + if (global_ddl_log.first_free == NULL) + { + if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc( + sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME)))) + { + sql_print_error("Failed to allocate memory for ddl log free list"); + DBUG_RETURN(TRUE); + } + global_ddl_log.num_entries++; + used_entry->entry_pos= global_ddl_log.num_entries; + *write_header= TRUE; + } + else + { + used_entry= global_ddl_log.first_free; + global_ddl_log.first_free= used_entry->next_log_entry; + *write_header= FALSE; + } + /* + Move from free list to used list + */ + used_entry->next_log_entry= first_used; + used_entry->prev_log_entry= NULL; + global_ddl_log.first_used= used_entry; + if (first_used) + first_used->prev_log_entry= used_entry; + + *active_entry= used_entry; + DBUG_RETURN(FALSE); +} + + +/* + External interface methods for the DDL log Module + --------------------------------------------------- +*/ + +/* + SYNOPSIS + write_ddl_log_entry() + ddl_log_entry Information about log entry + out:entry_written Entry information written into + + RETURN VALUES + TRUE Error + FALSE Success + + DESCRIPTION + A careful write of the ddl log is performed to ensure that we can + handle crashes occurring during CREATE and ALTER TABLE processing. +*/ + +bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry, + DDL_LOG_MEMORY_ENTRY **active_entry) +{ + bool error, write_header; + DBUG_ENTER("write_ddl_log_entry"); + + if (init_ddl_log()) + { + DBUG_RETURN(TRUE); + } + global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= + (char)DDL_LOG_ENTRY_CODE; + global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= + (char)ddl_log_entry->action_type; + global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0; + int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], + ddl_log_entry->next_entry); + DBUG_ASSERT(strlen(ddl_log_entry->name) < FN_LEN); + strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS], + ddl_log_entry->name, FN_LEN - 1); + if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION || + ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION) + { + DBUG_ASSERT(strlen(ddl_log_entry->from_name) < FN_LEN); + strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN], + ddl_log_entry->from_name, FN_LEN - 1); + } + else + global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; + DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < FN_LEN); + strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_LEN)], + ddl_log_entry->handler_name, FN_LEN - 1); + if (get_free_ddl_log_entry(active_entry, &write_header)) + { + DBUG_RETURN(TRUE); + } + error= FALSE; + if (write_ddl_log_file_entry((*active_entry)->entry_pos)) + { + error= TRUE; + sql_print_error("Failed to write entry_no = %u", + (*active_entry)->entry_pos); + } + if (write_header && !error) + { + VOID(sync_ddl_log()); + if (write_ddl_log_header()) + error= TRUE; + } + if (error) + release_ddl_log_memory_entry(*active_entry); + DBUG_RETURN(error); +} + + +/* + Write final entry in the ddl log + SYNOPSIS + write_execute_ddl_log_entry() + first_entry First entry in linked list of entries + to execute, if 0 = NULL it means that + the entry is removed and the entries + are put into the free list. + complete Flag indicating we are simply writing + info about that entry has been completed + in:out:active_entry Entry to execute, 0 = NULL if the entry + is written first time and needs to be + returned. In this case the entry written + is returned in this parameter + RETURN VALUES + TRUE Error + FALSE Success + + DESCRIPTION + This is the last write in the ddl log. The previous log entries have + already been written but not yet synched to disk. + We write a couple of log entries that describes action to perform. + This entries are set-up in a linked list, however only when a first + execute entry is put as the first entry these will be executed. + This routine writes this first +*/ + +bool write_execute_ddl_log_entry(uint first_entry, + bool complete, + DDL_LOG_MEMORY_ENTRY **active_entry) +{ + bool write_header= FALSE; + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + DBUG_ENTER("write_execute_ddl_log_entry"); + + if (init_ddl_log()) + { + DBUG_RETURN(TRUE); + } + if (!complete) + { + /* + We haven't synched the log entries yet, we synch them now before + writing the execute entry. If complete is true we haven't written + any log entries before, we are only here to write the execute + entry to indicate it is done. + */ + VOID(sync_ddl_log()); + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_EXECUTE_CODE; + } + else + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_IGNORE_LOG_ENTRY_CODE; + file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */ + file_entry_buf[DDL_LOG_PHASE_POS]= 0; + int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry); + file_entry_buf[DDL_LOG_NAME_POS]= 0; + file_entry_buf[DDL_LOG_NAME_POS + FN_LEN]= 0; + file_entry_buf[DDL_LOG_NAME_POS + 2*FN_LEN]= 0; + if (!(*active_entry)) + { + if (get_free_ddl_log_entry(active_entry, &write_header)) + { + DBUG_RETURN(TRUE); + } + } + if (write_ddl_log_file_entry((*active_entry)->entry_pos)) + { + sql_print_error("Error writing execute entry in ddl log"); + release_ddl_log_memory_entry(*active_entry); + DBUG_RETURN(TRUE); + } + VOID(sync_ddl_log()); + if (write_header) + { + if (write_ddl_log_header()) + { + release_ddl_log_memory_entry(*active_entry); + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(FALSE); +} + + +/* + For complex rename operations we need to deactivate individual entries. + SYNOPSIS + deactivate_ddl_log_entry() + entry_no Entry position of record to change + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + During replace operations where we start with an existing table called + t1 and a replacement table called t1#temp or something else and where + we want to delete t1 and rename t1#temp to t1 this is not possible to + do in a safe manner unless the ddl log is informed of the phases in + the change. + + Delete actions are 1-phase actions that can be ignored immediately after + being executed. + Rename actions from x to y is also a 1-phase action since there is no + interaction with any other handlers named x and y. + Replace action where drop y and x -> y happens needs to be a two-phase + action. Thus the first phase will drop y and the second phase will + rename x -> y. +*/ + +bool deactivate_ddl_log_entry(uint entry_no) +{ + char *file_entry_buf= (char*)global_ddl_log.file_entry_buf; + DBUG_ENTER("deactivate_ddl_log_entry"); + + if (!read_ddl_log_file_entry(entry_no)) + { + if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE) + { + if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_DELETE_ACTION || + file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_RENAME_ACTION || + (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION && + file_entry_buf[DDL_LOG_PHASE_POS] == 1)) + file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE; + else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION) + { + DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] == 0); + file_entry_buf[DDL_LOG_PHASE_POS]= 1; + } + else + { + DBUG_ASSERT(0); + } + if (write_ddl_log_file_entry(entry_no)) + { + sql_print_error("Error in deactivating log entry. Position = %u", + entry_no); + DBUG_RETURN(TRUE); + } + } + } + else + { + sql_print_error("Failed in reading entry before deactivating it"); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + + +/* + Sync ddl log file + SYNOPSIS + sync_ddl_log() + RETURN VALUES + TRUE Error + FALSE Success +*/ + +bool sync_ddl_log() +{ + bool error= FALSE; + DBUG_ENTER("sync_ddl_log"); + + if ((!global_ddl_log.recovery_phase) && + init_ddl_log()) + { + DBUG_RETURN(TRUE); + } + if (my_sync(global_ddl_log.file_id, MYF(0))) + { + /* Write to error log */ + sql_print_error("Failed to sync ddl log"); + error= TRUE; + } + DBUG_RETURN(error); +} + + +/* + Release a log memory entry + SYNOPSIS + release_ddl_log_memory_entry() + log_memory_entry Log memory entry to release + RETURN VALUES + NONE +*/ + +void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry) +{ + DDL_LOG_MEMORY_ENTRY *first_free= global_ddl_log.first_free; + DDL_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry; + DDL_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry; + DBUG_ENTER("release_ddl_log_memory_entry"); + + global_ddl_log.first_free= log_entry; + log_entry->next_log_entry= first_free; + + if (prev_log_entry) + prev_log_entry->next_log_entry= next_log_entry; + else + global_ddl_log.first_used= next_log_entry; + if (next_log_entry) + next_log_entry->prev_log_entry= prev_log_entry; + DBUG_VOID_RETURN; +} + + +/* + Execute one entry in the ddl log. Executing an entry means executing + a linked list of actions. + SYNOPSIS + execute_ddl_log_entry() + first_entry Reference to first action in entry + RETURN VALUES + TRUE Error + FALSE Success +*/ + +bool execute_ddl_log_entry(THD *thd, uint first_entry) +{ + DDL_LOG_ENTRY ddl_log_entry; + uint read_entry= first_entry; + DBUG_ENTER("execute_ddl_log_entry"); + + pthread_mutex_lock(&LOCK_gdl); + do + { + if (read_ddl_log_entry(read_entry, &ddl_log_entry)) + { + /* Write to error log and continue with next log entry */ + sql_print_error("Failed to read entry = %u from ddl log", + read_entry); + break; + } + DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE || + ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE); + + if (execute_ddl_log_action(thd, &ddl_log_entry)) + { + /* Write to error log and continue with next log entry */ + sql_print_error("Failed to execute action for entry = %u from ddl log", + read_entry); + break; + } + read_entry= ddl_log_entry.next_entry; + } while (read_entry); + pthread_mutex_unlock(&LOCK_gdl); + DBUG_RETURN(FALSE); +} + + +/* + Execute the ddl log at recovery of MySQL Server + SYNOPSIS + execute_ddl_log_recovery() + RETURN VALUES + NONE +*/ + +void execute_ddl_log_recovery() +{ + uint num_entries, i; + THD *thd; + DDL_LOG_ENTRY ddl_log_entry; + char file_name[FN_REFLEN]; + DBUG_ENTER("execute_ddl_log_recovery"); + + /* + To be able to run this from boot, we allocate a temporary THD + */ + if (!(thd=new THD)) + DBUG_VOID_RETURN; + thd->thread_stack= (char*) &thd; + thd->store_globals(); + + num_entries= read_ddl_log_header(); + for (i= 1; i < num_entries + 1; i++) + { + if (read_ddl_log_entry(i, &ddl_log_entry)) + { + sql_print_error("Failed to read entry no = %u from ddl log", + i); + continue; + } + if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE) + { + if (execute_ddl_log_entry(thd, ddl_log_entry.next_entry)) + { + /* Real unpleasant scenario but we continue anyways. */ + continue; + } + } + } + create_ddl_log_file_name(file_name); + VOID(my_delete(file_name, MYF(0))); + global_ddl_log.recovery_phase= FALSE; + delete thd; + /* Remember that we don't have a THD */ + my_pthread_setspecific_ptr(THR_THD, 0); + DBUG_VOID_RETURN; +} + + +/* + Release all memory allocated to the ddl log + SYNOPSIS + release_ddl_log() + RETURN VALUES + NONE +*/ + +void release_ddl_log() +{ + DDL_LOG_MEMORY_ENTRY *free_list= global_ddl_log.first_free; + DDL_LOG_MEMORY_ENTRY *used_list= global_ddl_log.first_used; + DBUG_ENTER("release_ddl_log"); + + pthread_mutex_lock(&LOCK_gdl); + while (used_list) + { + DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry; + my_free((char*)used_list, MYF(0)); + used_list= tmp; + } + while (free_list) + { + DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry; + my_free((char*)free_list, MYF(0)); + free_list= tmp; + } + VOID(my_close(global_ddl_log.file_id, MYF(0))); + pthread_mutex_unlock(&LOCK_gdl); + VOID(pthread_mutex_destroy(&LOCK_gdl)); + DBUG_VOID_RETURN; +} + + +/* +--------------------------------------------------------------------------- + + END MODULE DDL log + -------------------- + +--------------------------------------------------------------------------- +*/ + /* SYNOPSIS @@ -281,83 +1179,68 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ int error= 0; char path[FN_REFLEN+1]; + char shadow_path[FN_REFLEN+1]; + char shadow_frm_name[FN_REFLEN+1]; char frm_name[FN_REFLEN+1]; DBUG_ENTER("mysql_write_frm"); - if (flags & WFRM_INITIAL_WRITE) + /* + Build shadow frm file name + */ + build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, + lpt->table_name, "#"); + strxmov(shadow_frm_name, shadow_path, reg_ext, NullS); + if (flags & WFRM_WRITE_SHADOW) { - error= mysql_copy_create_list(lpt->create_list, - &lpt->new_create_list); - error+= mysql_copy_key_list(lpt->key_list, - &lpt->new_key_list); - if (error) + if (mysql_copy_create_list(lpt->create_list, + &lpt->new_create_list) || + mysql_copy_key_list(lpt->key_list, + &lpt->new_key_list) || + mysql_prepare_table(lpt->thd, lpt->create_info, + &lpt->new_create_list, + &lpt->new_key_list, + /*tmp_table*/ 1, + &lpt->db_options, + lpt->table->file, + &lpt->key_info_buffer, + &lpt->key_count, + /*select_field_count*/ 0)) { DBUG_RETURN(TRUE); } - } - build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); - strxmov(frm_name, path, reg_ext, NullS); - if ((flags & WFRM_INITIAL_WRITE) && - (mysql_prepare_table(lpt->thd, lpt->create_info, &lpt->new_create_list, - &lpt->new_key_list,/*tmp_table*/ 1, &lpt->db_options, - lpt->table->file, &lpt->key_info_buffer, - &lpt->key_count, /*select_field_count*/ 0))) - { - DBUG_RETURN(TRUE); - } #ifdef WITH_PARTITION_STORAGE_ENGINE - { - partition_info *part_info= lpt->table->part_info; - char *part_syntax_buf; - uint syntax_len, i; - bool any_unnormal_state= FALSE; - - if (part_info) { - uint max_part_state_len= part_info->partitions.elements + - part_info->temp_partitions.elements; - if (!(part_info->part_state= (uchar*)sql_alloc(max_part_state_len))) + partition_info *part_info= lpt->table->part_info; + char *part_syntax_buf; + uint syntax_len; + + if (part_info) { - DBUG_RETURN(TRUE); + if (!(part_syntax_buf= generate_partition_syntax(part_info, + &syntax_len, + TRUE, FALSE))) + { + DBUG_RETURN(TRUE); + } + part_info->part_info_string= part_syntax_buf; + part_info->part_info_len= syntax_len; } - part_info->part_state_len= 0; - if (!(part_syntax_buf= generate_partition_syntax(part_info, - &syntax_len, - TRUE, FALSE))) - { - DBUG_RETURN(TRUE); - } - for (i= 0; i < part_info->part_state_len; i++) - { - enum partition_state part_state= - (enum partition_state)part_info->part_state[i]; - if (part_state != PART_NORMAL && part_state != PART_IS_ADDED) - any_unnormal_state= TRUE; - } - if (!any_unnormal_state) - { - part_info->part_state= NULL; - part_info->part_state_len= 0; - } - part_info->part_info_string= part_syntax_buf; - part_info->part_info_len= syntax_len; } - } #endif - /* - We write the frm file with the LOCK_open mutex since otherwise we could - overwrite the frm file as another is reading it in open_table. - */ - lpt->create_info->table_options= lpt->db_options; - VOID(pthread_mutex_lock(&LOCK_open)); - if ((mysql_create_frm(lpt->thd, frm_name, lpt->db, lpt->table_name, - lpt->create_info, lpt->new_create_list, lpt->key_count, - lpt->key_info_buffer, lpt->table->file)) || - ((flags & WFRM_CREATE_HANDLER_FILES) && - lpt->table->file->create_handler_files(path, lpt->create_info))) - { - error= 1; - goto end; + /* Write shadow frm file */ + lpt->create_info->table_options= lpt->db_options; + if ((mysql_create_frm(lpt->thd, shadow_frm_name, lpt->db, + lpt->table_name, lpt->create_info, + lpt->new_create_list, lpt->key_count, + lpt->key_info_buffer, lpt->table->file)) || + lpt->table->file->create_handler_files(shadow_path, NULL, + CHF_CREATE_FLAG, + lpt->create_info)) + { + my_delete(shadow_frm_name, MYF(0)); + error= 1; + goto end; + } } if (flags & WFRM_PACK_FRM) { @@ -369,7 +1252,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ const void *data= 0; uint length= 0; - if (readfrm(path, &data, &length) || + if (readfrm(shadow_path, &data, &length) || packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len)) { my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR)); @@ -378,11 +1261,56 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) error= 1; goto end; } - error= my_delete(frm_name, MYF(MY_WME)); + error= my_delete(shadow_frm_name, MYF(MY_WME)); } - /* Frm file have been updated to reflect the change about to happen. */ + if (flags & WFRM_INSTALL_SHADOW) + { +#ifdef WITH_PARTITION_STORAGE_ENGINE + partition_info *part_info= lpt->part_info; +#endif + /* + Build frm file name + */ + build_table_filename(path, sizeof(path), lpt->db, + lpt->table_name, ""); + strxmov(frm_name, path, reg_ext, NullS); + /* + When we are changing to use new frm file we need to ensure that we + don't collide with another thread in process to open the frm file. + We start by deleting the .frm file and possible .par file. Then we + write to the DDL log that we have completed the delete phase by + increasing the phase of the log entry. Next step is to rename the + new .frm file and the new .par file to the real name. After + completing this we write a new phase to the log entry that will + deactivate it. + */ + VOID(pthread_mutex_lock(&LOCK_open)); + if (my_delete(frm_name, MYF(MY_WME)) || +#ifdef WITH_PARTITION_STORAGE_ENGINE + lpt->table->file->create_handler_files(path, shadow_path, + CHF_DELETE_FLAG, NULL) || + deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) || + (sync_ddl_log(), FALSE) || +#endif +#ifdef WITH_PARTITION_STORAGE_ENGINE + my_rename(shadow_frm_name, frm_name, MYF(MY_WME)) || + lpt->table->file->create_handler_files(path, shadow_path, + CHF_RENAME_FLAG, NULL)) +#else + my_rename(shadow_frm_name, frm_name, MYF(MY_WME))) +#endif + { + error= 1; + } + VOID(pthread_mutex_unlock(&LOCK_open)); +#ifdef WITH_PARTITION_STORAGE_ENGINE + deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos); + part_info->frm_log_entry= NULL; + VOID(sync_ddl_log()); +#endif + } + end: - VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(error); } @@ -4790,7 +5718,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, error= (mysql_create_frm(thd, reg_path, db, table_name, create_info, prepared_create_list, key_count, key_info_buffer, table->file) || - table->file->create_handler_files(path, create_info)); + table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG, + create_info)); VOID(pthread_mutex_unlock(&LOCK_open)); if (error) goto err; @@ -4836,7 +5765,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, error= (mysql_create_frm(thd, reg_path, db, table_name, create_info, prepared_create_list, key_count, key_info_buffer, table->file) || - table->file->create_handler_files(path, create_info)); + table->file->create_handler_files(reg_path, NULL, CHF_INDEX_FLAG, + create_info)); VOID(pthread_mutex_unlock(&LOCK_open)); if (error) goto err; @@ -5060,7 +5990,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, VOID(pthread_mutex_lock(&LOCK_open)); } /* Tell the handler that a new frm file is in place. */ - if (table->file->create_handler_files(path, create_info)) + if (table->file->create_handler_files(path, NULL, CHF_INDEX_FLAG, + create_info)) { VOID(pthread_mutex_unlock(&LOCK_open)); goto err; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 18217094ff7..707a885df99 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -773,6 +773,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table) SELECT_LEX *end, *view_select; LEX *old_lex, *lex; Query_arena *arena, backup; + TABLE_LIST *top_view= table->top_table(); int res; bool result; DBUG_ENTER("mysql_make_view"); @@ -800,6 +801,24 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table) DBUG_RETURN(0); } + /* check loop via view definition */ + for (TABLE_LIST *precedent= table->referencing_view; + precedent; + precedent= precedent->referencing_view) + { + if (precedent->view_name.length == table->table_name_length && + precedent->view_db.length == table->db_length && + my_strcasecmp(system_charset_info, + precedent->view_name.str, table->table_name) == 0 && + my_strcasecmp(system_charset_info, + precedent->view_db.str, table->db) == 0) + { + my_error(ER_VIEW_RECURSIVE, MYF(0), + top_view->view_db.str, top_view->view_name.str); + DBUG_RETURN(TRUE); + } + } + /* For now we assume that tables will not be changed during PS life (it will be TRUE as far as we make new table cache). @@ -898,7 +917,6 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table) } if (!res && !thd->is_fatal_error) { - TABLE_LIST *top_view= table->top_table(); TABLE_LIST *view_tables= lex->query_tables; TABLE_LIST *view_tables_tail= 0; TABLE_LIST *tbl; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2f91472ad2d..47f0b1e259e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1819,22 +1819,23 @@ sp_fdparam: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_pvar(&$1, TRUE)) + if (spc->find_variable(&$1, TRUE)) { my_error(ER_SP_DUP_PARAM, MYF(0), $1.str); YYABORT; } - sp_pvar_t *pvar= spc->push_pvar(&$1, (enum enum_field_types)$3, - sp_param_in); + sp_variable_t *spvar= spc->push_variable(&$1, + (enum enum_field_types)$3, + sp_param_in); if (lex->sphead->fill_field_definition(YYTHD, lex, (enum enum_field_types) $3, - &pvar->field_def)) + &spvar->field_def)) { YYABORT; } - pvar->field_def.field_name= pvar->name.str; - pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; + spvar->field_def.field_name= spvar->name.str; + spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; } ; @@ -1855,22 +1856,23 @@ sp_pdparam: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_pvar(&$3, TRUE)) + if (spc->find_variable(&$3, TRUE)) { my_error(ER_SP_DUP_PARAM, MYF(0), $3.str); YYABORT; } - sp_pvar_t *pvar= spc->push_pvar(&$3, (enum enum_field_types)$4, - (sp_param_mode_t)$1); + sp_variable_t *spvar= spc->push_variable(&$3, + (enum enum_field_types)$4, + (sp_param_mode_t)$1); if (lex->sphead->fill_field_definition(YYTHD, lex, (enum enum_field_types) $4, - &pvar->field_def)) + &spvar->field_def)) { YYABORT; } - pvar->field_def.field_name= pvar->name.str; - pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; + spvar->field_def.field_name= spvar->name.str; + spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; } ; @@ -1934,7 +1936,7 @@ sp_decl: { LEX *lex= Lex; sp_pcontext *pctx= lex->spcont; - uint num_vars= pctx->context_pvars(); + uint num_vars= pctx->context_var_count(); enum enum_field_types var_type= (enum enum_field_types) $4; Item *dflt_value_item= $5; create_field *create_field_op; @@ -1947,23 +1949,23 @@ sp_decl: for (uint i = num_vars-$2 ; i < num_vars ; i++) { - uint var_idx= pctx->pvar_context2index(i); - sp_pvar_t *pvar= pctx->find_pvar(var_idx); + uint var_idx= pctx->var_context2runtime(i); + sp_variable_t *spvar= pctx->find_variable(var_idx); - if (!pvar) + if (!spvar) YYABORT; - pvar->type= var_type; - pvar->dflt= dflt_value_item; + spvar->type= var_type; + spvar->dflt= dflt_value_item; if (lex->sphead->fill_field_definition(YYTHD, lex, var_type, - &pvar->field_def)) + &spvar->field_def)) { YYABORT; } - pvar->field_def.field_name= pvar->name.str; - pvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; + spvar->field_def.field_name= spvar->name.str; + spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL; /* The last instruction is responsible for freeing LEX. */ @@ -2000,7 +2002,7 @@ sp_decl: sp_pcontext *ctx= lex->spcont; sp_instr_hpush_jump *i= new sp_instr_hpush_jump(sp->instructions(), ctx, $2, - ctx->current_pvars()); + ctx->current_var_count()); sp->add_instr(i); sp->push_backpatch(i, ctx->push_label((char *)"", 0)); @@ -2017,7 +2019,7 @@ sp_decl: if ($2 == SP_HANDLER_CONTINUE) { i= new sp_instr_hreturn(sp->instructions(), ctx, - ctx->current_pvars()); + ctx->current_var_count()); sp->add_instr(i); } else @@ -2048,7 +2050,7 @@ sp_decl: YYABORT; } i= new sp_instr_cpush(sp->instructions(), ctx, $5, - ctx->current_cursors()); + ctx->current_cursor_count()); sp->add_instr(i); ctx->push_cursor(&$2); $$.vars= $$.conds= $$.hndlrs= 0; @@ -2203,12 +2205,12 @@ sp_decl_idents: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_pvar(&$1, TRUE)) + if (spc->find_variable(&$1, TRUE)) { my_error(ER_SP_DUP_VAR, MYF(0), $1.str); YYABORT; } - spc->push_pvar(&$1, (enum_field_types)0, sp_param_in); + spc->push_variable(&$1, (enum_field_types)0, sp_param_in); $$= 1; } | sp_decl_idents ',' ident @@ -2218,12 +2220,12 @@ sp_decl_idents: LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - if (spc->find_pvar(&$3, TRUE)) + if (spc->find_variable(&$3, TRUE)) { my_error(ER_SP_DUP_VAR, MYF(0), $3.str); YYABORT; } - spc->push_pvar(&$3, (enum_field_types)0, sp_param_in); + spc->push_variable(&$3, (enum_field_types)0, sp_param_in); $$= $1 + 1; } ; @@ -2606,9 +2608,9 @@ sp_fetch_list: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *spc= lex->spcont; - sp_pvar_t *spv; + sp_variable_t *spv; - if (!spc || !(spv = spc->find_pvar(&$1))) + if (!spc || !(spv = spc->find_variable(&$1))) { my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); YYABORT; @@ -2627,9 +2629,9 @@ sp_fetch_list: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *spc= lex->spcont; - sp_pvar_t *spv; + sp_variable_t *spv; - if (!spc || !(spv = spc->find_pvar(&$3))) + if (!spc || !(spv = spc->find_variable(&$3))) { my_error(ER_SP_UNDECLARED_VAR, MYF(0), $3.str); YYABORT; @@ -3558,75 +3560,14 @@ part_definition: LEX *lex= Lex; partition_info *part_info= lex->part_info; partition_element *p_elem= new partition_element(); - uint part_id= part_info->partitions.elements + - part_info->temp_partitions.elements; - enum partition_state part_state; + uint part_id= part_info->partitions.elements; - if (part_info->part_state) - part_state= (enum partition_state)part_info->part_state[part_id]; - else - part_state= PART_NORMAL; - switch (part_state) + if (!p_elem || part_info->partitions.push_back(p_elem)) { - case PART_TO_BE_DROPPED: - /* - This part is currently removed so we keep it in a - temporary list for REPAIR TABLE to be able to handle - failures during drop partition process. - */ - case PART_TO_BE_ADDED: - /* - This part is currently being added so we keep it in a - temporary list for REPAIR TABLE to be able to handle - failures during add partition process. - */ - if (!p_elem || part_info->temp_partitions.push_back(p_elem)) - { - mem_alloc_error(sizeof(partition_element)); - YYABORT; - } - break; - case PART_IS_ADDED: - /* - Part has been added and is now a normal partition - */ - case PART_TO_BE_REORGED: - /* - This part is currently reorganised, it is still however - used so we keep it in the list of partitions. We do - however need the state to be able to handle REPAIR TABLE - after failures in the reorganisation process. - */ - case PART_REORGED_DROPPED: - /* - This part is currently reorganised as part of a - COALESCE PARTITION and it will be dropped without a new - replacement partition after completing the reorganisation. - */ - case PART_CHANGED: - /* - This part is currently split or merged as part of ADD - PARTITION for a hash partition or as part of COALESCE - PARTITION for a hash partitioned table. - */ - case PART_IS_CHANGED: - /* - This part has been split or merged as part of ADD - PARTITION for a hash partition or as part of COALESCE - PARTITION for a hash partitioned table. - */ - case PART_NORMAL: - if (!p_elem || part_info->partitions.push_back(p_elem)) - { - mem_alloc_error(sizeof(partition_element)); - YYABORT; - } - break; - default: - mem_alloc_error((part_id * 1000) + part_state); - YYABORT; + mem_alloc_error(sizeof(partition_element)); + YYABORT; } - p_elem->part_state= part_state; + p_elem->part_state= PART_NORMAL; part_info->curr_part_elem= p_elem; part_info->current_partition= p_elem; part_info->use_default_partitions= FALSE; @@ -4801,7 +4742,7 @@ alter: lex->sql_command= SQLCOM_CREATE_VIEW; lex->create_view_mode= VIEW_ALTER; /* first table in list is target VIEW name */ - lex->select_lex.add_table_to_list(thd, $6, NULL, 0); + lex->select_lex.add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING); } view_list_opt AS view_select view_check_option {} @@ -7595,9 +7536,9 @@ select_var_ident: | ident_or_text { LEX *lex=Lex; - sp_pvar_t *t; + sp_variable_t *t; - if (!lex->spcont || !(t=lex->spcont->find_pvar(&$1))) + if (!lex->spcont || !(t=lex->spcont->find_variable(&$1))) { my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); YYABORT; @@ -9034,10 +8975,10 @@ order_ident: simple_ident: ident { - sp_pvar_t *spv; + sp_variable_t *spv; LEX *lex = Lex; sp_pcontext *spc = lex->spcont; - if (spc && (spv = spc->find_pvar(&$1))) + if (spc && (spv = spc->find_variable(&$1))) { /* We're compiling a stored procedure and found a variable */ Item_splocal *splocal; @@ -9825,7 +9766,7 @@ sys_option_value: { /* An SP local variable */ sp_pcontext *ctx= lex->spcont; - sp_pvar_t *spv; + sp_variable_t *spv; sp_instr_set *sp_set; Item *it; if ($1) @@ -9834,7 +9775,7 @@ sys_option_value: YYABORT; } - spv= ctx->find_pvar(&$2.base_name); + spv= ctx->find_variable(&$2.base_name); if ($4) it= $4; @@ -9883,7 +9824,7 @@ option_value: names.str= (char *)"names"; names.length= 5; - if (spc && spc->find_pvar(&names)) + if (spc && spc->find_variable(&names)) my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str); else yyerror(ER(ER_SYNTAX_ERROR)); @@ -9913,7 +9854,7 @@ option_value: pw.str= (char *)"password"; pw.length= 8; - if (spc && spc->find_pvar(&pw)) + if (spc && spc->find_variable(&pw)) { my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str); YYABORT; @@ -9935,10 +9876,10 @@ internal_variable_name: { LEX *lex= Lex; sp_pcontext *spc= lex->spcont; - sp_pvar_t *spv; + sp_variable_t *spv; /* We have to lookup here since local vars can shadow sysvars */ - if (!spc || !(spv = spc->find_pvar(&$1))) + if (!spc || !(spv = spc->find_variable(&$1))) { /* Not an SP local variable */ sys_var *tmp=find_sys_var($1.str, $1.length); @@ -10904,7 +10845,7 @@ view_tail: LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; /* first table in list is target VIEW name */ - if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)) + if (!lex->select_lex.add_table_to_list(thd, $3, NULL, TL_OPTION_UPDATING)) YYABORT; } view_list_opt AS view_select view_check_option diff --git a/sql/table.cc b/sql/table.cc index 41621a19900..6ba66569f5c 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -667,36 +667,17 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, #endif next_chunk+= 5 + partition_info_len; } - if (share->mysql_version > 50105 && next_chunk + 5 < buff_end) +#if MYSQL_VERSION_ID < 50200 + if (share->mysql_version >= 50106 && share->mysql_version <= 50109) { /* - Partition state was introduced to support partition management in version 5.1.5 + Partition state array was here in version 5.1.6 to 5.1.9, this code + makes it possible to load a 5.1.6 table in later versions. Can most + likely be removed at some point in time. Will only be used for + upgrades within 5.1 series of versions. Upgrade to 5.2 can only be + done from newer 5.1 versions. */ - uint32 part_state_len= uint4korr(next_chunk); -#ifdef WITH_PARTITION_STORAGE_ENGINE - if ((share->part_state_len= part_state_len)) - if (!(share->part_state= - (uchar*) memdup_root(&share->mem_root, next_chunk + 4, - part_state_len))) - { - my_free(buff, MYF(0)); - goto err; - } -#else - if (part_state_len) - { - DBUG_PRINT("info", ("WITH_PARTITION_STORAGE_ENGINE is not defined")); - my_free(buff, MYF(0)); - goto err; - } -#endif - next_chunk+= 4 + part_state_len; - } -#ifdef WITH_PARTITION_STORAGE_ENGINE - else - { - share->part_state_len= 0; - share->part_state= NULL; + next_chunk+= 4; } #endif keyinfo= share->key_info; diff --git a/sql/unireg.cc b/sql/unireg.cc index bb197181e2a..bbb4d970d37 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -136,7 +136,6 @@ bool mysql_create_frm(THD *thd, const char *file_name, if (part_info) { create_info->extra_size+= part_info->part_info_len; - create_info->extra_size+= part_info->part_state_len; } #endif @@ -209,12 +208,6 @@ bool mysql_create_frm(THD *thd, const char *file_name, my_write(file, (const byte*)part_info->part_info_string, part_info->part_info_len + 1, MYF_RW)) goto err; - DBUG_PRINT("info", ("Part state len = %d", part_info->part_state_len)); - int4store(buff, part_info->part_state_len); - if (my_write(file, (const byte*)buff, 4, MYF_RW) || - my_write(file, (const byte*)part_info->part_state, - part_info->part_state_len, MYF_RW)) - goto err; } else #endif @@ -330,7 +323,7 @@ int rea_create_table(THD *thd, const char *path, // Make sure mysql_create_frm din't remove extension DBUG_ASSERT(*fn_rext(frm_name)); - if (file->create_handler_files(path, create_info)) + if (file->create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info)) goto err_handler; if (!create_info->frm_only && ha_create_table(thd, path, db, table_name, create_info,0)) diff --git a/storage/innobase/Makefile.am b/storage/innobase/Makefile.am index 22796b45882..0cceac97688 100644 --- a/storage/innobase/Makefile.am +++ b/storage/innobase/Makefile.am @@ -76,7 +76,7 @@ EXTRA_DIST = include/btr0btr.h include/btr0btr.ic include/btr0cur.h include/btr include/univ.i include/usr0sess.h include/usr0sess.ic include/usr0types.h \ include/ut0byte.h include/ut0byte.ic include/ut0dbg.h include/ut0lst.h \ include/ut0mem.h include/ut0mem.ic include/ut0rnd.h include/ut0rnd.ic \ - include/ut0sort.h include/ut0ut.h include/ut0ut.ic \ + include/ut0sort.h include/ut0ut.h include/ut0ut.ic include/ut0vec.h include/ut0vec.ic \ cmakelists.txt # Don't update the files from bitkeeper diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 4ece0e36b19..5e338f97982 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -144,7 +144,7 @@ btr_root_get( root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr); ut_a((ibool)!!page_is_comp(root) == - dict_table_is_comp(UT_LIST_GET_FIRST(tree->tree_indexes)->table)); + dict_table_is_comp(tree->tree_index->table)); return(root); } @@ -259,7 +259,7 @@ btr_page_create( ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); page_create(page, mtr, - dict_table_is_comp(UT_LIST_GET_FIRST(tree->tree_indexes)->table)); + dict_table_is_comp(tree->tree_index->table)); buf_block_align(page)->check_index_page_at_flush = TRUE; btr_page_set_index_id(page, tree->id, mtr); @@ -574,7 +574,7 @@ btr_page_get_father_for_rec( tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap, btr_page_get_level(page, mtr)); - index = UT_LIST_GET_FIRST(tree->tree_indexes); + index = tree->tree_index; /* In the following, we choose just any index from the tree as the first parameter for btr_cur_search_to_nth_level. */ @@ -1073,8 +1073,7 @@ btr_root_raise_and_insert( /* fprintf(stderr, "Root raise new page no %lu\n", buf_frame_get_page_no(new_page)); */ - ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes), - new_page); + ibuf_reset_free_bits(tree->tree_index, new_page); /* Reposition the cursor to the child node */ page_cur_search(new_page, cursor->index, tuple, PAGE_CUR_LE, page_cursor); @@ -1415,7 +1414,7 @@ btr_insert_on_non_leaf_level( /* In the following, choose just any index from the tree as the first parameter for btr_cur_search_to_nth_level. */ - btr_cur_search_to_nth_level(UT_LIST_GET_FIRST(tree->tree_indexes), + btr_cur_search_to_nth_level(tree->tree_index, level, tuple, PAGE_CUR_LE, BTR_CONT_MODIFY_TREE, &cursor, 0, mtr); @@ -1479,7 +1478,7 @@ btr_attach_half_pages( btr_node_ptr_set_child_page_no(node_ptr, rec_get_offsets(node_ptr, - UT_LIST_GET_FIRST(tree->tree_indexes), + tree->tree_index, NULL, ULINT_UNDEFINED, &heap), lower_page_no, mtr); mem_heap_empty(heap); @@ -1768,8 +1767,8 @@ func_start: buf_frame_get_page_no(left_page), buf_frame_get_page_no(right_page)); */ - ut_ad(page_validate(left_page, UT_LIST_GET_FIRST(tree->tree_indexes))); - ut_ad(page_validate(right_page, UT_LIST_GET_FIRST(tree->tree_indexes))); + ut_ad(page_validate(left_page, tree->tree_index)); + ut_ad(page_validate(right_page, tree->tree_index)); mem_heap_free(heap); return(rec); @@ -1910,8 +1909,7 @@ btr_node_ptr_delete( node_ptr = btr_page_get_father_node_ptr(tree, page, mtr); - btr_cur_position(UT_LIST_GET_FIRST(tree->tree_indexes), node_ptr, - &cursor); + btr_cur_position(tree->tree_index, node_ptr, &cursor); compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE, mtr); ut_a(err == DB_SUCCESS); @@ -1947,7 +1945,7 @@ btr_lift_page_up( btr_page_get_father_node_ptr(tree, page, mtr)); page_level = btr_page_get_level(page, mtr); - index = UT_LIST_GET_FIRST(tree->tree_indexes); + index = tree->tree_index; btr_search_drop_page_hash_index(page); @@ -2180,8 +2178,7 @@ btr_discard_only_page_on_level( btr_page_empty(father_page, mtr); /* We play safe and reset the free bits for the father */ - ibuf_reset_free_bits(UT_LIST_GET_FIRST(tree->tree_indexes), - father_page); + ibuf_reset_free_bits(tree->tree_index, father_page); } else { ut_ad(page_get_n_recs(father_page) == 1); @@ -2449,7 +2446,7 @@ btr_check_node_ptr( ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr, rec_get_offsets(node_ptr, - dict_tree_find_index(tree, node_ptr), + tree->tree_index, NULL, ULINT_UNDEFINED, &heap)) == 0); mem_heap_free(heap); @@ -2692,7 +2689,7 @@ btr_validate_level( space = buf_frame_get_space_id(page); - index = UT_LIST_GET_FIRST(tree->tree_indexes); + index = tree->tree_index; while (level != btr_page_get_level(page, &mtr)) { diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 14e991bb3c6..deba3e23487 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -1606,7 +1606,7 @@ btr_cur_optimistic_update( new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update, - NULL); + FALSE, NULL); old_rec_size = rec_offs_size(offsets); new_rec_size = rec_get_converted_size(index, new_entry); @@ -1846,7 +1846,7 @@ btr_cur_pessimistic_update( new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update, - heap); + FALSE, heap); if (!(flags & BTR_KEEP_SYS_FLAG)) { row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR, roll_ptr); @@ -1915,13 +1915,13 @@ btr_cur_pessimistic_update( ut_a(rec || optim_err != DB_UNDERFLOW); if (rec) { - offsets = rec_get_offsets(rec, index, offsets, - ULINT_UNDEFINED, &heap); - lock_rec_restore_from_page_infimum(rec, page); rec_set_field_extern_bits(rec, index, ext_vect, n_ext_vect, mtr); + offsets = rec_get_offsets(rec, index, offsets, + ULINT_UNDEFINED, &heap); + if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) { /* The new inserted record owns its possible externally stored fields */ @@ -2371,8 +2371,7 @@ btr_cur_compress( ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(btr_cur_get_tree(cursor)), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, buf_block_align( - btr_cur_get_page(cursor)), + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), MTR_MEMO_PAGE_X_FIX)); ut_ad(btr_page_get_level(btr_cur_get_page(cursor), mtr) == 0); @@ -2398,8 +2397,7 @@ btr_cur_compress_if_useful( ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(btr_cur_get_tree(cursor)), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, buf_block_align( - btr_cur_get_page(cursor)), + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), MTR_MEMO_PAGE_X_FIX)); if (btr_cur_compress_recommendation(cursor, mtr)) { @@ -2437,7 +2435,7 @@ btr_cur_optimistic_delete( ibool no_compress_needed; *offsets_ = (sizeof offsets_) / sizeof *offsets_; - ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_page(cursor)), + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), MTR_MEMO_PAGE_X_FIX)); /* This is intended only for leaf page deletions */ @@ -3330,7 +3328,10 @@ btr_store_big_rec_extern_fields( dict_index_t* index, /* in: index of rec; the index tree MUST be X-latched */ rec_t* rec, /* in: record */ - const ulint* offsets, /* in: rec_get_offsets(rec, index) */ + const ulint* offsets, /* in: rec_get_offsets(rec, index); + the "external storage" flags in offsets + will not correspond to rec when + this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ mtr_t* local_mtr __attribute__((unused))) /* in: mtr diff --git a/storage/innobase/btr/btr0pcur.c b/storage/innobase/btr/btr0pcur.c index e3ba50a2d5b..85a6577bafb 100644 --- a/storage/innobase/btr/btr0pcur.c +++ b/storage/innobase/btr/btr0pcur.c @@ -259,10 +259,7 @@ btr_pcur_restore_position( cursor->latch_mode = latch_mode; #ifdef UNIV_DEBUG rec = btr_pcur_get_rec(cursor); - index = dict_tree_find_index( - btr_cur_get_tree( - btr_pcur_get_btr_cur(cursor)), - rec); + index = btr_pcur_get_btr_cur(cursor)->index; heap = mem_heap_create(256); offsets1 = rec_get_offsets(cursor->old_rec, diff --git a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c index 428b4d9a6b7..be7bb7c421f 100644 --- a/storage/innobase/btr/btr0sea.c +++ b/storage/innobase/btr/btr0sea.c @@ -24,8 +24,8 @@ ulint btr_search_this_is_zero = 0; /* A dummy variable to fool the #ifdef UNIV_SEARCH_PERF_STAT ulint btr_search_n_succ = 0; -#endif /* UNIV_SEARCH_PERF_STAT */ ulint btr_search_n_hash_fail = 0; +#endif /* UNIV_SEARCH_PERF_STAT */ byte btr_sea_pad1[64]; /* padding to prevent other memory update hotspots from residing on the same memory @@ -59,9 +59,6 @@ before hash index building is started */ #define BTR_SEARCH_BUILD_LIMIT 100 -/* How many cells to check before temporarily releasing btr_search_latch */ -#define BTR_CHUNK_SIZE 10000 - /************************************************************************ Builds a hash index on a page with the given parameters. If the page already has a hash index with different parameters, the old hash index is removed. @@ -172,10 +169,12 @@ btr_search_info_create( info->last_hash_succ = FALSE; +#ifdef UNIV_SEARCH_PERF_STAT info->n_hash_succ = 0; info->n_hash_fail = 0; info->n_patt_succ = 0; info->n_searches = 0; +#endif /* UNIV_SEARCH_PERF_STAT */ /* Set some sensible values */ info->n_fields = 1; @@ -487,7 +486,9 @@ btr_search_info_update_slow( if (cursor->flag == BTR_CUR_HASH_FAIL) { /* Update the hash node reference, if appropriate */ +#ifdef UNIV_SEARCH_PERF_STAT btr_search_n_hash_fail++; +#endif /* UNIV_SEARCH_PERF_STAT */ rw_lock_x_lock(&btr_search_latch); @@ -872,11 +873,11 @@ failure_unlock: rw_lock_s_unlock(&btr_search_latch); } failure: - info->n_hash_fail++; - cursor->flag = BTR_CUR_HASH_FAIL; #ifdef UNIV_SEARCH_PERF_STAT + info->n_hash_fail++; + if (info->n_hash_succ > 0) { info->n_hash_succ--; } @@ -1607,21 +1608,26 @@ btr_search_validate(void) mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; + + /* How many cells to check before temporarily releasing + btr_search_latch. */ + ulint chunk_size = 10000; + *offsets_ = (sizeof offsets_) / sizeof *offsets_; rw_lock_x_lock(&btr_search_latch); cell_count = hash_get_n_cells(btr_search_sys->hash_index); - + for (i = 0; i < cell_count; i++) { /* We release btr_search_latch every once in a while to give other queries a chance to run. */ - if ((i != 0) && ((i % BTR_CHUNK_SIZE) == 0)) { + if ((i != 0) && ((i % chunk_size) == 0)) { rw_lock_x_unlock(&btr_search_latch); os_thread_yield(); rw_lock_x_lock(&btr_search_latch); } - + node = hash_get_nth_cell(btr_search_sys->hash_index, i)->node; while (node != NULL) { @@ -1675,9 +1681,9 @@ btr_search_validate(void) } } - for (i = 0; i < cell_count; i += BTR_CHUNK_SIZE) { - ulint end_index = ut_min(i + BTR_CHUNK_SIZE - 1, cell_count - 1); - + for (i = 0; i < cell_count; i += chunk_size) { + ulint end_index = ut_min(i + chunk_size - 1, cell_count - 1); + /* We release btr_search_latch every once in a while to give other queries a chance to run. */ if (i != 0) { diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index 3b6c47a21e9..08be5811a4b 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -294,14 +294,14 @@ buf_LRU_try_free_flushed_blocks(void) } /********************************************************************** -Returns TRUE if less than 15 % of the buffer pool is available. This can be +Returns TRUE if less than 25 % of the buffer pool is available. This can be used in heuristics to prevent huge transactions eating up the whole buffer pool for their locks. */ ibool buf_LRU_buf_pool_running_out(void) /*==============================*/ - /* out: TRUE if less than 15 % of buffer pool + /* out: TRUE if less than 25 % of buffer pool left */ { ibool ret = FALSE; @@ -309,7 +309,7 @@ buf_LRU_buf_pool_running_out(void) mutex_enter(&(buf_pool->mutex)); if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) - + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 7) { + + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 4) { ret = TRUE; } @@ -340,11 +340,11 @@ loop: mutex_enter(&(buf_pool->mutex)); if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) - + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 10) { + + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 20) { ut_print_timestamp(stderr); fprintf(stderr, -" InnoDB: ERROR: over 9 / 10 of the buffer pool is occupied by\n" +" InnoDB: ERROR: over 95 percent of the buffer pool is occupied by\n" "InnoDB: lock heaps or the adaptive hash index! Check that your\n" "InnoDB: transactions do not set too many row locks.\n" "InnoDB: Your buffer pool size is %lu MB. Maybe you should make\n" @@ -356,17 +356,17 @@ loop: ut_error; } else if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) - + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 5) { + + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 3) { if (!buf_lru_switched_on_innodb_mon) { - /* Over 80 % of the buffer pool is occupied by lock + /* Over 67 % of the buffer pool is occupied by lock heaps or the adaptive hash index. This may be a memory leak! */ ut_print_timestamp(stderr); fprintf(stderr, -" InnoDB: WARNING: over 4 / 5 of the buffer pool is occupied by\n" +" InnoDB: WARNING: over 67 percent of the buffer pool is occupied by\n" "InnoDB: lock heaps or the adaptive hash index! Check that your\n" "InnoDB: transactions do not set too many row locks.\n" "InnoDB: Your buffer pool size is %lu MB. Maybe you should make\n" @@ -881,10 +881,10 @@ buf_LRU_block_remove_hashed_page( if (buf_page_hash_get(block->space, block->offset)) { fprintf(stderr, "InnoDB: From hash table we find block %p of %lu %lu which is not %p\n", - buf_page_hash_get(block->space, block->offset), + (void*) buf_page_hash_get(block->space, block->offset), (ulong) buf_page_hash_get(block->space, block->offset)->space, (ulong) buf_page_hash_get(block->space, block->offset)->offset, - block); + (void*) block); } #ifdef UNIV_DEBUG diff --git a/storage/innobase/cmakelists.txt b/storage/innobase/cmakelists.txt index de46430e2ab..def51873725 100644 --- a/storage/innobase/cmakelists.txt +++ b/storage/innobase/cmakelists.txt @@ -32,4 +32,4 @@ ADD_LIBRARY(innobase btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c thr/thr0loc.c trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c usr/usr0sess.c - ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c) + ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c) diff --git a/storage/innobase/configure.in b/storage/innobase/configure.in index e0521471c2f..91afcc1c9b3 100644 --- a/storage/innobase/configure.in +++ b/storage/innobase/configure.in @@ -89,6 +89,25 @@ else CXXFLAGS="$OPTIMIZE_CXXFLAGS -DDBUG_OFF $CXXFLAGS -DDEBUG_OFF" fi +# NOTE: The flags below are disabled by default since we can't easily get +# rid of the "string over 509 characters in length" warnings, and thus can't +# add -Werror. But it's a good idea to enable these for a test compile +# before shipping a new snapshot to MySQL to catch errors that could make +# the compile fail on non-C99 compilers. + +# If using gcc, disallow usage of C99 features to avoid accidentally +# introducing problems on compilers that only implement C89. +#if test "$ac_cv_prog_gcc" = "yes" +#then +# CFLAGS="$CFLAGS -std=c89 -ansi -pedantic -Wno-long-long" +#fi + +# If using gcc, add some extra warning flags. +if test "$ac_cv_prog_gcc" = "yes" +then + CFLAGS="$CFLAGS -Werror-implicit-function-declaration" +fi + case "$target_os" in lin*) CFLAGS="$CFLAGS -DUNIV_LINUX";; diff --git a/storage/innobase/data/data0type.c b/storage/innobase/data/data0type.c index 3ac1139d952..2f36e7250fc 100644 --- a/storage/innobase/data/data0type.c +++ b/storage/innobase/data/data0type.c @@ -216,20 +216,43 @@ dtype_print( mtype = type->mtype; prtype = type->prtype; - if (mtype == DATA_VARCHAR) { + + switch (mtype) { + case DATA_VARCHAR: fputs("DATA_VARCHAR", stderr); - } else if (mtype == DATA_CHAR) { + break; + + case DATA_CHAR: fputs("DATA_CHAR", stderr); - } else if (mtype == DATA_BINARY) { + break; + + case DATA_BINARY: fputs("DATA_BINARY", stderr); - } else if (mtype == DATA_INT) { + break; + + case DATA_FIXBINARY: + fputs("DATA_FIXBINARY", stderr); + break; + + case DATA_BLOB: + fputs("DATA_BLOB", stderr); + break; + + case DATA_INT: fputs("DATA_INT", stderr); - } else if (mtype == DATA_MYSQL) { + break; + + case DATA_MYSQL: fputs("DATA_MYSQL", stderr); - } else if (mtype == DATA_SYS) { + break; + + case DATA_SYS: fputs("DATA_SYS", stderr); - } else { + break; + + default: fprintf(stderr, "type %lu", (ulong) mtype); + break; } len = type->len; @@ -254,6 +277,18 @@ dtype_print( } else { fprintf(stderr, "prtype %lu", (ulong) prtype); } + } else { + if (prtype & DATA_UNSIGNED) { + fputs(" DATA_UNSIGNED", stderr); + } + + if (prtype & DATA_BINARY_TYPE) { + fputs(" DATA_BINARY_TYPE", stderr); + } + + if (prtype & DATA_NOT_NULL) { + fputs(" DATA_NOT_NULL", stderr); + } } fprintf(stderr, " len %lu prec %lu", (ulong) len, (ulong) type->prec); diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 6f0a81296ac..4233cb05773 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -24,6 +24,7 @@ Created 1/8/1996 Heikki Tuuri #include "pars0pars.h" #include "trx0roll.h" #include "usr0sess.h" +#include "ut0vec.h" /********************************************************************* Based on a table object, this function builds the entry to be inserted @@ -74,14 +75,14 @@ dict_create_sys_tables_tuple( dfield = dtuple_get_nth_field(entry, 3); ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, table->type); + mach_write_to_4(ptr, DICT_TABLE_ORDINARY); dfield_set_data(dfield, ptr, 4); /* 6: MIX_ID ---------------------------*/ dfield = dtuple_get_nth_field(entry, 4); ptr = mem_heap_alloc(heap, 8); - mach_write_to_8(ptr, table->mix_id); + memset(ptr, 0, 8); dfield_set_data(dfield, ptr, 8); /* 7: MIX_LEN --------------------------*/ @@ -89,19 +90,13 @@ dict_create_sys_tables_tuple( dfield = dtuple_get_nth_field(entry, 5); ptr = mem_heap_alloc(heap, 4); - mach_write_to_4(ptr, table->mix_len); + memset(ptr, 0, 4); dfield_set_data(dfield, ptr, 4); /* 8: CLUSTER_NAME ---------------------*/ dfield = dtuple_get_nth_field(entry, 6); + dfield_set_data(dfield, NULL, UNIV_SQL_NULL); /* not supported */ - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - dfield_set_data(dfield, table->cluster_name, - ut_strlen(table->cluster_name)); - ut_error; /* Oracle-style clusters are not supported yet */ - } else { - dfield_set_data(dfield, NULL, UNIV_SQL_NULL); - } /* 9: SPACE ----------------------------*/ dfield = dtuple_get_nth_field(entry, 7); @@ -207,7 +202,6 @@ dict_build_table_def_step( tab_node_t* node) /* in: table create node */ { dict_table_t* table; - dict_table_t* cluster_table; dtuple_t* row; ulint error; const char* path_or_name; @@ -235,23 +229,6 @@ dict_build_table_def_step( return(DB_TOO_BIG_RECORD); } - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - - cluster_table = dict_table_get_low(table->cluster_name); - - if (cluster_table == NULL) { - - return(DB_CLUSTER_NOT_FOUND); - } - - /* Inherit space and mix len from the cluster */ - - table->space = cluster_table->space; - table->mix_len = cluster_table->mix_len; - - table->mix_id = dict_hdr_get_new_id(DICT_HDR_MIX_ID); - } - if (srv_file_per_table) { /* We create a new single-table tablespace for the table. We initially let it be 4 pages: @@ -614,15 +591,6 @@ dict_create_index_tree_step( sys_indexes = dict_sys->sys_indexes; - if (index->type & DICT_CLUSTERED - && table->type == DICT_TABLE_CLUSTER_MEMBER) { - - /* Do not create a new index tree: entries are put to the - cluster tree */ - - return(DB_SUCCESS); - } - /* Run a mini-transaction in which the index tree is allocated for the index and its root address is written to the index entry in sys_indexes */ @@ -1159,11 +1127,8 @@ dict_create_or_check_foreign_constraint_tables(void) { dict_table_t* table1; dict_table_t* table2; - que_thr_t* thr; - que_t* graph; ulint error; trx_t* trx; - const char* str; mutex_enter(&(dict_sys->mutex)); @@ -1215,7 +1180,7 @@ dict_create_or_check_foreign_constraint_tables(void) VARBINARY, like in other InnoDB system tables, to get a clean design. */ - str = + error = que_eval_sql(NULL, "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n" "BEGIN\n" "CREATE TABLE\n" @@ -1227,22 +1192,8 @@ dict_create_or_check_foreign_constraint_tables(void) "SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n" "CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS);\n" "COMMIT WORK;\n" - "END;\n"; - - graph = pars_sql(str); - - ut_a(graph); - - graph->trx = trx; - trx->graph = NULL; - - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - - ut_a(thr = que_fork_start_command(graph)); - - que_run_threads(thr); - - error = trx->error_state; + "END;\n" + , trx); if (error != DB_SUCCESS) { fprintf(stderr, "InnoDB: error %lu in creation\n", @@ -1261,8 +1212,6 @@ dict_create_or_check_foreign_constraint_tables(void) error = DB_MUST_GET_MORE_FILE_SPACE; } - que_graph_free(graph); - trx->op_info = ""; row_mysql_unlock_data_dictionary(trx); @@ -1277,150 +1226,23 @@ dict_create_or_check_foreign_constraint_tables(void) return(error); } -/************************************************************************ -Adds foreign key definitions to data dictionary tables in the database. We -look at table->foreign_list, and also generate names to constraints that were -not named by the user. A generated constraint has a name of the format -databasename/tablename_ibfk_, where the numbers start from 1, and are -given locally for this table, that is, the number is not global, as in the -old format constraints < 4.0.18 it used to be. */ +/******************************************************************** +Evaluate the given foreign key SQL statement. */ ulint -dict_create_add_foreigns_to_dictionary( -/*===================================*/ +dict_foreign_eval_sql( +/*==================*/ /* out: error code or DB_SUCCESS */ - ulint start_id,/* in: if we are actually doing ALTER TABLE - ADD CONSTRAINT, we want to generate constraint - numbers which are bigger than in the table so - far; we number the constraints from - start_id + 1 up; start_id should be set to 0 if - we are creating a new table, or if the table - so far has no constraints for which the name - was generated here */ + pars_info_t* info, /* in: info struct, or NULL */ + const char* sql, /* in: SQL string to evaluate */ dict_table_t* table, /* in: table */ + dict_foreign_t* foreign,/* in: foreign */ trx_t* trx) /* in: transaction */ { - dict_foreign_t* foreign; - que_thr_t* thr; - que_t* graph; - ulint number = start_id + 1; - ulint len; ulint error; FILE* ef = dict_foreign_err_file; - ulint i; - char* sql; - char* sqlend; - /* This procedure builds an InnoDB stored procedure which will insert - the necessary rows into SYS_FOREIGN and SYS_FOREIGN_COLS. */ - static const char str1[] = "PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n" - "BEGIN\n" - "INSERT INTO SYS_FOREIGN VALUES("; - static const char str2[] = ");\n"; - static const char str3[] = - "INSERT INTO SYS_FOREIGN_COLS VALUES("; - static const char str4[] = - "COMMIT WORK;\n" - "END;\n"; -#ifdef UNIV_SYNC_DEBUG - ut_ad(mutex_own(&(dict_sys->mutex))); -#endif /* UNIV_SYNC_DEBUG */ - - if (NULL == dict_table_get_low("SYS_FOREIGN")) { - fprintf(stderr, -"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n"); - - return(DB_ERROR); - } - - foreign = UT_LIST_GET_FIRST(table->foreign_list); -loop: - if (foreign == NULL) { - - return(DB_SUCCESS); - } - - if (foreign->id == NULL) { - /* Generate a new constraint id */ - ulint namelen = strlen(table->name); - char* id = mem_heap_alloc(foreign->heap, namelen + 20); - /* no overflow if number < 1e13 */ - sprintf(id, "%s_ibfk_%lu", table->name, (ulong) number++); - foreign->id = id; - } - - len = (sizeof str1) + (sizeof str2) + (sizeof str4) - 3 - + 9/* ' and , chars */ + 10/* 32-bit integer */ - + ut_strlenq(foreign->id, '\'') * (foreign->n_fields + 1) - + ut_strlenq(table->name, '\'') - + ut_strlenq(foreign->referenced_table_name, '\''); - - for (i = 0; i < foreign->n_fields; i++) { - len += 9/* ' and , chars */ + 10/* 32-bit integer */ - + (sizeof str3) + (sizeof str2) - 2 - + ut_strlenq(foreign->foreign_col_names[i], '\'') - + ut_strlenq(foreign->referenced_col_names[i], '\''); - } - - sql = sqlend = mem_alloc(len + 1); - - /* INSERT INTO SYS_FOREIGN VALUES(...); */ - memcpy(sqlend, str1, (sizeof str1) - 1); - sqlend += (sizeof str1) - 1; - *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', foreign->id); - *sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', table->name); - *sqlend++ = '\'', *sqlend++ = ',', *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', foreign->referenced_table_name); - *sqlend++ = '\'', *sqlend++ = ','; - sqlend += sprintf(sqlend, "%010lu", - foreign->n_fields + (foreign->type << 24)); - memcpy(sqlend, str2, (sizeof str2) - 1); - sqlend += (sizeof str2) - 1; - - for (i = 0; i < foreign->n_fields; i++) { - /* INSERT INTO SYS_FOREIGN_COLS VALUES(...); */ - memcpy(sqlend, str3, (sizeof str3) - 1); - sqlend += (sizeof str3) - 1; - *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', foreign->id); - *sqlend++ = '\''; *sqlend++ = ','; - sqlend += sprintf(sqlend, "%010lu", (ulong) i); - *sqlend++ = ','; *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', - foreign->foreign_col_names[i]); - *sqlend++ = '\''; *sqlend++ = ','; *sqlend++ = '\''; - sqlend = ut_strcpyq(sqlend, '\'', - foreign->referenced_col_names[i]); - *sqlend++ = '\''; - memcpy(sqlend, str2, (sizeof str2) - 1); - sqlend += (sizeof str2) - 1; - } - - memcpy(sqlend, str4, sizeof str4); - sqlend += sizeof str4; - - ut_a(sqlend == sql + len + 1); - - graph = pars_sql(sql); - - ut_a(graph); - - mem_free(sql); - - graph->trx = trx; - trx->graph = NULL; - - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - - ut_a(thr = que_fork_start_command(graph)); - - que_run_threads(thr); - - error = trx->error_state; - - que_graph_free(graph); + error = que_eval_sql(info, sql, trx); if (error == DB_DUPLICATE_KEY) { mutex_enter(&dict_foreign_err_mutex); @@ -1466,7 +1288,163 @@ loop: return(error); } - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - - goto loop; + return(DB_SUCCESS); +} + +/************************************************************************ +Add a single foreign key field definition to the data dictionary tables in +the database. */ +static +ulint +dict_create_add_foreign_field_to_dictionary( +/*========================================*/ + /* out: error code or DB_SUCCESS */ + ulint field_nr, /* in: foreign field number */ + dict_table_t* table, /* in: table */ + dict_foreign_t* foreign, /* in: foreign */ + trx_t* trx) /* in: transaction */ +{ + pars_info_t* info = pars_info_create(); + + pars_info_add_str_literal(info, "id", foreign->id); + + pars_info_add_int4_literal(info, "pos", field_nr); + + pars_info_add_str_literal(info, "for_col_name", + foreign->foreign_col_names[field_nr]); + + pars_info_add_str_literal(info, "ref_col_name", + foreign->referenced_col_names[field_nr]); + + return dict_foreign_eval_sql(info, + "PROCEDURE P () IS\n" + "BEGIN\n" + "INSERT INTO SYS_FOREIGN_COLS VALUES" + "(:id, :pos, :for_col_name, :ref_col_name);\n" + "END;\n" + , table, foreign, trx); +} + +/************************************************************************ +Add a single foreign key definition to the data dictionary tables in the +database. We also generate names to constraints that were not named by the +user. A generated constraint has a name of the format +databasename/tablename_ibfk_, where the numbers start from 1, and +are given locally for this table, that is, the number is not global, as in +the old format constraints < 4.0.18 it used to be. */ +static +ulint +dict_create_add_foreign_to_dictionary( +/*==================================*/ + /* out: error code or DB_SUCCESS */ + ulint* id_nr, /* in/out: number to use in id generation; + incremented if used */ + dict_table_t* table, /* in: table */ + dict_foreign_t* foreign,/* in: foreign */ + trx_t* trx) /* in: transaction */ +{ + ulint error; + ulint i; + + pars_info_t* info = pars_info_create(); + + if (foreign->id == NULL) { + /* Generate a new constraint id */ + ulint namelen = strlen(table->name); + char* id = mem_heap_alloc(foreign->heap, namelen + 20); + /* no overflow if number < 1e13 */ + sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++); + foreign->id = id; + } + + pars_info_add_str_literal(info, "id", foreign->id); + + pars_info_add_str_literal(info, "for_name", table->name); + + pars_info_add_str_literal(info, "ref_name", + foreign->referenced_table_name); + + pars_info_add_int4_literal(info, "n_cols", + foreign->n_fields + (foreign->type << 24)); + + error = dict_foreign_eval_sql(info, + "PROCEDURE P () IS\n" + "BEGIN\n" + "INSERT INTO SYS_FOREIGN VALUES" + "(:id, :for_name, :ref_name, :n_cols);\n" + "END;\n" + , table, foreign, trx); + + if (error != DB_SUCCESS) { + + return(error); + } + + for (i = 0; i < foreign->n_fields; i++) { + error = dict_create_add_foreign_field_to_dictionary(i, + table, foreign, trx); + + if (error != DB_SUCCESS) { + + return(error); + } + } + + error = dict_foreign_eval_sql(NULL, + "PROCEDURE P () IS\n" + "BEGIN\n" + "COMMIT WORK;\n" + "END;\n" + , table, foreign, trx); + + return(error); +} + +/************************************************************************ +Adds foreign key definitions to data dictionary tables in the database. */ + +ulint +dict_create_add_foreigns_to_dictionary( +/*===================================*/ + /* out: error code or DB_SUCCESS */ + ulint start_id,/* in: if we are actually doing ALTER TABLE + ADD CONSTRAINT, we want to generate constraint + numbers which are bigger than in the table so + far; we number the constraints from + start_id + 1 up; start_id should be set to 0 if + we are creating a new table, or if the table + so far has no constraints for which the name + was generated here */ + dict_table_t* table, /* in: table */ + trx_t* trx) /* in: transaction */ +{ + dict_foreign_t* foreign; + ulint number = start_id + 1; + ulint error; + +#ifdef UNIV_SYNC_DEBUG + ut_ad(mutex_own(&(dict_sys->mutex))); +#endif /* UNIV_SYNC_DEBUG */ + + if (NULL == dict_table_get_low("SYS_FOREIGN")) { + fprintf(stderr, +"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n"); + + return(DB_ERROR); + } + + for (foreign = UT_LIST_GET_FIRST(table->foreign_list); + foreign; + foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) { + + error = dict_create_add_foreign_to_dictionary(&number, + table, foreign, trx); + + if (error != DB_SUCCESS) { + + return(error); + } + } + + return(DB_SUCCESS); } diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 1fac5e26fa9..877d4afe8f0 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -657,6 +657,19 @@ dict_table_get_nth_col_pos( n)); } +/************************************************************************ +Check whether the table uses the compact page format. */ + +ibool +dict_table_is_comp_noninline( +/*=========================*/ + /* out: TRUE if table uses the + compact page format */ + const dict_table_t* table) /* in: table */ +{ + return(dict_table_is_comp(table)); +} + /************************************************************************ Checks if a column is in the ordering columns of the clustered index of a table. Column prefixes are treated like whole columns. */ @@ -870,13 +883,6 @@ dict_table_add_to_cache( ut_a(table2 == NULL); } - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - - table->mix_id_len = mach_dulint_get_compressed_size( - table->mix_id); - mach_dulint_write_compressed(table->mix_id_buf, table->mix_id); - } - /* Add the columns to the column hash table */ for (i = 0; i < table->n_cols; i++) { dict_col_add_to_cache(table, dict_table_get_nth_col(table, i)); @@ -1251,15 +1257,13 @@ dict_table_remove_from_cache( /* Remove table from LRU list of tables */ UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table); - mutex_free(&(table->autoinc_mutex)); - size = mem_heap_get_size(table->heap); ut_ad(dict_sys->size >= size); dict_sys->size -= size; - mem_heap_free(table->heap); + dict_mem_table_free(table); } /************************************************************************** @@ -1380,6 +1384,38 @@ dict_col_reposition_in_cache( HASH_INSERT(dict_col_t, hash, dict_sys->col_hash, fold, col); } +/******************************************************************** +If the given column name is reserved for InnoDB system columns, return +TRUE. */ + +ibool +dict_col_name_is_reserved( +/*======================*/ + /* out: TRUE if name is reserved */ + const char* name) /* in: column name */ +{ + /* This check reminds that if a new system column is added to + the program, it should be dealt with here. */ +#if DATA_N_SYS_COLS != 4 +#error "DATA_N_SYS_COLS != 4" +#endif + + static const char* reserved_names[] = { + "DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR", "DB_MIX_ID" + }; + + ulint i; + + for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) { + if (strcmp(name, reserved_names[i]) == 0) { + + return(TRUE); + } + } + + return(FALSE); +} + /************************************************************************** Adds an index to the dictionary cache. */ @@ -1394,7 +1430,6 @@ dict_index_add_to_cache( { dict_index_t* new_index; dict_tree_t* tree; - dict_table_t* cluster; dict_field_t* field; ulint n_ord; ibool success; @@ -1468,21 +1503,11 @@ dict_index_add_to_cache( dict_field_get_col(field)->ord_part++; } - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - /* The index tree is found from the cluster object */ + /* Create an index tree memory object for the index */ + tree = dict_tree_create(new_index, page_no); + ut_ad(tree); - cluster = dict_table_get_low(table->cluster_name); - - tree = dict_index_get_tree( - UT_LIST_GET_FIRST(cluster->indexes)); - new_index->tree = tree; - } else { - /* Create an index tree memory object for the index */ - tree = dict_tree_create(new_index, page_no); - ut_ad(tree); - - new_index->tree = tree; - } + new_index->tree = tree; if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) { @@ -1500,7 +1525,7 @@ dict_index_add_to_cache( } /* Add the index to the list of indexes stored in the tree */ - UT_LIST_ADD_LAST(tree_indexes, tree->tree_indexes, new_index); + tree->tree_index = new_index; /* If the dictionary cache grows too big, trim the table LRU list */ @@ -1532,7 +1557,7 @@ dict_index_remove_from_cache( ut_ad(mutex_own(&(dict_sys->mutex))); #endif /* UNIV_SYNC_DEBUG */ - ut_ad(UT_LIST_GET_LEN((index->tree)->tree_indexes) == 1); + ut_ad(index->tree->tree_index); dict_tree_free(index->tree); /* Decrement the ord_part counts in columns which are ordering */ @@ -1553,7 +1578,7 @@ dict_index_remove_from_cache( dict_sys->size -= size; - mem_heap_free(index->heap); + dict_mem_index_free(index); } /*********************************************************************** @@ -1699,8 +1724,6 @@ dict_table_copy_types( dtype_t* type; ulint i; - ut_ad(!(table->type & DICT_UNIVERSAL)); - for (i = 0; i < dtuple_get_n_fields(tuple); i++) { dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i)); @@ -1749,22 +1772,8 @@ dict_index_build_internal_clust( new_index->id = index->id; - if (table->type != DICT_TABLE_ORDINARY) { - /* The index is mixed: copy common key prefix fields */ - - dict_index_copy(new_index, index, 0, table->mix_len); - - /* Add the mix id column */ - dict_index_add_col(new_index, - dict_table_get_sys_col(table, DATA_MIX_ID), 0); - - /* Copy the rest of fields */ - dict_index_copy(new_index, index, table->mix_len, - index->n_fields); - } else { - /* Copy the fields of index */ - dict_index_copy(new_index, index, 0, index->n_fields); - } + /* Copy the fields of index */ + dict_index_copy(new_index, index, 0, index->n_fields); if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) { /* No fixed number of fields determines an entry uniquely */ @@ -3641,7 +3650,7 @@ dict_tree_create( tree->id = index->id; - UT_LIST_INIT(tree->tree_indexes); + tree->tree_index = NULL; tree->magic_n = DICT_TREE_MAGIC_N; @@ -3667,135 +3676,7 @@ dict_tree_free( mem_free(tree); } -/************************************************************************** -In an index tree, finds the index corresponding to a record in the tree. */ -UNIV_INLINE -dict_index_t* -dict_tree_find_index_low( -/*=====================*/ - /* out: index */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec) /* in: record for which to find correct - index */ -{ - dict_index_t* index; - dict_table_t* table; - dulint mix_id; - ulint len; - - index = UT_LIST_GET_FIRST(tree->tree_indexes); - ut_ad(index); - table = index->table; - - if ((index->type & DICT_CLUSTERED) - && UNIV_UNLIKELY(table->type != DICT_TABLE_ORDINARY)) { - - /* Get the mix id of the record */ - ut_a(!dict_table_is_comp(table)); - - mix_id = mach_dulint_read_compressed( - rec_get_nth_field_old(rec, table->mix_len, &len)); - - while (ut_dulint_cmp(table->mix_id, mix_id) != 0) { - - index = UT_LIST_GET_NEXT(tree_indexes, index); - table = index->table; - ut_ad(index); - } - } - - return(index); -} - -/************************************************************************** -In an index tree, finds the index corresponding to a record in the tree. */ - -dict_index_t* -dict_tree_find_index( -/*=================*/ - /* out: index */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec) /* in: record for which to find correct - index */ -{ - dict_index_t* index; - - index = dict_tree_find_index_low(tree, rec); - - return(index); -} - -/************************************************************************** -In an index tree, finds the index corresponding to a dtuple which is used -in a search to a tree. */ - -dict_index_t* -dict_tree_find_index_for_tuple( -/*===========================*/ - /* out: index; NULL if the tuple does not - contain the mix id field in a mixed tree */ - dict_tree_t* tree, /* in: index tree */ - dtuple_t* tuple) /* in: tuple for which to find index */ -{ - dict_index_t* index; - dict_table_t* table; - dulint mix_id; - - ut_ad(dtuple_check_typed(tuple)); - - if (UT_LIST_GET_LEN(tree->tree_indexes) == 1) { - - return(UT_LIST_GET_FIRST(tree->tree_indexes)); - } - - index = UT_LIST_GET_FIRST(tree->tree_indexes); - ut_ad(index); - table = index->table; - - if (dtuple_get_n_fields(tuple) <= table->mix_len) { - - return(NULL); - } - - /* Get the mix id of the record */ - - mix_id = mach_dulint_read_compressed( - dfield_get_data( - dtuple_get_nth_field(tuple, table->mix_len))); - - while (ut_dulint_cmp(table->mix_id, mix_id) != 0) { - - index = UT_LIST_GET_NEXT(tree_indexes, index); - table = index->table; - ut_ad(index); - } - - return(index); -} - -/*********************************************************************** -Checks if a table which is a mixed cluster member owns a record. */ - -ibool -dict_is_mixed_table_rec( -/*====================*/ - /* out: TRUE if the record belongs to this - table */ - dict_table_t* table, /* in: table in a mixed cluster */ - rec_t* rec) /* in: user record in the clustered index */ -{ - byte* mix_id_field; - ulint len; - - ut_ad(!dict_table_is_comp(table)); - - mix_id_field = rec_get_nth_field_old(rec, - table->mix_len, &len); - - return(len == table->mix_id_len - && !ut_memcmp(table->mix_id_buf, mix_id_field, len)); -} - +#ifdef UNIV_DEBUG /************************************************************************** Checks that a tuple has n_fields_cmp value in a sensible range, so that no comparison can occur with the page number field in a node pointer. */ @@ -3807,19 +3688,14 @@ dict_tree_check_search_tuple( dict_tree_t* tree, /* in: index tree */ dtuple_t* tuple) /* in: tuple used in a search */ { - dict_index_t* index; - - index = dict_tree_find_index_for_tuple(tree, tuple); - - if (index == NULL) { - - return(TRUE); - } + dict_index_t* index = tree->tree_index; + ut_a(index); ut_a(dtuple_get_n_fields_cmp(tuple) <= dict_index_get_n_unique_in_tree(index)); return(TRUE); } +#endif /* UNIV_DEBUG */ /************************************************************************** Builds a node pointer out of a physical record and a page number. */ @@ -3842,7 +3718,7 @@ dict_tree_build_node_ptr( byte* buf; ulint n_unique; - ind = dict_tree_find_index_low(tree, rec); + ind = tree->tree_index; if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) { /* In a universal index tree, we take the whole record as @@ -3910,7 +3786,7 @@ dict_tree_copy_rec_order_prefix( ulint n; UNIV_PREFETCH_R(rec); - index = dict_tree_find_index_low(tree, rec); + index = tree->tree_index; if (UNIV_UNLIKELY(tree->type & DICT_UNIVERSAL)) { ut_a(!dict_table_is_comp(index->table)); @@ -3938,7 +3814,7 @@ dict_tree_build_data_tuple( dtuple_t* tuple; dict_index_t* ind; - ind = dict_tree_find_index_low(tree, rec); + ind = tree->tree_index; ut_ad(dict_table_is_comp(ind->table) || n_fields <= rec_get_n_fields_old(rec)); @@ -4096,6 +3972,18 @@ dict_update_statistics( dict_update_statistics_low(table, FALSE); } +/************************************************************************** +A noninlined version of dict_table_get_low. */ + +dict_table_t* +dict_table_get_low_noninlined( +/*==========================*/ + /* out: table, NULL if not found */ + const char* table_name) /* in: table name */ +{ + return(dict_table_get_low(table_name)); +} + /************************************************************************** Prints info of a foreign key constraint. */ static @@ -4520,15 +4408,3 @@ dict_index_name_print( fputs(" of table ", file); ut_print_name(file, trx, index->table_name); } - -/************************************************************************ -Export an inlined function for use in ha_innodb.c. */ -ibool -innodb_dict_table_is_comp( -/*===============*/ - /* out: TRUE if table uses the - compact page format */ - const dict_table_t* table) /* in: table */ -{ - return dict_table_is_comp(table); -} diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 09935c03288..4779e50f176 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -768,7 +768,7 @@ dict_load_table( if (!btr_pcur_is_on_user_rec(&pcur, &mtr) || rec_get_deleted_flag(rec, 0)) { /* Not found */ - + err_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); mem_heap_free(heap); @@ -780,11 +780,8 @@ dict_load_table( /* Check if the table name in record is the searched one */ if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) { - btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); - return(NULL); + goto err_exit; } ut_a(0 == ut_strcmp("SPACE", @@ -848,36 +845,17 @@ dict_load_table( table->id = mach_read_from_8(field); field = rec_get_nth_field_old(rec, 5, &len); - table->type = mach_read_from_4(field); - - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - ut_error; -#if 0 /* clustered tables have not been implemented yet */ - field = rec_get_nth_field_old(rec, 6, &len); - table->mix_id = mach_read_from_8(field); - - field = rec_get_nth_field_old(rec, 8, &len); - table->cluster_name = mem_heap_strdupl(heap, (char*) field, len); -#endif - } - - if ((table->type == DICT_TABLE_CLUSTER) - || (table->type == DICT_TABLE_CLUSTER_MEMBER)) { - - field = rec_get_nth_field_old(rec, 7, &len); - ut_a(len == 4); - table->mix_len = mach_read_from_4(field); + if (UNIV_UNLIKELY(mach_read_from_4(field) != DICT_TABLE_ORDINARY)) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: table %s: unknown table type %lu\n", + name, (ulong) mach_read_from_4(field)); + goto err_exit; } btr_pcur_close(&pcur); mtr_commit(&mtr); - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - /* Load the cluster table definition if not yet in - memory cache */ - dict_table_get_low(table->cluster_name); - } - dict_load_columns(table, heap); dict_table_add_to_cache(table); diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c index d9f0ad3d84e..fe21890adc8 100644 --- a/storage/innobase/dict/dict0mem.c +++ b/storage/innobase/dict/dict0mem.c @@ -50,7 +50,6 @@ dict_mem_table_create( table->heap = heap; - table->type = DICT_TABLE_ORDINARY; table->flags = flags; table->name = mem_heap_strdup(heap, name); table->dir_path_of_temp_table = NULL; @@ -66,9 +65,6 @@ dict_mem_table_create( table->cached = FALSE; - table->mix_id = ut_dulint_zero; - table->mix_len = 0; - table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS) * sizeof(dict_col_t)); UT_LIST_INIT(table->indexes); @@ -97,42 +93,19 @@ dict_mem_table_create( return(table); } -/************************************************************************** -Creates a cluster memory object. */ - -dict_table_t* -dict_mem_cluster_create( -/*====================*/ - /* out, own: cluster object */ - const char* name, /* in: cluster name */ - ulint space, /* in: space where the clustered indexes - of the member tables are placed */ - ulint n_cols, /* in: number of columns */ - ulint mix_len)/* in: length of the common key prefix in the - cluster */ -{ - dict_table_t* cluster; - - /* Clustered tables cannot work with the compact record format. */ - cluster = dict_mem_table_create(name, space, n_cols, 0); - - cluster->type = DICT_TABLE_CLUSTER; - cluster->mix_len = mix_len; - - return(cluster); -} - -/************************************************************************** -Declares a non-published table as a member in a cluster. */ +/******************************************************************** +Free a table memory object. */ void -dict_mem_table_make_cluster_member( -/*===============================*/ - dict_table_t* table, /* in: non-published table */ - const char* cluster_name) /* in: cluster name */ +dict_mem_table_free( +/*================*/ + dict_table_t* table) /* in: table */ { - table->type = DICT_TABLE_CLUSTER_MEMBER; - table->cluster_name = cluster_name; + ut_ad(table); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + + mutex_free(&(table->autoinc_mutex)); + mem_heap_free(table->heap); } /************************************************************************** @@ -286,5 +259,8 @@ dict_mem_index_free( /*================*/ dict_index_t* index) /* in: index */ { + ut_ad(index); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + mem_heap_free(index->heap); } diff --git a/storage/innobase/eval/eval0proc.c b/storage/innobase/eval/eval0proc.c index dcbdc0da5fc..96b8ef75955 100644 --- a/storage/innobase/eval/eval0proc.c +++ b/storage/innobase/eval/eval0proc.c @@ -212,6 +212,38 @@ for_step( return(thr); } +/************************************************************************** +Performs an execution step of an exit statement node. */ + +que_thr_t* +exit_step( +/*======*/ + /* out: query thread to run next or NULL */ + que_thr_t* thr) /* in: query thread */ +{ + exit_node_t* node; + que_node_t* loop_node; + + ut_ad(thr); + + node = thr->run_node; + + ut_ad(que_node_get_type(node) == QUE_NODE_EXIT); + + /* Loops exit by setting thr->run_node as the loop node's parent, so + find our containing loop node and get its parent. */ + + loop_node = que_node_get_containing_loop_node(node); + + /* If someone uses an EXIT statement outside of a loop, this will + trigger. */ + ut_a(loop_node); + + thr->run_node = que_node_get_parent(loop_node); + + return(thr); +} + /************************************************************************** Performs an execution step of a return-statement node. */ diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 36cc97e5e0e..3263a0efd5b 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -1170,9 +1170,9 @@ ibuf_dummy_index_free( dict_index_t* index) /* in: dummy index */ { dict_table_t* table = index->table; - mem_heap_free(index->heap); - mutex_free(&(table->autoinc_mutex)); - mem_heap_free(table->heap); + + dict_mem_index_free(index); + dict_mem_table_free(table); } /************************************************************************* diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index cb6cb1b1a4d..d5dd4f3010a 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -459,7 +459,10 @@ btr_store_big_rec_extern_fields( dict_index_t* index, /* in: index of rec; the index tree MUST be X-latched */ rec_t* rec, /* in: record */ - const ulint* offsets, /* in: rec_get_offsets(rec, index) */ + const ulint* offsets, /* in: rec_get_offsets(rec, index); + the "external storage" flags in offsets + will not correspond to rec when + this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ mtr_t* local_mtr); /* in: mtr containing the latch to diff --git a/storage/innobase/include/btr0cur.ic b/storage/innobase/include/btr0cur.ic index 5d2ae768416..a199c3d4d32 100644 --- a/storage/innobase/include/btr0cur.ic +++ b/storage/innobase/include/btr0cur.ic @@ -98,8 +98,7 @@ btr_cur_compress_recommendation( { page_t* page; - ut_ad(mtr_memo_contains(mtr, buf_block_align( - btr_cur_get_page(cursor)), + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), MTR_MEMO_PAGE_X_FIX)); page = btr_cur_get_page(cursor); @@ -142,8 +141,7 @@ btr_cur_can_delete_without_compress( { page_t* page; - ut_ad(mtr_memo_contains(mtr, buf_block_align( - btr_cur_get_page(cursor)), + ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)), MTR_MEMO_PAGE_X_FIX)); page = btr_cur_get_page(cursor); diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h index b64d5e62e03..62b1d2db559 100644 --- a/storage/innobase/include/btr0sea.h +++ b/storage/innobase/include/btr0sea.h @@ -180,12 +180,14 @@ struct btr_search_struct{ the same prefix should be indexed in the hash index */ /*----------------------*/ +#ifdef UNIV_SEARCH_PERF_STAT ulint n_hash_succ; /* number of successful hash searches thus far */ ulint n_hash_fail; /* number of failed hash searches */ ulint n_patt_succ; /* number of successful pattern searches thus far */ ulint n_searches; /* number of searches */ +#endif /* UNIV_SEARCH_PERF_STAT */ }; #define BTR_SEARCH_MAGIC_N 1112765 @@ -218,8 +220,8 @@ extern rw_lock_t* btr_search_latch_temp; #ifdef UNIV_SEARCH_PERF_STAT extern ulint btr_search_n_succ; -#endif /* UNIV_SEARCH_PERF_STAT */ extern ulint btr_search_n_hash_fail; +#endif /* UNIV_SEARCH_PERF_STAT */ /* After change in n_fields or n_bytes in info, this many rounds are waited before starting the hash analysis again: this is to save CPU time when there diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index f8150db0437..6d26fd4d3b2 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -26,14 +26,14 @@ void buf_LRU_try_free_flushed_blocks(void); /*==================================*/ /********************************************************************** -Returns TRUE if less than 15 % of the buffer pool is available. This can be +Returns TRUE if less than 25 % of the buffer pool is available. This can be used in heuristics to prevent huge transactions eating up the whole buffer pool for their locks. */ ibool buf_LRU_buf_pool_running_out(void); /*==============================*/ - /* out: TRUE if less than 15 % of buffer pool + /* out: TRUE if less than 25 % of buffer pool left */ /*####################################################################### diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 9de5c5b52d5..39cde5bfb55 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -100,6 +100,15 @@ ulint dict_col_get_clust_pos( /*===================*/ dict_col_t* col); +/******************************************************************** +If the given column name is reserved for InnoDB system columns, return +TRUE. */ + +ibool +dict_col_name_is_reserved( +/*======================*/ + /* out: TRUE if name is reserved */ + const char* name); /* in: column name */ /************************************************************************ Initializes the autoinc counter. It is not an error to initialize an already initialized counter. */ @@ -321,6 +330,14 @@ dict_table_get_low( /* out: table, NULL if not found */ const char* table_name); /* in: table name */ /************************************************************************** +A noninlined version of dict_table_get_low. */ + +dict_table_t* +dict_table_get_low_noninlined( +/*==========================*/ + /* out: table, NULL if not found */ + const char* table_name); /* in: table name */ +/************************************************************************** Returns an index object. */ UNIV_INLINE dict_index_t* @@ -496,10 +513,11 @@ dict_table_is_comp( compact page format */ const dict_table_t* table); /* in: table */ /************************************************************************ -Non inlined version of 'dict_table_is_comp' above. */ +Check whether the table uses the compact page format. */ + ibool -innodb_dict_table_is_comp( -/*===============*/ +dict_table_is_comp_noninline( +/*=========================*/ /* out: TRUE if table uses the compact page format */ const dict_table_t* table); /* in: table */ @@ -725,33 +743,6 @@ dict_tree_free( /************************************************************************** In an index tree, finds the index corresponding to a record in the tree. */ -dict_index_t* -dict_tree_find_index( -/*=================*/ - /* out: index */ - dict_tree_t* tree, /* in: index tree */ - rec_t* rec); /* in: record for which to find correct index */ -/************************************************************************** -In an index tree, finds the index corresponding to a dtuple which is used -in a search to a tree. */ - -dict_index_t* -dict_tree_find_index_for_tuple( -/*===========================*/ - /* out: index; NULL if the tuple does not - contain the mix id field in a mixed tree */ - dict_tree_t* tree, /* in: index tree */ - dtuple_t* tuple); /* in: tuple for which to find index */ -/*********************************************************************** -Checks if a table which is a mixed cluster member owns a record. */ - -ibool -dict_is_mixed_table_rec( -/*====================*/ - /* out: TRUE if the record belongs to this - table */ - dict_table_t* table, /* in: table in a mixed cluster */ - rec_t* rec); /* in: user record in the clustered index */ /************************************************************************** Returns an index object if it is found in the dictionary cache. */ @@ -760,6 +751,7 @@ dict_index_get_if_in_cache( /*=======================*/ /* out: index, NULL if not found */ dulint index_id); /* in: index id */ +#ifdef UNIV_DEBUG /************************************************************************** Checks that a tuple has n_fields_cmp value in a sensible range, so that no comparison can occur with the page number field in a node pointer. */ @@ -770,6 +762,7 @@ dict_tree_check_search_tuple( /* out: TRUE if ok */ dict_tree_t* tree, /* in: index tree */ dtuple_t* tuple); /* in: tuple used in a search */ +#endif /* UNIV_DEBUG */ /************************************************************************** Builds a node pointer out of a physical record and a page number. */ @@ -916,7 +909,6 @@ dict_tables_have_same_db( dbname '/' tablename */ const char* name2); /* in: table name in the form dbname '/' tablename */ - /************************************************************************* Scans from pointer onwards. Stops if is at the start of a copy of 'string' where characters are compared without case sensitivity. Stops @@ -928,7 +920,6 @@ dict_scan_to( /* out: scanned up to this */ const char* ptr, /* in: scan from */ const char* string);/* in: look for this */ - /* Buffers for storing detailed information about the latest foreign key and unique key errors */ extern FILE* dict_foreign_err_file; diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index b99ca7815a8..0b5a23e9380 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -92,7 +92,6 @@ dict_table_get_n_user_cols( { ut_ad(table); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - ut_ad(table->cached); return(table->n_cols - DATA_N_SYS_COLS); } @@ -126,7 +125,6 @@ dict_table_get_n_cols( { ut_ad(table); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - ut_ad(table->cached); return(table->n_cols); } diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index ab07213de3b..0135ba3874d 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -35,9 +35,11 @@ combination of types */ /* Types for a table object */ #define DICT_TABLE_ORDINARY 1 +#if 0 /* not implemented */ #define DICT_TABLE_CLUSTER_MEMBER 2 #define DICT_TABLE_CLUSTER 3 /* this means that the table is really a cluster definition */ +#endif /* Table flags */ #define DICT_TF_COMPACT 1 /* compact page format */ @@ -56,29 +58,13 @@ dict_mem_table_create( a member of a cluster */ ulint n_cols, /* in: number of columns */ ulint flags); /* in: table flags */ -/************************************************************************** -Creates a cluster memory object. */ - -dict_cluster_t* -dict_mem_cluster_create( -/*====================*/ - /* out, own: cluster object (where the - type dict_cluster_t == dict_table_t) */ - const char* name, /* in: cluster name */ - ulint space, /* in: space where the clustered - indexes of the member tables are - placed */ - ulint n_cols, /* in: number of columns */ - ulint mix_len); /* in: length of the common key prefix - in the cluster */ -/************************************************************************** -Declares a non-published table as a member in a cluster. */ +/******************************************************************** +Free a table memory object. */ void -dict_mem_table_make_cluster_member( -/*===============================*/ - dict_table_t* table, /* in: non-published table */ - const char* cluster_name); /* in: cluster name */ +dict_mem_table_free( +/*================*/ + dict_table_t* table); /* in: table */ /************************************************************************** Adds a column definition to a table. */ @@ -176,9 +162,7 @@ struct dict_field_struct{ /* Data structure for an index tree */ struct dict_tree_struct{ ulint type; /* tree type */ - dulint id; /* id of the index stored in the tree, in the - case of a mixed index, the id of the clustered - index of the cluster table */ + dulint id; /* id of the index stored in the tree */ ulint space; /* space of index tree */ ulint page; /* index tree root page number */ byte pad[64];/* Padding to prevent other memory hotspots on @@ -189,13 +173,8 @@ struct dict_tree_struct{ struct has been memoryfixed (by mini- transactions wanting to access the index tree) */ - UT_LIST_BASE_NODE_T(dict_index_t) - tree_indexes; /* list of indexes stored in the - index tree: if the tree is not of the - mixed type there is only one index in - the list; if the tree is of the mixed - type, the first index in the list is the - index of the cluster which owns the tree */ + dict_index_t* tree_index; /* the index stored in the + index tree */ ulint magic_n;/* magic number */ }; @@ -301,8 +280,7 @@ a foreign key constraint is enforced, therefore RESTRICT just means no flag */ /* Data structure for a database table */ struct dict_table_struct{ - dulint id; /* id of the table or cluster */ - ulint type; /* DICT_TABLE_ORDINARY, ... */ + dulint id; /* id of the table */ ulint flags; /* DICT_TF_COMPACT, ... */ mem_heap_t* heap; /* memory heap */ const char* name; /* table name */ @@ -371,17 +349,6 @@ struct dict_table_struct{ UT_LIST_BASE_NODE_T(lock_t) locks; /* list of locks on the table */ /*----------------------*/ - dulint mix_id; /* if the table is a member in a cluster, - this is its mix id */ - ulint mix_len;/* if the table is a cluster or a member - this is the common key prefix lenght */ - ulint mix_id_len;/* mix id length in a compressed form */ - byte mix_id_buf[12]; - /* mix id of a mixed table written in - a compressed form */ - const char* cluster_name; /* if the table is a member in a - cluster, this is the name of the cluster */ - /*----------------------*/ ibool does_not_fit_in_memory; /* this field is used to specify in simulations tables which are so big that disk should be diff --git a/storage/innobase/include/eval0proc.h b/storage/innobase/include/eval0proc.h index 2cf98f26265..8416551d0ba 100644 --- a/storage/innobase/include/eval0proc.h +++ b/storage/innobase/include/eval0proc.h @@ -63,6 +63,14 @@ proc_eval_step( /* out: query thread to run next or NULL */ que_thr_t* thr); /* in: query thread */ /************************************************************************** +Performs an execution step of an exit statement node. */ + +que_thr_t* +exit_step( +/*======*/ + /* out: query thread to run next or NULL */ + que_thr_t* thr); /* in: query thread */ +/************************************************************************** Performs an execution step of a return-statement node. */ que_thr_t* diff --git a/storage/innobase/include/hash0hash.h b/storage/innobase/include/hash0hash.h index a5cd32d956f..31c5c57ae35 100644 --- a/storage/innobase/include/hash0hash.h +++ b/storage/innobase/include/hash0hash.h @@ -222,6 +222,32 @@ do {\ mem_heap_free_top(hash_get_heap(TABLE, fold111), sizeof(TYPE));\ } while (0) +/******************************************************************** +Move all hash table entries from OLD_TABLE to NEW_TABLE.*/ + +#define HASH_MIGRATE(OLD_TABLE, NEW_TABLE, NODE_TYPE, PTR_NAME, FOLD_FUNC) \ +do {\ + ulint i2222;\ + ulint cell_count2222;\ +\ + cell_count2222 = hash_get_n_cells(OLD_TABLE);\ +\ + for (i2222 = 0; i2222 < cell_count2222; i2222++) {\ + NODE_TYPE* node2222 = HASH_GET_FIRST((OLD_TABLE), i2222);\ +\ + while (node2222) {\ + NODE_TYPE* next2222 = node2222->PTR_NAME;\ + ulint fold2222 = FOLD_FUNC(node2222);\ +\ + HASH_INSERT(NODE_TYPE, PTR_NAME, (NEW_TABLE),\ + fold2222, node2222);\ +\ + node2222 = next2222;\ + }\ + }\ +} while (0) + + /**************************************************************** Gets the mutex index for a fold value in a hash table. */ UNIV_INLINE diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 3dda3a7cca8..6b863e32183 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -595,6 +595,15 @@ ibool lock_validate(void); /*===============*/ /* out: TRUE if ok */ +/************************************************************************* +Return approximate number or record locks (bits set in the bitmap) for +this transaction. Since delete-marked records ma ybe removed, the +record count will not be precise. */ + +ulint +lock_number_of_rows_locked( +/*=======================*/ + trx_t* trx); /* in: transaction */ /* The lock system */ extern lock_sys_t* lock_sys; diff --git a/storage/innobase/include/mem0mem.h b/storage/innobase/include/mem0mem.h index e2f8be98b01..f9342e962f2 100644 --- a/storage/innobase/include/mem0mem.h +++ b/storage/innobase/include/mem0mem.h @@ -311,6 +311,17 @@ mem_heap_strdupl( const char* str, /* in: string to be copied */ ulint len); /* in: length of str, in bytes */ +/************************************************************************** +Concatenate two strings and return the result, using a memory heap. */ + +char* +mem_heap_strcat( +/*============*/ + /* out, own: the result */ + mem_heap_t* heap, /* in: memory heap where string is allocated */ + const char* s1, /* in: string 1 */ + const char* s2); /* in: string 2 */ + #ifdef MEM_PERIODIC_CHECK /********************************************************************** Goes through the list of all allocated mem blocks, checks their magic diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index 2f651b40319..b33eeaceb1c 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -175,19 +175,6 @@ page_rec_is_comp( /* out: nonzero if in compact format */ const rec_t* rec) /* in: record */ { -#ifdef UNIV_RELEASE_NOT_YET_STABLE - if (UNIV_UNLIKELY((ulint)rec < (ulint)(buf_pool->frame_zero)) - || UNIV_UNLIKELY((ulint)rec >= (ulint)(buf_pool->high_end))) { - - ut_print_timestamp(stderr); - fprintf(stderr, -"InnoDB: Error: trying to read a stray page rec %p\n" -"InnoDB: buf pool start is at %p, end at %p\n", - rec, buf_pool->frame_zero, - buf_pool->high_end); - ut_error; - } -#endif return(page_is_comp(ut_align_down((rec_t*) rec, UNIV_PAGE_SIZE))); } diff --git a/storage/innobase/include/pars0grm.h b/storage/innobase/include/pars0grm.h index e35fcf47692..996fc37f13b 100644 --- a/storage/innobase/include/pars0grm.h +++ b/storage/innobase/include/pars0grm.h @@ -32,177 +32,187 @@ PARS_INT_LIT = 258, PARS_FLOAT_LIT = 259, PARS_STR_LIT = 260, - PARS_NULL_LIT = 261, - PARS_ID_TOKEN = 262, - PARS_AND_TOKEN = 263, - PARS_OR_TOKEN = 264, - PARS_NOT_TOKEN = 265, - PARS_GE_TOKEN = 266, - PARS_LE_TOKEN = 267, - PARS_NE_TOKEN = 268, - PARS_PROCEDURE_TOKEN = 269, - PARS_IN_TOKEN = 270, - PARS_OUT_TOKEN = 271, - PARS_BINARY_TOKEN = 272, - PARS_BLOB_TOKEN = 273, - PARS_INT_TOKEN = 274, - PARS_INTEGER_TOKEN = 275, - PARS_FLOAT_TOKEN = 276, - PARS_CHAR_TOKEN = 277, - PARS_IS_TOKEN = 278, - PARS_BEGIN_TOKEN = 279, - PARS_END_TOKEN = 280, - PARS_IF_TOKEN = 281, - PARS_THEN_TOKEN = 282, - PARS_ELSE_TOKEN = 283, - PARS_ELSIF_TOKEN = 284, - PARS_LOOP_TOKEN = 285, - PARS_WHILE_TOKEN = 286, - PARS_RETURN_TOKEN = 287, - PARS_SELECT_TOKEN = 288, - PARS_SUM_TOKEN = 289, - PARS_COUNT_TOKEN = 290, - PARS_DISTINCT_TOKEN = 291, - PARS_FROM_TOKEN = 292, - PARS_WHERE_TOKEN = 293, - PARS_FOR_TOKEN = 294, - PARS_DDOT_TOKEN = 295, - PARS_CONSISTENT_TOKEN = 296, - PARS_READ_TOKEN = 297, - PARS_ORDER_TOKEN = 298, - PARS_BY_TOKEN = 299, - PARS_ASC_TOKEN = 300, - PARS_DESC_TOKEN = 301, - PARS_INSERT_TOKEN = 302, - PARS_INTO_TOKEN = 303, - PARS_VALUES_TOKEN = 304, - PARS_UPDATE_TOKEN = 305, - PARS_SET_TOKEN = 306, - PARS_DELETE_TOKEN = 307, - PARS_CURRENT_TOKEN = 308, - PARS_OF_TOKEN = 309, - PARS_CREATE_TOKEN = 310, - PARS_TABLE_TOKEN = 311, - PARS_INDEX_TOKEN = 312, - PARS_UNIQUE_TOKEN = 313, - PARS_CLUSTERED_TOKEN = 314, - PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 315, - PARS_ON_TOKEN = 316, - PARS_ASSIGN_TOKEN = 317, - PARS_DECLARE_TOKEN = 318, - PARS_CURSOR_TOKEN = 319, - PARS_SQL_TOKEN = 320, - PARS_OPEN_TOKEN = 321, - PARS_FETCH_TOKEN = 322, - PARS_CLOSE_TOKEN = 323, - PARS_NOTFOUND_TOKEN = 324, - PARS_TO_CHAR_TOKEN = 325, - PARS_TO_NUMBER_TOKEN = 326, - PARS_TO_BINARY_TOKEN = 327, - PARS_BINARY_TO_NUMBER_TOKEN = 328, - PARS_SUBSTR_TOKEN = 329, - PARS_REPLSTR_TOKEN = 330, - PARS_CONCAT_TOKEN = 331, - PARS_INSTR_TOKEN = 332, - PARS_LENGTH_TOKEN = 333, - PARS_SYSDATE_TOKEN = 334, - PARS_PRINTF_TOKEN = 335, - PARS_ASSERT_TOKEN = 336, - PARS_RND_TOKEN = 337, - PARS_RND_STR_TOKEN = 338, - PARS_ROW_PRINTF_TOKEN = 339, - PARS_COMMIT_TOKEN = 340, - PARS_ROLLBACK_TOKEN = 341, - PARS_WORK_TOKEN = 342, - NEG = 343 + PARS_FIXBINARY_LIT = 261, + PARS_BLOB_LIT = 262, + PARS_NULL_LIT = 263, + PARS_ID_TOKEN = 264, + PARS_AND_TOKEN = 265, + PARS_OR_TOKEN = 266, + PARS_NOT_TOKEN = 267, + PARS_GE_TOKEN = 268, + PARS_LE_TOKEN = 269, + PARS_NE_TOKEN = 270, + PARS_PROCEDURE_TOKEN = 271, + PARS_IN_TOKEN = 272, + PARS_OUT_TOKEN = 273, + PARS_BINARY_TOKEN = 274, + PARS_BLOB_TOKEN = 275, + PARS_INT_TOKEN = 276, + PARS_INTEGER_TOKEN = 277, + PARS_FLOAT_TOKEN = 278, + PARS_CHAR_TOKEN = 279, + PARS_IS_TOKEN = 280, + PARS_BEGIN_TOKEN = 281, + PARS_END_TOKEN = 282, + PARS_IF_TOKEN = 283, + PARS_THEN_TOKEN = 284, + PARS_ELSE_TOKEN = 285, + PARS_ELSIF_TOKEN = 286, + PARS_LOOP_TOKEN = 287, + PARS_WHILE_TOKEN = 288, + PARS_RETURN_TOKEN = 289, + PARS_SELECT_TOKEN = 290, + PARS_SUM_TOKEN = 291, + PARS_COUNT_TOKEN = 292, + PARS_DISTINCT_TOKEN = 293, + PARS_FROM_TOKEN = 294, + PARS_WHERE_TOKEN = 295, + PARS_FOR_TOKEN = 296, + PARS_DDOT_TOKEN = 297, + PARS_CONSISTENT_TOKEN = 298, + PARS_READ_TOKEN = 299, + PARS_ORDER_TOKEN = 300, + PARS_BY_TOKEN = 301, + PARS_ASC_TOKEN = 302, + PARS_DESC_TOKEN = 303, + PARS_INSERT_TOKEN = 304, + PARS_INTO_TOKEN = 305, + PARS_VALUES_TOKEN = 306, + PARS_UPDATE_TOKEN = 307, + PARS_SET_TOKEN = 308, + PARS_DELETE_TOKEN = 309, + PARS_CURRENT_TOKEN = 310, + PARS_OF_TOKEN = 311, + PARS_CREATE_TOKEN = 312, + PARS_TABLE_TOKEN = 313, + PARS_INDEX_TOKEN = 314, + PARS_UNIQUE_TOKEN = 315, + PARS_CLUSTERED_TOKEN = 316, + PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 317, + PARS_ON_TOKEN = 318, + PARS_ASSIGN_TOKEN = 319, + PARS_DECLARE_TOKEN = 320, + PARS_CURSOR_TOKEN = 321, + PARS_SQL_TOKEN = 322, + PARS_OPEN_TOKEN = 323, + PARS_FETCH_TOKEN = 324, + PARS_CLOSE_TOKEN = 325, + PARS_NOTFOUND_TOKEN = 326, + PARS_TO_CHAR_TOKEN = 327, + PARS_TO_NUMBER_TOKEN = 328, + PARS_TO_BINARY_TOKEN = 329, + PARS_BINARY_TO_NUMBER_TOKEN = 330, + PARS_SUBSTR_TOKEN = 331, + PARS_REPLSTR_TOKEN = 332, + PARS_CONCAT_TOKEN = 333, + PARS_INSTR_TOKEN = 334, + PARS_LENGTH_TOKEN = 335, + PARS_SYSDATE_TOKEN = 336, + PARS_PRINTF_TOKEN = 337, + PARS_ASSERT_TOKEN = 338, + PARS_RND_TOKEN = 339, + PARS_RND_STR_TOKEN = 340, + PARS_ROW_PRINTF_TOKEN = 341, + PARS_COMMIT_TOKEN = 342, + PARS_ROLLBACK_TOKEN = 343, + PARS_WORK_TOKEN = 344, + PARS_UNSIGNED_TOKEN = 345, + PARS_EXIT_TOKEN = 346, + PARS_FUNCTION_TOKEN = 347, + NEG = 348 }; #endif #define PARS_INT_LIT 258 #define PARS_FLOAT_LIT 259 #define PARS_STR_LIT 260 -#define PARS_NULL_LIT 261 -#define PARS_ID_TOKEN 262 -#define PARS_AND_TOKEN 263 -#define PARS_OR_TOKEN 264 -#define PARS_NOT_TOKEN 265 -#define PARS_GE_TOKEN 266 -#define PARS_LE_TOKEN 267 -#define PARS_NE_TOKEN 268 -#define PARS_PROCEDURE_TOKEN 269 -#define PARS_IN_TOKEN 270 -#define PARS_OUT_TOKEN 271 -#define PARS_BINARY_TOKEN 272 -#define PARS_BLOB_TOKEN 273 -#define PARS_INT_TOKEN 274 -#define PARS_INTEGER_TOKEN 275 -#define PARS_FLOAT_TOKEN 276 -#define PARS_CHAR_TOKEN 277 -#define PARS_IS_TOKEN 278 -#define PARS_BEGIN_TOKEN 279 -#define PARS_END_TOKEN 280 -#define PARS_IF_TOKEN 281 -#define PARS_THEN_TOKEN 282 -#define PARS_ELSE_TOKEN 283 -#define PARS_ELSIF_TOKEN 284 -#define PARS_LOOP_TOKEN 285 -#define PARS_WHILE_TOKEN 286 -#define PARS_RETURN_TOKEN 287 -#define PARS_SELECT_TOKEN 288 -#define PARS_SUM_TOKEN 289 -#define PARS_COUNT_TOKEN 290 -#define PARS_DISTINCT_TOKEN 291 -#define PARS_FROM_TOKEN 292 -#define PARS_WHERE_TOKEN 293 -#define PARS_FOR_TOKEN 294 -#define PARS_DDOT_TOKEN 295 -#define PARS_CONSISTENT_TOKEN 296 -#define PARS_READ_TOKEN 297 -#define PARS_ORDER_TOKEN 298 -#define PARS_BY_TOKEN 299 -#define PARS_ASC_TOKEN 300 -#define PARS_DESC_TOKEN 301 -#define PARS_INSERT_TOKEN 302 -#define PARS_INTO_TOKEN 303 -#define PARS_VALUES_TOKEN 304 -#define PARS_UPDATE_TOKEN 305 -#define PARS_SET_TOKEN 306 -#define PARS_DELETE_TOKEN 307 -#define PARS_CURRENT_TOKEN 308 -#define PARS_OF_TOKEN 309 -#define PARS_CREATE_TOKEN 310 -#define PARS_TABLE_TOKEN 311 -#define PARS_INDEX_TOKEN 312 -#define PARS_UNIQUE_TOKEN 313 -#define PARS_CLUSTERED_TOKEN 314 -#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 315 -#define PARS_ON_TOKEN 316 -#define PARS_ASSIGN_TOKEN 317 -#define PARS_DECLARE_TOKEN 318 -#define PARS_CURSOR_TOKEN 319 -#define PARS_SQL_TOKEN 320 -#define PARS_OPEN_TOKEN 321 -#define PARS_FETCH_TOKEN 322 -#define PARS_CLOSE_TOKEN 323 -#define PARS_NOTFOUND_TOKEN 324 -#define PARS_TO_CHAR_TOKEN 325 -#define PARS_TO_NUMBER_TOKEN 326 -#define PARS_TO_BINARY_TOKEN 327 -#define PARS_BINARY_TO_NUMBER_TOKEN 328 -#define PARS_SUBSTR_TOKEN 329 -#define PARS_REPLSTR_TOKEN 330 -#define PARS_CONCAT_TOKEN 331 -#define PARS_INSTR_TOKEN 332 -#define PARS_LENGTH_TOKEN 333 -#define PARS_SYSDATE_TOKEN 334 -#define PARS_PRINTF_TOKEN 335 -#define PARS_ASSERT_TOKEN 336 -#define PARS_RND_TOKEN 337 -#define PARS_RND_STR_TOKEN 338 -#define PARS_ROW_PRINTF_TOKEN 339 -#define PARS_COMMIT_TOKEN 340 -#define PARS_ROLLBACK_TOKEN 341 -#define PARS_WORK_TOKEN 342 -#define NEG 343 +#define PARS_FIXBINARY_LIT 261 +#define PARS_BLOB_LIT 262 +#define PARS_NULL_LIT 263 +#define PARS_ID_TOKEN 264 +#define PARS_AND_TOKEN 265 +#define PARS_OR_TOKEN 266 +#define PARS_NOT_TOKEN 267 +#define PARS_GE_TOKEN 268 +#define PARS_LE_TOKEN 269 +#define PARS_NE_TOKEN 270 +#define PARS_PROCEDURE_TOKEN 271 +#define PARS_IN_TOKEN 272 +#define PARS_OUT_TOKEN 273 +#define PARS_BINARY_TOKEN 274 +#define PARS_BLOB_TOKEN 275 +#define PARS_INT_TOKEN 276 +#define PARS_INTEGER_TOKEN 277 +#define PARS_FLOAT_TOKEN 278 +#define PARS_CHAR_TOKEN 279 +#define PARS_IS_TOKEN 280 +#define PARS_BEGIN_TOKEN 281 +#define PARS_END_TOKEN 282 +#define PARS_IF_TOKEN 283 +#define PARS_THEN_TOKEN 284 +#define PARS_ELSE_TOKEN 285 +#define PARS_ELSIF_TOKEN 286 +#define PARS_LOOP_TOKEN 287 +#define PARS_WHILE_TOKEN 288 +#define PARS_RETURN_TOKEN 289 +#define PARS_SELECT_TOKEN 290 +#define PARS_SUM_TOKEN 291 +#define PARS_COUNT_TOKEN 292 +#define PARS_DISTINCT_TOKEN 293 +#define PARS_FROM_TOKEN 294 +#define PARS_WHERE_TOKEN 295 +#define PARS_FOR_TOKEN 296 +#define PARS_DDOT_TOKEN 297 +#define PARS_CONSISTENT_TOKEN 298 +#define PARS_READ_TOKEN 299 +#define PARS_ORDER_TOKEN 300 +#define PARS_BY_TOKEN 301 +#define PARS_ASC_TOKEN 302 +#define PARS_DESC_TOKEN 303 +#define PARS_INSERT_TOKEN 304 +#define PARS_INTO_TOKEN 305 +#define PARS_VALUES_TOKEN 306 +#define PARS_UPDATE_TOKEN 307 +#define PARS_SET_TOKEN 308 +#define PARS_DELETE_TOKEN 309 +#define PARS_CURRENT_TOKEN 310 +#define PARS_OF_TOKEN 311 +#define PARS_CREATE_TOKEN 312 +#define PARS_TABLE_TOKEN 313 +#define PARS_INDEX_TOKEN 314 +#define PARS_UNIQUE_TOKEN 315 +#define PARS_CLUSTERED_TOKEN 316 +#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 317 +#define PARS_ON_TOKEN 318 +#define PARS_ASSIGN_TOKEN 319 +#define PARS_DECLARE_TOKEN 320 +#define PARS_CURSOR_TOKEN 321 +#define PARS_SQL_TOKEN 322 +#define PARS_OPEN_TOKEN 323 +#define PARS_FETCH_TOKEN 324 +#define PARS_CLOSE_TOKEN 325 +#define PARS_NOTFOUND_TOKEN 326 +#define PARS_TO_CHAR_TOKEN 327 +#define PARS_TO_NUMBER_TOKEN 328 +#define PARS_TO_BINARY_TOKEN 329 +#define PARS_BINARY_TO_NUMBER_TOKEN 330 +#define PARS_SUBSTR_TOKEN 331 +#define PARS_REPLSTR_TOKEN 332 +#define PARS_CONCAT_TOKEN 333 +#define PARS_INSTR_TOKEN 334 +#define PARS_LENGTH_TOKEN 335 +#define PARS_SYSDATE_TOKEN 336 +#define PARS_PRINTF_TOKEN 337 +#define PARS_ASSERT_TOKEN 338 +#define PARS_RND_TOKEN 339 +#define PARS_RND_STR_TOKEN 340 +#define PARS_ROW_PRINTF_TOKEN 341 +#define PARS_COMMIT_TOKEN 342 +#define PARS_ROLLBACK_TOKEN 343 +#define PARS_WORK_TOKEN 344 +#define PARS_UNSIGNED_TOKEN 345 +#define PARS_EXIT_TOKEN 346 +#define PARS_FUNCTION_TOKEN 347 +#define NEG 348 diff --git a/storage/innobase/include/pars0pars.h b/storage/innobase/include/pars0pars.h index 2ae2d6cff74..68b8ae41cc0 100644 --- a/storage/innobase/include/pars0pars.h +++ b/storage/innobase/include/pars0pars.h @@ -15,6 +15,13 @@ Created 11/19/1996 Heikki Tuuri #include "pars0types.h" #include "row0types.h" #include "trx0types.h" +#include "ut0vec.h" + +/* Type of the user functions. The first argument is always InnoDB-supplied +and varies in type, while 'user_arg' is a user-supplied argument. The +meaning of the return type also varies. See the individual use cases, e.g. +the FETCH statement, for details on them. */ +typedef void* (*pars_user_func_cb_t)(void* arg, void* user_arg); extern int yydebug; @@ -77,6 +84,7 @@ que_t* pars_sql( /*=====*/ /* out, own: the query graph */ + pars_info_t* info, /* in: extra information, or NULL */ const char* str); /* in: SQL string */ /***************************************************************** Retrieves characters to the lexical analyzer. */ @@ -157,6 +165,15 @@ pars_cursor_declaration( table */ sel_node_t* select_node); /* in: select node */ /************************************************************************* +Parses a function declaration. */ + +que_node_t* +pars_function_declaration( +/*======================*/ + /* out: sym_node */ + sym_node_t* sym_node); /* in: function id node in the symbol + table */ +/************************************************************************* Parses a select statement. */ sel_node_t* @@ -269,6 +286,13 @@ pars_while_statement( que_node_t* cond, /* in: while-condition */ que_node_t* stat_list); /* in: statement list */ /************************************************************************* +Parses an exit statement. */ + +exit_node_t* +pars_exit_statement(void); +/*=====================*/ + /* out: exit statement node */ +/************************************************************************* Parses a return-statement. */ return_node_t* @@ -294,14 +318,16 @@ pars_assignment_statement( sym_node_t* var, /* in: variable to assign */ que_node_t* val); /* in: value to assign */ /************************************************************************* -Parses a fetch statement. */ +Parses a fetch statement. into_list or user_func (but not both) must be +non-NULL. */ fetch_node_t* pars_fetch_statement( /*=================*/ /* out: fetch statement node */ sym_node_t* cursor, /* in: cursor node */ - sym_node_t* into_list); /* in: variables to set */ + sym_node_t* into_list, /* in: variables to set, or NULL */ + sym_node_t* user_func); /* in: user function name, or NULL */ /************************************************************************* Parses an open or close cursor statement. */ @@ -345,6 +371,8 @@ pars_column_def( pars_res_word_t* type, /* in: data type */ sym_node_t* len, /* in: length of column, or NULL */ + void* is_unsigned, /* in: if not NULL, column + is of type UNSIGNED. */ void* is_not_null); /* in: if not NULL, column is of type NOT NULL. */ /************************************************************************* @@ -418,6 +446,142 @@ pars_complete_graph_for_exec( trx_t* trx, /* in: transaction handle */ mem_heap_t* heap); /* in: memory heap from which allocated */ +/******************************************************************** +Create parser info struct.*/ + +pars_info_t* +pars_info_create(void); +/*==================*/ + /* out, own: info struct */ + +/******************************************************************** +Free info struct and everything it contains.*/ + +void +pars_info_free( +/*===========*/ + pars_info_t* info); /* in: info struct */ + +/******************************************************************** +Add bound literal. */ + +void +pars_info_add_literal( +/*==================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + const void* address, /* in: address */ + ulint length, /* in: length of data */ + ulint type, /* in: type, e.g. DATA_FIXBINARY */ + ulint prtype); /* in: precise type, e.g. + DATA_UNSIGNED */ + +/******************************************************************** +Equivalent to pars_info_add_literal(info, name, str, strlen(str), +DATA_VARCHAR, DATA_ENGLISH). */ + +void +pars_info_add_str_literal( +/*======================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + const char* str); /* in: string */ + +/******************************************************************** +Equivalent to: + +char buf[4]; +mach_write_to_4(buf, val); +pars_info_add_literal(info, name, buf, 4, DATA_INT, 0); + +except that the buffer is dynamically allocated from the info struct's +heap. */ + +void +pars_info_add_int4_literal( +/*=======================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + lint val); /* in: value */ + +/******************************************************************** +Equivalent to: + +char buf[8]; +mach_write_to_8(buf, val); +pars_info_add_literal(info, name, buf, 8, DATA_BINARY, 0); + +except that the buffer is dynamically allocated from the info struct's +heap. */ + +void +pars_info_add_dulint_literal( +/*=========================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + dulint val); /* in: value */ +/******************************************************************** +Add user function. */ + +void +pars_info_add_function( +/*===================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: function name */ + pars_user_func_cb_t func, /* in: function address */ + void* arg); /* in: user-supplied argument */ + +/******************************************************************** +Get user function with the given name.*/ + +pars_user_func_t* +pars_info_get_user_func( +/*====================*/ + /* out: user func, or NULL if not + found */ + pars_info_t* info, /* in: info struct */ + const char* name); /* in: function name to find*/ + +/******************************************************************** +Get bound literal with the given name.*/ + +pars_bound_lit_t* +pars_info_get_bound_lit( +/*====================*/ + /* out: bound literal, or NULL if + not found */ + pars_info_t* info, /* in: info struct */ + const char* name); /* in: bound literal name to find */ + + +/* Extra information supplied for pars_sql(). */ +struct pars_info_struct { + mem_heap_t* heap; /* our own memory heap */ + + ib_vector_t* funcs; /* user functions, or NUll + (pars_user_func_t*) */ + ib_vector_t* bound_lits; /* bound literals, or NULL + (pars_bound_lit_t*) */ + + ibool graph_owns_us; /* if TRUE (which is the default), + que_graph_free() will free us */ +}; + +/* User-supplied function and argument. */ +struct pars_user_func_struct { + const char* name; /* function name */ + pars_user_func_cb_t func; /* function address */ + void* arg; /* user-supplied argument */ +}; + +/* Bound literal. */ +struct pars_bound_lit_struct { + const char* name; /* name */ + const void* address; /* address */ + ulint length; /* length of data */ + ulint type; /* type, e.g. DATA_FIXBINARY */ + ulint prtype; /* precise type, e.g. DATA_UNSIGNED */ +}; /* Struct used to denote a reserved word in a parsing tree */ struct pars_res_word_struct{ @@ -498,6 +662,11 @@ struct for_node_struct{ que_node_t* stat_list; /* statement list */ }; +/* exit statement node */ +struct exit_node_struct{ + que_common_t common; /* type: QUE_NODE_EXIT */ +}; + /* return-statement node */ struct return_node_struct{ que_common_t common; /* type: QUE_NODE_RETURN */ diff --git a/storage/innobase/include/pars0sym.h b/storage/innobase/include/pars0sym.h index a10d70d48b6..14f762d5b7a 100644 --- a/storage/innobase/include/pars0sym.h +++ b/storage/innobase/include/pars0sym.h @@ -54,6 +54,16 @@ sym_tab_add_str_lit( it */ ulint len); /* in: string length */ /********************************************************************** +Add a bound literal to a symbol table. */ + +sym_node_t* +sym_tab_add_bound_lit( +/*==================*/ + /* out: symbol table node */ + sym_tab_t* sym_tab, /* in: symbol table */ + const char* name, /* in: name of bound literal */ + ulint* lit_type); /* out: type of literal (PARS_*_LIT) */ +/********************************************************************** Adds an SQL null literal to a symbol table. */ sym_node_t* @@ -83,6 +93,19 @@ struct sym_node_struct{ been allocated from dynamic memory and it should be freed when the symbol table is discarded */ + /* 'alias' and 'indirection' are almost the same, but not quite. + 'alias' always points to the primary instance of the variable, while + 'indirection' does the same only if we should use the primary + instance's values for the node's data. This is usually the case, but + when initializing a cursor (e.g., "DECLARE CURSOR c IS SELECT * FROM + t WHERE id = x;"), we copy the values from the primary instance to + the cursor's instance so that they are fixed for the duration of the + cursor, and set 'indirection' to NULL. If we did not, the value of + 'x' could change between fetches and things would break horribly. + + TODO: It would be cleaner to make 'indirection' a boolean field and + always use 'alias' to refer to the primary node. */ + sym_node_t* indirection; /* pointer to another symbol table node which contains @@ -158,6 +181,7 @@ struct sym_tab_struct{ /* position of the next character in sql_string to give to the lexical analyzer */ + pars_info_t* info; /* extra information, or NULL */ sym_node_list_t sym_list; /* list of symbol nodes in the symbol table */ @@ -180,6 +204,7 @@ struct sym_tab_struct{ #define SYM_CURSOR 96 /* named cursor */ #define SYM_PROCEDURE_NAME 97 /* stored procedure name */ #define SYM_INDEX 98 /* database index name */ +#define SYM_FUNCTION 99 /* user function name */ #ifndef UNIV_NONINL #include "pars0sym.ic" diff --git a/storage/innobase/include/pars0types.h b/storage/innobase/include/pars0types.h index cf62617e066..6fcfaf23024 100644 --- a/storage/innobase/include/pars0types.h +++ b/storage/innobase/include/pars0types.h @@ -9,6 +9,9 @@ Created 1/11/1998 Heikki Tuuri #ifndef pars0types_h #define pars0types_h +typedef struct pars_info_struct pars_info_t; +typedef struct pars_user_func_struct pars_user_func_t; +typedef struct pars_bound_lit_struct pars_bound_lit_t; typedef struct sym_node_struct sym_node_t; typedef struct sym_tab_struct sym_tab_t; typedef struct pars_res_word_struct pars_res_word_t; @@ -19,6 +22,7 @@ typedef struct elsif_node_struct elsif_node_t; typedef struct if_node_struct if_node_t; typedef struct while_node_struct while_node_t; typedef struct for_node_struct for_node_t; +typedef struct exit_node_struct exit_node_t; typedef struct return_node_struct return_node_t; typedef struct assign_node_struct assign_node_t; typedef struct col_assign_node_struct col_assign_node_t; diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h index 4e31e2db4b7..c3314a1167b 100644 --- a/storage/innobase/include/que0que.h +++ b/storage/innobase/include/que0que.h @@ -277,6 +277,15 @@ que_node_get_parent( /*================*/ /* out: parent node or NULL */ que_node_t* node); /* in: node */ +/******************************************************************** +Get the first containing loop node (e.g. while_node_t or for_node_t) for the +given node, or NULL if the node is not within a loop. */ + +que_node_t* +que_node_get_containing_loop_node( +/*==============================*/ + /* out: containing loop node, or NULL. */ + que_node_t* node); /* in: node */ /************************************************************************* Catenates a query graph node to a list of them, possible empty list. */ UNIV_INLINE @@ -322,8 +331,15 @@ void que_node_print_info( /*================*/ que_node_t* node); /* in: query graph node */ +/************************************************************************* +Evaluate the given SQL */ - +ulint +que_eval_sql( +/*=========*/ + pars_info_t* info, /* out: error code or DB_SUCCESS */ + const char* sql, /* in: info struct, or NULL */ + trx_t* trx); /* in: trx */ /* Query graph query thread node: the fields are protected by the kernel mutex with the exceptions named below */ @@ -388,6 +404,7 @@ struct que_fork_struct{ sym_tab_t* sym_tab; /* symbol table of the query, generated by the parser, or NULL if the graph was created 'by hand' */ + pars_info_t* info; /* in: info struct, or NULL */ /* The following cur_... fields are relevant only in a select graph */ ulint cur_end; /* QUE_CUR_NOT_DEFINED, QUE_CUR_START, @@ -469,6 +486,7 @@ struct que_fork_struct{ #define QUE_NODE_ROW_PRINTF 29 #define QUE_NODE_ELSIF 30 #define QUE_NODE_CALL 31 +#define QUE_NODE_EXIT 32 /* Query thread states */ #define QUE_THR_RUNNING 1 diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 8ff8a0476a1..48fb7432b54 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -244,7 +244,8 @@ row_update_for_mysql( row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL handle */ /************************************************************************* -This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before +This can only be used when srv_locks_unsafe_for_binlog is TRUE or +session is using a READ COMMITTED isolation level. Before calling this function we must use trx_reset_new_rec_lock_info() and trx_register_new_rec_lock() to store the information which new record locks really were set. This function removes a newly set lock under prebuilt->pcur, diff --git a/storage/innobase/include/row0sel.h b/storage/innobase/include/row0sel.h index c9f2389d3dd..70b08d82994 100644 --- a/storage/innobase/include/row0sel.h +++ b/storage/innobase/include/row0sel.h @@ -78,6 +78,26 @@ fetch_step( /*=======*/ /* out: query thread to run next or NULL */ que_thr_t* thr); /* in: query thread */ +/******************************************************************** +Sample callback function for fetch that prints each row.*/ + +void* +row_fetch_print( +/*============*/ + /* out: always returns non-NULL */ + void* row, /* in: sel_node_t* */ + void* user_arg); /* in: not used */ +/******************************************************************** +Callback function for fetch that stores an unsigned 4 byte integer to the +location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length += 4. */ + +void* +row_fetch_store_uint4( +/*==================*/ + /* out: always returns NULL */ + void* row, /* in: sel_node_t* */ + void* user_arg); /* in: data pointer */ /*************************************************************** Prints a row in a select result. */ @@ -204,8 +224,6 @@ struct plan_struct{ ulint first_prefetched;/* index of the first cached row in select buffer arrays for each column */ ibool no_prefetch; /* no prefetch for this table */ - ibool mixed_index; /* TRUE if index is a clustered index - in a mixed cluster */ sym_node_list_t columns; /* symbol table nodes for the columns to retrieve from the table */ UT_LIST_BASE_NODE_T(func_node_t) @@ -311,6 +329,20 @@ struct fetch_node_struct{ que_common_t common; /* type: QUE_NODE_FETCH */ sel_node_t* cursor_def; /* cursor definition */ sym_node_t* into_list; /* variables to set */ + + pars_user_func_t* + func; /* User callback function or NULL. + The first argument to the function + is a sel_node_t*, containing the + results of the SELECT operation for + one row. If the function returns + NULL, it is not interested in + further rows and the cursor is + modified so (cursor % NOTFOUND) is + true. If it returns not-NULL, + continue normally. See + row_fetch_print() for an example + (and a useful debugging tool). */ }; /* Open or close cursor statement node */ diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index 41cce851d87..efbc6d6facf 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -185,6 +185,10 @@ row_upd_index_replace_new_col_vals_index_pos( upd_t* update, /* in: an update vector built for the index so that the field number in an upd_field is the index position */ + ibool order_only, + /* in: if TRUE, limit the replacement to + ordering fields of index; note that this + does not work for non-clustered indexes. */ mem_heap_t* heap); /* in: memory heap to which we allocate and copy the new values, set this as NULL if you do not want allocation */ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 4278d602675..838b5b546c7 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -544,7 +544,9 @@ struct trx_struct{ the transaction; note that it is also in the lock list trx_locks */ dict_index_t* new_rec_locks[2];/* these are normally NULL; if - srv_locks_unsafe_for_binlog is TRUE, + srv_locks_unsafe_for_binlog is TRUE + or session is using READ COMMITTED + isolation level, in a cursor search, if we set a new record lock on an index, this is set to point to the index; this is diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index de57f6f07b8..5b294ae0769 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -82,10 +82,6 @@ memory is read outside the allocated blocks. */ /* Make a non-inline debug version */ -/* You can remove this define when the release is stable. This define adds -some consistency checks to code. They use a little CPU time. */ -#define UNIV_RELEASE_NOT_YET_STABLE - /* #define UNIV_DEBUG #define UNIV_MEM_DEBUG @@ -128,7 +124,7 @@ by one. */ #ifdef __WIN__ #define UNIV_INLINE __inline #else -#define UNIV_INLINE static inline +#define UNIV_INLINE static __inline__ #endif #else @@ -178,6 +174,16 @@ management to ensure correct alignment for doubles etc. */ /* Note that inside MySQL 'byte' is defined as char on Linux! */ #define byte unsigned char +/* Define an unsigned integer type that is exactly 32 bits. */ + +#if SIZEOF_INT == 4 +typedef unsigned int ib_uint32_t; +#elif SIZEOF_LONG == 4 +typedef unsigned long ib_uint32_t; +#else +#error "Neither int or long is 4 bytes" +#endif + /* Another basic type we use is unsigned long integer which should be equal to the word size of the machine, that is on a 32-bit platform 32 bits, and on a 64-bit platform 64 bits. We also give the printf format for the type as a @@ -205,9 +211,6 @@ typedef longlong ib_longlong; #endif #endif -/* The following type should be at least a 64-bit floating point number */ -typedef double utfloat; - /* The 'undefined' value for a ulint */ #define ULINT_UNDEFINED ((ulint)(-1)) diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h index 6e4a265349f..90c16f4fad5 100644 --- a/storage/innobase/include/ut0mem.h +++ b/storage/innobase/include/ut0mem.h @@ -181,6 +181,30 @@ ut_memcpyq( const char* src, /* in: string to be quoted */ ulint len); /* in: length of src */ +/************************************************************************** +Return the number of times s2 occurs in s1. Overlapping instances of s2 +are only counted once. */ + +ulint +ut_strcount( +/*========*/ + /* out: the number of times s2 occurs in s1 */ + const char* s1, /* in: string to search in */ + const char* s2); /* in: string to search for */ + +/************************************************************************** +Replace every occurrence of s1 in str with s2. Overlapping instances of s1 +are only replaced once. */ + +char * +ut_strreplace( +/*==========*/ + /* out, own: modified string, must be + freed with mem_free() */ + const char* str, /* in: string to operate on */ + const char* s1, /* in: string to replace */ + const char* s2); /* in: string to replace s1 with */ + #ifndef UNIV_NONINL #include "ut0mem.ic" #endif diff --git a/storage/innobase/include/ut0vec.h b/storage/innobase/include/ut0vec.h new file mode 100644 index 00000000000..e0cc4dfb009 --- /dev/null +++ b/storage/innobase/include/ut0vec.h @@ -0,0 +1,73 @@ +#ifndef IB_VECTOR_H +#define IB_VECTOR_H + +#include "univ.i" +#include "mem0mem.h" + +typedef struct ib_vector_struct ib_vector_t; + +/* An automatically resizing vector datatype with the following properties: + + -Contains void* items. + + -The items are owned by the caller. + + -All memory allocation is done through a heap owned by the caller, who is + responsible for freeing it when done with the vector. + + -When the vector is resized, the old memory area is left allocated since it + uses the same heap as the new memory area, so this is best used for + relatively small or short-lived uses. +*/ + +/******************************************************************** +Create a new vector with the given initial size. */ + +ib_vector_t* +ib_vector_create( +/*=============*/ + /* out: vector */ + mem_heap_t* heap, /* in: heap */ + ulint size); /* in: initial size */ + +/******************************************************************** +Push a new element to the vector, increasing its size if necessary. */ + +void +ib_vector_push( +/*===========*/ + ib_vector_t* vec, /* in: vector */ + void* elem); /* in: data element */ + +/******************************************************************** +Get the number of elements in the vector. */ +UNIV_INLINE +ulint +ib_vector_size( +/*===========*/ + /* out: number of elements in vector */ + ib_vector_t* vec); /* in: vector */ + +/******************************************************************** +Get the n'th element. */ +UNIV_INLINE +void* +ib_vector_get( +/*==========*/ + /* out: n'th element */ + ib_vector_t* vec, /* in: vector */ + ulint n); /* in: element index to get */ + +/* See comment at beginning of file. */ +struct ib_vector_struct { + mem_heap_t* heap; /* heap */ + void** data; /* data elements */ + ulint used; /* number of elements currently used */ + ulint total; /* number of elements allocated */ +}; + +#ifndef UNIV_NONINL +#include "ut0vec.ic" +#endif + +#endif diff --git a/storage/innobase/include/ut0vec.ic b/storage/innobase/include/ut0vec.ic new file mode 100644 index 00000000000..417a17d951f --- /dev/null +++ b/storage/innobase/include/ut0vec.ic @@ -0,0 +1,26 @@ +/******************************************************************** +Get number of elements in vector. */ +UNIV_INLINE +ulint +ib_vector_size( +/*===========*/ + /* out: number of elements in vector */ + ib_vector_t* vec) /* in: vector */ +{ + return(vec->used); +} + +/******************************************************************** +Get n'th element. */ +UNIV_INLINE +void* +ib_vector_get( +/*==========*/ + /* out: n'th element */ + ib_vector_t* vec, /* in: vector */ + ulint n) /* in: element index to get */ +{ + ut_a(n < vec->used); + + return(vec->data[n]); +} diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c index 1152e0c89ea..34e3296c9bc 100644 --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -1698,6 +1698,40 @@ lock_sec_rec_some_has_impl_off_kernel( return(row_vers_impl_x_locked_off_kernel(rec, index, offsets)); } +/************************************************************************* +Return approximate number or record locks (bits set in the bitmap) for +this transaction. Since delete-marked records may be removed, the +record count will not be precise. */ + +ulint +lock_number_of_rows_locked( +/*=======================*/ + trx_t* trx) /* in: transaction */ +{ + lock_t* lock; + ulint n_records = 0; + ulint n_bits; + ulint n_bit; + + lock = UT_LIST_GET_FIRST(trx->trx_locks); + + while (lock) { + if (lock_get_type(lock) == LOCK_REC) { + n_bits = lock_rec_get_n_bits(lock); + + for (n_bit = 0; n_bit < n_bits; n_bit++) { + if (lock_rec_get_nth_bit(lock, n_bit)) { + n_records++; + } + } + } + + lock = UT_LIST_GET_NEXT(trx_locks, lock); + } + + return (n_records); +} + /*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/ /************************************************************************* @@ -2001,7 +2035,8 @@ lock_rec_lock_fast( if (!impl) { lock_rec_create(mode, rec, index, trx); - if (srv_locks_unsafe_for_binlog) { + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { trx_register_new_rec_lock(trx, index); } } @@ -2027,7 +2062,8 @@ lock_rec_lock_fast( if (!lock_rec_get_nth_bit(lock, heap_no)) { lock_rec_set_nth_bit(lock, heap_no); - if (srv_locks_unsafe_for_binlog) { + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { trx_register_new_rec_lock(trx, index); } } @@ -2087,7 +2123,8 @@ lock_rec_lock_slow( err = lock_rec_enqueue_waiting(mode, rec, index, thr); - if (srv_locks_unsafe_for_binlog) { + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { trx_register_new_rec_lock(trx, index); } } else { @@ -2096,7 +2133,8 @@ lock_rec_lock_slow( lock_rec_add_to_queue(LOCK_REC | mode, rec, index, trx); - if (srv_locks_unsafe_for_binlog) { + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { trx_register_new_rec_lock(trx, index); } } @@ -2436,15 +2474,18 @@ lock_rec_inherit_to_gap( lock = lock_rec_get_first(rec); - /* If srv_locks_unsafe_for_binlog is TRUE, we do not want locks set + /* If srv_locks_unsafe_for_binlog is TRUE or session is using + READ COMMITTED isolation level, we do not want locks set by an UPDATE or a DELETE to be inherited as gap type locks. But we DO want S-locks set by a consistency constraint to be inherited also then. */ while (lock != NULL) { if (!lock_rec_get_insert_intention(lock) - && !(srv_locks_unsafe_for_binlog - && lock_get_mode(lock) == LOCK_X)) { + && !((srv_locks_unsafe_for_binlog + || lock->trx->isolation_level == + TRX_ISO_READ_COMMITTED) + && lock_get_mode(lock) == LOCK_X)) { lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock) | LOCK_GAP, @@ -4320,6 +4361,10 @@ loop: (ulong) ut_dulint_get_low(trx->read_view->up_limit_id)); } + fprintf(file, + "Trx has approximately %lu row locks\n", + (ulong) lock_number_of_rows_locked(trx)); + if (trx->que_state == TRX_QUE_LOCK_WAIT) { fprintf(file, "------- TRX HAS BEEN WAITING %lu SEC FOR THIS LOCK TO BE GRANTED:\n", @@ -5167,3 +5212,4 @@ lock_clust_rec_read_check_and_lock_alt( } return(ret); } + diff --git a/storage/innobase/log/log0recv.c b/storage/innobase/log/log0recv.c index f210afe6b5d..2457ca76e72 100644 --- a/storage/innobase/log/log0recv.c +++ b/storage/innobase/log/log0recv.c @@ -897,9 +897,9 @@ recv_parse_or_apply_log_rec_body( ut_ad(!page || ptr); if (index) { dict_table_t* table = index->table; - mem_heap_free(index->heap); - mutex_free(&(table->autoinc_mutex)); - mem_heap_free(table->heap); + + dict_mem_index_free(index); + dict_mem_table_free(table); } return(ptr); diff --git a/storage/innobase/mem/mem0dbg.c b/storage/innobase/mem/mem0dbg.c index 86d5beb9c80..86c33a22531 100644 --- a/storage/innobase/mem/mem0dbg.c +++ b/storage/innobase/mem/mem0dbg.c @@ -445,7 +445,7 @@ mem_heap_validate_or_print( && (mem_block_get_len(block) > UNIV_PAGE_SIZE)) { fprintf(stderr, -"InnoDB: Error: mem block %p length %lu > UNIV_PAGE_SIZE\n", block, +"InnoDB: Error: mem block %p length %lu > UNIV_PAGE_SIZE\n", (void*) block, (ulong) mem_block_get_len(block)); /* error */ diff --git a/storage/innobase/mem/mem0mem.c b/storage/innobase/mem/mem0mem.c index 90d3f4fa6b1..5e7c48d3d3d 100644 --- a/storage/innobase/mem/mem0mem.c +++ b/storage/innobase/mem/mem0mem.c @@ -114,6 +114,31 @@ mem_heap_strdup( return(memcpy(mem_heap_alloc(heap, len), str, len)); } +/************************************************************************** +Concatenate two strings and return the result, using a memory heap. */ + +char* +mem_heap_strcat( +/*============*/ + /* out, own: the result */ + mem_heap_t* heap, /* in: memory heap where string is allocated */ + const char* s1, /* in: string 1 */ + const char* s2) /* in: string 2 */ +{ + char* s; + ulint s1_len = strlen(s1); + ulint s2_len = strlen(s2); + + s = mem_heap_alloc(heap, s1_len + s2_len + 1); + + memcpy(s, s1, s1_len); + memcpy(s + s1_len, s2, s2_len); + + s[s1_len + s2_len] = '\0'; + + return(s); +} + /******************************************************************* Creates a memory heap block where data can be allocated. */ diff --git a/storage/innobase/os/os0sync.c b/storage/innobase/os/os0sync.c index 706c10ac613..eceedcb66b2 100644 --- a/storage/innobase/os/os0sync.c +++ b/storage/innobase/os/os0sync.c @@ -641,7 +641,7 @@ os_fast_mutex_free( " InnoDB: error: return value %lu when calling\n" "InnoDB: pthread_mutex_destroy().\n", (ulint)ret); fprintf(stderr, -"InnoDB: Byte contents of the pthread mutex at %p:\n", fast_mutex); +"InnoDB: Byte contents of the pthread mutex at %p:\n", (void*) fast_mutex); ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t)); fprintf(stderr, "\n"); } diff --git a/storage/innobase/pars/lexyy.c b/storage/innobase/pars/lexyy.c index d64ecbbfcbc..bbe78db1613 100644 --- a/storage/innobase/pars/lexyy.c +++ b/storage/innobase/pars/lexyy.c @@ -1,7 +1,7 @@ - -#line 3 "lex.yy.c" - #include "univ.i" +#line 2 "_flex_tmp.c" + +#line 4 "_flex_tmp.c" #define YY_INT_ALIGNED short int @@ -356,8 +356,8 @@ static void yy_fatal_error (yyconst char msg[] ); *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 109 -#define YY_END_OF_BUFFER 110 +#define YY_NUM_RULES 116 +#define YY_END_OF_BUFFER 117 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -365,48 +365,52 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[370] = +static yyconst flex_int16_t yy_accept[394] = { 0, - 0, 0, 104, 104, 0, 0, 110, 108, 107, 107, - 99, 3, 88, 94, 97, 95, 92, 96, 108, 98, - 1, 108, 93, 91, 89, 90, 102, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 82, 82, 82, 82, 100, 101, 104, 105, 4, - 5, 107, 83, 103, 2, 1, 84, 85, 87, 86, - 82, 82, 82, 82, 82, 82, 40, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 23, 12, 20, 82, 82, 82, 82, 50, 57, - 82, 9, 82, 82, 82, 82, 82, 82, 82, 82, + 0, 0, 111, 111, 0, 0, 0, 0, 117, 115, + 114, 114, 7, 106, 4, 95, 101, 104, 102, 99, + 103, 115, 105, 1, 115, 100, 98, 96, 97, 109, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 107, 108, + 111, 112, 5, 6, 8, 9, 114, 90, 110, 2, + 1, 3, 91, 92, 94, 93, 89, 89, 89, 89, + 89, 89, 44, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 27, + 16, 24, 89, 89, 89, 89, 54, 61, 89, 13, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 104, - 105, 105, 106, 4, 5, 2, 8, 41, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 22, 82, 82, 36, - 82, 82, 82, 16, 82, 82, 10, 82, 82, 82, - 13, 82, 82, 82, 82, 82, 76, 82, 82, 82, - 47, 7, 82, 31, 82, 82, 82, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 15, 19, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 42, 82, 82, 25, 82, 82, 82, 34, 82, 82, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 111, 112, 112, + 113, 5, 6, 8, 9, 2, 12, 45, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 26, 89, 89, 89, + 40, 89, 89, 89, 89, 20, 89, 89, 14, 89, + 89, 89, 17, 89, 89, 89, 89, 89, 80, 89, + 89, 89, 51, 11, 89, 35, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 19, 23, 89, 89, 89, 89, 89, 89, 89, 89, - 82, 82, 44, 82, 27, 82, 6, 60, 82, 82, - 82, 38, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 24, 82, 82, 82, 82, 82, 82, 82, 82, - 81, 82, 21, 82, 62, 82, 82, 82, 82, 32, - 82, 82, 82, 82, 82, 82, 82, 26, 61, 18, - 53, 82, 71, 82, 82, 82, 39, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 52, 82, 82, - 82, 82, 82, 82, 35, 28, 75, 14, 82, 79, - 70, 82, 51, 82, 59, 82, 48, 82, 82, 43, - 82, 72, 82, 74, 82, 82, 29, 82, 82, 82, + 89, 89, 89, 46, 89, 89, 29, 89, 87, 89, + 89, 38, 89, 89, 89, 89, 89, 48, 89, 31, + 89, 10, 64, 89, 89, 89, 42, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 28, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 85, 89, 25, 89, + 66, 89, 89, 89, 89, 36, 89, 89, 89, 89, + 89, 89, 89, 30, 65, 22, 89, 57, 89, 75, + 89, 89, 89, 43, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 56, 89, 89, 89, 89, 89, + 89, 89, 39, 32, 79, 18, 89, 83, 74, 89, + + 55, 89, 63, 89, 52, 89, 89, 89, 47, 89, + 76, 89, 78, 89, 89, 33, 89, 89, 89, 34, + 72, 89, 89, 89, 89, 58, 89, 50, 49, 89, + 89, 89, 53, 62, 89, 89, 89, 21, 89, 89, + 73, 81, 89, 89, 77, 89, 68, 89, 89, 89, + 89, 89, 37, 89, 88, 67, 89, 84, 89, 89, + 89, 86, 89, 59, 89, 89, 15, 89, 70, 69, + 89, 41, 89, 82, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 71, 89, 89, 89, 89, 89, + 89, 60, 0 - 30, 68, 82, 82, 82, 82, 54, 46, 45, 82, - 82, 82, 49, 58, 82, 82, 17, 82, 82, 69, - 77, 82, 82, 73, 82, 64, 82, 82, 82, 82, - 33, 82, 63, 82, 80, 82, 82, 82, 82, 55, - 82, 82, 11, 82, 66, 65, 82, 37, 82, 78, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 67, 82, 82, 82, 82, 82, 82, 56, 0 } ; static yyconst flex_int32_t yy_ec[256] = @@ -414,17 +418,17 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 1, 1, 1, 1, 4, 1, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 15, 16, 17, - 18, 19, 20, 1, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 30, - 1, 1, 1, 1, 46, 1, 30, 30, 30, 30, + 1, 2, 1, 4, 1, 1, 5, 1, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 16, 17, 18, + 19, 20, 21, 1, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 31, + 1, 1, 1, 1, 47, 1, 31, 31, 31, 31, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 47, 1, 48, 1, 1, 1, 1, 1, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 48, 1, 49, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -441,209 +445,229 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[49] = +static yyconst flex_int32_t yy_meta[50] = { 0, - 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, - 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 1, 1 + 1, 1, 1, 2, 1, 3, 1, 1, 4, 1, + 1, 1, 1, 1, 5, 1, 1, 1, 6, 1, + 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 1, 1 } ; -static yyconst flex_int16_t yy_base[376] = +static yyconst flex_int16_t yy_base[403] = { 0, - 0, 0, 390, 389, 391, 390, 394, 399, 47, 49, - 399, 399, 399, 399, 399, 399, 399, 399, 381, 384, - 41, 373, 399, 38, 399, 372, 399, 20, 33, 32, - 46, 29, 44, 0, 46, 49, 42, 60, 351, 65, - 66, 67, 32, 367, 69, 399, 399, 0, 79, 0, - 382, 103, 399, 399, 372, 96, 399, 399, 399, 399, - 0, 361, 70, 357, 349, 347, 0, 360, 77, 80, - 355, 341, 92, 339, 352, 337, 351, 334, 338, 334, - 336, 0, 93, 0, 336, 334, 328, 335, 0, 0, - 341, 341, 324, 87, 98, 339, 93, 88, 330, 104, + 0, 0, 434, 433, 435, 434, 435, 434, 437, 444, + 48, 50, 444, 444, 444, 444, 444, 444, 444, 444, + 444, 423, 426, 41, 415, 444, 38, 444, 414, 444, + 20, 33, 32, 46, 40, 44, 0, 54, 52, 48, + 60, 393, 65, 66, 74, 27, 409, 69, 444, 444, + 0, 97, 0, 424, 0, 425, 111, 444, 444, 413, + 54, 408, 444, 444, 444, 444, 0, 401, 69, 397, + 389, 387, 0, 400, 79, 82, 395, 381, 94, 379, + 392, 377, 391, 385, 373, 377, 373, 375, 375, 0, + 82, 0, 374, 372, 366, 373, 0, 0, 379, 379, - 322, 338, 334, 312, 328, 332, 323, 98, 316, 0, - 122, 131, 399, 0, 348, 338, 0, 0, 326, 321, - 328, 326, 309, 307, 306, 311, 106, 309, 321, 102, - 309, 315, 316, 298, 298, 117, 0, 313, 314, 0, - 301, 308, 118, 122, 305, 295, 304, 297, 294, 302, - 0, 292, 302, 300, 291, 281, 275, 288, 273, 293, - 0, 0, 278, 0, 292, 283, 280, 126, 276, 291, - 270, 272, 277, 277, 269, 272, 267, 0, 0, 279, - 263, 273, 280, 271, 259, 258, 272, 261, 274, 254, - 0, 264, 246, 0, 265, 262, 249, 0, 244, 249, + 362, 89, 98, 377, 93, 95, 368, 106, 360, 376, + 372, 350, 101, 371, 362, 112, 355, 0, 134, 135, + 444, 0, 387, 0, 388, 376, 0, 0, 364, 359, + 366, 364, 347, 345, 344, 349, 106, 347, 359, 93, + 347, 353, 354, 336, 336, 121, 0, 334, 350, 351, + 0, 338, 347, 344, 119, 126, 341, 331, 340, 333, + 330, 338, 0, 328, 338, 336, 327, 317, 311, 324, + 309, 329, 0, 0, 314, 0, 328, 319, 316, 130, + 312, 319, 326, 305, 307, 312, 312, 304, 307, 302, + 0, 0, 314, 298, 308, 315, 306, 294, 293, 307, - 248, 258, 0, 244, 0, 248, 0, 0, 244, 241, - 255, 0, 240, 240, 238, 254, 239, 251, 233, 251, - 246, 0, 241, 241, 227, 226, 226, 240, 239, 238, - 0, 222, 0, 216, 0, 235, 219, 218, 218, 0, - 231, 221, 216, 215, 227, 217, 216, 0, 0, 0, - 0, 209, 0, 223, 219, 205, 0, 219, 220, 203, - 208, 201, 219, 201, 198, 199, 196, 0, 201, 213, - 200, 207, 206, 191, 0, 0, 0, 183, 190, 0, - 0, 187, 0, 186, 0, 200, 0, 201, 188, 0, - 184, 0, 187, 0, 179, 181, 0, 180, 194, 187, + 296, 309, 289, 0, 299, 281, 0, 300, 0, 297, + 284, 0, 283, 278, 283, 282, 292, 0, 278, 0, + 282, 0, 0, 278, 275, 289, 0, 274, 274, 272, + 288, 273, 285, 267, 285, 280, 0, 275, 275, 261, + 260, 273, 259, 273, 272, 271, 0, 255, 0, 249, + 0, 268, 252, 251, 251, 0, 264, 254, 249, 248, + 260, 250, 249, 0, 0, 0, 253, 0, 241, 0, + 255, 251, 237, 0, 251, 252, 235, 240, 233, 251, + 233, 230, 231, 228, 0, 233, 245, 232, 239, 229, + 237, 222, 0, 0, 0, 214, 221, 0, 0, 218, - 0, 0, 190, 193, 175, 190, 0, 0, 0, 171, - 185, 184, 0, 0, 168, 167, 0, 182, 167, 0, - 0, 173, 169, 0, 164, 0, 176, 165, 175, 164, - 0, 151, 0, 171, 0, 155, 149, 155, 146, 0, - 151, 164, 0, 163, 0, 0, 154, 0, 158, 0, - 145, 145, 151, 137, 160, 152, 153, 137, 121, 110, - 0, 122, 129, 120, 117, 113, 105, 0, 399, 160, - 164, 85, 168, 172, 176 + 0, 217, 0, 231, 0, 232, 219, 218, 0, 214, + 0, 217, 0, 209, 211, 0, 210, 224, 217, 0, + 0, 220, 223, 205, 220, 0, 216, 0, 0, 200, + 214, 213, 0, 0, 197, 196, 201, 0, 210, 195, + 0, 0, 201, 197, 0, 192, 0, 204, 204, 192, + 202, 191, 0, 178, 0, 0, 198, 0, 182, 176, + 182, 0, 173, 0, 178, 191, 0, 190, 0, 0, + 181, 0, 185, 0, 172, 172, 178, 164, 187, 175, + 174, 154, 125, 116, 0, 127, 133, 124, 121, 117, + 109, 0, 444, 165, 171, 177, 179, 145, 185, 191, + + 197, 203 } ; -static yyconst flex_int16_t yy_def[376] = +static yyconst flex_int16_t yy_def[403] = { 0, - 369, 1, 370, 370, 371, 371, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 369, 369, 373, 374, 375, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, + 393, 1, 394, 394, 395, 395, 396, 396, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 397, 393, 393, 393, 393, 393, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 393, 393, + 399, 400, 401, 393, 402, 393, 393, 393, 393, 393, + 393, 397, 393, 393, 393, 393, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 373, - 374, 374, 369, 375, 369, 369, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 399, 400, 400, + 393, 401, 393, 402, 393, 393, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 0, 369, - 369, 369, 369, 369, 369 + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, + 398, 398, 0, 393, 393, 393, 393, 393, 393, 393, + + 393, 393 } ; -static yyconst flex_int16_t yy_nxt[448] = +static yyconst flex_int16_t yy_nxt[494] = { 0, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 34, 35, 34, - 34, 36, 34, 37, 38, 39, 34, 40, 41, 42, - 43, 44, 45, 34, 34, 34, 46, 47, 52, 52, - 52, 52, 55, 62, 56, 58, 59, 64, 63, 68, - 76, 65, 77, 69, 66, 105, 70, 106, 78, 71, - 73, 82, 72, 85, 74, 79, 87, 67, 80, 83, - 75, 81, 88, 86, 84, 89, 112, 102, 61, 95, - 98, 113, 118, 90, 103, 91, 108, 92, 96, 97, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, + 37, 37, 39, 37, 40, 41, 42, 37, 43, 44, + 45, 46, 47, 48, 37, 37, 37, 49, 50, 57, + 57, 57, 57, 60, 68, 61, 64, 65, 70, 69, + 74, 113, 71, 114, 75, 72, 60, 76, 61, 85, + 77, 79, 82, 78, 83, 80, 86, 93, 73, 87, + 90, 81, 88, 95, 84, 89, 97, 94, 91, 96, + 103, 106, 128, 92, 98, 110, 99, 116, 100, 104, - 93, 104, 99, 109, 52, 52, 100, 55, 119, 56, - 101, 124, 126, 127, 131, 152, 142, 125, 154, 160, - 128, 153, 172, 132, 158, 163, 173, 161, 183, 369, - 133, 143, 144, 155, 369, 159, 164, 156, 112, 187, - 188, 194, 200, 113, 184, 195, 202, 223, 224, 368, - 367, 366, 365, 364, 363, 362, 203, 201, 361, 225, - 48, 48, 48, 48, 50, 50, 50, 50, 110, 110, - 360, 110, 111, 111, 111, 111, 114, 359, 114, 114, - 358, 357, 356, 355, 354, 353, 352, 351, 350, 349, - 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, + 105, 101, 111, 107, 117, 120, 154, 108, 129, 112, + 121, 109, 57, 57, 134, 136, 137, 141, 164, 166, + 135, 155, 156, 138, 165, 170, 142, 172, 175, 196, + 181, 200, 201, 143, 167, 173, 171, 185, 168, 176, + 182, 186, 393, 120, 215, 197, 207, 393, 121, 67, + 208, 217, 238, 239, 392, 391, 390, 389, 388, 216, + 387, 218, 386, 385, 240, 51, 51, 51, 51, 51, + 51, 53, 53, 53, 53, 53, 53, 55, 55, 55, + 55, 55, 55, 62, 62, 118, 118, 118, 384, 118, + 118, 119, 119, 119, 119, 119, 119, 122, 122, 383, - 338, 337, 336, 335, 334, 333, 332, 331, 330, 329, - 328, 327, 326, 325, 324, 323, 322, 321, 320, 319, - 318, 317, 316, 315, 314, 313, 312, 311, 310, 309, - 308, 307, 306, 305, 304, 303, 302, 301, 300, 299, - 298, 297, 296, 295, 294, 293, 292, 291, 290, 289, - 288, 287, 286, 285, 284, 283, 282, 281, 280, 279, - 278, 277, 276, 275, 274, 273, 272, 271, 270, 269, - 268, 267, 266, 265, 264, 263, 262, 261, 260, 259, - 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, - 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, + 122, 122, 122, 124, 382, 124, 124, 124, 124, 381, + 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, + 370, 369, 368, 367, 366, 365, 364, 363, 362, 361, + 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, + 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, + 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, + 330, 329, 328, 327, 326, 325, 324, 323, 322, 321, + 320, 319, 318, 317, 316, 315, 314, 313, 312, 311, + 310, 309, 308, 307, 306, 305, 304, 303, 302, 301, + 300, 299, 298, 297, 296, 295, 294, 293, 292, 291, - 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, - 228, 227, 226, 222, 221, 220, 219, 218, 217, 216, - 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, - 205, 204, 199, 198, 197, 196, 193, 192, 191, 190, - 189, 186, 185, 182, 181, 180, 179, 178, 177, 176, - 175, 116, 115, 174, 171, 170, 169, 168, 167, 166, - 165, 162, 157, 151, 150, 149, 148, 147, 146, 145, - 141, 140, 139, 138, 137, 136, 135, 134, 130, 129, - 123, 122, 121, 120, 117, 116, 115, 107, 94, 60, - 57, 54, 53, 369, 51, 51, 49, 49, 7, 369, + 290, 289, 288, 287, 286, 285, 284, 283, 282, 281, + 280, 279, 278, 277, 276, 275, 274, 273, 272, 271, + 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, + 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, + 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, + 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, + 227, 226, 225, 224, 223, 222, 221, 220, 219, 214, + 213, 212, 211, 210, 209, 206, 205, 204, 203, 202, + 199, 198, 195, 194, 193, 192, 191, 190, 189, 188, + 126, 125, 123, 187, 184, 183, 180, 179, 178, 177, + + 174, 169, 163, 162, 161, 160, 159, 158, 157, 153, + 152, 151, 150, 149, 148, 147, 146, 145, 144, 140, + 139, 133, 132, 131, 130, 127, 393, 126, 125, 123, + 115, 102, 66, 63, 59, 58, 393, 56, 56, 54, + 54, 52, 52, 9, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393 - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369 } ; -static yyconst flex_int16_t yy_chk[448] = +static yyconst flex_int16_t yy_chk[494] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, - 10, 10, 21, 28, 21, 24, 24, 29, 28, 30, - 32, 29, 32, 30, 29, 43, 30, 43, 33, 30, - 31, 35, 30, 36, 31, 33, 37, 29, 33, 35, - 31, 33, 37, 36, 35, 38, 49, 42, 372, 40, - 41, 49, 63, 38, 42, 38, 45, 38, 40, 40, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, + 11, 12, 12, 24, 31, 24, 27, 27, 32, 31, + 33, 46, 32, 46, 33, 32, 61, 33, 61, 36, + 33, 34, 35, 33, 35, 34, 36, 39, 32, 36, + 38, 34, 36, 40, 35, 36, 41, 39, 38, 40, + 43, 44, 69, 38, 41, 45, 41, 48, 41, 43, - 38, 42, 41, 45, 52, 52, 41, 56, 63, 56, - 41, 69, 70, 70, 73, 94, 83, 69, 95, 98, - 70, 94, 108, 73, 97, 100, 108, 98, 127, 111, - 73, 83, 83, 95, 111, 97, 100, 95, 112, 130, - 130, 136, 143, 112, 127, 136, 144, 168, 168, 367, - 366, 365, 364, 363, 362, 360, 144, 143, 359, 168, - 370, 370, 370, 370, 371, 371, 371, 371, 373, 373, - 358, 373, 374, 374, 374, 374, 375, 357, 375, 375, - 356, 355, 354, 353, 352, 351, 349, 347, 344, 342, - 341, 339, 338, 337, 336, 334, 332, 330, 329, 328, + 43, 41, 45, 44, 48, 52, 91, 44, 69, 45, + 52, 44, 57, 57, 75, 76, 76, 79, 102, 103, + 75, 91, 91, 76, 102, 105, 79, 106, 108, 137, + 113, 140, 140, 79, 103, 106, 105, 116, 103, 108, + 113, 116, 119, 120, 155, 137, 146, 119, 120, 398, + 146, 156, 180, 180, 391, 390, 389, 388, 387, 155, + 386, 156, 384, 383, 180, 394, 394, 394, 394, 394, + 394, 395, 395, 395, 395, 395, 395, 396, 396, 396, + 396, 396, 396, 397, 397, 399, 399, 399, 382, 399, + 399, 400, 400, 400, 400, 400, 400, 401, 401, 381, - 327, 325, 323, 322, 319, 318, 316, 315, 312, 311, - 310, 306, 305, 304, 303, 300, 299, 298, 296, 295, - 293, 291, 289, 288, 286, 284, 282, 279, 278, 274, - 273, 272, 271, 270, 269, 267, 266, 265, 264, 263, - 262, 261, 260, 259, 258, 256, 255, 254, 252, 247, - 246, 245, 244, 243, 242, 241, 239, 238, 237, 236, - 234, 232, 230, 229, 228, 227, 226, 225, 224, 223, - 221, 220, 219, 218, 217, 216, 215, 214, 213, 211, - 210, 209, 206, 204, 202, 201, 200, 199, 197, 196, - 195, 193, 192, 190, 189, 188, 187, 186, 185, 184, + 401, 401, 401, 402, 380, 402, 402, 402, 402, 379, + 378, 377, 376, 375, 373, 371, 368, 366, 365, 363, + 361, 360, 359, 357, 354, 352, 351, 350, 349, 348, + 346, 344, 343, 340, 339, 337, 336, 335, 332, 331, + 330, 327, 325, 324, 323, 322, 319, 318, 317, 315, + 314, 312, 310, 308, 307, 306, 304, 302, 300, 297, + 296, 292, 291, 290, 289, 288, 287, 286, 284, 283, + 282, 281, 280, 279, 278, 277, 276, 275, 273, 272, + 271, 269, 267, 263, 262, 261, 260, 259, 258, 257, + 255, 254, 253, 252, 250, 248, 246, 245, 244, 243, - 183, 182, 181, 180, 177, 176, 175, 174, 173, 172, - 171, 170, 169, 167, 166, 165, 163, 160, 159, 158, - 157, 156, 155, 154, 153, 152, 150, 149, 148, 147, - 146, 145, 142, 141, 139, 138, 135, 134, 133, 132, - 131, 129, 128, 126, 125, 124, 123, 122, 121, 120, - 119, 116, 115, 109, 107, 106, 105, 104, 103, 102, - 101, 99, 96, 93, 92, 91, 88, 87, 86, 85, - 81, 80, 79, 78, 77, 76, 75, 74, 72, 71, - 68, 66, 65, 64, 62, 55, 51, 44, 39, 26, - 22, 20, 19, 7, 6, 5, 4, 3, 369, 369, + 242, 241, 240, 239, 238, 236, 235, 234, 233, 232, + 231, 230, 229, 228, 226, 225, 224, 221, 219, 217, + 216, 215, 214, 213, 211, 210, 208, 206, 205, 203, + 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, + 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, + 179, 178, 177, 175, 172, 171, 170, 169, 168, 167, + 166, 165, 164, 162, 161, 160, 159, 158, 157, 154, + 153, 152, 150, 149, 148, 145, 144, 143, 142, 141, + 139, 138, 136, 135, 134, 133, 132, 131, 130, 129, + 126, 125, 123, 117, 115, 114, 112, 111, 110, 109, + + 107, 104, 101, 100, 99, 96, 95, 94, 93, 89, + 88, 87, 86, 85, 84, 83, 82, 81, 80, 78, + 77, 74, 72, 71, 70, 68, 62, 60, 56, 54, + 47, 42, 29, 25, 23, 22, 9, 8, 7, 6, + 5, 4, 3, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393, 393, 393, 393, 393, 393, 393, 393, + 393, 393, 393 - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369 } ; static yy_state_type yy_last_accepting_state; @@ -675,34 +699,16 @@ not automatically generate them from pars0grm.y and pars0lex.l. How to make the InnoDB parser and lexer C files: -1. First do - bison -d pars0grm.y - That generates pars0grm.tab.c and pars0grm.tab.h. +1. Run ./make_flex.sh to generate lexer files. -2. Rename pars0grm.tab.c to pars0grm.c and pars0grm.tab.h to pars0grm.h. +2. Run ./make_bison.sh to generate parser files. -3. Copy pars0grm.h also to /innobase/include - -4. Do - flex pars0lex.l - That generates lex.yy.c. - -5. Rename lex.yy.c to lexyy.c. - -6. Remove the #include of unistd.h from about line 2500 of lexyy.c - -7. Add '#include "univ.i"' before #include in lexyy.c - (Needed for AIX) - -8. Add a type cast to int to the assignment below the comment - 'need more input.' (Removes a warning on Win64) - -These instructions seem to work at least with bison-1.28 and flex-2.5.4 on +These instructions seem to work at least with bison-1.875d and flex-2.5.31 on Linux. *******************************************************/ #define YY_NO_INPUT 1 #define YY_NO_UNISTD_H 1 -#line 56 "pars0lex.l" +#line 38 "pars0lex.l" #define YYSTYPE que_node_t* #include "univ.i" @@ -749,11 +755,13 @@ string_append( -#line 751 "lex.yy.c" + +#line 759 "_flex_tmp.c" #define INITIAL 0 #define comment 1 #define quoted 2 +#define id 3 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way @@ -900,10 +908,10 @@ YY_DECL register char *yy_cp, *yy_bp; register int yy_act; -#line 106 "pars0lex.l" +#line 91 "pars0lex.l" -#line 905 "lex.yy.c" +#line 914 "_flex_tmp.c" if ( (yy_init) ) { @@ -956,13 +964,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 370 ) + if ( yy_current_state >= 394 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_current_state != 369 ); + while ( yy_current_state != 393 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); @@ -984,7 +992,7 @@ do_action: /* This label is used only to access EOF actions. */ case 1: YY_RULE_SETUP -#line 108 "pars0lex.l" +#line 93 "pars0lex.l" { yylval = sym_tab_add_int_lit(pars_sym_tab_global, atoi(yytext)); @@ -993,7 +1001,7 @@ YY_RULE_SETUP YY_BREAK case 2: YY_RULE_SETUP -#line 114 "pars0lex.l" +#line 99 "pars0lex.l" { ut_error; /* not implemented */ @@ -1002,7 +1010,19 @@ YY_RULE_SETUP YY_BREAK case 3: YY_RULE_SETUP -#line 120 "pars0lex.l" +#line 105 "pars0lex.l" +{ + ulint type; + + yylval = sym_tab_add_bound_lit(pars_sym_tab_global, + yytext + 1, &type); + + return(type); +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 114 "pars0lex.l" { /* Quoted character string literals are handled in an explicit start state 'quoted'. This state is entered and the buffer for @@ -1013,19 +1033,19 @@ In the state 'quoted', only two actions are possible (defined below). */ stringbuf_len = 0; } YY_BREAK -case 4: -/* rule 4 can match eol */ +case 5: +/* rule 5 can match eol */ YY_RULE_SETUP -#line 129 "pars0lex.l" +#line 123 "pars0lex.l" { /* Got a sequence of characters other than "'": append to string buffer */ string_append(yytext, yyleng); } YY_BREAK -case 5: +case 6: YY_RULE_SETUP -#line 134 "pars0lex.l" +#line 128 "pars0lex.l" { /* Got a sequence of "'" characters: append half of them to string buffer, @@ -1050,18 +1070,69 @@ YY_RULE_SETUP } } YY_BREAK -case 6: +case 7: YY_RULE_SETUP -#line 158 "pars0lex.l" +#line 152 "pars0lex.l" +{ +/* Quoted identifiers are handled in an explicit start state 'id'. +This state is entered and the buffer for the scanned string is emptied +upon encountering a starting quote. + +In the state 'id', only two actions are possible (defined below). */ + BEGIN(id); + stringbuf_len = 0; +} + YY_BREAK +case 8: +/* rule 8 can match eol */ +YY_RULE_SETUP +#line 161 "pars0lex.l" +{ + /* Got a sequence of characters other than '"': + append to string buffer */ + string_append(yytext, yyleng); +} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 166 "pars0lex.l" +{ + /* Got a sequence of '"' characters: + append half of them to string buffer, + as '""' represents a single '"'. + We apply truncating division, + so that '"""' will result in '"'. */ + + string_append(yytext, yyleng / 2); + + /* If we got an odd number of quotes, then the + last quote we got is the terminating quote. + At the end of the string, we return to the + initial start state and report the scanned + identifier. */ + + if (yyleng % 2) { + BEGIN(INITIAL); + yylval = sym_tab_add_id( + pars_sym_tab_global, + (byte*) stringbuf, stringbuf_len); + + return(PARS_ID_TOKEN); + } +} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 191 "pars0lex.l" { yylval = sym_tab_add_null_lit(pars_sym_tab_global); return(PARS_NULL_LIT); } YY_BREAK -case 7: +case 11: YY_RULE_SETUP -#line 164 "pars0lex.l" +#line 197 "pars0lex.l" { /* Implicit cursor name */ yylval = sym_tab_add_str_lit(pars_sym_tab_global, @@ -1069,527 +1140,548 @@ YY_RULE_SETUP return(PARS_SQL_TOKEN); } YY_BREAK -case 8: +case 12: YY_RULE_SETUP -#line 171 "pars0lex.l" +#line 204 "pars0lex.l" { return(PARS_AND_TOKEN); } YY_BREAK -case 9: +case 13: YY_RULE_SETUP -#line 175 "pars0lex.l" +#line 208 "pars0lex.l" { return(PARS_OR_TOKEN); } YY_BREAK -case 10: +case 14: YY_RULE_SETUP -#line 179 "pars0lex.l" +#line 212 "pars0lex.l" { return(PARS_NOT_TOKEN); } YY_BREAK -case 11: +case 15: YY_RULE_SETUP -#line 183 "pars0lex.l" +#line 216 "pars0lex.l" { return(PARS_PROCEDURE_TOKEN); } YY_BREAK -case 12: +case 16: YY_RULE_SETUP -#line 187 "pars0lex.l" +#line 220 "pars0lex.l" { return(PARS_IN_TOKEN); } YY_BREAK -case 13: +case 17: YY_RULE_SETUP -#line 191 "pars0lex.l" +#line 224 "pars0lex.l" { return(PARS_OUT_TOKEN); } YY_BREAK -case 14: +case 18: YY_RULE_SETUP -#line 195 "pars0lex.l" +#line 228 "pars0lex.l" { return(PARS_BINARY_TOKEN); } YY_BREAK -case 15: +case 19: YY_RULE_SETUP -#line 199 "pars0lex.l" +#line 232 "pars0lex.l" { return(PARS_BLOB_TOKEN); } YY_BREAK -case 16: -YY_RULE_SETUP -#line 203 "pars0lex.l" -{ - return(PARS_INT_TOKEN); -} - YY_BREAK -case 17: -YY_RULE_SETUP -#line 207 "pars0lex.l" -{ - return(PARS_INT_TOKEN); -} - YY_BREAK -case 18: -YY_RULE_SETUP -#line 211 "pars0lex.l" -{ - return(PARS_FLOAT_TOKEN); -} - YY_BREAK -case 19: -YY_RULE_SETUP -#line 215 "pars0lex.l" -{ - return(PARS_CHAR_TOKEN); -} - YY_BREAK case 20: YY_RULE_SETUP -#line 219 "pars0lex.l" +#line 236 "pars0lex.l" { - return(PARS_IS_TOKEN); + return(PARS_INT_TOKEN); } YY_BREAK case 21: YY_RULE_SETUP -#line 223 "pars0lex.l" +#line 240 "pars0lex.l" { - return(PARS_BEGIN_TOKEN); + return(PARS_INT_TOKEN); } YY_BREAK case 22: YY_RULE_SETUP -#line 227 "pars0lex.l" +#line 244 "pars0lex.l" { - return(PARS_END_TOKEN); + return(PARS_FLOAT_TOKEN); } YY_BREAK case 23: YY_RULE_SETUP -#line 231 "pars0lex.l" +#line 248 "pars0lex.l" { - return(PARS_IF_TOKEN); + return(PARS_CHAR_TOKEN); } YY_BREAK case 24: YY_RULE_SETUP -#line 235 "pars0lex.l" +#line 252 "pars0lex.l" { - return(PARS_THEN_TOKEN); + return(PARS_IS_TOKEN); } YY_BREAK case 25: YY_RULE_SETUP -#line 239 "pars0lex.l" +#line 256 "pars0lex.l" { - return(PARS_ELSE_TOKEN); + return(PARS_BEGIN_TOKEN); } YY_BREAK case 26: YY_RULE_SETUP -#line 243 "pars0lex.l" +#line 260 "pars0lex.l" { - return(PARS_ELSIF_TOKEN); + return(PARS_END_TOKEN); } YY_BREAK case 27: YY_RULE_SETUP -#line 247 "pars0lex.l" +#line 264 "pars0lex.l" { - return(PARS_LOOP_TOKEN); + return(PARS_IF_TOKEN); } YY_BREAK case 28: YY_RULE_SETUP -#line 251 "pars0lex.l" +#line 268 "pars0lex.l" { - return(PARS_WHILE_TOKEN); + return(PARS_THEN_TOKEN); } YY_BREAK case 29: YY_RULE_SETUP -#line 255 "pars0lex.l" +#line 272 "pars0lex.l" { - return(PARS_RETURN_TOKEN); + return(PARS_ELSE_TOKEN); } YY_BREAK case 30: YY_RULE_SETUP -#line 259 "pars0lex.l" +#line 276 "pars0lex.l" { - return(PARS_SELECT_TOKEN); + return(PARS_ELSIF_TOKEN); } YY_BREAK case 31: YY_RULE_SETUP -#line 263 "pars0lex.l" +#line 280 "pars0lex.l" { - return(PARS_SUM_TOKEN); + return(PARS_LOOP_TOKEN); } YY_BREAK case 32: YY_RULE_SETUP -#line 267 "pars0lex.l" +#line 284 "pars0lex.l" { - return(PARS_COUNT_TOKEN); + return(PARS_WHILE_TOKEN); } YY_BREAK case 33: YY_RULE_SETUP -#line 271 "pars0lex.l" +#line 288 "pars0lex.l" { - return(PARS_DISTINCT_TOKEN); + return(PARS_RETURN_TOKEN); } YY_BREAK case 34: YY_RULE_SETUP -#line 275 "pars0lex.l" +#line 292 "pars0lex.l" { - return(PARS_FROM_TOKEN); + return(PARS_SELECT_TOKEN); } YY_BREAK case 35: YY_RULE_SETUP -#line 279 "pars0lex.l" +#line 296 "pars0lex.l" { - return(PARS_WHERE_TOKEN); + return(PARS_SUM_TOKEN); } YY_BREAK case 36: YY_RULE_SETUP -#line 283 "pars0lex.l" +#line 300 "pars0lex.l" { - return(PARS_FOR_TOKEN); + return(PARS_COUNT_TOKEN); } YY_BREAK case 37: YY_RULE_SETUP -#line 287 "pars0lex.l" +#line 304 "pars0lex.l" { - return(PARS_CONSISTENT_TOKEN); + return(PARS_DISTINCT_TOKEN); } YY_BREAK case 38: YY_RULE_SETUP -#line 291 "pars0lex.l" +#line 308 "pars0lex.l" { - return(PARS_READ_TOKEN); + return(PARS_FROM_TOKEN); } YY_BREAK case 39: YY_RULE_SETUP -#line 295 "pars0lex.l" +#line 312 "pars0lex.l" { - return(PARS_ORDER_TOKEN); + return(PARS_WHERE_TOKEN); } YY_BREAK case 40: YY_RULE_SETUP -#line 299 "pars0lex.l" +#line 316 "pars0lex.l" { - return(PARS_BY_TOKEN); + return(PARS_FOR_TOKEN); } YY_BREAK case 41: YY_RULE_SETUP -#line 303 "pars0lex.l" +#line 320 "pars0lex.l" { - return(PARS_ASC_TOKEN); + return(PARS_CONSISTENT_TOKEN); } YY_BREAK case 42: YY_RULE_SETUP -#line 307 "pars0lex.l" +#line 324 "pars0lex.l" { - return(PARS_DESC_TOKEN); + return(PARS_READ_TOKEN); } YY_BREAK case 43: YY_RULE_SETUP -#line 311 "pars0lex.l" +#line 328 "pars0lex.l" { - return(PARS_INSERT_TOKEN); + return(PARS_ORDER_TOKEN); } YY_BREAK case 44: YY_RULE_SETUP -#line 315 "pars0lex.l" +#line 332 "pars0lex.l" { - return(PARS_INTO_TOKEN); + return(PARS_BY_TOKEN); } YY_BREAK case 45: YY_RULE_SETUP -#line 319 "pars0lex.l" +#line 336 "pars0lex.l" { - return(PARS_VALUES_TOKEN); + return(PARS_ASC_TOKEN); } YY_BREAK case 46: YY_RULE_SETUP -#line 323 "pars0lex.l" +#line 340 "pars0lex.l" { - return(PARS_UPDATE_TOKEN); + return(PARS_DESC_TOKEN); } YY_BREAK case 47: YY_RULE_SETUP -#line 327 "pars0lex.l" +#line 344 "pars0lex.l" { - return(PARS_SET_TOKEN); + return(PARS_INSERT_TOKEN); } YY_BREAK case 48: YY_RULE_SETUP -#line 331 "pars0lex.l" +#line 348 "pars0lex.l" { - return(PARS_DELETE_TOKEN); + return(PARS_INTO_TOKEN); } YY_BREAK case 49: YY_RULE_SETUP -#line 335 "pars0lex.l" +#line 352 "pars0lex.l" { - return(PARS_CURRENT_TOKEN); + return(PARS_VALUES_TOKEN); } YY_BREAK case 50: YY_RULE_SETUP -#line 339 "pars0lex.l" +#line 356 "pars0lex.l" { - return(PARS_OF_TOKEN); + return(PARS_UPDATE_TOKEN); } YY_BREAK case 51: YY_RULE_SETUP -#line 343 "pars0lex.l" +#line 360 "pars0lex.l" { - return(PARS_CREATE_TOKEN); + return(PARS_SET_TOKEN); } YY_BREAK case 52: YY_RULE_SETUP -#line 347 "pars0lex.l" +#line 364 "pars0lex.l" { - return(PARS_TABLE_TOKEN); + return(PARS_DELETE_TOKEN); } YY_BREAK case 53: YY_RULE_SETUP -#line 351 "pars0lex.l" +#line 368 "pars0lex.l" { - return(PARS_INDEX_TOKEN); + return(PARS_CURRENT_TOKEN); } YY_BREAK case 54: YY_RULE_SETUP -#line 355 "pars0lex.l" +#line 372 "pars0lex.l" { - return(PARS_UNIQUE_TOKEN); + return(PARS_OF_TOKEN); } YY_BREAK case 55: YY_RULE_SETUP -#line 359 "pars0lex.l" +#line 376 "pars0lex.l" { - return(PARS_CLUSTERED_TOKEN); + return(PARS_CREATE_TOKEN); } YY_BREAK case 56: YY_RULE_SETUP -#line 363 "pars0lex.l" +#line 380 "pars0lex.l" { - return(PARS_DOES_NOT_FIT_IN_MEM_TOKEN); + return(PARS_TABLE_TOKEN); } YY_BREAK case 57: YY_RULE_SETUP -#line 367 "pars0lex.l" +#line 384 "pars0lex.l" { - return(PARS_ON_TOKEN); + return(PARS_INDEX_TOKEN); } YY_BREAK case 58: YY_RULE_SETUP -#line 371 "pars0lex.l" +#line 388 "pars0lex.l" { - return(PARS_DECLARE_TOKEN); + return(PARS_UNIQUE_TOKEN); } YY_BREAK case 59: YY_RULE_SETUP -#line 375 "pars0lex.l" +#line 392 "pars0lex.l" { - return(PARS_CURSOR_TOKEN); + return(PARS_CLUSTERED_TOKEN); } YY_BREAK case 60: YY_RULE_SETUP -#line 379 "pars0lex.l" +#line 396 "pars0lex.l" { - return(PARS_OPEN_TOKEN); + return(PARS_DOES_NOT_FIT_IN_MEM_TOKEN); } YY_BREAK case 61: YY_RULE_SETUP -#line 383 "pars0lex.l" +#line 400 "pars0lex.l" { - return(PARS_FETCH_TOKEN); + return(PARS_ON_TOKEN); } YY_BREAK case 62: YY_RULE_SETUP -#line 387 "pars0lex.l" +#line 404 "pars0lex.l" { - return(PARS_CLOSE_TOKEN); + return(PARS_DECLARE_TOKEN); } YY_BREAK case 63: YY_RULE_SETUP -#line 391 "pars0lex.l" +#line 408 "pars0lex.l" { - return(PARS_NOTFOUND_TOKEN); + return(PARS_CURSOR_TOKEN); } YY_BREAK case 64: YY_RULE_SETUP -#line 395 "pars0lex.l" +#line 412 "pars0lex.l" { - return(PARS_TO_CHAR_TOKEN); + return(PARS_OPEN_TOKEN); } YY_BREAK case 65: YY_RULE_SETUP -#line 399 "pars0lex.l" +#line 416 "pars0lex.l" { - return(PARS_TO_NUMBER_TOKEN); + return(PARS_FETCH_TOKEN); } YY_BREAK case 66: YY_RULE_SETUP -#line 403 "pars0lex.l" +#line 420 "pars0lex.l" { - return(PARS_TO_BINARY_TOKEN); + return(PARS_CLOSE_TOKEN); } YY_BREAK case 67: YY_RULE_SETUP -#line 407 "pars0lex.l" +#line 424 "pars0lex.l" { - return(PARS_BINARY_TO_NUMBER_TOKEN); + return(PARS_NOTFOUND_TOKEN); } YY_BREAK case 68: YY_RULE_SETUP -#line 411 "pars0lex.l" +#line 428 "pars0lex.l" { - return(PARS_SUBSTR_TOKEN); + return(PARS_TO_CHAR_TOKEN); } YY_BREAK case 69: YY_RULE_SETUP -#line 415 "pars0lex.l" +#line 432 "pars0lex.l" { - return(PARS_REPLSTR_TOKEN); + return(PARS_TO_NUMBER_TOKEN); } YY_BREAK case 70: YY_RULE_SETUP -#line 419 "pars0lex.l" +#line 436 "pars0lex.l" { - return(PARS_CONCAT_TOKEN); + return(PARS_TO_BINARY_TOKEN); } YY_BREAK case 71: YY_RULE_SETUP -#line 423 "pars0lex.l" +#line 440 "pars0lex.l" { - return(PARS_INSTR_TOKEN); + return(PARS_BINARY_TO_NUMBER_TOKEN); } YY_BREAK case 72: YY_RULE_SETUP -#line 427 "pars0lex.l" +#line 444 "pars0lex.l" { - return(PARS_LENGTH_TOKEN); + return(PARS_SUBSTR_TOKEN); } YY_BREAK case 73: YY_RULE_SETUP -#line 431 "pars0lex.l" +#line 448 "pars0lex.l" { - return(PARS_SYSDATE_TOKEN); + return(PARS_REPLSTR_TOKEN); } YY_BREAK case 74: YY_RULE_SETUP -#line 435 "pars0lex.l" +#line 452 "pars0lex.l" { - return(PARS_PRINTF_TOKEN); + return(PARS_CONCAT_TOKEN); } YY_BREAK case 75: YY_RULE_SETUP -#line 439 "pars0lex.l" +#line 456 "pars0lex.l" { - return(PARS_ASSERT_TOKEN); + return(PARS_INSTR_TOKEN); } YY_BREAK case 76: YY_RULE_SETUP -#line 443 "pars0lex.l" +#line 460 "pars0lex.l" { - return(PARS_RND_TOKEN); + return(PARS_LENGTH_TOKEN); } YY_BREAK case 77: YY_RULE_SETUP -#line 447 "pars0lex.l" +#line 464 "pars0lex.l" { - return(PARS_RND_STR_TOKEN); + return(PARS_SYSDATE_TOKEN); } YY_BREAK case 78: YY_RULE_SETUP -#line 451 "pars0lex.l" +#line 468 "pars0lex.l" { - return(PARS_ROW_PRINTF_TOKEN); + return(PARS_PRINTF_TOKEN); } YY_BREAK case 79: YY_RULE_SETUP -#line 455 "pars0lex.l" +#line 472 "pars0lex.l" { - return(PARS_COMMIT_TOKEN); + return(PARS_ASSERT_TOKEN); } YY_BREAK case 80: YY_RULE_SETUP -#line 459 "pars0lex.l" +#line 476 "pars0lex.l" { - return(PARS_ROLLBACK_TOKEN); + return(PARS_RND_TOKEN); } YY_BREAK case 81: YY_RULE_SETUP -#line 463 "pars0lex.l" +#line 480 "pars0lex.l" { - return(PARS_WORK_TOKEN); + return(PARS_RND_STR_TOKEN); } YY_BREAK case 82: YY_RULE_SETUP -#line 467 "pars0lex.l" +#line 484 "pars0lex.l" +{ + return(PARS_ROW_PRINTF_TOKEN); +} + YY_BREAK +case 83: +YY_RULE_SETUP +#line 488 "pars0lex.l" +{ + return(PARS_COMMIT_TOKEN); +} + YY_BREAK +case 84: +YY_RULE_SETUP +#line 492 "pars0lex.l" +{ + return(PARS_ROLLBACK_TOKEN); +} + YY_BREAK +case 85: +YY_RULE_SETUP +#line 496 "pars0lex.l" +{ + return(PARS_WORK_TOKEN); +} + YY_BREAK +case 86: +YY_RULE_SETUP +#line 500 "pars0lex.l" +{ + return(PARS_UNSIGNED_TOKEN); +} + YY_BREAK +case 87: +YY_RULE_SETUP +#line 504 "pars0lex.l" +{ + return(PARS_EXIT_TOKEN); +} + YY_BREAK +case 88: +YY_RULE_SETUP +#line 508 "pars0lex.l" +{ + return(PARS_FUNCTION_TOKEN); +} + YY_BREAK +case 89: +YY_RULE_SETUP +#line 512 "pars0lex.l" { yylval = sym_tab_add_id(pars_sym_tab_global, (byte*)yytext, @@ -1597,122 +1689,50 @@ YY_RULE_SETUP return(PARS_ID_TOKEN); } YY_BREAK -case 83: +case 90: YY_RULE_SETUP -#line 474 "pars0lex.l" +#line 519 "pars0lex.l" { return(PARS_DDOT_TOKEN); } YY_BREAK -case 84: +case 91: YY_RULE_SETUP -#line 478 "pars0lex.l" +#line 523 "pars0lex.l" { return(PARS_ASSIGN_TOKEN); } YY_BREAK -case 85: +case 92: YY_RULE_SETUP -#line 482 "pars0lex.l" +#line 527 "pars0lex.l" { return(PARS_LE_TOKEN); } YY_BREAK -case 86: +case 93: YY_RULE_SETUP -#line 486 "pars0lex.l" +#line 531 "pars0lex.l" { return(PARS_GE_TOKEN); } YY_BREAK -case 87: +case 94: YY_RULE_SETUP -#line 490 "pars0lex.l" +#line 535 "pars0lex.l" { return(PARS_NE_TOKEN); } YY_BREAK -case 88: -YY_RULE_SETUP -#line 494 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 89: -YY_RULE_SETUP -#line 499 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 90: -YY_RULE_SETUP -#line 504 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 91: -YY_RULE_SETUP -#line 509 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 92: -YY_RULE_SETUP -#line 514 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 93: -YY_RULE_SETUP -#line 519 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 94: -YY_RULE_SETUP -#line 524 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK case 95: YY_RULE_SETUP -#line 529 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 96: -YY_RULE_SETUP -#line 534 "pars0lex.l" -{ - - return((int)(*yytext)); -} - YY_BREAK -case 97: -YY_RULE_SETUP #line 539 "pars0lex.l" { return((int)(*yytext)); } YY_BREAK -case 98: +case 96: YY_RULE_SETUP #line 544 "pars0lex.l" { @@ -1720,7 +1740,7 @@ YY_RULE_SETUP return((int)(*yytext)); } YY_BREAK -case 99: +case 97: YY_RULE_SETUP #line 549 "pars0lex.l" { @@ -1728,7 +1748,7 @@ YY_RULE_SETUP return((int)(*yytext)); } YY_BREAK -case 100: +case 98: YY_RULE_SETUP #line 554 "pars0lex.l" { @@ -1736,7 +1756,7 @@ YY_RULE_SETUP return((int)(*yytext)); } YY_BREAK -case 101: +case 99: YY_RULE_SETUP #line 559 "pars0lex.l" { @@ -1744,7 +1764,7 @@ YY_RULE_SETUP return((int)(*yytext)); } YY_BREAK -case 102: +case 100: YY_RULE_SETUP #line 564 "pars0lex.l" { @@ -1752,37 +1772,109 @@ YY_RULE_SETUP return((int)(*yytext)); } YY_BREAK -case 103: +case 101: YY_RULE_SETUP #line 569 "pars0lex.l" -BEGIN(comment); /* eat up comment */ +{ + + return((int)(*yytext)); +} + YY_BREAK +case 102: +YY_RULE_SETUP +#line 574 "pars0lex.l" +{ + + return((int)(*yytext)); +} + YY_BREAK +case 103: +YY_RULE_SETUP +#line 579 "pars0lex.l" +{ + + return((int)(*yytext)); +} YY_BREAK case 104: -/* rule 104 can match eol */ YY_RULE_SETUP -#line 571 "pars0lex.l" +#line 584 "pars0lex.l" +{ + return((int)(*yytext)); +} YY_BREAK case 105: -/* rule 105 can match eol */ YY_RULE_SETUP -#line 572 "pars0lex.l" +#line 589 "pars0lex.l" +{ + return((int)(*yytext)); +} YY_BREAK case 106: YY_RULE_SETUP -#line 573 "pars0lex.l" -BEGIN(INITIAL); +#line 594 "pars0lex.l" +{ + + return((int)(*yytext)); +} YY_BREAK case 107: -/* rule 107 can match eol */ YY_RULE_SETUP -#line 575 "pars0lex.l" -/* eat up whitespace */ +#line 599 "pars0lex.l" +{ + + return((int)(*yytext)); +} YY_BREAK case 108: YY_RULE_SETUP -#line 578 "pars0lex.l" +#line 604 "pars0lex.l" +{ + + return((int)(*yytext)); +} + YY_BREAK +case 109: +YY_RULE_SETUP +#line 609 "pars0lex.l" +{ + + return((int)(*yytext)); +} + YY_BREAK +case 110: +YY_RULE_SETUP +#line 614 "pars0lex.l" +BEGIN(comment); /* eat up comment */ + YY_BREAK +case 111: +/* rule 111 can match eol */ +YY_RULE_SETUP +#line 616 "pars0lex.l" + + YY_BREAK +case 112: +/* rule 112 can match eol */ +YY_RULE_SETUP +#line 617 "pars0lex.l" + + YY_BREAK +case 113: +YY_RULE_SETUP +#line 618 "pars0lex.l" +BEGIN(INITIAL); + YY_BREAK +case 114: +/* rule 114 can match eol */ +YY_RULE_SETUP +#line 620 "pars0lex.l" +/* eat up whitespace */ + YY_BREAK +case 115: +YY_RULE_SETUP +#line 623 "pars0lex.l" { fprintf(stderr,"Unrecognized character: %02x\n", *yytext); @@ -1792,15 +1884,16 @@ YY_RULE_SETUP return(0); } YY_BREAK -case 109: +case 116: YY_RULE_SETUP -#line 587 "pars0lex.l" +#line 632 "pars0lex.l" YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK -#line 1799 "lex.yy.c" +#line 1892 "_flex_tmp.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(comment): case YY_STATE_EOF(quoted): +case YY_STATE_EOF(id): yyterminate(); case YY_END_OF_BUFFER: @@ -2084,7 +2177,7 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 370 ) + if ( yy_current_state >= 394 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -2112,11 +2205,11 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 370 ) + if ( yy_current_state >= 394 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 369); + yy_is_jam = (yy_current_state == 393); return yy_is_jam ? 0 : yy_current_state; } @@ -2145,7 +2238,7 @@ static int yy_get_next_buffer (void) else { /* need more input */ - int offset = (int)(yy_c_buf_p - yytext_ptr); + int offset = (int)((yy_c_buf_p) - (yytext_ptr)); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) @@ -2639,7 +2732,7 @@ void yyfree (void * ptr ) #undef YY_DECL_IS_OURS #undef YY_DECL #endif -#line 587 "pars0lex.l" +#line 632 "pars0lex.l" diff --git a/storage/innobase/pars/make_bison.sh b/storage/innobase/pars/make_bison.sh index 43b0322494c..c11456230c4 100755 --- a/storage/innobase/pars/make_bison.sh +++ b/storage/innobase/pars/make_bison.sh @@ -1,7 +1,6 @@ #!/bin/bash # -# regenerate parser from bison input files as documented at the top of -# pars0lex.l. +# generate parser files from bison input files. set -eu diff --git a/storage/innobase/pars/make_flex.sh b/storage/innobase/pars/make_flex.sh new file mode 100755 index 00000000000..c015327bf8c --- /dev/null +++ b/storage/innobase/pars/make_flex.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# generate lexer files from flex input files. + +set -eu + +TMPFILE=_flex_tmp.c +OUTFILE=lexyy.c + +flex -o $TMPFILE pars0lex.l + +# AIX needs its includes done in a certain order, so include "univ.i" first +# to be sure we get it right. +echo '#include "univ.i"' > $OUTFILE + +# flex assigns a pointer to an int in one place without a cast, resulting in +# a warning on Win64. this adds the cast. +sed -e 's/int offset = (yy_c_buf_p) - (yytext_ptr);/int offset = (int)((yy_c_buf_p) - (yytext_ptr));/;' < $TMPFILE >> $OUTFILE + +rm $TMPFILE diff --git a/storage/innobase/pars/pars0grm.c b/storage/innobase/pars/pars0grm.c index 3800cdda88e..2cce7cb1c8b 100644 --- a/storage/innobase/pars/pars0grm.c +++ b/storage/innobase/pars/pars0grm.c @@ -56,177 +56,187 @@ PARS_INT_LIT = 258, PARS_FLOAT_LIT = 259, PARS_STR_LIT = 260, - PARS_NULL_LIT = 261, - PARS_ID_TOKEN = 262, - PARS_AND_TOKEN = 263, - PARS_OR_TOKEN = 264, - PARS_NOT_TOKEN = 265, - PARS_GE_TOKEN = 266, - PARS_LE_TOKEN = 267, - PARS_NE_TOKEN = 268, - PARS_PROCEDURE_TOKEN = 269, - PARS_IN_TOKEN = 270, - PARS_OUT_TOKEN = 271, - PARS_BINARY_TOKEN = 272, - PARS_BLOB_TOKEN = 273, - PARS_INT_TOKEN = 274, - PARS_INTEGER_TOKEN = 275, - PARS_FLOAT_TOKEN = 276, - PARS_CHAR_TOKEN = 277, - PARS_IS_TOKEN = 278, - PARS_BEGIN_TOKEN = 279, - PARS_END_TOKEN = 280, - PARS_IF_TOKEN = 281, - PARS_THEN_TOKEN = 282, - PARS_ELSE_TOKEN = 283, - PARS_ELSIF_TOKEN = 284, - PARS_LOOP_TOKEN = 285, - PARS_WHILE_TOKEN = 286, - PARS_RETURN_TOKEN = 287, - PARS_SELECT_TOKEN = 288, - PARS_SUM_TOKEN = 289, - PARS_COUNT_TOKEN = 290, - PARS_DISTINCT_TOKEN = 291, - PARS_FROM_TOKEN = 292, - PARS_WHERE_TOKEN = 293, - PARS_FOR_TOKEN = 294, - PARS_DDOT_TOKEN = 295, - PARS_CONSISTENT_TOKEN = 296, - PARS_READ_TOKEN = 297, - PARS_ORDER_TOKEN = 298, - PARS_BY_TOKEN = 299, - PARS_ASC_TOKEN = 300, - PARS_DESC_TOKEN = 301, - PARS_INSERT_TOKEN = 302, - PARS_INTO_TOKEN = 303, - PARS_VALUES_TOKEN = 304, - PARS_UPDATE_TOKEN = 305, - PARS_SET_TOKEN = 306, - PARS_DELETE_TOKEN = 307, - PARS_CURRENT_TOKEN = 308, - PARS_OF_TOKEN = 309, - PARS_CREATE_TOKEN = 310, - PARS_TABLE_TOKEN = 311, - PARS_INDEX_TOKEN = 312, - PARS_UNIQUE_TOKEN = 313, - PARS_CLUSTERED_TOKEN = 314, - PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 315, - PARS_ON_TOKEN = 316, - PARS_ASSIGN_TOKEN = 317, - PARS_DECLARE_TOKEN = 318, - PARS_CURSOR_TOKEN = 319, - PARS_SQL_TOKEN = 320, - PARS_OPEN_TOKEN = 321, - PARS_FETCH_TOKEN = 322, - PARS_CLOSE_TOKEN = 323, - PARS_NOTFOUND_TOKEN = 324, - PARS_TO_CHAR_TOKEN = 325, - PARS_TO_NUMBER_TOKEN = 326, - PARS_TO_BINARY_TOKEN = 327, - PARS_BINARY_TO_NUMBER_TOKEN = 328, - PARS_SUBSTR_TOKEN = 329, - PARS_REPLSTR_TOKEN = 330, - PARS_CONCAT_TOKEN = 331, - PARS_INSTR_TOKEN = 332, - PARS_LENGTH_TOKEN = 333, - PARS_SYSDATE_TOKEN = 334, - PARS_PRINTF_TOKEN = 335, - PARS_ASSERT_TOKEN = 336, - PARS_RND_TOKEN = 337, - PARS_RND_STR_TOKEN = 338, - PARS_ROW_PRINTF_TOKEN = 339, - PARS_COMMIT_TOKEN = 340, - PARS_ROLLBACK_TOKEN = 341, - PARS_WORK_TOKEN = 342, - NEG = 343 + PARS_FIXBINARY_LIT = 261, + PARS_BLOB_LIT = 262, + PARS_NULL_LIT = 263, + PARS_ID_TOKEN = 264, + PARS_AND_TOKEN = 265, + PARS_OR_TOKEN = 266, + PARS_NOT_TOKEN = 267, + PARS_GE_TOKEN = 268, + PARS_LE_TOKEN = 269, + PARS_NE_TOKEN = 270, + PARS_PROCEDURE_TOKEN = 271, + PARS_IN_TOKEN = 272, + PARS_OUT_TOKEN = 273, + PARS_BINARY_TOKEN = 274, + PARS_BLOB_TOKEN = 275, + PARS_INT_TOKEN = 276, + PARS_INTEGER_TOKEN = 277, + PARS_FLOAT_TOKEN = 278, + PARS_CHAR_TOKEN = 279, + PARS_IS_TOKEN = 280, + PARS_BEGIN_TOKEN = 281, + PARS_END_TOKEN = 282, + PARS_IF_TOKEN = 283, + PARS_THEN_TOKEN = 284, + PARS_ELSE_TOKEN = 285, + PARS_ELSIF_TOKEN = 286, + PARS_LOOP_TOKEN = 287, + PARS_WHILE_TOKEN = 288, + PARS_RETURN_TOKEN = 289, + PARS_SELECT_TOKEN = 290, + PARS_SUM_TOKEN = 291, + PARS_COUNT_TOKEN = 292, + PARS_DISTINCT_TOKEN = 293, + PARS_FROM_TOKEN = 294, + PARS_WHERE_TOKEN = 295, + PARS_FOR_TOKEN = 296, + PARS_DDOT_TOKEN = 297, + PARS_CONSISTENT_TOKEN = 298, + PARS_READ_TOKEN = 299, + PARS_ORDER_TOKEN = 300, + PARS_BY_TOKEN = 301, + PARS_ASC_TOKEN = 302, + PARS_DESC_TOKEN = 303, + PARS_INSERT_TOKEN = 304, + PARS_INTO_TOKEN = 305, + PARS_VALUES_TOKEN = 306, + PARS_UPDATE_TOKEN = 307, + PARS_SET_TOKEN = 308, + PARS_DELETE_TOKEN = 309, + PARS_CURRENT_TOKEN = 310, + PARS_OF_TOKEN = 311, + PARS_CREATE_TOKEN = 312, + PARS_TABLE_TOKEN = 313, + PARS_INDEX_TOKEN = 314, + PARS_UNIQUE_TOKEN = 315, + PARS_CLUSTERED_TOKEN = 316, + PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 317, + PARS_ON_TOKEN = 318, + PARS_ASSIGN_TOKEN = 319, + PARS_DECLARE_TOKEN = 320, + PARS_CURSOR_TOKEN = 321, + PARS_SQL_TOKEN = 322, + PARS_OPEN_TOKEN = 323, + PARS_FETCH_TOKEN = 324, + PARS_CLOSE_TOKEN = 325, + PARS_NOTFOUND_TOKEN = 326, + PARS_TO_CHAR_TOKEN = 327, + PARS_TO_NUMBER_TOKEN = 328, + PARS_TO_BINARY_TOKEN = 329, + PARS_BINARY_TO_NUMBER_TOKEN = 330, + PARS_SUBSTR_TOKEN = 331, + PARS_REPLSTR_TOKEN = 332, + PARS_CONCAT_TOKEN = 333, + PARS_INSTR_TOKEN = 334, + PARS_LENGTH_TOKEN = 335, + PARS_SYSDATE_TOKEN = 336, + PARS_PRINTF_TOKEN = 337, + PARS_ASSERT_TOKEN = 338, + PARS_RND_TOKEN = 339, + PARS_RND_STR_TOKEN = 340, + PARS_ROW_PRINTF_TOKEN = 341, + PARS_COMMIT_TOKEN = 342, + PARS_ROLLBACK_TOKEN = 343, + PARS_WORK_TOKEN = 344, + PARS_UNSIGNED_TOKEN = 345, + PARS_EXIT_TOKEN = 346, + PARS_FUNCTION_TOKEN = 347, + NEG = 348 }; #endif #define PARS_INT_LIT 258 #define PARS_FLOAT_LIT 259 #define PARS_STR_LIT 260 -#define PARS_NULL_LIT 261 -#define PARS_ID_TOKEN 262 -#define PARS_AND_TOKEN 263 -#define PARS_OR_TOKEN 264 -#define PARS_NOT_TOKEN 265 -#define PARS_GE_TOKEN 266 -#define PARS_LE_TOKEN 267 -#define PARS_NE_TOKEN 268 -#define PARS_PROCEDURE_TOKEN 269 -#define PARS_IN_TOKEN 270 -#define PARS_OUT_TOKEN 271 -#define PARS_BINARY_TOKEN 272 -#define PARS_BLOB_TOKEN 273 -#define PARS_INT_TOKEN 274 -#define PARS_INTEGER_TOKEN 275 -#define PARS_FLOAT_TOKEN 276 -#define PARS_CHAR_TOKEN 277 -#define PARS_IS_TOKEN 278 -#define PARS_BEGIN_TOKEN 279 -#define PARS_END_TOKEN 280 -#define PARS_IF_TOKEN 281 -#define PARS_THEN_TOKEN 282 -#define PARS_ELSE_TOKEN 283 -#define PARS_ELSIF_TOKEN 284 -#define PARS_LOOP_TOKEN 285 -#define PARS_WHILE_TOKEN 286 -#define PARS_RETURN_TOKEN 287 -#define PARS_SELECT_TOKEN 288 -#define PARS_SUM_TOKEN 289 -#define PARS_COUNT_TOKEN 290 -#define PARS_DISTINCT_TOKEN 291 -#define PARS_FROM_TOKEN 292 -#define PARS_WHERE_TOKEN 293 -#define PARS_FOR_TOKEN 294 -#define PARS_DDOT_TOKEN 295 -#define PARS_CONSISTENT_TOKEN 296 -#define PARS_READ_TOKEN 297 -#define PARS_ORDER_TOKEN 298 -#define PARS_BY_TOKEN 299 -#define PARS_ASC_TOKEN 300 -#define PARS_DESC_TOKEN 301 -#define PARS_INSERT_TOKEN 302 -#define PARS_INTO_TOKEN 303 -#define PARS_VALUES_TOKEN 304 -#define PARS_UPDATE_TOKEN 305 -#define PARS_SET_TOKEN 306 -#define PARS_DELETE_TOKEN 307 -#define PARS_CURRENT_TOKEN 308 -#define PARS_OF_TOKEN 309 -#define PARS_CREATE_TOKEN 310 -#define PARS_TABLE_TOKEN 311 -#define PARS_INDEX_TOKEN 312 -#define PARS_UNIQUE_TOKEN 313 -#define PARS_CLUSTERED_TOKEN 314 -#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 315 -#define PARS_ON_TOKEN 316 -#define PARS_ASSIGN_TOKEN 317 -#define PARS_DECLARE_TOKEN 318 -#define PARS_CURSOR_TOKEN 319 -#define PARS_SQL_TOKEN 320 -#define PARS_OPEN_TOKEN 321 -#define PARS_FETCH_TOKEN 322 -#define PARS_CLOSE_TOKEN 323 -#define PARS_NOTFOUND_TOKEN 324 -#define PARS_TO_CHAR_TOKEN 325 -#define PARS_TO_NUMBER_TOKEN 326 -#define PARS_TO_BINARY_TOKEN 327 -#define PARS_BINARY_TO_NUMBER_TOKEN 328 -#define PARS_SUBSTR_TOKEN 329 -#define PARS_REPLSTR_TOKEN 330 -#define PARS_CONCAT_TOKEN 331 -#define PARS_INSTR_TOKEN 332 -#define PARS_LENGTH_TOKEN 333 -#define PARS_SYSDATE_TOKEN 334 -#define PARS_PRINTF_TOKEN 335 -#define PARS_ASSERT_TOKEN 336 -#define PARS_RND_TOKEN 337 -#define PARS_RND_STR_TOKEN 338 -#define PARS_ROW_PRINTF_TOKEN 339 -#define PARS_COMMIT_TOKEN 340 -#define PARS_ROLLBACK_TOKEN 341 -#define PARS_WORK_TOKEN 342 -#define NEG 343 +#define PARS_FIXBINARY_LIT 261 +#define PARS_BLOB_LIT 262 +#define PARS_NULL_LIT 263 +#define PARS_ID_TOKEN 264 +#define PARS_AND_TOKEN 265 +#define PARS_OR_TOKEN 266 +#define PARS_NOT_TOKEN 267 +#define PARS_GE_TOKEN 268 +#define PARS_LE_TOKEN 269 +#define PARS_NE_TOKEN 270 +#define PARS_PROCEDURE_TOKEN 271 +#define PARS_IN_TOKEN 272 +#define PARS_OUT_TOKEN 273 +#define PARS_BINARY_TOKEN 274 +#define PARS_BLOB_TOKEN 275 +#define PARS_INT_TOKEN 276 +#define PARS_INTEGER_TOKEN 277 +#define PARS_FLOAT_TOKEN 278 +#define PARS_CHAR_TOKEN 279 +#define PARS_IS_TOKEN 280 +#define PARS_BEGIN_TOKEN 281 +#define PARS_END_TOKEN 282 +#define PARS_IF_TOKEN 283 +#define PARS_THEN_TOKEN 284 +#define PARS_ELSE_TOKEN 285 +#define PARS_ELSIF_TOKEN 286 +#define PARS_LOOP_TOKEN 287 +#define PARS_WHILE_TOKEN 288 +#define PARS_RETURN_TOKEN 289 +#define PARS_SELECT_TOKEN 290 +#define PARS_SUM_TOKEN 291 +#define PARS_COUNT_TOKEN 292 +#define PARS_DISTINCT_TOKEN 293 +#define PARS_FROM_TOKEN 294 +#define PARS_WHERE_TOKEN 295 +#define PARS_FOR_TOKEN 296 +#define PARS_DDOT_TOKEN 297 +#define PARS_CONSISTENT_TOKEN 298 +#define PARS_READ_TOKEN 299 +#define PARS_ORDER_TOKEN 300 +#define PARS_BY_TOKEN 301 +#define PARS_ASC_TOKEN 302 +#define PARS_DESC_TOKEN 303 +#define PARS_INSERT_TOKEN 304 +#define PARS_INTO_TOKEN 305 +#define PARS_VALUES_TOKEN 306 +#define PARS_UPDATE_TOKEN 307 +#define PARS_SET_TOKEN 308 +#define PARS_DELETE_TOKEN 309 +#define PARS_CURRENT_TOKEN 310 +#define PARS_OF_TOKEN 311 +#define PARS_CREATE_TOKEN 312 +#define PARS_TABLE_TOKEN 313 +#define PARS_INDEX_TOKEN 314 +#define PARS_UNIQUE_TOKEN 315 +#define PARS_CLUSTERED_TOKEN 316 +#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 317 +#define PARS_ON_TOKEN 318 +#define PARS_ASSIGN_TOKEN 319 +#define PARS_DECLARE_TOKEN 320 +#define PARS_CURSOR_TOKEN 321 +#define PARS_SQL_TOKEN 322 +#define PARS_OPEN_TOKEN 323 +#define PARS_FETCH_TOKEN 324 +#define PARS_CLOSE_TOKEN 325 +#define PARS_NOTFOUND_TOKEN 326 +#define PARS_TO_CHAR_TOKEN 327 +#define PARS_TO_NUMBER_TOKEN 328 +#define PARS_TO_BINARY_TOKEN 329 +#define PARS_BINARY_TO_NUMBER_TOKEN 330 +#define PARS_SUBSTR_TOKEN 331 +#define PARS_REPLSTR_TOKEN 332 +#define PARS_CONCAT_TOKEN 333 +#define PARS_INSTR_TOKEN 334 +#define PARS_LENGTH_TOKEN 335 +#define PARS_SYSDATE_TOKEN 336 +#define PARS_PRINTF_TOKEN 337 +#define PARS_ASSERT_TOKEN 338 +#define PARS_RND_TOKEN 339 +#define PARS_RND_STR_TOKEN 340 +#define PARS_ROW_PRINTF_TOKEN 341 +#define PARS_COMMIT_TOKEN 342 +#define PARS_ROLLBACK_TOKEN 343 +#define PARS_WORK_TOKEN 344 +#define PARS_UNSIGNED_TOKEN 345 +#define PARS_EXIT_TOKEN 346 +#define PARS_FUNCTION_TOKEN 347 +#define NEG 348 @@ -279,7 +289,7 @@ typedef int YYSTYPE; /* Line 214 of yacc.c. */ -#line 283 "pars0grm.tab.c" +#line 293 "pars0grm.tab.c" #if ! defined (yyoverflow) || YYERROR_VERBOSE @@ -383,22 +393,22 @@ union yyalloc #endif /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 95 +#define YYFINAL 99 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 734 +#define YYLAST 756 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 104 +#define YYNTOKENS 109 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 64 +#define YYNNTS 69 /* YYNRULES -- Number of rules. */ -#define YYNRULES 164 +#define YYNRULES 175 /* YYNRULES -- Number of states. */ -#define YYNSTATES 321 +#define YYNSTATES 337 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 343 +#define YYMAXUTOK 348 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -409,16 +419,16 @@ static const unsigned char yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 96, 2, 2, - 98, 99, 93, 92, 101, 91, 2, 94, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, - 89, 88, 90, 100, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 101, 2, 2, + 103, 104, 98, 97, 106, 96, 2, 99, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 102, + 94, 93, 95, 105, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 102, 2, 103, 2, 2, 2, 2, + 2, 2, 2, 107, 2, 108, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -440,7 +450,7 @@ static const unsigned char yytranslate[] = 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 95 + 85, 86, 87, 88, 89, 90, 91, 92, 100 }; #if YYDEBUG @@ -450,100 +460,105 @@ static const unsigned short int yyprhs[] = { 0, 0, 3, 6, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, - 56, 59, 62, 65, 68, 70, 73, 75, 80, 82, - 84, 86, 88, 90, 94, 98, 102, 106, 109, 113, - 117, 121, 125, 129, 133, 137, 141, 145, 148, 152, - 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, - 176, 178, 179, 181, 185, 192, 197, 199, 201, 203, - 205, 209, 210, 212, 216, 217, 219, 223, 225, 230, - 236, 241, 242, 244, 248, 250, 254, 256, 257, 260, - 261, 264, 265, 268, 269, 271, 273, 274, 279, 288, - 292, 298, 301, 305, 307, 311, 316, 321, 324, 327, - 331, 334, 337, 340, 344, 349, 351, 354, 355, 358, - 360, 368, 375, 386, 388, 391, 394, 399, 404, 406, - 410, 411, 415, 416, 419, 420, 422, 430, 432, 436, - 437, 439, 440, 442, 453, 456, 459, 461, 463, 465, - 467, 469, 473, 477, 478, 480, 484, 488, 489, 491, - 494, 501, 502, 504, 507 + 56, 59, 62, 65, 68, 71, 73, 76, 78, 83, + 85, 87, 89, 91, 93, 95, 97, 101, 105, 109, + 113, 116, 120, 124, 128, 132, 136, 140, 144, 148, + 152, 155, 159, 163, 165, 167, 169, 171, 173, 175, + 177, 179, 181, 183, 185, 186, 188, 192, 199, 204, + 206, 208, 210, 214, 216, 220, 221, 223, 227, 228, + 230, 234, 236, 241, 247, 252, 253, 255, 259, 261, + 265, 267, 268, 271, 272, 275, 276, 279, 280, 282, + 284, 285, 290, 299, 303, 309, 312, 316, 318, 322, + 327, 332, 335, 338, 342, 345, 348, 351, 355, 360, + 362, 365, 366, 369, 371, 379, 386, 397, 399, 401, + 404, 407, 412, 417, 423, 425, 429, 430, 434, 435, + 437, 438, 441, 442, 444, 452, 454, 458, 459, 461, + 462, 464, 475, 478, 481, 483, 485, 487, 489, 491, + 495, 499, 500, 502, 506, 510, 511, 513, 516, 523, + 528, 530, 532, 533, 535, 538 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const short int yyrhs[] = { - 105, 0, -1, 167, 97, -1, 110, -1, 111, 97, - -1, 142, 97, -1, 143, 97, -1, 141, 97, -1, - 144, 97, -1, 137, 97, -1, 124, 97, -1, 126, - 97, -1, 136, 97, -1, 134, 97, -1, 135, 97, - -1, 131, 97, -1, 132, 97, -1, 145, 97, -1, - 147, 97, -1, 146, 97, -1, 158, 97, -1, 159, - 97, -1, 153, 97, -1, 157, 97, -1, 105, -1, - 106, 105, -1, 7, -1, 108, 98, 115, 99, -1, - 3, -1, 4, -1, 5, -1, 6, -1, 65, -1, - 107, 92, 107, -1, 107, 91, 107, -1, 107, 93, - 107, -1, 107, 94, 107, -1, 91, 107, -1, 98, - 107, 99, -1, 107, 88, 107, -1, 107, 89, 107, - -1, 107, 90, 107, -1, 107, 11, 107, -1, 107, - 12, 107, -1, 107, 13, 107, -1, 107, 8, 107, - -1, 107, 9, 107, -1, 10, 107, -1, 7, 96, - 69, -1, 65, 96, 69, -1, 70, -1, 71, -1, - 72, -1, 73, -1, 74, -1, 76, -1, 77, -1, - 78, -1, 79, -1, 82, -1, 83, -1, -1, 100, - -1, 109, 101, 100, -1, 102, 7, 98, 109, 99, - 103, -1, 112, 98, 115, 99, -1, 75, -1, 80, - -1, 81, -1, 7, -1, 113, 101, 7, -1, -1, - 7, -1, 114, 101, 7, -1, -1, 107, -1, 115, - 101, 107, -1, 107, -1, 35, 98, 93, 99, -1, - 35, 98, 36, 7, 99, -1, 34, 98, 107, 99, - -1, -1, 116, -1, 117, 101, 116, -1, 93, -1, - 117, 48, 114, -1, 117, -1, -1, 38, 107, -1, - -1, 39, 50, -1, -1, 41, 42, -1, -1, 45, - -1, 46, -1, -1, 43, 44, 7, 122, -1, 33, - 118, 37, 113, 119, 120, 121, 123, -1, 47, 48, - 7, -1, 125, 49, 98, 115, 99, -1, 125, 124, - -1, 7, 88, 107, -1, 127, -1, 128, 101, 127, - -1, 38, 53, 54, 7, -1, 50, 7, 51, 128, - -1, 130, 119, -1, 130, 129, -1, 52, 37, 7, - -1, 133, 119, -1, 133, 129, -1, 84, 124, -1, - 7, 62, 107, -1, 29, 107, 27, 106, -1, 138, - -1, 139, 138, -1, -1, 28, 106, -1, 139, -1, - 26, 107, 27, 106, 140, 25, 26, -1, 31, 107, - 30, 106, 25, 30, -1, 39, 7, 15, 107, 40, - 107, 30, 106, 25, 30, -1, 32, -1, 66, 7, - -1, 68, 7, -1, 67, 7, 48, 114, -1, 7, - 160, 150, 151, -1, 148, -1, 149, 101, 148, -1, - -1, 98, 3, 99, -1, -1, 10, 6, -1, -1, - 60, -1, 55, 56, 7, 98, 149, 99, 152, -1, - 7, -1, 154, 101, 7, -1, -1, 58, -1, -1, - 59, -1, 55, 155, 156, 57, 7, 61, 7, 98, - 154, 99, -1, 85, 87, -1, 86, 87, -1, 19, - -1, 20, -1, 22, -1, 17, -1, 18, -1, 7, - 15, 160, -1, 7, 16, 160, -1, -1, 161, -1, - 162, 101, 161, -1, 7, 160, 97, -1, -1, 163, - -1, 164, 163, -1, 63, 64, 7, 23, 124, 97, - -1, -1, 165, -1, 166, 165, -1, 14, 7, 98, - 162, 99, 23, 164, 166, 24, 106, 25, -1 + 110, 0, -1, 177, 102, -1, 115, -1, 116, 102, + -1, 148, 102, -1, 149, 102, -1, 150, 102, -1, + 147, 102, -1, 151, 102, -1, 143, 102, -1, 130, + 102, -1, 132, 102, -1, 142, 102, -1, 140, 102, + -1, 141, 102, -1, 137, 102, -1, 138, 102, -1, + 152, 102, -1, 154, 102, -1, 153, 102, -1, 166, + 102, -1, 167, 102, -1, 161, 102, -1, 165, 102, + -1, 110, -1, 111, 110, -1, 9, -1, 113, 103, + 121, 104, -1, 3, -1, 4, -1, 5, -1, 6, + -1, 7, -1, 8, -1, 67, -1, 112, 97, 112, + -1, 112, 96, 112, -1, 112, 98, 112, -1, 112, + 99, 112, -1, 96, 112, -1, 103, 112, 104, -1, + 112, 93, 112, -1, 112, 94, 112, -1, 112, 95, + 112, -1, 112, 13, 112, -1, 112, 14, 112, -1, + 112, 15, 112, -1, 112, 10, 112, -1, 112, 11, + 112, -1, 12, 112, -1, 9, 101, 71, -1, 67, + 101, 71, -1, 72, -1, 73, -1, 74, -1, 75, + -1, 76, -1, 78, -1, 79, -1, 80, -1, 81, + -1, 84, -1, 85, -1, -1, 105, -1, 114, 106, + 105, -1, 107, 9, 103, 114, 104, 108, -1, 117, + 103, 121, 104, -1, 77, -1, 82, -1, 83, -1, + 9, 103, 104, -1, 9, -1, 119, 106, 9, -1, + -1, 9, -1, 120, 106, 9, -1, -1, 112, -1, + 121, 106, 112, -1, 112, -1, 37, 103, 98, 104, + -1, 37, 103, 38, 9, 104, -1, 36, 103, 112, + 104, -1, -1, 122, -1, 123, 106, 122, -1, 98, + -1, 123, 50, 120, -1, 123, -1, -1, 40, 112, + -1, -1, 41, 52, -1, -1, 43, 44, -1, -1, + 47, -1, 48, -1, -1, 45, 46, 9, 128, -1, + 35, 124, 39, 119, 125, 126, 127, 129, -1, 49, + 50, 9, -1, 131, 51, 103, 121, 104, -1, 131, + 130, -1, 9, 93, 112, -1, 133, -1, 134, 106, + 133, -1, 40, 55, 56, 9, -1, 52, 9, 53, + 134, -1, 136, 125, -1, 136, 135, -1, 54, 39, + 9, -1, 139, 125, -1, 139, 135, -1, 86, 130, + -1, 9, 64, 112, -1, 31, 112, 29, 111, -1, + 144, -1, 145, 144, -1, -1, 30, 111, -1, 145, + -1, 28, 112, 29, 111, 146, 27, 28, -1, 33, + 112, 32, 111, 27, 32, -1, 41, 9, 17, 112, + 42, 112, 32, 111, 27, 32, -1, 91, -1, 34, + -1, 68, 9, -1, 70, 9, -1, 69, 9, 50, + 120, -1, 69, 9, 50, 118, -1, 9, 168, 157, + 158, 159, -1, 155, -1, 156, 106, 155, -1, -1, + 103, 3, 104, -1, -1, 90, -1, -1, 12, 8, + -1, -1, 62, -1, 57, 58, 9, 103, 156, 104, + 160, -1, 9, -1, 162, 106, 9, -1, -1, 60, + -1, -1, 61, -1, 57, 163, 164, 59, 9, 63, + 9, 103, 162, 104, -1, 87, 89, -1, 88, 89, + -1, 21, -1, 22, -1, 24, -1, 19, -1, 20, + -1, 9, 17, 168, -1, 9, 18, 168, -1, -1, + 169, -1, 170, 106, 169, -1, 9, 168, 102, -1, + -1, 171, -1, 172, 171, -1, 65, 66, 9, 25, + 130, 102, -1, 65, 92, 9, 102, -1, 173, -1, + 174, -1, -1, 175, -1, 176, 175, -1, 16, 9, + 103, 170, 104, 25, 172, 176, 26, 111, 27, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const unsigned short int yyrline[] = { - 0, 131, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 156, 157, 162, 163, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 187, - 192, 193, 194, 195, 197, 198, 199, 200, 201, 202, - 203, 206, 208, 209, 213, 218, 223, 224, 225, 229, - 230, 235, 236, 237, 242, 243, 244, 248, 249, 254, - 260, 267, 268, 269, 274, 276, 278, 282, 283, 287, - 288, 293, 294, 299, 300, 301, 305, 306, 311, 321, - 326, 328, 333, 337, 338, 343, 349, 356, 361, 366, - 372, 377, 382, 387, 392, 398, 399, 404, 405, 407, - 411, 418, 424, 432, 436, 442, 448, 453, 458, 459, - 464, 465, 470, 471, 477, 478, 484, 490, 491, 496, - 497, 501, 502, 506, 514, 519, 524, 525, 526, 527, - 528, 532, 535, 541, 542, 543, 548, 552, 554, 555, - 559, 564, 566, 567, 571 + 0, 136, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 162, 163, 168, 169, 171, + 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 195, 200, 201, 202, 203, 205, 206, 207, + 208, 209, 210, 211, 214, 216, 217, 221, 226, 231, + 232, 233, 237, 241, 242, 247, 248, 249, 254, 255, + 256, 260, 261, 266, 272, 279, 280, 281, 286, 288, + 290, 294, 295, 299, 300, 305, 306, 311, 312, 313, + 317, 318, 323, 333, 338, 340, 345, 349, 350, 355, + 361, 368, 373, 378, 384, 389, 394, 399, 404, 410, + 411, 416, 417, 419, 423, 430, 436, 444, 448, 452, + 458, 464, 466, 471, 476, 477, 482, 483, 488, 489, + 495, 496, 502, 503, 509, 515, 516, 521, 522, 526, + 527, 531, 539, 544, 549, 550, 551, 552, 553, 557, + 560, 566, 567, 568, 573, 577, 579, 580, 584, 590, + 595, 596, 599, 601, 602, 606 }; #endif @@ -553,38 +568,40 @@ static const unsigned short int yyrline[] = static const char *const yytname[] = { "$end", "error", "$undefined", "PARS_INT_LIT", "PARS_FLOAT_LIT", - "PARS_STR_LIT", "PARS_NULL_LIT", "PARS_ID_TOKEN", "PARS_AND_TOKEN", - "PARS_OR_TOKEN", "PARS_NOT_TOKEN", "PARS_GE_TOKEN", "PARS_LE_TOKEN", - "PARS_NE_TOKEN", "PARS_PROCEDURE_TOKEN", "PARS_IN_TOKEN", - "PARS_OUT_TOKEN", "PARS_BINARY_TOKEN", "PARS_BLOB_TOKEN", - "PARS_INT_TOKEN", "PARS_INTEGER_TOKEN", "PARS_FLOAT_TOKEN", - "PARS_CHAR_TOKEN", "PARS_IS_TOKEN", "PARS_BEGIN_TOKEN", "PARS_END_TOKEN", - "PARS_IF_TOKEN", "PARS_THEN_TOKEN", "PARS_ELSE_TOKEN", - "PARS_ELSIF_TOKEN", "PARS_LOOP_TOKEN", "PARS_WHILE_TOKEN", - "PARS_RETURN_TOKEN", "PARS_SELECT_TOKEN", "PARS_SUM_TOKEN", - "PARS_COUNT_TOKEN", "PARS_DISTINCT_TOKEN", "PARS_FROM_TOKEN", - "PARS_WHERE_TOKEN", "PARS_FOR_TOKEN", "PARS_DDOT_TOKEN", - "PARS_CONSISTENT_TOKEN", "PARS_READ_TOKEN", "PARS_ORDER_TOKEN", - "PARS_BY_TOKEN", "PARS_ASC_TOKEN", "PARS_DESC_TOKEN", - "PARS_INSERT_TOKEN", "PARS_INTO_TOKEN", "PARS_VALUES_TOKEN", - "PARS_UPDATE_TOKEN", "PARS_SET_TOKEN", "PARS_DELETE_TOKEN", - "PARS_CURRENT_TOKEN", "PARS_OF_TOKEN", "PARS_CREATE_TOKEN", - "PARS_TABLE_TOKEN", "PARS_INDEX_TOKEN", "PARS_UNIQUE_TOKEN", - "PARS_CLUSTERED_TOKEN", "PARS_DOES_NOT_FIT_IN_MEM_TOKEN", - "PARS_ON_TOKEN", "PARS_ASSIGN_TOKEN", "PARS_DECLARE_TOKEN", - "PARS_CURSOR_TOKEN", "PARS_SQL_TOKEN", "PARS_OPEN_TOKEN", - "PARS_FETCH_TOKEN", "PARS_CLOSE_TOKEN", "PARS_NOTFOUND_TOKEN", - "PARS_TO_CHAR_TOKEN", "PARS_TO_NUMBER_TOKEN", "PARS_TO_BINARY_TOKEN", - "PARS_BINARY_TO_NUMBER_TOKEN", "PARS_SUBSTR_TOKEN", "PARS_REPLSTR_TOKEN", - "PARS_CONCAT_TOKEN", "PARS_INSTR_TOKEN", "PARS_LENGTH_TOKEN", - "PARS_SYSDATE_TOKEN", "PARS_PRINTF_TOKEN", "PARS_ASSERT_TOKEN", - "PARS_RND_TOKEN", "PARS_RND_STR_TOKEN", "PARS_ROW_PRINTF_TOKEN", - "PARS_COMMIT_TOKEN", "PARS_ROLLBACK_TOKEN", "PARS_WORK_TOKEN", "'='", - "'<'", "'>'", "'-'", "'+'", "'*'", "'/'", "NEG", "'%'", "';'", "'('", - "')'", "'?'", "','", "'{'", "'}'", "$accept", "statement", - "statement_list", "exp", "function_name", "question_mark_list", - "stored_procedure_call", "predefined_procedure_call", - "predefined_procedure_name", "table_list", "variable_list", "exp_list", + "PARS_STR_LIT", "PARS_FIXBINARY_LIT", "PARS_BLOB_LIT", "PARS_NULL_LIT", + "PARS_ID_TOKEN", "PARS_AND_TOKEN", "PARS_OR_TOKEN", "PARS_NOT_TOKEN", + "PARS_GE_TOKEN", "PARS_LE_TOKEN", "PARS_NE_TOKEN", + "PARS_PROCEDURE_TOKEN", "PARS_IN_TOKEN", "PARS_OUT_TOKEN", + "PARS_BINARY_TOKEN", "PARS_BLOB_TOKEN", "PARS_INT_TOKEN", + "PARS_INTEGER_TOKEN", "PARS_FLOAT_TOKEN", "PARS_CHAR_TOKEN", + "PARS_IS_TOKEN", "PARS_BEGIN_TOKEN", "PARS_END_TOKEN", "PARS_IF_TOKEN", + "PARS_THEN_TOKEN", "PARS_ELSE_TOKEN", "PARS_ELSIF_TOKEN", + "PARS_LOOP_TOKEN", "PARS_WHILE_TOKEN", "PARS_RETURN_TOKEN", + "PARS_SELECT_TOKEN", "PARS_SUM_TOKEN", "PARS_COUNT_TOKEN", + "PARS_DISTINCT_TOKEN", "PARS_FROM_TOKEN", "PARS_WHERE_TOKEN", + "PARS_FOR_TOKEN", "PARS_DDOT_TOKEN", "PARS_CONSISTENT_TOKEN", + "PARS_READ_TOKEN", "PARS_ORDER_TOKEN", "PARS_BY_TOKEN", "PARS_ASC_TOKEN", + "PARS_DESC_TOKEN", "PARS_INSERT_TOKEN", "PARS_INTO_TOKEN", + "PARS_VALUES_TOKEN", "PARS_UPDATE_TOKEN", "PARS_SET_TOKEN", + "PARS_DELETE_TOKEN", "PARS_CURRENT_TOKEN", "PARS_OF_TOKEN", + "PARS_CREATE_TOKEN", "PARS_TABLE_TOKEN", "PARS_INDEX_TOKEN", + "PARS_UNIQUE_TOKEN", "PARS_CLUSTERED_TOKEN", + "PARS_DOES_NOT_FIT_IN_MEM_TOKEN", "PARS_ON_TOKEN", "PARS_ASSIGN_TOKEN", + "PARS_DECLARE_TOKEN", "PARS_CURSOR_TOKEN", "PARS_SQL_TOKEN", + "PARS_OPEN_TOKEN", "PARS_FETCH_TOKEN", "PARS_CLOSE_TOKEN", + "PARS_NOTFOUND_TOKEN", "PARS_TO_CHAR_TOKEN", "PARS_TO_NUMBER_TOKEN", + "PARS_TO_BINARY_TOKEN", "PARS_BINARY_TO_NUMBER_TOKEN", + "PARS_SUBSTR_TOKEN", "PARS_REPLSTR_TOKEN", "PARS_CONCAT_TOKEN", + "PARS_INSTR_TOKEN", "PARS_LENGTH_TOKEN", "PARS_SYSDATE_TOKEN", + "PARS_PRINTF_TOKEN", "PARS_ASSERT_TOKEN", "PARS_RND_TOKEN", + "PARS_RND_STR_TOKEN", "PARS_ROW_PRINTF_TOKEN", "PARS_COMMIT_TOKEN", + "PARS_ROLLBACK_TOKEN", "PARS_WORK_TOKEN", "PARS_UNSIGNED_TOKEN", + "PARS_EXIT_TOKEN", "PARS_FUNCTION_TOKEN", "'='", "'<'", "'>'", "'-'", + "'+'", "'*'", "'/'", "NEG", "'%'", "';'", "'('", "')'", "'?'", "','", + "'{'", "'}'", "$accept", "statement", "statement_list", "exp", + "function_name", "question_mark_list", "stored_procedure_call", + "predefined_procedure_call", "predefined_procedure_name", + "user_function_call", "table_list", "variable_list", "exp_list", "select_item", "select_item_list", "select_list", "search_condition", "for_update_clause", "consistent_read_clause", "order_direction", "order_by_clause", "select_statement", "insert_statement_start", @@ -594,15 +611,16 @@ static const char *const yytname[] = "delete_statement_start", "delete_statement_searched", "delete_statement_positioned", "row_printf_statement", "assignment_statement", "elsif_element", "elsif_list", "else_part", - "if_statement", "while_statement", "for_statement", "return_statement", - "open_cursor_statement", "close_cursor_statement", "fetch_statement", - "column_def", "column_def_list", "opt_column_len", "opt_not_null", - "not_fit_in_memory", "create_table", "column_list", "unique_def", - "clustered_def", "create_index", "commit_statement", - "rollback_statement", "type_name", "parameter_declaration", - "parameter_declaration_list", "variable_declaration", - "variable_declaration_list", "cursor_declaration", "declaration_list", - "procedure_definition", 0 + "if_statement", "while_statement", "for_statement", "exit_statement", + "return_statement", "open_cursor_statement", "close_cursor_statement", + "fetch_statement", "column_def", "column_def_list", "opt_column_len", + "opt_unsigned", "opt_not_null", "not_fit_in_memory", "create_table", + "column_list", "unique_def", "clustered_def", "create_index", + "commit_statement", "rollback_statement", "type_name", + "parameter_declaration", "parameter_declaration_list", + "variable_declaration", "variable_declaration_list", + "cursor_declaration", "function_declaration", "declaration", + "declaration_list", "procedure_definition", 0 }; #endif @@ -619,32 +637,33 @@ static const unsigned short int yytoknum[] = 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 61, 60, - 62, 45, 43, 42, 47, 343, 37, 59, 40, 41, - 63, 44, 123, 125 + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 61, 60, 62, 45, 43, 42, 47, + 348, 37, 59, 40, 41, 63, 44, 123, 125 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const unsigned char yyr1[] = { - 0, 104, 105, 105, 105, 105, 105, 105, 105, 105, - 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, - 105, 105, 105, 105, 106, 106, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, - 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 109, 109, 109, 110, 111, 112, 112, 112, 113, - 113, 114, 114, 114, 115, 115, 115, 116, 116, 116, - 116, 117, 117, 117, 118, 118, 118, 119, 119, 120, - 120, 121, 121, 122, 122, 122, 123, 123, 124, 125, - 126, 126, 127, 128, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 139, 140, 140, 140, - 141, 142, 143, 144, 145, 146, 147, 148, 149, 149, - 150, 150, 151, 151, 152, 152, 153, 154, 154, 155, - 155, 156, 156, 157, 158, 159, 160, 160, 160, 160, - 160, 161, 161, 162, 162, 162, 163, 164, 164, 164, - 165, 166, 166, 166, 167 + 0, 109, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 111, 111, 112, 112, 112, + 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, + 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, + 112, 112, 112, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 114, 114, 114, 115, 116, 117, + 117, 117, 118, 119, 119, 120, 120, 120, 121, 121, + 121, 122, 122, 122, 122, 123, 123, 123, 124, 124, + 124, 125, 125, 126, 126, 127, 127, 128, 128, 128, + 129, 129, 130, 131, 132, 132, 133, 134, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 145, 146, 146, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 154, 155, 156, 156, 157, 157, 158, 158, + 159, 159, 160, 160, 161, 162, 162, 163, 163, 164, + 164, 165, 166, 167, 168, 168, 168, 168, 168, 169, + 169, 170, 170, 170, 171, 172, 172, 172, 173, 174, + 175, 175, 176, 176, 176, 177 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -652,21 +671,22 @@ static const unsigned char yyr2[] = { 0, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 1, 2, 1, 4, 1, 1, - 1, 1, 1, 3, 3, 3, 3, 2, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, 1, 3, 6, 4, 1, 1, 1, 1, - 3, 0, 1, 3, 0, 1, 3, 1, 4, 5, - 4, 0, 1, 3, 1, 3, 1, 0, 2, 0, - 2, 0, 2, 0, 1, 1, 0, 4, 8, 3, - 5, 2, 3, 1, 3, 4, 4, 2, 2, 3, - 2, 2, 2, 3, 4, 1, 2, 0, 2, 1, - 7, 6, 10, 1, 2, 2, 4, 4, 1, 3, - 0, 3, 0, 2, 0, 1, 7, 1, 3, 0, - 1, 0, 1, 10, 2, 2, 1, 1, 1, 1, - 1, 3, 3, 0, 1, 3, 3, 0, 1, 2, - 6, 0, 1, 2, 11 + 2, 2, 2, 2, 2, 1, 2, 1, 4, 1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 3, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 3, 6, 4, 1, + 1, 1, 3, 1, 3, 0, 1, 3, 0, 1, + 3, 1, 4, 5, 4, 0, 1, 3, 1, 3, + 1, 0, 2, 0, 2, 0, 2, 0, 1, 1, + 0, 4, 8, 3, 5, 2, 3, 1, 3, 4, + 4, 2, 2, 3, 2, 2, 2, 3, 4, 1, + 2, 0, 2, 1, 7, 6, 10, 1, 1, 2, + 2, 4, 4, 5, 1, 3, 0, 3, 0, 1, + 0, 2, 0, 1, 7, 1, 3, 0, 1, 0, + 1, 10, 2, 2, 1, 1, 1, 1, 1, 3, + 3, 0, 1, 3, 3, 0, 1, 2, 6, 4, + 1, 1, 0, 1, 2, 11 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -674,103 +694,105 @@ static const unsigned char yyr2[] = means the default is an error. */ static const unsigned char yydefact[] = { - 0, 0, 0, 0, 0, 123, 81, 0, 0, 0, - 0, 139, 0, 0, 0, 66, 67, 68, 0, 0, - 0, 0, 0, 3, 0, 0, 0, 0, 0, 87, - 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 128, 85, 0, 0, 0, + 0, 147, 0, 0, 0, 69, 70, 71, 0, 0, + 0, 127, 0, 0, 3, 0, 0, 0, 0, 0, + 91, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 28, 29, 30, 31, 26, 0, 32, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 0, - 0, 0, 0, 0, 0, 0, 84, 77, 82, 86, - 0, 0, 0, 0, 0, 0, 140, 141, 124, 0, - 125, 112, 144, 145, 0, 1, 4, 74, 10, 0, - 101, 11, 0, 107, 108, 15, 16, 110, 111, 13, - 14, 12, 9, 7, 5, 6, 8, 17, 19, 18, - 22, 23, 20, 21, 2, 113, 153, 0, 47, 0, - 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 74, 0, 0, 0, 71, - 0, 0, 0, 99, 0, 109, 0, 142, 0, 71, - 61, 75, 0, 74, 0, 88, 0, 154, 0, 48, - 49, 38, 45, 46, 42, 43, 44, 24, 117, 39, - 40, 41, 34, 33, 35, 36, 0, 0, 0, 0, - 0, 72, 85, 83, 69, 87, 0, 0, 103, 106, - 0, 0, 126, 62, 0, 65, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 25, 115, 119, 0, 27, - 0, 80, 0, 78, 0, 0, 0, 89, 0, 0, - 0, 0, 128, 0, 0, 0, 0, 76, 100, 105, - 149, 150, 146, 147, 148, 151, 152, 157, 155, 118, - 0, 116, 0, 121, 79, 73, 70, 0, 91, 0, - 102, 104, 130, 134, 0, 0, 64, 63, 0, 158, - 161, 0, 120, 90, 0, 96, 0, 0, 132, 135, - 136, 129, 0, 0, 0, 159, 162, 0, 114, 92, - 0, 98, 0, 0, 0, 127, 0, 156, 0, 0, - 163, 0, 0, 131, 133, 137, 0, 0, 0, 93, - 122, 143, 0, 0, 164, 94, 95, 97, 138, 0, - 160 + 0, 0, 0, 29, 30, 31, 32, 33, 34, 27, + 0, 35, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 0, 0, 0, 0, 0, 0, 0, + 88, 81, 86, 90, 0, 0, 0, 0, 0, 0, + 148, 149, 129, 0, 130, 116, 152, 153, 0, 1, + 4, 78, 11, 0, 105, 12, 0, 111, 112, 16, + 17, 114, 115, 14, 15, 13, 10, 8, 5, 6, + 7, 9, 18, 20, 19, 23, 24, 21, 22, 2, + 117, 161, 0, 50, 0, 40, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 78, 0, 0, 0, 75, 0, 0, 0, 103, 0, + 113, 0, 150, 0, 75, 64, 79, 0, 78, 0, + 92, 0, 162, 0, 51, 52, 41, 48, 49, 45, + 46, 47, 25, 121, 42, 43, 44, 37, 36, 38, + 39, 0, 0, 0, 0, 0, 76, 89, 87, 73, + 91, 0, 0, 107, 110, 0, 0, 76, 132, 131, + 65, 0, 68, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26, 119, 123, 0, 28, 0, 84, 0, + 82, 0, 0, 0, 93, 0, 0, 0, 0, 134, + 0, 0, 0, 0, 0, 80, 104, 109, 157, 158, + 154, 155, 156, 159, 160, 165, 163, 122, 0, 120, + 0, 125, 83, 77, 74, 0, 95, 0, 106, 108, + 136, 142, 0, 0, 72, 67, 66, 0, 166, 172, + 0, 124, 94, 0, 100, 0, 0, 138, 143, 144, + 135, 0, 0, 0, 167, 170, 171, 173, 0, 118, + 96, 0, 102, 0, 0, 139, 140, 0, 164, 0, + 0, 0, 174, 0, 0, 137, 0, 133, 145, 0, + 0, 0, 0, 97, 126, 141, 151, 0, 0, 169, + 175, 98, 99, 101, 146, 0, 168 }; /* YYDEFGOTO[NTERM-NUM]. */ static const short int yydefgoto[] = { - -1, 177, 178, 161, 72, 204, 23, 24, 25, 195, - 192, 162, 78, 79, 80, 103, 258, 275, 317, 291, - 26, 27, 28, 198, 199, 104, 29, 30, 31, 32, - 33, 34, 35, 36, 216, 217, 218, 37, 38, 39, - 40, 41, 42, 43, 232, 233, 278, 295, 280, 44, - 306, 87, 158, 45, 46, 47, 245, 167, 168, 269, - 270, 286, 287, 48 + -1, 182, 183, 166, 76, 211, 24, 25, 26, 208, + 200, 197, 167, 82, 83, 84, 107, 266, 284, 333, + 302, 27, 28, 29, 203, 204, 108, 30, 31, 32, + 33, 34, 35, 36, 37, 223, 224, 225, 38, 39, + 40, 41, 42, 43, 44, 45, 239, 240, 287, 306, + 317, 289, 46, 319, 91, 163, 47, 48, 49, 253, + 172, 173, 278, 279, 295, 296, 297, 298, 50 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -205 +#define YYPACT_NINF -209 static const short int yypact[] = { - 454, -48, 30, 521, 521, -205, 12, 42, -18, 46, - -4, -33, 67, 69, 71, -205, -205, -205, 47, -8, - -6, 85, 93, -205, 1, -2, 2, -20, 3, 59, - 5, 7, 59, 24, 27, 28, 31, 32, 33, 39, - 50, 51, 55, 56, 57, 58, 60, 62, 63, 521, - 22, -205, -205, -205, -205, 48, 521, 65, -205, -205, - -205, -205, -205, -205, -205, -205, -205, -205, -205, 521, - 521, 252, 64, 576, 66, 68, -205, 640, -205, -40, - 86, 111, 120, 105, 156, 161, -205, 110, -205, 122, - -205, -205, -205, -205, 73, -205, -205, 521, -205, 74, - -205, -205, 492, -205, -205, -205, -205, -205, -205, -205, - -205, -205, -205, -205, -205, -205, -205, -205, -205, -205, - -205, -205, -205, -205, -205, 640, 167, 106, 309, 107, - 168, 23, 521, 521, 521, 521, 521, 454, 521, 521, - 521, 521, 521, 521, 521, 521, 454, 521, -27, 178, - 204, 179, 521, -205, 181, -205, 91, -205, 134, 178, - 92, 640, -75, 521, 139, 640, 29, -205, -59, -205, - -205, -205, 309, 309, 15, 15, 640, -205, 151, 15, - 15, 15, 25, 25, 168, 168, -58, 284, 535, 187, - 96, -205, 95, -205, -205, -31, 568, 109, -205, 98, - 193, 195, 95, -205, -49, -205, 521, -45, 197, 40, - 40, 189, 167, 454, 521, -205, -205, 186, 191, -205, - 190, -205, 123, -205, 214, 521, 216, 194, 521, 521, - 181, 40, -205, -36, 164, 126, 130, 640, -205, -205, - -205, -205, -205, -205, -205, -205, -205, 227, -205, 454, - 605, -205, 215, -205, -205, -205, -205, 192, 199, 633, - 640, -205, 145, 184, 193, 238, -205, -205, 40, -205, - 4, 454, -205, -205, 205, 203, 454, 245, 240, -205, - -205, -205, 153, 155, 198, -205, -205, -12, 454, -205, - 210, -205, 341, 157, 249, -205, 250, -205, 251, 454, - -205, 259, 229, -205, -205, -205, -26, 244, 398, 26, - -205, -205, 261, 47, -205, -205, -205, -205, -205, 173, - -205 + 578, -30, 40, 256, 256, -209, 19, 44, 7, 55, + 26, -16, 62, 69, 73, -209, -209, -209, 48, -5, + -4, -209, 78, 75, -209, -13, -15, -6, -18, 4, + 67, 6, 12, 67, 17, 18, 21, 29, 30, 32, + 33, 39, 47, 50, 51, 64, 65, 70, 82, 83, + 84, 256, 13, -209, -209, -209, -209, -209, -209, 8, + 256, 20, -209, -209, -209, -209, -209, -209, -209, -209, + -209, -209, -209, 256, 256, 295, 15, 421, 77, 86, + -209, 657, -209, -44, 129, 152, 178, 137, 182, 189, + -209, 142, -209, 154, -209, -209, -209, -209, 104, -209, + -209, 256, -209, 105, -209, -209, 170, -209, -209, -209, + -209, -209, -209, -209, -209, -209, -209, -209, -209, -209, + -209, -209, -209, -209, -209, -209, -209, -209, -209, -209, + 657, 200, 139, 582, 140, 198, 66, 256, 256, 256, + 256, 256, 578, 256, 256, 256, 256, 256, 256, 256, + 256, 578, 256, -31, 205, 121, 206, 256, -209, 207, + -209, 115, -209, 160, 212, 117, 657, -63, 256, 167, + 657, -2, -209, -59, -209, -209, -209, 582, 582, 14, + 14, 657, -209, 330, 14, 14, 14, 3, 3, 198, + 198, -58, 392, 279, 217, 123, -209, 122, -209, -209, + -32, 607, 136, -209, 124, 223, 224, 133, -209, 122, + -209, -52, -209, 256, -46, 229, 16, 16, 214, 200, + 578, 256, -209, -209, 209, 220, -209, 221, -209, 148, + -209, 232, 256, 247, 226, 256, 256, 207, 16, -209, + -43, 195, 165, 162, 166, 657, -209, -209, -209, -209, + -209, -209, -209, -209, -209, 263, -209, 578, 483, -209, + 246, -209, -209, -209, -209, 225, 233, 626, 657, -209, + 172, 216, 223, 270, -209, -209, -209, 16, -209, 1, + 578, -209, -209, 236, 237, 578, 278, 193, -209, -209, + -209, 181, 183, -53, -209, -209, -209, -209, -14, 578, + -209, 240, -209, 454, 184, -209, 275, 282, -209, 286, + 287, 578, -209, 288, 266, -209, 292, -209, -209, -36, + 276, 202, 516, -28, -209, -209, -209, 293, 48, -209, + -209, -209, -209, -209, -209, 210, -209 }; /* YYPGOTO[NTERM-NUM]. */ static const short int yypgoto[] = { - -205, 0, -126, -1, -205, -205, -205, -205, -205, -205, - 112, -124, 135, -205, -205, -28, -205, -205, -205, -205, - -17, -205, -205, 43, -205, 257, -205, -205, -205, -205, - -205, -205, -205, -205, 76, -205, -205, -205, -205, -205, - -205, -205, -205, -205, 8, -205, -205, -205, -205, -205, - -205, -205, -205, -205, -205, -205, -204, 72, -205, 20, - -205, 10, -205, -205 + -209, 0, -130, -1, -209, -209, -209, -209, -209, -209, + -209, 143, -136, 158, -209, -209, -29, -209, -209, -209, + -209, -17, -209, -209, 79, -209, 281, -209, -209, -209, + -209, -209, -209, -209, -209, 91, -209, -209, -209, -209, + -209, -209, -209, -209, -209, -209, 45, -209, -209, -209, + -209, -209, -209, -209, -209, -209, -209, -209, -209, -208, + 99, -209, 41, -209, -209, -209, 23, -209, -209 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -780,197 +802,202 @@ static const short int yypgoto[] = #define YYTABLE_NINF -1 static const unsigned short int yytable[] = { - 22, 91, 71, 73, 107, 77, 246, 225, 149, 189, - 100, 268, 299, 6, 49, 51, 52, 53, 54, 55, - 187, 186, 56, 85, 205, 86, 206, 262, 136, 99, - 82, 132, 133, 84, 134, 135, 136, 50, 136, 207, - 211, 219, 212, 206, 209, 210, 74, 75, 125, 81, - 235, 284, 236, 83, 238, 128, 206, 240, 241, 242, - 243, 150, 244, 263, 283, 264, 190, 284, 130, 131, - 226, 315, 316, 311, 88, 312, 89, 57, 90, 92, - 6, 93, 58, 59, 60, 61, 62, 249, 63, 64, - 65, 66, 94, 95, 67, 68, 97, 102, 96, 98, - 101, 165, 105, 69, 106, 76, 141, 142, 143, 144, - 70, 138, 139, 140, 141, 142, 143, 144, 143, 144, - 126, 109, 171, 151, 110, 111, 152, 153, 112, 113, - 114, 172, 173, 174, 175, 176, 115, 179, 180, 181, - 182, 183, 184, 185, 127, 288, 188, 116, 117, 77, - 292, 196, 118, 119, 120, 121, 154, 122, 1, 123, - 124, 129, 145, 155, 147, 2, 148, 227, 156, 157, - 159, 160, 163, 308, 166, 169, 170, 3, 215, 213, - 214, 136, 4, 5, 6, 191, 194, 215, 197, 200, - 7, 201, 203, 208, 222, 223, 224, 229, 8, 230, - 231, 9, 234, 10, 239, 237, 11, 51, 52, 53, - 54, 55, 247, 250, 56, 214, 252, 12, 13, 14, - 253, 255, 254, 256, 165, 265, 15, 259, 260, 266, - 267, 16, 17, 257, 268, 18, 19, 20, 74, 75, - 274, 272, 273, 277, 279, 282, 290, 289, 293, 215, - 294, 296, 297, 21, 301, 304, 303, 305, 307, 310, - 132, 133, 298, 134, 135, 136, 309, 313, 318, 57, - 320, 202, 281, 261, 58, 59, 60, 61, 62, 137, - 63, 64, 65, 66, 248, 193, 67, 68, 215, 108, - 285, 1, 215, 251, 0, 69, 319, 300, 2, 0, - 0, 0, 70, 0, 0, 0, 0, 0, 215, 220, - 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, - 134, 135, 136, 7, 0, 0, 0, 0, 0, 0, + 23, 95, 75, 77, 111, 81, 154, 194, 232, 254, + 277, 104, 311, 309, 191, 216, 217, 6, 141, 331, + 332, 192, 53, 54, 55, 56, 57, 58, 59, 141, + 270, 60, 214, 103, 51, 248, 249, 250, 251, 310, + 252, 212, 89, 213, 90, 218, 226, 219, 213, 52, + 130, 293, 243, 85, 244, 78, 79, 86, 246, 133, + 213, 271, 155, 272, 87, 88, 293, 195, 326, 292, + 327, 92, 135, 136, 233, 99, 137, 138, 93, 139, + 140, 141, 94, 6, 96, 97, 61, 98, 101, 100, + 257, 62, 63, 64, 65, 66, 102, 67, 68, 69, + 70, 148, 149, 71, 72, 170, 105, 106, 109, 132, + 146, 147, 148, 149, 110, 73, 131, 80, 150, 113, + 114, 134, 74, 115, 53, 54, 55, 56, 57, 58, + 59, 116, 117, 60, 118, 119, 177, 178, 179, 180, + 181, 120, 184, 185, 186, 187, 188, 189, 190, 121, + 299, 193, 122, 123, 81, 303, 201, 78, 79, 143, + 144, 145, 146, 147, 148, 149, 124, 125, 156, 157, + 176, 234, 126, 53, 54, 55, 56, 57, 58, 59, + 152, 322, 60, 222, 127, 128, 129, 158, 61, 153, + 159, 160, 222, 62, 63, 64, 65, 66, 161, 67, + 68, 69, 70, 162, 164, 71, 72, 165, 168, 171, + 174, 175, 245, 141, 196, 199, 202, 73, 205, 206, + 258, 207, 210, 215, 74, 169, 229, 230, 231, 236, + 237, 170, 238, 241, 267, 268, 242, 61, 247, 255, + 221, 263, 62, 63, 64, 65, 66, 260, 67, 68, + 69, 70, 262, 261, 71, 72, 264, 222, 273, 53, + 54, 55, 56, 57, 58, 59, 73, 265, 60, 274, + 275, 276, 277, 74, 281, 286, 283, 282, 288, 291, + 300, 304, 301, 305, 307, 308, 313, 316, 315, 137, + 138, 318, 139, 140, 141, 320, 321, 323, 324, 222, + 325, 328, 334, 222, 329, 137, 138, 209, 139, 140, + 141, 335, 336, 198, 112, 259, 269, 290, 256, 0, + 294, 312, 222, 61, 142, 0, 0, 0, 62, 63, + 64, 65, 66, 0, 67, 68, 69, 70, 0, 1, + 71, 72, 0, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 73, 0, 0, 0, 0, 0, 3, 74, + 220, 221, 0, 4, 5, 6, 0, 0, 0, 0, + 0, 7, 143, 144, 145, 146, 147, 148, 149, 8, + 0, 0, 9, 228, 10, 0, 0, 11, 143, 144, + 145, 146, 147, 148, 149, 0, 0, 0, 12, 13, + 14, 1, 0, 0, 0, 0, 0, 15, 2, 0, + 0, 0, 16, 17, 0, 0, 18, 19, 20, 227, + 3, 21, 0, 0, 0, 4, 5, 6, 0, 0, + 0, 137, 138, 7, 139, 140, 141, 22, 0, 0, 0, 8, 0, 0, 9, 0, 10, 0, 0, 11, - 138, 139, 140, 141, 142, 143, 144, 0, 1, 0, - 12, 13, 14, 0, 0, 2, 0, 0, 0, 15, - 0, 0, 0, 0, 16, 17, 302, 3, 18, 19, - 20, 0, 4, 5, 6, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 0, 0, 21, 0, 8, 0, - 0, 9, 0, 10, 0, 0, 11, 138, 139, 140, - 141, 142, 143, 144, 0, 1, 0, 12, 13, 14, - 0, 0, 2, 0, 0, 0, 15, 0, 0, 0, - 0, 16, 17, 314, 3, 18, 19, 20, 0, 4, + 0, 0, 0, 151, 0, 0, 0, 0, 0, 0, + 12, 13, 14, 1, 0, 0, 0, 0, 0, 15, + 2, 0, 0, 0, 16, 17, 0, 0, 18, 19, + 20, 314, 3, 21, 0, 0, 0, 4, 5, 6, + 0, 0, 0, 137, 138, 7, 139, 140, 141, 22, + 0, 0, 0, 8, 0, 0, 9, 0, 10, 0, + 0, 11, 280, 0, 143, 144, 145, 146, 147, 148, + 149, 0, 12, 13, 14, 1, 0, 0, 0, 0, + 0, 15, 2, 0, 0, 0, 16, 17, 0, 0, + 18, 19, 20, 330, 3, 21, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 0, 7, 0, 0, - 0, 0, 0, 21, 0, 8, 0, 0, 9, 0, - 10, 0, 0, 11, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 12, 13, 14, 0, 2, 0, - 0, 0, 0, 15, 0, 0, 0, 0, 16, 17, - 3, 0, 18, 19, 20, 4, 5, 6, 0, 0, - 0, 0, 0, 7, 0, 51, 52, 53, 54, 55, - 21, 8, 56, 0, 9, 0, 10, 0, 0, 11, + 0, 22, 0, 0, 0, 8, 0, 0, 9, 0, + 10, 0, 0, 11, 0, 0, 143, 144, 145, 146, + 147, 148, 149, 0, 12, 13, 14, 1, 0, 0, + 0, 0, 0, 15, 2, 139, 140, 141, 16, 17, + 0, 0, 18, 19, 20, 0, 3, 21, 0, 0, + 0, 4, 5, 6, 0, 0, 0, 137, 138, 7, + 139, 140, 141, 22, 0, 0, 0, 8, 0, 0, + 9, 0, 10, 0, 0, 11, 137, 138, 0, 139, + 140, 141, 0, 0, 0, 0, 12, 13, 14, 235, + 0, 0, 0, 0, 0, 15, 0, 0, 285, 0, + 16, 17, 0, 0, 18, 19, 20, 137, 138, 21, + 139, 140, 141, 0, 0, 143, 144, 145, 146, 147, + 148, 149, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 12, 13, 14, 0, 51, 52, 53, 54, 55, 15, - 0, 56, 0, 0, 16, 17, 0, 0, 18, 19, - 20, 0, 0, 132, 133, 164, 134, 135, 136, 0, - 0, 0, 0, 0, 0, 0, 21, 57, 0, 0, - 0, 0, 58, 59, 60, 61, 62, 0, 63, 64, - 65, 66, 0, 0, 67, 68, 132, 133, 0, 134, - 135, 136, 0, 69, 132, 133, 57, 134, 135, 136, - 70, 58, 59, 60, 61, 62, 0, 63, 64, 65, - 66, 0, 0, 67, 68, 0, 146, 0, 228, 0, - 0, 0, 69, 132, 133, 0, 134, 135, 136, 70, - 0, 0, 0, 138, 139, 140, 141, 142, 143, 144, - 0, 0, 271, 0, 221, 0, 0, 0, 0, 0, - 0, 132, 133, 0, 134, 135, 136, 0, 132, 133, - 0, 134, 135, 136, 0, 0, 138, 139, 140, 141, - 142, 143, 144, 276, 138, 139, 140, 141, 142, 143, - 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 138, 139, 140, 141, 142, 143, 144, + 143, 144, 145, 146, 147, 148, 149, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, + 144, 145, 146, 147, 148, 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 138, 139, 140, 141, 142, 143, 144, 138, 139, - 140, 141, 142, 143, 144 + 143, 144, 145, 146, 147, 148, 149 }; static const short int yycheck[] = { - 0, 18, 3, 4, 32, 6, 210, 38, 48, 36, - 27, 7, 24, 33, 62, 3, 4, 5, 6, 7, - 146, 145, 10, 56, 99, 58, 101, 231, 13, 49, - 48, 8, 9, 37, 11, 12, 13, 7, 13, 163, - 99, 99, 101, 101, 15, 16, 34, 35, 49, 7, - 99, 63, 101, 7, 99, 56, 101, 17, 18, 19, - 20, 101, 22, 99, 268, 101, 93, 63, 69, 70, - 101, 45, 46, 99, 7, 101, 7, 65, 7, 87, - 33, 87, 70, 71, 72, 73, 74, 213, 76, 77, - 78, 79, 7, 0, 82, 83, 98, 38, 97, 97, - 97, 102, 97, 91, 97, 93, 91, 92, 93, 94, - 98, 88, 89, 90, 91, 92, 93, 94, 93, 94, - 98, 97, 99, 37, 97, 97, 15, 7, 97, 97, - 97, 132, 133, 134, 135, 136, 97, 138, 139, 140, - 141, 142, 143, 144, 96, 271, 147, 97, 97, 150, - 276, 152, 97, 97, 97, 97, 51, 97, 7, 97, - 97, 96, 98, 7, 98, 14, 98, 195, 7, 59, - 48, 98, 98, 299, 7, 69, 69, 26, 178, 28, - 29, 13, 31, 32, 33, 7, 7, 187, 7, 98, - 39, 57, 100, 54, 7, 99, 101, 88, 47, 101, - 7, 50, 7, 52, 7, 206, 55, 3, 4, 5, - 6, 7, 23, 214, 10, 29, 25, 66, 67, 68, - 30, 7, 99, 7, 225, 61, 75, 228, 229, 103, - 100, 80, 81, 39, 7, 84, 85, 86, 34, 35, - 41, 26, 50, 98, 60, 7, 43, 42, 3, 249, - 10, 98, 97, 102, 44, 6, 99, 7, 7, 30, - 8, 9, 64, 11, 12, 13, 7, 23, 7, 65, - 97, 159, 264, 230, 70, 71, 72, 73, 74, 27, - 76, 77, 78, 79, 212, 150, 82, 83, 288, 32, - 270, 7, 292, 217, -1, 91, 313, 287, 14, -1, - -1, -1, 98, -1, -1, -1, -1, -1, 308, 25, - 26, -1, -1, -1, -1, 31, 32, 33, -1, -1, - 11, 12, 13, 39, -1, -1, -1, -1, -1, -1, - -1, 47, -1, -1, 50, -1, 52, -1, -1, 55, - 88, 89, 90, 91, 92, 93, 94, -1, 7, -1, - 66, 67, 68, -1, -1, 14, -1, -1, -1, 75, - -1, -1, -1, -1, 80, 81, 25, 26, 84, 85, - 86, -1, 31, 32, 33, -1, -1, -1, -1, -1, - 39, -1, -1, -1, -1, -1, 102, -1, 47, -1, - -1, 50, -1, 52, -1, -1, 55, 88, 89, 90, - 91, 92, 93, 94, -1, 7, -1, 66, 67, 68, - -1, -1, 14, -1, -1, -1, 75, -1, -1, -1, - -1, 80, 81, 25, 26, 84, 85, 86, -1, 31, - 32, 33, -1, -1, -1, -1, -1, 39, -1, -1, - -1, -1, -1, 102, -1, 47, -1, -1, 50, -1, - 52, -1, -1, 55, -1, -1, -1, -1, -1, -1, - -1, 7, -1, -1, 66, 67, 68, -1, 14, -1, - -1, -1, -1, 75, -1, -1, -1, -1, 80, 81, - 26, -1, 84, 85, 86, 31, 32, 33, -1, -1, - -1, -1, -1, 39, -1, 3, 4, 5, 6, 7, - 102, 47, 10, -1, 50, -1, 52, -1, -1, 55, + 0, 18, 3, 4, 33, 6, 50, 38, 40, 217, + 9, 28, 26, 66, 150, 17, 18, 35, 15, 47, + 48, 151, 3, 4, 5, 6, 7, 8, 9, 15, + 238, 12, 168, 51, 64, 19, 20, 21, 22, 92, + 24, 104, 58, 106, 60, 104, 104, 106, 106, 9, + 51, 65, 104, 9, 106, 36, 37, 50, 104, 60, + 106, 104, 106, 106, 9, 39, 65, 98, 104, 277, + 106, 9, 73, 74, 106, 0, 10, 11, 9, 13, + 14, 15, 9, 35, 89, 89, 67, 9, 103, 102, + 220, 72, 73, 74, 75, 76, 102, 78, 79, 80, + 81, 98, 99, 84, 85, 106, 102, 40, 102, 101, + 96, 97, 98, 99, 102, 96, 103, 98, 103, 102, + 102, 101, 103, 102, 3, 4, 5, 6, 7, 8, + 9, 102, 102, 12, 102, 102, 137, 138, 139, 140, + 141, 102, 143, 144, 145, 146, 147, 148, 149, 102, + 280, 152, 102, 102, 155, 285, 157, 36, 37, 93, + 94, 95, 96, 97, 98, 99, 102, 102, 39, 17, + 104, 200, 102, 3, 4, 5, 6, 7, 8, 9, + 103, 311, 12, 183, 102, 102, 102, 9, 67, 103, + 53, 9, 192, 72, 73, 74, 75, 76, 9, 78, + 79, 80, 81, 61, 50, 84, 85, 103, 103, 9, + 71, 71, 213, 15, 9, 9, 9, 96, 103, 59, + 221, 9, 105, 56, 103, 55, 9, 104, 106, 93, + 106, 232, 9, 9, 235, 236, 103, 67, 9, 25, + 31, 9, 72, 73, 74, 75, 76, 27, 78, 79, + 80, 81, 104, 32, 84, 85, 9, 257, 63, 3, + 4, 5, 6, 7, 8, 9, 96, 41, 12, 104, + 108, 105, 9, 103, 28, 103, 43, 52, 62, 9, + 44, 3, 45, 90, 103, 102, 46, 12, 104, 10, + 11, 9, 13, 14, 15, 9, 9, 9, 32, 299, + 8, 25, 9, 303, 102, 10, 11, 164, 13, 14, + 15, 328, 102, 155, 33, 224, 237, 272, 219, -1, + 279, 298, 322, 67, 29, -1, -1, -1, 72, 73, + 74, 75, 76, -1, 78, 79, 80, 81, -1, 9, + 84, 85, -1, -1, -1, -1, 16, -1, -1, -1, + -1, -1, 96, -1, -1, -1, -1, -1, 28, 103, + 30, 31, -1, 33, 34, 35, -1, -1, -1, -1, + -1, 41, 93, 94, 95, 96, 97, 98, 99, 49, + -1, -1, 52, 104, 54, -1, -1, 57, 93, 94, + 95, 96, 97, 98, 99, -1, -1, -1, 68, 69, + 70, 9, -1, -1, -1, -1, -1, 77, 16, -1, + -1, -1, 82, 83, -1, -1, 86, 87, 88, 27, + 28, 91, -1, -1, -1, 33, 34, 35, -1, -1, + -1, 10, 11, 41, 13, 14, 15, 107, -1, -1, + -1, 49, -1, -1, 52, -1, 54, -1, -1, 57, + -1, -1, -1, 32, -1, -1, -1, -1, -1, -1, + 68, 69, 70, 9, -1, -1, -1, -1, -1, 77, + 16, -1, -1, -1, 82, 83, -1, -1, 86, 87, + 88, 27, 28, 91, -1, -1, -1, 33, 34, 35, + -1, -1, -1, 10, 11, 41, 13, 14, 15, 107, + -1, -1, -1, 49, -1, -1, 52, -1, 54, -1, + -1, 57, 29, -1, 93, 94, 95, 96, 97, 98, + 99, -1, 68, 69, 70, 9, -1, -1, -1, -1, + -1, 77, 16, -1, -1, -1, 82, 83, -1, -1, + 86, 87, 88, 27, 28, 91, -1, -1, -1, 33, + 34, 35, -1, -1, -1, -1, -1, 41, -1, -1, + -1, 107, -1, -1, -1, 49, -1, -1, 52, -1, + 54, -1, -1, 57, -1, -1, 93, 94, 95, 96, + 97, 98, 99, -1, 68, 69, 70, 9, -1, -1, + -1, -1, -1, 77, 16, 13, 14, 15, 82, 83, + -1, -1, 86, 87, 88, -1, 28, 91, -1, -1, + -1, 33, 34, 35, -1, -1, -1, 10, 11, 41, + 13, 14, 15, 107, -1, -1, -1, 49, -1, -1, + 52, -1, 54, -1, -1, 57, 10, 11, -1, 13, + 14, 15, -1, -1, -1, -1, 68, 69, 70, 42, + -1, -1, -1, -1, -1, 77, -1, -1, 32, -1, + 82, 83, -1, -1, 86, 87, 88, 10, 11, 91, + 13, 14, 15, -1, -1, 93, 94, 95, 96, 97, + 98, 99, -1, -1, -1, 107, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 66, 67, 68, -1, 3, 4, 5, 6, 7, 75, - -1, 10, -1, -1, 80, 81, -1, -1, 84, 85, - 86, -1, -1, 8, 9, 53, 11, 12, 13, -1, - -1, -1, -1, -1, -1, -1, 102, 65, -1, -1, - -1, -1, 70, 71, 72, 73, 74, -1, 76, 77, - 78, 79, -1, -1, 82, 83, 8, 9, -1, 11, - 12, 13, -1, 91, 8, 9, 65, 11, 12, 13, - 98, 70, 71, 72, 73, 74, -1, 76, 77, 78, - 79, -1, -1, 82, 83, -1, 30, -1, 40, -1, - -1, -1, 91, 8, 9, -1, 11, 12, 13, 98, - -1, -1, -1, 88, 89, 90, 91, 92, 93, 94, - -1, -1, 27, -1, 99, -1, -1, -1, -1, -1, - -1, 8, 9, -1, 11, 12, 13, -1, 8, 9, - -1, 11, 12, 13, -1, -1, 88, 89, 90, 91, - 92, 93, 94, 30, 88, 89, 90, 91, 92, 93, - 94, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 88, 89, 90, 91, 92, 93, 94, + 93, 94, 95, 96, 97, 98, 99, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, + 94, 95, 96, 97, 98, 99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 88, 89, 90, 91, 92, 93, 94, 88, 89, - 90, 91, 92, 93, 94 + 93, 94, 95, 96, 97, 98, 99 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const unsigned char yystos[] = { - 0, 7, 14, 26, 31, 32, 33, 39, 47, 50, - 52, 55, 66, 67, 68, 75, 80, 81, 84, 85, - 86, 102, 105, 110, 111, 112, 124, 125, 126, 130, - 131, 132, 133, 134, 135, 136, 137, 141, 142, 143, - 144, 145, 146, 147, 153, 157, 158, 159, 167, 62, - 7, 3, 4, 5, 6, 7, 10, 65, 70, 71, - 72, 73, 74, 76, 77, 78, 79, 82, 83, 91, - 98, 107, 108, 107, 34, 35, 93, 107, 116, 117, - 118, 7, 48, 7, 37, 56, 58, 155, 7, 7, - 7, 124, 87, 87, 7, 0, 97, 98, 97, 49, - 124, 97, 38, 119, 129, 97, 97, 119, 129, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 107, 98, 96, 107, 96, - 107, 107, 8, 9, 11, 12, 13, 27, 88, 89, - 90, 91, 92, 93, 94, 98, 30, 98, 98, 48, - 101, 37, 15, 7, 51, 7, 7, 59, 156, 48, - 98, 107, 115, 98, 53, 107, 7, 161, 162, 69, - 69, 99, 107, 107, 107, 107, 107, 105, 106, 107, - 107, 107, 107, 107, 107, 107, 115, 106, 107, 36, - 93, 7, 114, 116, 7, 113, 107, 7, 127, 128, - 98, 57, 114, 100, 109, 99, 101, 115, 54, 15, - 16, 99, 101, 28, 29, 105, 138, 139, 140, 99, - 25, 99, 7, 99, 101, 38, 101, 119, 40, 88, - 101, 7, 148, 149, 7, 99, 101, 107, 99, 7, - 17, 18, 19, 20, 22, 160, 160, 23, 161, 106, - 107, 138, 25, 30, 99, 7, 7, 39, 120, 107, - 107, 127, 160, 99, 101, 61, 103, 100, 7, 163, - 164, 27, 26, 50, 41, 121, 30, 98, 150, 60, - 152, 148, 7, 160, 63, 163, 165, 166, 106, 42, - 43, 123, 106, 3, 10, 151, 98, 97, 64, 24, - 165, 44, 25, 99, 6, 7, 154, 7, 106, 7, - 30, 99, 101, 23, 25, 45, 46, 122, 7, 124, - 97 + 0, 9, 16, 28, 33, 34, 35, 41, 49, 52, + 54, 57, 68, 69, 70, 77, 82, 83, 86, 87, + 88, 91, 107, 110, 115, 116, 117, 130, 131, 132, + 136, 137, 138, 139, 140, 141, 142, 143, 147, 148, + 149, 150, 151, 152, 153, 154, 161, 165, 166, 167, + 177, 64, 9, 3, 4, 5, 6, 7, 8, 9, + 12, 67, 72, 73, 74, 75, 76, 78, 79, 80, + 81, 84, 85, 96, 103, 112, 113, 112, 36, 37, + 98, 112, 122, 123, 124, 9, 50, 9, 39, 58, + 60, 163, 9, 9, 9, 130, 89, 89, 9, 0, + 102, 103, 102, 51, 130, 102, 40, 125, 135, 102, + 102, 125, 135, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 112, 103, 101, 112, 101, 112, 112, 10, 11, 13, + 14, 15, 29, 93, 94, 95, 96, 97, 98, 99, + 103, 32, 103, 103, 50, 106, 39, 17, 9, 53, + 9, 9, 61, 164, 50, 103, 112, 121, 103, 55, + 112, 9, 169, 170, 71, 71, 104, 112, 112, 112, + 112, 112, 110, 111, 112, 112, 112, 112, 112, 112, + 112, 121, 111, 112, 38, 98, 9, 120, 122, 9, + 119, 112, 9, 133, 134, 103, 59, 9, 118, 120, + 105, 114, 104, 106, 121, 56, 17, 18, 104, 106, + 30, 31, 110, 144, 145, 146, 104, 27, 104, 9, + 104, 106, 40, 106, 125, 42, 93, 106, 9, 155, + 156, 9, 103, 104, 106, 112, 104, 9, 19, 20, + 21, 22, 24, 168, 168, 25, 169, 111, 112, 144, + 27, 32, 104, 9, 9, 41, 126, 112, 112, 133, + 168, 104, 106, 63, 104, 108, 105, 9, 171, 172, + 29, 28, 52, 43, 127, 32, 103, 157, 62, 160, + 155, 9, 168, 65, 171, 173, 174, 175, 176, 111, + 44, 45, 129, 111, 3, 90, 158, 103, 102, 66, + 92, 26, 175, 46, 27, 104, 12, 159, 9, 162, + 9, 9, 111, 9, 32, 8, 104, 106, 25, 102, + 27, 47, 48, 128, 9, 130, 102 }; #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) @@ -1581,271 +1608,286 @@ yyreduce: YY_REDUCE_PRINT (yyn); switch (yyn) { - case 24: -#line 156 "pars0grm.y" + case 25: +#line 162 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; - case 25: -#line 158 "pars0grm.y" + case 26: +#line 164 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-1], yyvsp[0]); ;} break; - case 26: -#line 162 "pars0grm.y" - { yyval = yyvsp[0];;} - break; - case 27: -#line 164 "pars0grm.y" - { yyval = pars_func(yyvsp[-3], yyvsp[-1]); ;} - break; - - case 28: -#line 165 "pars0grm.y" - { yyval = yyvsp[0];;} - break; - - case 29: -#line 166 "pars0grm.y" - { yyval = yyvsp[0];;} - break; - - case 30: -#line 167 "pars0grm.y" - { yyval = yyvsp[0];;} - break; - - case 31: #line 168 "pars0grm.y" { yyval = yyvsp[0];;} break; + case 28: +#line 170 "pars0grm.y" + { yyval = pars_func(yyvsp[-3], yyvsp[-1]); ;} + break; + + case 29: +#line 171 "pars0grm.y" + { yyval = yyvsp[0];;} + break; + + case 30: +#line 172 "pars0grm.y" + { yyval = yyvsp[0];;} + break; + + case 31: +#line 173 "pars0grm.y" + { yyval = yyvsp[0];;} + break; + case 32: -#line 169 "pars0grm.y" +#line 174 "pars0grm.y" { yyval = yyvsp[0];;} break; case 33: -#line 170 "pars0grm.y" - { yyval = pars_op('+', yyvsp[-2], yyvsp[0]); ;} +#line 175 "pars0grm.y" + { yyval = yyvsp[0];;} break; case 34: -#line 171 "pars0grm.y" - { yyval = pars_op('-', yyvsp[-2], yyvsp[0]); ;} +#line 176 "pars0grm.y" + { yyval = yyvsp[0];;} break; case 35: -#line 172 "pars0grm.y" - { yyval = pars_op('*', yyvsp[-2], yyvsp[0]); ;} +#line 177 "pars0grm.y" + { yyval = yyvsp[0];;} break; case 36: -#line 173 "pars0grm.y" - { yyval = pars_op('/', yyvsp[-2], yyvsp[0]); ;} +#line 178 "pars0grm.y" + { yyval = pars_op('+', yyvsp[-2], yyvsp[0]); ;} break; case 37: -#line 174 "pars0grm.y" - { yyval = pars_op('-', yyvsp[0], NULL); ;} +#line 179 "pars0grm.y" + { yyval = pars_op('-', yyvsp[-2], yyvsp[0]); ;} break; case 38: -#line 175 "pars0grm.y" - { yyval = yyvsp[-1]; ;} +#line 180 "pars0grm.y" + { yyval = pars_op('*', yyvsp[-2], yyvsp[0]); ;} break; case 39: -#line 176 "pars0grm.y" - { yyval = pars_op('=', yyvsp[-2], yyvsp[0]); ;} +#line 181 "pars0grm.y" + { yyval = pars_op('/', yyvsp[-2], yyvsp[0]); ;} break; case 40: -#line 177 "pars0grm.y" - { yyval = pars_op('<', yyvsp[-2], yyvsp[0]); ;} +#line 182 "pars0grm.y" + { yyval = pars_op('-', yyvsp[0], NULL); ;} break; case 41: -#line 178 "pars0grm.y" - { yyval = pars_op('>', yyvsp[-2], yyvsp[0]); ;} +#line 183 "pars0grm.y" + { yyval = yyvsp[-1]; ;} break; case 42: -#line 179 "pars0grm.y" - { yyval = pars_op(PARS_GE_TOKEN, yyvsp[-2], yyvsp[0]); ;} +#line 184 "pars0grm.y" + { yyval = pars_op('=', yyvsp[-2], yyvsp[0]); ;} break; case 43: -#line 180 "pars0grm.y" - { yyval = pars_op(PARS_LE_TOKEN, yyvsp[-2], yyvsp[0]); ;} +#line 185 "pars0grm.y" + { yyval = pars_op('<', yyvsp[-2], yyvsp[0]); ;} break; case 44: -#line 181 "pars0grm.y" - { yyval = pars_op(PARS_NE_TOKEN, yyvsp[-2], yyvsp[0]); ;} +#line 186 "pars0grm.y" + { yyval = pars_op('>', yyvsp[-2], yyvsp[0]); ;} break; case 45: -#line 182 "pars0grm.y" - { yyval = pars_op(PARS_AND_TOKEN, yyvsp[-2], yyvsp[0]); ;} +#line 187 "pars0grm.y" + { yyval = pars_op(PARS_GE_TOKEN, yyvsp[-2], yyvsp[0]); ;} break; case 46: -#line 183 "pars0grm.y" - { yyval = pars_op(PARS_OR_TOKEN, yyvsp[-2], yyvsp[0]); ;} +#line 188 "pars0grm.y" + { yyval = pars_op(PARS_LE_TOKEN, yyvsp[-2], yyvsp[0]); ;} break; case 47: -#line 184 "pars0grm.y" - { yyval = pars_op(PARS_NOT_TOKEN, yyvsp[0], NULL); ;} +#line 189 "pars0grm.y" + { yyval = pars_op(PARS_NE_TOKEN, yyvsp[-2], yyvsp[0]); ;} break; case 48: -#line 186 "pars0grm.y" - { yyval = pars_op(PARS_NOTFOUND_TOKEN, yyvsp[-2], NULL); ;} +#line 190 "pars0grm.y" + { yyval = pars_op(PARS_AND_TOKEN, yyvsp[-2], yyvsp[0]); ;} break; case 49: -#line 188 "pars0grm.y" - { yyval = pars_op(PARS_NOTFOUND_TOKEN, yyvsp[-2], NULL); ;} +#line 191 "pars0grm.y" + { yyval = pars_op(PARS_OR_TOKEN, yyvsp[-2], yyvsp[0]); ;} break; case 50: #line 192 "pars0grm.y" - { yyval = &pars_to_char_token; ;} + { yyval = pars_op(PARS_NOT_TOKEN, yyvsp[0], NULL); ;} break; case 51: -#line 193 "pars0grm.y" - { yyval = &pars_to_number_token; ;} +#line 194 "pars0grm.y" + { yyval = pars_op(PARS_NOTFOUND_TOKEN, yyvsp[-2], NULL); ;} break; case 52: -#line 194 "pars0grm.y" - { yyval = &pars_to_binary_token; ;} +#line 196 "pars0grm.y" + { yyval = pars_op(PARS_NOTFOUND_TOKEN, yyvsp[-2], NULL); ;} break; case 53: -#line 196 "pars0grm.y" - { yyval = &pars_binary_to_number_token; ;} +#line 200 "pars0grm.y" + { yyval = &pars_to_char_token; ;} break; case 54: -#line 197 "pars0grm.y" - { yyval = &pars_substr_token; ;} +#line 201 "pars0grm.y" + { yyval = &pars_to_number_token; ;} break; case 55: -#line 198 "pars0grm.y" - { yyval = &pars_concat_token; ;} +#line 202 "pars0grm.y" + { yyval = &pars_to_binary_token; ;} break; case 56: -#line 199 "pars0grm.y" - { yyval = &pars_instr_token; ;} +#line 204 "pars0grm.y" + { yyval = &pars_binary_to_number_token; ;} break; case 57: -#line 200 "pars0grm.y" - { yyval = &pars_length_token; ;} +#line 205 "pars0grm.y" + { yyval = &pars_substr_token; ;} break; case 58: -#line 201 "pars0grm.y" - { yyval = &pars_sysdate_token; ;} +#line 206 "pars0grm.y" + { yyval = &pars_concat_token; ;} break; case 59: -#line 202 "pars0grm.y" - { yyval = &pars_rnd_token; ;} +#line 207 "pars0grm.y" + { yyval = &pars_instr_token; ;} break; case 60: -#line 203 "pars0grm.y" +#line 208 "pars0grm.y" + { yyval = &pars_length_token; ;} + break; + + case 61: +#line 209 "pars0grm.y" + { yyval = &pars_sysdate_token; ;} + break; + + case 62: +#line 210 "pars0grm.y" + { yyval = &pars_rnd_token; ;} + break; + + case 63: +#line 211 "pars0grm.y" { yyval = &pars_rnd_str_token; ;} break; - case 64: -#line 214 "pars0grm.y" + case 67: +#line 222 "pars0grm.y" { yyval = pars_stored_procedure_call(yyvsp[-4]); ;} break; - case 65: -#line 219 "pars0grm.y" + case 68: +#line 227 "pars0grm.y" { yyval = pars_procedure_call(yyvsp[-3], yyvsp[-1]); ;} break; - case 66: -#line 223 "pars0grm.y" + case 69: +#line 231 "pars0grm.y" { yyval = &pars_replstr_token; ;} break; - case 67: -#line 224 "pars0grm.y" + case 70: +#line 232 "pars0grm.y" { yyval = &pars_printf_token; ;} break; - case 68: -#line 225 "pars0grm.y" + case 71: +#line 233 "pars0grm.y" { yyval = &pars_assert_token; ;} break; - case 69: -#line 229 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} - break; - - case 70: -#line 231 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} - break; - - case 71: -#line 235 "pars0grm.y" - { yyval = NULL; ;} - break; - case 72: -#line 236 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} +#line 237 "pars0grm.y" + { yyval = yyvsp[-2]; ;} break; case 73: -#line 238 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} +#line 241 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; case 74: -#line 242 "pars0grm.y" - { yyval = NULL; ;} - break; - - case 75: #line 243 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]);;} - break; - - case 76: -#line 244 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} break; - case 77: + case 75: +#line 247 "pars0grm.y" + { yyval = NULL; ;} + break; + + case 76: #line 248 "pars0grm.y" - { yyval = yyvsp[0]; ;} + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} + break; + + case 77: +#line 250 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} break; case 78: -#line 250 "pars0grm.y" +#line 254 "pars0grm.y" + { yyval = NULL; ;} + break; + + case 79: +#line 255 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]);;} + break; + + case 80: +#line 256 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} + break; + + case 81: +#line 260 "pars0grm.y" + { yyval = yyvsp[0]; ;} + break; + + case 82: +#line 262 "pars0grm.y" { yyval = pars_func(&pars_count_token, que_node_list_add_last(NULL, sym_tab_add_int_lit( pars_sym_tab_global, 1))); ;} break; - case 79: -#line 255 "pars0grm.y" + case 83: +#line 267 "pars0grm.y" { yyval = pars_func(&pars_count_token, que_node_list_add_last(NULL, pars_func(&pars_distinct_token, @@ -1853,410 +1895,436 @@ yyreduce: NULL, yyvsp[-1])))); ;} break; - case 80: -#line 261 "pars0grm.y" + case 84: +#line 273 "pars0grm.y" { yyval = pars_func(&pars_sum_token, que_node_list_add_last(NULL, yyvsp[-1])); ;} break; - case 81: -#line 267 "pars0grm.y" + case 85: +#line 279 "pars0grm.y" { yyval = NULL; ;} break; - case 82: -#line 268 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} - break; - - case 83: -#line 270 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} - break; - - case 84: -#line 274 "pars0grm.y" - { yyval = pars_select_list(&pars_star_denoter, - NULL); ;} - break; - - case 85: -#line 277 "pars0grm.y" - { yyval = pars_select_list(yyvsp[-2], yyvsp[0]); ;} - break; - case 86: -#line 278 "pars0grm.y" - { yyval = pars_select_list(yyvsp[0], NULL); ;} +#line 280 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; case 87: #line 282 "pars0grm.y" - { yyval = NULL; ;} + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} break; case 88: -#line 283 "pars0grm.y" - { yyval = yyvsp[0]; ;} +#line 286 "pars0grm.y" + { yyval = pars_select_list(&pars_star_denoter, + NULL); ;} break; case 89: -#line 287 "pars0grm.y" - { yyval = NULL; ;} +#line 289 "pars0grm.y" + { yyval = pars_select_list(yyvsp[-2], yyvsp[0]); ;} break; case 90: -#line 289 "pars0grm.y" - { yyval = &pars_update_token; ;} +#line 290 "pars0grm.y" + { yyval = pars_select_list(yyvsp[0], NULL); ;} break; case 91: -#line 293 "pars0grm.y" +#line 294 "pars0grm.y" { yyval = NULL; ;} break; case 92: #line 295 "pars0grm.y" - { yyval = &pars_consistent_token; ;} + { yyval = yyvsp[0]; ;} break; case 93: #line 299 "pars0grm.y" - { yyval = &pars_asc_token; ;} + { yyval = NULL; ;} break; case 94: -#line 300 "pars0grm.y" - { yyval = &pars_asc_token; ;} +#line 301 "pars0grm.y" + { yyval = &pars_update_token; ;} break; case 95: -#line 301 "pars0grm.y" - { yyval = &pars_desc_token; ;} - break; - - case 96: #line 305 "pars0grm.y" { yyval = NULL; ;} break; - case 97: + case 96: #line 307 "pars0grm.y" - { yyval = pars_order_by(yyvsp[-1], yyvsp[0]); ;} + { yyval = &pars_consistent_token; ;} + break; + + case 97: +#line 311 "pars0grm.y" + { yyval = &pars_asc_token; ;} break; case 98: -#line 316 "pars0grm.y" +#line 312 "pars0grm.y" + { yyval = &pars_asc_token; ;} + break; + + case 99: +#line 313 "pars0grm.y" + { yyval = &pars_desc_token; ;} + break; + + case 100: +#line 317 "pars0grm.y" + { yyval = NULL; ;} + break; + + case 101: +#line 319 "pars0grm.y" + { yyval = pars_order_by(yyvsp[-1], yyvsp[0]); ;} + break; + + case 102: +#line 328 "pars0grm.y" { yyval = pars_select_statement(yyvsp[-6], yyvsp[-4], yyvsp[-3], yyvsp[-2], yyvsp[-1], yyvsp[0]); ;} break; - case 99: -#line 322 "pars0grm.y" - { yyval = yyvsp[0]; ;} - break; - - case 100: -#line 327 "pars0grm.y" - { yyval = pars_insert_statement(yyvsp[-4], yyvsp[-1], NULL); ;} - break; - - case 101: -#line 329 "pars0grm.y" - { yyval = pars_insert_statement(yyvsp[-1], NULL, yyvsp[0]); ;} - break; - - case 102: -#line 333 "pars0grm.y" - { yyval = pars_column_assignment(yyvsp[-2], yyvsp[0]); ;} - break; - case 103: -#line 337 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} +#line 334 "pars0grm.y" + { yyval = yyvsp[0]; ;} break; case 104: #line 339 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} + { yyval = pars_insert_statement(yyvsp[-4], yyvsp[-1], NULL); ;} break; case 105: -#line 345 "pars0grm.y" - { yyval = yyvsp[0]; ;} +#line 341 "pars0grm.y" + { yyval = pars_insert_statement(yyvsp[-1], NULL, yyvsp[0]); ;} break; case 106: +#line 345 "pars0grm.y" + { yyval = pars_column_assignment(yyvsp[-2], yyvsp[0]); ;} + break; + + case 107: +#line 349 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} + break; + + case 108: #line 351 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} + break; + + case 109: +#line 357 "pars0grm.y" + { yyval = yyvsp[0]; ;} + break; + + case 110: +#line 363 "pars0grm.y" { yyval = pars_update_statement_start(FALSE, yyvsp[-2], yyvsp[0]); ;} break; - case 107: -#line 357 "pars0grm.y" + case 111: +#line 369 "pars0grm.y" { yyval = pars_update_statement(yyvsp[-1], NULL, yyvsp[0]); ;} break; - case 108: -#line 362 "pars0grm.y" + case 112: +#line 374 "pars0grm.y" { yyval = pars_update_statement(yyvsp[-1], yyvsp[0], NULL); ;} break; - case 109: -#line 367 "pars0grm.y" + case 113: +#line 379 "pars0grm.y" { yyval = pars_update_statement_start(TRUE, yyvsp[0], NULL); ;} break; - case 110: -#line 373 "pars0grm.y" + case 114: +#line 385 "pars0grm.y" { yyval = pars_update_statement(yyvsp[-1], NULL, yyvsp[0]); ;} break; - case 111: -#line 378 "pars0grm.y" + case 115: +#line 390 "pars0grm.y" { yyval = pars_update_statement(yyvsp[-1], yyvsp[0], NULL); ;} break; - case 112: -#line 383 "pars0grm.y" + case 116: +#line 395 "pars0grm.y" { yyval = pars_row_printf_statement(yyvsp[0]); ;} break; - case 113: -#line 388 "pars0grm.y" - { yyval = pars_assignment_statement(yyvsp[-2], yyvsp[0]); ;} - break; - - case 114: -#line 394 "pars0grm.y" - { yyval = pars_elsif_element(yyvsp[-2], yyvsp[0]); ;} - break; - - case 115: -#line 398 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} - break; - - case 116: -#line 400 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-1], yyvsp[0]); ;} - break; - case 117: -#line 404 "pars0grm.y" - { yyval = NULL; ;} +#line 400 "pars0grm.y" + { yyval = pars_assignment_statement(yyvsp[-2], yyvsp[0]); ;} break; case 118: #line 406 "pars0grm.y" - { yyval = yyvsp[0]; ;} + { yyval = pars_elsif_element(yyvsp[-2], yyvsp[0]); ;} break; case 119: -#line 407 "pars0grm.y" - { yyval = yyvsp[0]; ;} +#line 410 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; case 120: -#line 414 "pars0grm.y" - { yyval = pars_if_statement(yyvsp[-5], yyvsp[-3], yyvsp[-2]); ;} +#line 412 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-1], yyvsp[0]); ;} break; case 121: -#line 420 "pars0grm.y" - { yyval = pars_while_statement(yyvsp[-4], yyvsp[-2]); ;} +#line 416 "pars0grm.y" + { yyval = NULL; ;} break; case 122: -#line 428 "pars0grm.y" - { yyval = pars_for_statement(yyvsp[-8], yyvsp[-6], yyvsp[-4], yyvsp[-2]); ;} +#line 418 "pars0grm.y" + { yyval = yyvsp[0]; ;} break; case 123: -#line 432 "pars0grm.y" - { yyval = pars_return_statement(); ;} +#line 419 "pars0grm.y" + { yyval = yyvsp[0]; ;} break; case 124: -#line 437 "pars0grm.y" +#line 426 "pars0grm.y" + { yyval = pars_if_statement(yyvsp[-5], yyvsp[-3], yyvsp[-2]); ;} + break; + + case 125: +#line 432 "pars0grm.y" + { yyval = pars_while_statement(yyvsp[-4], yyvsp[-2]); ;} + break; + + case 126: +#line 440 "pars0grm.y" + { yyval = pars_for_statement(yyvsp[-8], yyvsp[-6], yyvsp[-4], yyvsp[-2]); ;} + break; + + case 127: +#line 444 "pars0grm.y" + { yyval = pars_exit_statement(); ;} + break; + + case 128: +#line 448 "pars0grm.y" + { yyval = pars_return_statement(); ;} + break; + + case 129: +#line 453 "pars0grm.y" { yyval = pars_open_statement( ROW_SEL_OPEN_CURSOR, yyvsp[0]); ;} break; - case 125: -#line 443 "pars0grm.y" + case 130: +#line 459 "pars0grm.y" { yyval = pars_open_statement( ROW_SEL_CLOSE_CURSOR, yyvsp[0]); ;} break; - case 126: -#line 449 "pars0grm.y" - { yyval = pars_fetch_statement(yyvsp[-2], yyvsp[0]); ;} - break; - - case 127: -#line 454 "pars0grm.y" - { yyval = pars_column_def(yyvsp[-3], yyvsp[-2], yyvsp[-1], yyvsp[0]); ;} - break; - - case 128: -#line 458 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} - break; - - case 129: -#line 460 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} - break; - - case 130: -#line 464 "pars0grm.y" - { yyval = NULL; ;} - break; - case 131: -#line 466 "pars0grm.y" - { yyval = yyvsp[-1]; ;} +#line 465 "pars0grm.y" + { yyval = pars_fetch_statement(yyvsp[-2], yyvsp[0], NULL); ;} break; case 132: -#line 470 "pars0grm.y" - { yyval = NULL; ;} +#line 467 "pars0grm.y" + { yyval = pars_fetch_statement(yyvsp[-2], NULL, yyvsp[0]); ;} break; case 133: #line 472 "pars0grm.y" - { yyval = &pars_int_token; - /* pass any non-NULL pointer */ ;} + { yyval = pars_column_def(yyvsp[-4], yyvsp[-3], yyvsp[-2], yyvsp[-1], yyvsp[0]); ;} break; case 134: -#line 477 "pars0grm.y" - { yyval = NULL; ;} +#line 476 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; case 135: -#line 479 "pars0grm.y" +#line 478 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} + break; + + case 136: +#line 482 "pars0grm.y" + { yyval = NULL; ;} + break; + + case 137: +#line 484 "pars0grm.y" + { yyval = yyvsp[-1]; ;} + break; + + case 138: +#line 488 "pars0grm.y" + { yyval = NULL; ;} + break; + + case 139: +#line 490 "pars0grm.y" { yyval = &pars_int_token; /* pass any non-NULL pointer */ ;} break; - case 136: -#line 486 "pars0grm.y" - { yyval = pars_create_table(yyvsp[-4], yyvsp[-2], yyvsp[0]); ;} - break; - - case 137: -#line 490 "pars0grm.y" - { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} - break; - - case 138: -#line 492 "pars0grm.y" - { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} - break; - - case 139: -#line 496 "pars0grm.y" - { yyval = NULL; ;} - break; - case 140: -#line 497 "pars0grm.y" - { yyval = &pars_unique_token; ;} +#line 495 "pars0grm.y" + { yyval = NULL; ;} break; case 141: -#line 501 "pars0grm.y" - { yyval = NULL; ;} +#line 497 "pars0grm.y" + { yyval = &pars_int_token; + /* pass any non-NULL pointer */ ;} break; case 142: #line 502 "pars0grm.y" - { yyval = &pars_clustered_token; ;} + { yyval = NULL; ;} break; case 143: -#line 510 "pars0grm.y" - { yyval = pars_create_index(yyvsp[-8], yyvsp[-7], yyvsp[-5], yyvsp[-3], yyvsp[-1]); ;} +#line 504 "pars0grm.y" + { yyval = &pars_int_token; + /* pass any non-NULL pointer */ ;} break; case 144: -#line 515 "pars0grm.y" - { yyval = pars_commit_statement(); ;} +#line 511 "pars0grm.y" + { yyval = pars_create_table(yyvsp[-4], yyvsp[-2], yyvsp[0]); ;} break; case 145: -#line 520 "pars0grm.y" - { yyval = pars_rollback_statement(); ;} +#line 515 "pars0grm.y" + { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; case 146: -#line 524 "pars0grm.y" - { yyval = &pars_int_token; ;} +#line 517 "pars0grm.y" + { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} break; case 147: -#line 525 "pars0grm.y" - { yyval = &pars_int_token; ;} +#line 521 "pars0grm.y" + { yyval = NULL; ;} break; case 148: -#line 526 "pars0grm.y" - { yyval = &pars_char_token; ;} +#line 522 "pars0grm.y" + { yyval = &pars_unique_token; ;} break; case 149: -#line 527 "pars0grm.y" - { yyval = &pars_binary_token; ;} +#line 526 "pars0grm.y" + { yyval = NULL; ;} break; case 150: -#line 528 "pars0grm.y" - { yyval = &pars_blob_token; ;} +#line 527 "pars0grm.y" + { yyval = &pars_clustered_token; ;} break; case 151: -#line 533 "pars0grm.y" +#line 535 "pars0grm.y" + { yyval = pars_create_index(yyvsp[-8], yyvsp[-7], yyvsp[-5], yyvsp[-3], yyvsp[-1]); ;} + break; + + case 152: +#line 540 "pars0grm.y" + { yyval = pars_commit_statement(); ;} + break; + + case 153: +#line 545 "pars0grm.y" + { yyval = pars_rollback_statement(); ;} + break; + + case 154: +#line 549 "pars0grm.y" + { yyval = &pars_int_token; ;} + break; + + case 155: +#line 550 "pars0grm.y" + { yyval = &pars_int_token; ;} + break; + + case 156: +#line 551 "pars0grm.y" + { yyval = &pars_char_token; ;} + break; + + case 157: +#line 552 "pars0grm.y" + { yyval = &pars_binary_token; ;} + break; + + case 158: +#line 553 "pars0grm.y" + { yyval = &pars_blob_token; ;} + break; + + case 159: +#line 558 "pars0grm.y" { yyval = pars_parameter_declaration(yyvsp[-2], PARS_INPUT, yyvsp[0]); ;} break; - case 152: -#line 536 "pars0grm.y" + case 160: +#line 561 "pars0grm.y" { yyval = pars_parameter_declaration(yyvsp[-2], PARS_OUTPUT, yyvsp[0]); ;} break; - case 153: -#line 541 "pars0grm.y" + case 161: +#line 566 "pars0grm.y" { yyval = NULL; ;} break; - case 154: -#line 542 "pars0grm.y" + case 162: +#line 567 "pars0grm.y" { yyval = que_node_list_add_last(NULL, yyvsp[0]); ;} break; - case 155: -#line 544 "pars0grm.y" + case 163: +#line 569 "pars0grm.y" { yyval = que_node_list_add_last(yyvsp[-2], yyvsp[0]); ;} break; - case 156: -#line 549 "pars0grm.y" + case 164: +#line 574 "pars0grm.y" { yyval = pars_variable_declaration(yyvsp[-2], yyvsp[-1]); ;} break; - case 160: -#line 561 "pars0grm.y" + case 168: +#line 586 "pars0grm.y" { yyval = pars_cursor_declaration(yyvsp[-3], yyvsp[-1]); ;} break; - case 164: -#line 577 "pars0grm.y" + case 169: +#line 591 "pars0grm.y" + { yyval = pars_function_declaration(yyvsp[-1]); ;} + break; + + case 175: +#line 612 "pars0grm.y" { yyval = pars_procedure_definition(yyvsp[-9], yyvsp[-7], yyvsp[-1]); ;} break; @@ -2265,7 +2333,7 @@ yyreduce: } /* Line 1010 of yacc.c. */ -#line 2269 "pars0grm.tab.c" +#line 2337 "pars0grm.tab.c" yyvsp -= yylen; yyssp -= yylen; @@ -2490,6 +2558,6 @@ yyreturn: } -#line 581 "pars0grm.y" +#line 616 "pars0grm.y" diff --git a/storage/innobase/pars/pars0grm.h b/storage/innobase/pars/pars0grm.h index e35fcf47692..996fc37f13b 100644 --- a/storage/innobase/pars/pars0grm.h +++ b/storage/innobase/pars/pars0grm.h @@ -32,177 +32,187 @@ PARS_INT_LIT = 258, PARS_FLOAT_LIT = 259, PARS_STR_LIT = 260, - PARS_NULL_LIT = 261, - PARS_ID_TOKEN = 262, - PARS_AND_TOKEN = 263, - PARS_OR_TOKEN = 264, - PARS_NOT_TOKEN = 265, - PARS_GE_TOKEN = 266, - PARS_LE_TOKEN = 267, - PARS_NE_TOKEN = 268, - PARS_PROCEDURE_TOKEN = 269, - PARS_IN_TOKEN = 270, - PARS_OUT_TOKEN = 271, - PARS_BINARY_TOKEN = 272, - PARS_BLOB_TOKEN = 273, - PARS_INT_TOKEN = 274, - PARS_INTEGER_TOKEN = 275, - PARS_FLOAT_TOKEN = 276, - PARS_CHAR_TOKEN = 277, - PARS_IS_TOKEN = 278, - PARS_BEGIN_TOKEN = 279, - PARS_END_TOKEN = 280, - PARS_IF_TOKEN = 281, - PARS_THEN_TOKEN = 282, - PARS_ELSE_TOKEN = 283, - PARS_ELSIF_TOKEN = 284, - PARS_LOOP_TOKEN = 285, - PARS_WHILE_TOKEN = 286, - PARS_RETURN_TOKEN = 287, - PARS_SELECT_TOKEN = 288, - PARS_SUM_TOKEN = 289, - PARS_COUNT_TOKEN = 290, - PARS_DISTINCT_TOKEN = 291, - PARS_FROM_TOKEN = 292, - PARS_WHERE_TOKEN = 293, - PARS_FOR_TOKEN = 294, - PARS_DDOT_TOKEN = 295, - PARS_CONSISTENT_TOKEN = 296, - PARS_READ_TOKEN = 297, - PARS_ORDER_TOKEN = 298, - PARS_BY_TOKEN = 299, - PARS_ASC_TOKEN = 300, - PARS_DESC_TOKEN = 301, - PARS_INSERT_TOKEN = 302, - PARS_INTO_TOKEN = 303, - PARS_VALUES_TOKEN = 304, - PARS_UPDATE_TOKEN = 305, - PARS_SET_TOKEN = 306, - PARS_DELETE_TOKEN = 307, - PARS_CURRENT_TOKEN = 308, - PARS_OF_TOKEN = 309, - PARS_CREATE_TOKEN = 310, - PARS_TABLE_TOKEN = 311, - PARS_INDEX_TOKEN = 312, - PARS_UNIQUE_TOKEN = 313, - PARS_CLUSTERED_TOKEN = 314, - PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 315, - PARS_ON_TOKEN = 316, - PARS_ASSIGN_TOKEN = 317, - PARS_DECLARE_TOKEN = 318, - PARS_CURSOR_TOKEN = 319, - PARS_SQL_TOKEN = 320, - PARS_OPEN_TOKEN = 321, - PARS_FETCH_TOKEN = 322, - PARS_CLOSE_TOKEN = 323, - PARS_NOTFOUND_TOKEN = 324, - PARS_TO_CHAR_TOKEN = 325, - PARS_TO_NUMBER_TOKEN = 326, - PARS_TO_BINARY_TOKEN = 327, - PARS_BINARY_TO_NUMBER_TOKEN = 328, - PARS_SUBSTR_TOKEN = 329, - PARS_REPLSTR_TOKEN = 330, - PARS_CONCAT_TOKEN = 331, - PARS_INSTR_TOKEN = 332, - PARS_LENGTH_TOKEN = 333, - PARS_SYSDATE_TOKEN = 334, - PARS_PRINTF_TOKEN = 335, - PARS_ASSERT_TOKEN = 336, - PARS_RND_TOKEN = 337, - PARS_RND_STR_TOKEN = 338, - PARS_ROW_PRINTF_TOKEN = 339, - PARS_COMMIT_TOKEN = 340, - PARS_ROLLBACK_TOKEN = 341, - PARS_WORK_TOKEN = 342, - NEG = 343 + PARS_FIXBINARY_LIT = 261, + PARS_BLOB_LIT = 262, + PARS_NULL_LIT = 263, + PARS_ID_TOKEN = 264, + PARS_AND_TOKEN = 265, + PARS_OR_TOKEN = 266, + PARS_NOT_TOKEN = 267, + PARS_GE_TOKEN = 268, + PARS_LE_TOKEN = 269, + PARS_NE_TOKEN = 270, + PARS_PROCEDURE_TOKEN = 271, + PARS_IN_TOKEN = 272, + PARS_OUT_TOKEN = 273, + PARS_BINARY_TOKEN = 274, + PARS_BLOB_TOKEN = 275, + PARS_INT_TOKEN = 276, + PARS_INTEGER_TOKEN = 277, + PARS_FLOAT_TOKEN = 278, + PARS_CHAR_TOKEN = 279, + PARS_IS_TOKEN = 280, + PARS_BEGIN_TOKEN = 281, + PARS_END_TOKEN = 282, + PARS_IF_TOKEN = 283, + PARS_THEN_TOKEN = 284, + PARS_ELSE_TOKEN = 285, + PARS_ELSIF_TOKEN = 286, + PARS_LOOP_TOKEN = 287, + PARS_WHILE_TOKEN = 288, + PARS_RETURN_TOKEN = 289, + PARS_SELECT_TOKEN = 290, + PARS_SUM_TOKEN = 291, + PARS_COUNT_TOKEN = 292, + PARS_DISTINCT_TOKEN = 293, + PARS_FROM_TOKEN = 294, + PARS_WHERE_TOKEN = 295, + PARS_FOR_TOKEN = 296, + PARS_DDOT_TOKEN = 297, + PARS_CONSISTENT_TOKEN = 298, + PARS_READ_TOKEN = 299, + PARS_ORDER_TOKEN = 300, + PARS_BY_TOKEN = 301, + PARS_ASC_TOKEN = 302, + PARS_DESC_TOKEN = 303, + PARS_INSERT_TOKEN = 304, + PARS_INTO_TOKEN = 305, + PARS_VALUES_TOKEN = 306, + PARS_UPDATE_TOKEN = 307, + PARS_SET_TOKEN = 308, + PARS_DELETE_TOKEN = 309, + PARS_CURRENT_TOKEN = 310, + PARS_OF_TOKEN = 311, + PARS_CREATE_TOKEN = 312, + PARS_TABLE_TOKEN = 313, + PARS_INDEX_TOKEN = 314, + PARS_UNIQUE_TOKEN = 315, + PARS_CLUSTERED_TOKEN = 316, + PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 317, + PARS_ON_TOKEN = 318, + PARS_ASSIGN_TOKEN = 319, + PARS_DECLARE_TOKEN = 320, + PARS_CURSOR_TOKEN = 321, + PARS_SQL_TOKEN = 322, + PARS_OPEN_TOKEN = 323, + PARS_FETCH_TOKEN = 324, + PARS_CLOSE_TOKEN = 325, + PARS_NOTFOUND_TOKEN = 326, + PARS_TO_CHAR_TOKEN = 327, + PARS_TO_NUMBER_TOKEN = 328, + PARS_TO_BINARY_TOKEN = 329, + PARS_BINARY_TO_NUMBER_TOKEN = 330, + PARS_SUBSTR_TOKEN = 331, + PARS_REPLSTR_TOKEN = 332, + PARS_CONCAT_TOKEN = 333, + PARS_INSTR_TOKEN = 334, + PARS_LENGTH_TOKEN = 335, + PARS_SYSDATE_TOKEN = 336, + PARS_PRINTF_TOKEN = 337, + PARS_ASSERT_TOKEN = 338, + PARS_RND_TOKEN = 339, + PARS_RND_STR_TOKEN = 340, + PARS_ROW_PRINTF_TOKEN = 341, + PARS_COMMIT_TOKEN = 342, + PARS_ROLLBACK_TOKEN = 343, + PARS_WORK_TOKEN = 344, + PARS_UNSIGNED_TOKEN = 345, + PARS_EXIT_TOKEN = 346, + PARS_FUNCTION_TOKEN = 347, + NEG = 348 }; #endif #define PARS_INT_LIT 258 #define PARS_FLOAT_LIT 259 #define PARS_STR_LIT 260 -#define PARS_NULL_LIT 261 -#define PARS_ID_TOKEN 262 -#define PARS_AND_TOKEN 263 -#define PARS_OR_TOKEN 264 -#define PARS_NOT_TOKEN 265 -#define PARS_GE_TOKEN 266 -#define PARS_LE_TOKEN 267 -#define PARS_NE_TOKEN 268 -#define PARS_PROCEDURE_TOKEN 269 -#define PARS_IN_TOKEN 270 -#define PARS_OUT_TOKEN 271 -#define PARS_BINARY_TOKEN 272 -#define PARS_BLOB_TOKEN 273 -#define PARS_INT_TOKEN 274 -#define PARS_INTEGER_TOKEN 275 -#define PARS_FLOAT_TOKEN 276 -#define PARS_CHAR_TOKEN 277 -#define PARS_IS_TOKEN 278 -#define PARS_BEGIN_TOKEN 279 -#define PARS_END_TOKEN 280 -#define PARS_IF_TOKEN 281 -#define PARS_THEN_TOKEN 282 -#define PARS_ELSE_TOKEN 283 -#define PARS_ELSIF_TOKEN 284 -#define PARS_LOOP_TOKEN 285 -#define PARS_WHILE_TOKEN 286 -#define PARS_RETURN_TOKEN 287 -#define PARS_SELECT_TOKEN 288 -#define PARS_SUM_TOKEN 289 -#define PARS_COUNT_TOKEN 290 -#define PARS_DISTINCT_TOKEN 291 -#define PARS_FROM_TOKEN 292 -#define PARS_WHERE_TOKEN 293 -#define PARS_FOR_TOKEN 294 -#define PARS_DDOT_TOKEN 295 -#define PARS_CONSISTENT_TOKEN 296 -#define PARS_READ_TOKEN 297 -#define PARS_ORDER_TOKEN 298 -#define PARS_BY_TOKEN 299 -#define PARS_ASC_TOKEN 300 -#define PARS_DESC_TOKEN 301 -#define PARS_INSERT_TOKEN 302 -#define PARS_INTO_TOKEN 303 -#define PARS_VALUES_TOKEN 304 -#define PARS_UPDATE_TOKEN 305 -#define PARS_SET_TOKEN 306 -#define PARS_DELETE_TOKEN 307 -#define PARS_CURRENT_TOKEN 308 -#define PARS_OF_TOKEN 309 -#define PARS_CREATE_TOKEN 310 -#define PARS_TABLE_TOKEN 311 -#define PARS_INDEX_TOKEN 312 -#define PARS_UNIQUE_TOKEN 313 -#define PARS_CLUSTERED_TOKEN 314 -#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 315 -#define PARS_ON_TOKEN 316 -#define PARS_ASSIGN_TOKEN 317 -#define PARS_DECLARE_TOKEN 318 -#define PARS_CURSOR_TOKEN 319 -#define PARS_SQL_TOKEN 320 -#define PARS_OPEN_TOKEN 321 -#define PARS_FETCH_TOKEN 322 -#define PARS_CLOSE_TOKEN 323 -#define PARS_NOTFOUND_TOKEN 324 -#define PARS_TO_CHAR_TOKEN 325 -#define PARS_TO_NUMBER_TOKEN 326 -#define PARS_TO_BINARY_TOKEN 327 -#define PARS_BINARY_TO_NUMBER_TOKEN 328 -#define PARS_SUBSTR_TOKEN 329 -#define PARS_REPLSTR_TOKEN 330 -#define PARS_CONCAT_TOKEN 331 -#define PARS_INSTR_TOKEN 332 -#define PARS_LENGTH_TOKEN 333 -#define PARS_SYSDATE_TOKEN 334 -#define PARS_PRINTF_TOKEN 335 -#define PARS_ASSERT_TOKEN 336 -#define PARS_RND_TOKEN 337 -#define PARS_RND_STR_TOKEN 338 -#define PARS_ROW_PRINTF_TOKEN 339 -#define PARS_COMMIT_TOKEN 340 -#define PARS_ROLLBACK_TOKEN 341 -#define PARS_WORK_TOKEN 342 -#define NEG 343 +#define PARS_FIXBINARY_LIT 261 +#define PARS_BLOB_LIT 262 +#define PARS_NULL_LIT 263 +#define PARS_ID_TOKEN 264 +#define PARS_AND_TOKEN 265 +#define PARS_OR_TOKEN 266 +#define PARS_NOT_TOKEN 267 +#define PARS_GE_TOKEN 268 +#define PARS_LE_TOKEN 269 +#define PARS_NE_TOKEN 270 +#define PARS_PROCEDURE_TOKEN 271 +#define PARS_IN_TOKEN 272 +#define PARS_OUT_TOKEN 273 +#define PARS_BINARY_TOKEN 274 +#define PARS_BLOB_TOKEN 275 +#define PARS_INT_TOKEN 276 +#define PARS_INTEGER_TOKEN 277 +#define PARS_FLOAT_TOKEN 278 +#define PARS_CHAR_TOKEN 279 +#define PARS_IS_TOKEN 280 +#define PARS_BEGIN_TOKEN 281 +#define PARS_END_TOKEN 282 +#define PARS_IF_TOKEN 283 +#define PARS_THEN_TOKEN 284 +#define PARS_ELSE_TOKEN 285 +#define PARS_ELSIF_TOKEN 286 +#define PARS_LOOP_TOKEN 287 +#define PARS_WHILE_TOKEN 288 +#define PARS_RETURN_TOKEN 289 +#define PARS_SELECT_TOKEN 290 +#define PARS_SUM_TOKEN 291 +#define PARS_COUNT_TOKEN 292 +#define PARS_DISTINCT_TOKEN 293 +#define PARS_FROM_TOKEN 294 +#define PARS_WHERE_TOKEN 295 +#define PARS_FOR_TOKEN 296 +#define PARS_DDOT_TOKEN 297 +#define PARS_CONSISTENT_TOKEN 298 +#define PARS_READ_TOKEN 299 +#define PARS_ORDER_TOKEN 300 +#define PARS_BY_TOKEN 301 +#define PARS_ASC_TOKEN 302 +#define PARS_DESC_TOKEN 303 +#define PARS_INSERT_TOKEN 304 +#define PARS_INTO_TOKEN 305 +#define PARS_VALUES_TOKEN 306 +#define PARS_UPDATE_TOKEN 307 +#define PARS_SET_TOKEN 308 +#define PARS_DELETE_TOKEN 309 +#define PARS_CURRENT_TOKEN 310 +#define PARS_OF_TOKEN 311 +#define PARS_CREATE_TOKEN 312 +#define PARS_TABLE_TOKEN 313 +#define PARS_INDEX_TOKEN 314 +#define PARS_UNIQUE_TOKEN 315 +#define PARS_CLUSTERED_TOKEN 316 +#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 317 +#define PARS_ON_TOKEN 318 +#define PARS_ASSIGN_TOKEN 319 +#define PARS_DECLARE_TOKEN 320 +#define PARS_CURSOR_TOKEN 321 +#define PARS_SQL_TOKEN 322 +#define PARS_OPEN_TOKEN 323 +#define PARS_FETCH_TOKEN 324 +#define PARS_CLOSE_TOKEN 325 +#define PARS_NOTFOUND_TOKEN 326 +#define PARS_TO_CHAR_TOKEN 327 +#define PARS_TO_NUMBER_TOKEN 328 +#define PARS_TO_BINARY_TOKEN 329 +#define PARS_BINARY_TO_NUMBER_TOKEN 330 +#define PARS_SUBSTR_TOKEN 331 +#define PARS_REPLSTR_TOKEN 332 +#define PARS_CONCAT_TOKEN 333 +#define PARS_INSTR_TOKEN 334 +#define PARS_LENGTH_TOKEN 335 +#define PARS_SYSDATE_TOKEN 336 +#define PARS_PRINTF_TOKEN 337 +#define PARS_ASSERT_TOKEN 338 +#define PARS_RND_TOKEN 339 +#define PARS_RND_STR_TOKEN 340 +#define PARS_ROW_PRINTF_TOKEN 341 +#define PARS_COMMIT_TOKEN 342 +#define PARS_ROLLBACK_TOKEN 343 +#define PARS_WORK_TOKEN 344 +#define PARS_UNSIGNED_TOKEN 345 +#define PARS_EXIT_TOKEN 346 +#define PARS_FUNCTION_TOKEN 347 +#define NEG 348 diff --git a/storage/innobase/pars/pars0grm.y b/storage/innobase/pars/pars0grm.y index 435025d7386..7f13312fc6e 100644 --- a/storage/innobase/pars/pars0grm.y +++ b/storage/innobase/pars/pars0grm.y @@ -29,10 +29,12 @@ que_node_t */ int yylex(void); %} - + %token PARS_INT_LIT %token PARS_FLOAT_LIT %token PARS_STR_LIT +%token PARS_FIXBINARY_LIT +%token PARS_BLOB_LIT %token PARS_NULL_LIT %token PARS_ID_TOKEN %token PARS_AND_TOKEN @@ -115,6 +117,9 @@ yylex(void); %token PARS_COMMIT_TOKEN %token PARS_ROLLBACK_TOKEN %token PARS_WORK_TOKEN +%token PARS_UNSIGNED_TOKEN +%token PARS_EXIT_TOKEN +%token PARS_FUNCTION_TOKEN %left PARS_AND_TOKEN PARS_OR_TOKEN %left PARS_NOT_TOKEN @@ -133,6 +138,7 @@ statement: | predefined_procedure_call ';' | while_statement ';' | for_statement ';' + | exit_statement ';' | if_statement ';' | return_statement ';' | assignment_statement ';' @@ -165,6 +171,8 @@ exp: | PARS_INT_LIT { $$ = $1;} | PARS_FLOAT_LIT { $$ = $1;} | PARS_STR_LIT { $$ = $1;} + | PARS_FIXBINARY_LIT { $$ = $1;} + | PARS_BLOB_LIT { $$ = $1;} | PARS_NULL_LIT { $$ = $1;} | PARS_SQL_TOKEN { $$ = $1;} | exp '+' exp { $$ = pars_op('+', $1, $3); } @@ -225,6 +233,10 @@ predefined_procedure_name: | PARS_ASSERT_TOKEN { $$ = &pars_assert_token; } ; +user_function_call: + PARS_ID_TOKEN '(' ')' { $$ = $1; } +; + table_list: PARS_ID_TOKEN { $$ = que_node_list_add_last(NULL, $1); } | table_list ',' PARS_ID_TOKEN @@ -262,14 +274,14 @@ select_item: que_node_list_add_last(NULL, $3)); } ; - + select_item_list: /* Nothing */ { $$ = NULL; } | select_item { $$ = que_node_list_add_last(NULL, $1); } | select_item_list ',' select_item { $$ = que_node_list_add_last($1, $3); } ; - + select_list: '*' { $$ = pars_select_list(&pars_star_denoter, NULL); } @@ -377,7 +389,7 @@ delete_statement_positioned: delete_statement_start cursor_positioned { $$ = pars_update_statement($1, $2, NULL); } ; - + row_printf_statement: PARS_ROW_PRINTF_TOKEN select_statement { $$ = pars_row_printf_statement($2); } @@ -428,6 +440,10 @@ for_statement: { $$ = pars_for_statement($2, $4, $6, $8); } ; +exit_statement: + PARS_EXIT_TOKEN { $$ = pars_exit_statement(); } +; + return_statement: PARS_RETURN_TOKEN { $$ = pars_return_statement(); } ; @@ -446,12 +462,14 @@ close_cursor_statement: fetch_statement: PARS_FETCH_TOKEN PARS_ID_TOKEN PARS_INTO_TOKEN variable_list - { $$ = pars_fetch_statement($2, $4); } + { $$ = pars_fetch_statement($2, $4, NULL); } + | PARS_FETCH_TOKEN PARS_ID_TOKEN PARS_INTO_TOKEN user_function_call + { $$ = pars_fetch_statement($2, NULL, $4); } ; column_def: - PARS_ID_TOKEN type_name opt_column_len opt_not_null - { $$ = pars_column_def($1, $2, $3, $4); } + PARS_ID_TOKEN type_name opt_column_len opt_unsigned opt_not_null + { $$ = pars_column_def($1, $2, $3, $4, $5); } ; column_def_list: @@ -466,6 +484,13 @@ opt_column_len: { $$ = $2; } ; +opt_unsigned: + /* Nothing */ { $$ = NULL; } + | PARS_UNSIGNED_TOKEN + { $$ = &pars_int_token; + /* pass any non-NULL pointer */ } +; + opt_not_null: /* Nothing */ { $$ = NULL; } | PARS_NOT_TOKEN PARS_NULL_LIT @@ -479,7 +504,7 @@ not_fit_in_memory: { $$ = &pars_int_token; /* pass any non-NULL pointer */ } ; - + create_table: PARS_CREATE_TOKEN PARS_TABLE_TOKEN PARS_ID_TOKEN '(' column_def_list ')' @@ -550,8 +575,8 @@ variable_declaration: ; variable_declaration_list: - /* Nothing */ - | variable_declaration + /* Nothing */ + | variable_declaration | variable_declaration_list variable_declaration ; @@ -561,10 +586,20 @@ cursor_declaration: { $$ = pars_cursor_declaration($3, $5); } ; +function_declaration: + PARS_DECLARE_TOKEN PARS_FUNCTION_TOKEN PARS_ID_TOKEN ';' + { $$ = pars_function_declaration($3); } +; + +declaration: + cursor_declaration + | function_declaration +; + declaration_list: /* Nothing */ - | cursor_declaration - | declaration_list cursor_declaration + | declaration + | declaration_list declaration ; procedure_definition: @@ -577,5 +612,5 @@ procedure_definition: PARS_END_TOKEN { $$ = pars_procedure_definition($2, $4, $10); } ; - + %% diff --git a/storage/innobase/pars/pars0lex.l b/storage/innobase/pars/pars0lex.l index 4224536d49e..ab1fe446924 100644 --- a/storage/innobase/pars/pars0lex.l +++ b/storage/innobase/pars/pars0lex.l @@ -12,27 +12,11 @@ not automatically generate them from pars0grm.y and pars0lex.l. How to make the InnoDB parser and lexer C files: -1. First do - bison -d pars0grm.y - That generates pars0grm.tab.c and pars0grm.tab.h. +1. Run ./make_flex.sh to generate lexer files. -2. Rename pars0grm.tab.c to pars0grm.c and pars0grm.tab.h to pars0grm.h. +2. Run ./make_bison.sh to generate parser files. -3. Copy pars0grm.h also to /innobase/include - -4. Do - flex pars0lex.l - That generates lex.yy.c. - -5. Rename lex.yy.c to lexyy.c. - -6. Add '#include "univ.i"' before #include in lexyy.c - (Needed for AIX) - -7. Add a type cast to int to the assignment below the comment - 'need more input.' (Removes a warning on Win64) - -These instructions seem to work at least with bison-1.28 and flex-2.5.4 on +These instructions seem to work at least with bison-1.875d and flex-2.5.31 on Linux. *******************************************************/ @@ -96,11 +80,14 @@ string_append( } %} - + DIGIT [0-9] ID [a-z_A-Z][a-z_A-Z0-9]* +BOUND_LIT \:[a-z_A-Z0-9]+ + %x comment %x quoted +%x id %% {DIGIT}+ { @@ -115,6 +102,15 @@ ID [a-z_A-Z][a-z_A-Z0-9]* return(PARS_FLOAT_LIT); } +{BOUND_LIT} { + ulint type; + + yylval = sym_tab_add_bound_lit(pars_sym_tab_global, + yytext + 1, &type); + + return(type); +} + "'" { /* Quoted character string literals are handled in an explicit start state 'quoted'. This state is entered and the buffer for @@ -153,6 +149,45 @@ In the state 'quoted', only two actions are possible (defined below). */ } } +\" { +/* Quoted identifiers are handled in an explicit start state 'id'. +This state is entered and the buffer for the scanned string is emptied +upon encountering a starting quote. + +In the state 'id', only two actions are possible (defined below). */ + BEGIN(id); + stringbuf_len = 0; +} +[^\"]+ { + /* Got a sequence of characters other than '"': + append to string buffer */ + string_append(yytext, yyleng); +} +\"+ { + /* Got a sequence of '"' characters: + append half of them to string buffer, + as '""' represents a single '"'. + We apply truncating division, + so that '"""' will result in '"'. */ + + string_append(yytext, yyleng / 2); + + /* If we got an odd number of quotes, then the + last quote we got is the terminating quote. + At the end of the string, we return to the + initial start state and report the scanned + identifier. */ + + if (yyleng % 2) { + BEGIN(INITIAL); + yylval = sym_tab_add_id( + pars_sym_tab_global, + (byte*) stringbuf, stringbuf_len); + + return(PARS_ID_TOKEN); + } +} + "NULL" { yylval = sym_tab_add_null_lit(pars_sym_tab_global); @@ -462,6 +497,18 @@ In the state 'quoted', only two actions are possible (defined below). */ return(PARS_WORK_TOKEN); } +"UNSIGNED" { + return(PARS_UNSIGNED_TOKEN); +} + +"EXIT" { + return(PARS_EXIT_TOKEN); +} + +"FUNCTION" { + return(PARS_FUNCTION_TOKEN); +} + {ID} { yylval = sym_tab_add_id(pars_sym_tab_global, (byte*)yytext, diff --git a/storage/innobase/pars/pars0opt.c b/storage/innobase/pars/pars0opt.c index bb41b5da074..4037f50cb5c 100644 --- a/storage/innobase/pars/pars0opt.c +++ b/storage/innobase/pars/pars0opt.c @@ -313,7 +313,6 @@ opt_calc_index_goodness( ulint goodness; ulint n_fields; ulint col_no; - ulint mix_id_col_no; ulint op; ulint j; @@ -326,8 +325,6 @@ opt_calc_index_goodness( n_fields = dict_index_get_n_unique_in_tree(index); - mix_id_col_no = dict_table_get_sys_col_no(index->table, DATA_MIX_ID); - for (j = 0; j < n_fields; j++) { col_no = dict_index_get_nth_col_no(index, j); @@ -335,13 +332,7 @@ opt_calc_index_goodness( exp = opt_look_for_col_in_cond_before(OPT_EQUAL, col_no, sel_node->search_cond, sel_node, nth_table, &op); - if (col_no == mix_id_col_no) { - ut_ad(exp == NULL); - - index_plan[j] = NULL; - *last_op = '='; - goodness += 4; - } else if (exp) { + if (exp) { /* The value for this column is exactly known already at this stage of the join */ @@ -531,7 +522,6 @@ opt_search_plan_for_table( warning */ ulint best_goodness; ulint best_last_op = 0; /* remove warning */ - ulint mix_id_pos; que_node_t* index_plan[256]; que_node_t* best_index_plan[256]; @@ -601,26 +591,6 @@ opt_search_plan_for_table( plan->unique_search = FALSE; } - if ((table->type != DICT_TABLE_ORDINARY) - && (best_index->type & DICT_CLUSTERED)) { - - plan->mixed_index = TRUE; - - mix_id_pos = table->mix_len; - - if (mix_id_pos < n_fields) { - /* We have to add the mix id as a (string) literal - expression to the tuple_exps */ - - plan->tuple_exps[mix_id_pos] = - sym_tab_add_str_lit(pars_sym_tab_global, - table->mix_id_buf, - table->mix_id_len); - } - } else { - plan->mixed_index = FALSE; - } - plan->old_vers_heap = NULL; btr_pcur_init(&(plan->pcur)); @@ -1055,7 +1025,6 @@ opt_clust_access( dict_table_t* table; dict_index_t* clust_index; dict_index_t* index; - dfield_t* dfield; mem_heap_t* heap; ulint n_fields; ulint pos; @@ -1109,22 +1078,7 @@ opt_clust_access( *(plan->clust_map + i) = pos; - ut_ad((pos != ULINT_UNDEFINED) - || ((table->type == DICT_TABLE_CLUSTER_MEMBER) - && (i == table->mix_len))); - } - - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - - /* Preset the mix id field to the mix id constant */ - - dfield = dtuple_get_nth_field(plan->clust_ref, table->mix_len); - - dfield_set_data(dfield, mem_heap_alloc(heap, - table->mix_id_len), - table->mix_id_len); - ut_memcpy(dfield_get_data(dfield), table->mix_id_buf, - table->mix_id_len); + ut_ad(pos != ULINT_UNDEFINED); } } diff --git a/storage/innobase/pars/pars0pars.c b/storage/innobase/pars/pars0pars.c index 1b7a3a653a9..7ef2f65c724 100644 --- a/storage/innobase/pars/pars0pars.c +++ b/storage/innobase/pars/pars0pars.c @@ -373,14 +373,15 @@ pars_resolve_exp_variables_and_types( } /* Not resolved yet: look in the symbol table for a variable - or a cursor with the same name */ + or a cursor or a function with the same name */ node = UT_LIST_GET_FIRST(pars_sym_tab_global->sym_list); while (node) { if (node->resolved && ((node->token_type == SYM_VAR) - || (node->token_type == SYM_CURSOR)) + || (node->token_type == SYM_CURSOR) + || (node->token_type == SYM_FUNCTION)) && node->name && (sym_node->name_len == node->name_len) && (ut_memcmp(sym_node->name, node->name, @@ -486,7 +487,7 @@ pars_resolve_exp_columns( while (t_node) { table = t_node->table; - n_cols = dict_table_get_n_user_cols(table); + n_cols = dict_table_get_n_cols(table); for (i = 0; i < n_cols; i++) { col = dict_table_get_nth_col(table, i); @@ -786,6 +787,26 @@ pars_cursor_declaration( return(sym_node); } +/************************************************************************* +Parses a function declaration. */ + +que_node_t* +pars_function_declaration( +/*======================*/ + /* out: sym_node */ + sym_node_t* sym_node) /* in: function id node in the symbol + table */ +{ + sym_node->resolved = TRUE; + sym_node->token_type = SYM_FUNCTION; + + /* Check that the function exists. */ + ut_a(pars_info_get_user_func(pars_sym_tab_global->info, + sym_node->name)); + + return(sym_node); +} + /************************************************************************* Parses a delete or update statement start. */ @@ -1085,6 +1106,8 @@ pars_set_dfield_type( pars_res_word_t* type, /* in: pointer to a type token */ ulint len, /* in: length, or 0 */ + ibool is_unsigned, /* in: if TRUE, column is + UNSIGNED. */ ibool is_not_null) /* in: if TRUE, column is NOT NULL. */ { @@ -1094,48 +1117,30 @@ pars_set_dfield_type( flags |= DATA_NOT_NULL; } + if (is_unsigned) { + flags |= DATA_UNSIGNED; + } + if (type == &pars_int_token) { - if (len != 0) { - ut_error; - } + ut_a(len == 0); dtype_set(dfield_get_type(dfield), DATA_INT, flags, 4, 0); } else if (type == &pars_char_token) { - if (len != 0) { - ut_error; - } + ut_a(len == 0); dtype_set(dfield_get_type(dfield), DATA_VARCHAR, DATA_ENGLISH | flags, 0, 0); } else if (type == &pars_binary_token) { - if (len == 0) { - ut_error; - } + ut_a(len != 0); dtype_set(dfield_get_type(dfield), DATA_FIXBINARY, DATA_BINARY_TYPE | flags, len, 0); } else if (type == &pars_blob_token) { - if (len != 0) { - ut_error; - } + ut_a(len == 0); dtype_set(dfield_get_type(dfield), DATA_BLOB, DATA_BINARY_TYPE | flags, 0, 0); - } else if (type == &pars_binary_token) { - if (len == 0) { - ut_error; - } - - dtype_set(dfield_get_type(dfield), DATA_FIXBINARY, - DATA_BINARY_TYPE, len, 0); - } else if (type == &pars_blob_token) { - if (len != 0) { - ut_error; - } - - dtype_set(dfield_get_type(dfield), DATA_BLOB, - DATA_BINARY_TYPE, 0, 0); } else { ut_error; } @@ -1158,7 +1163,7 @@ pars_variable_declaration( node->param_type = PARS_NOT_PARAM; - pars_set_dfield_type(que_node_get_val(node), type, 0, FALSE); + pars_set_dfield_type(que_node_get_val(node), type, 0, FALSE, FALSE); return(node); } @@ -1346,6 +1351,22 @@ pars_for_statement( return(node); } +/************************************************************************* +Parses an exit statement. */ + +exit_node_t* +pars_exit_statement(void) +/*=====================*/ + /* out: exit statement node */ +{ + exit_node_t* node; + + node = mem_heap_alloc(pars_sym_tab_global->heap, sizeof(exit_node_t)); + node->common.type = QUE_NODE_EXIT; + + return(node); +} + /************************************************************************* Parses a return-statement. */ @@ -1411,26 +1432,42 @@ pars_procedure_call( } /************************************************************************* -Parses a fetch statement. */ +Parses a fetch statement. into_list or user_func (but not both) must be +non-NULL. */ fetch_node_t* pars_fetch_statement( /*=================*/ /* out: fetch statement node */ sym_node_t* cursor, /* in: cursor node */ - sym_node_t* into_list) /* in: variables to set */ + sym_node_t* into_list, /* in: variables to set, or NULL */ + sym_node_t* user_func) /* in: user function name, or NULL */ { sym_node_t* cursor_decl; fetch_node_t* node; + /* Logical XOR. */ + ut_a(!into_list != !user_func); + node = mem_heap_alloc(pars_sym_tab_global->heap, sizeof(fetch_node_t)); node->common.type = QUE_NODE_FETCH; pars_resolve_exp_variables_and_types(NULL, cursor); - pars_resolve_exp_list_variables_and_types(NULL, into_list); - node->into_list = into_list; + if (into_list) { + pars_resolve_exp_list_variables_and_types(NULL, into_list); + node->into_list = into_list; + node->func = NULL; + } else { + pars_resolve_exp_variables_and_types(NULL, user_func); + + node->func = pars_info_get_user_func(pars_sym_tab_global->info, + user_func->name); + ut_a(node->func); + + node->into_list = NULL; + } cursor_decl = cursor->alias; @@ -1438,8 +1475,11 @@ pars_fetch_statement( node->cursor_def = cursor_decl->cursor_def; - ut_a(que_node_list_get_len(into_list) - == que_node_list_get_len(node->cursor_def->select_list)); + if (into_list) { + ut_a(que_node_list_get_len(into_list) + == que_node_list_get_len( + node->cursor_def->select_list)); + } return(node); } @@ -1529,6 +1569,8 @@ pars_column_def( pars_res_word_t* type, /* in: data type */ sym_node_t* len, /* in: length of column, or NULL */ + void* is_unsigned, /* in: if not NULL, column + is of type UNSIGNED. */ void* is_not_null) /* in: if not NULL, column is of type NOT NULL. */ { @@ -1541,7 +1583,7 @@ pars_column_def( } pars_set_dfield_type(que_node_get_val(sym_node), type, len2, - is_not_null != NULL); + is_unsigned != NULL, is_not_null != NULL); return(sym_node); } @@ -1798,6 +1840,7 @@ que_t* pars_sql( /*=====*/ /* out, own: the query graph */ + pars_info_t* info, /* in: extra information, or NULL */ const char* str) /* in: SQL string */ { sym_node_t* sym_node; @@ -1817,6 +1860,7 @@ pars_sql( pars_sym_tab_global->sql_string = mem_heap_strdup(heap, str); pars_sym_tab_global->string_len = strlen(str); pars_sym_tab_global->next_char_pos = 0; + pars_sym_tab_global->info = info; yyparse(); @@ -1831,6 +1875,7 @@ pars_sql( graph = pars_sym_tab_global->query_graph; graph->sym_tab = pars_sym_tab_global; + graph->info = info; /* fprintf(stderr, "SQL graph size %lu\n", mem_heap_get_size(heap)); */ @@ -1867,3 +1912,222 @@ pars_complete_graph_for_exec( return(thr); } + +/******************************************************************** +Create parser info struct.*/ + +pars_info_t* +pars_info_create(void) +/*==================*/ + /* out, own: info struct */ +{ + pars_info_t* info; + mem_heap_t* heap; + + heap = mem_heap_create(512); + + info = mem_heap_alloc(heap, sizeof(*info)); + + info->heap = heap; + info->funcs = NULL; + info->bound_lits = NULL; + info->graph_owns_us = TRUE; + + return(info); +} + +/******************************************************************** +Free info struct and everything it contains.*/ + +void +pars_info_free( +/*===========*/ + pars_info_t* info) /* in: info struct */ +{ + mem_heap_free(info->heap); +} + +/******************************************************************** +Add bound literal. */ + +void +pars_info_add_literal( +/*==================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + const void* address, /* in: address */ + ulint length, /* in: length of data */ + ulint type, /* in: type, e.g. DATA_FIXBINARY */ + ulint prtype) /* in: precise type, e.g. + DATA_UNSIGNED */ +{ + pars_bound_lit_t* pbl; + + ut_ad(!pars_info_get_bound_lit(info, name)); + + pbl = mem_heap_alloc(info->heap, sizeof(*pbl)); + + pbl->name = name; + pbl->address = address; + pbl->length = length; + pbl->type = type; + pbl->prtype = prtype; + + if (!info->bound_lits) { + info->bound_lits = ib_vector_create(info->heap, 8); + } + + ib_vector_push(info->bound_lits, pbl); +} + +/******************************************************************** +Equivalent to pars_info_add_literal(info, name, str, strlen(str), +DATA_VARCHAR, DATA_ENGLISH). */ + +void +pars_info_add_str_literal( +/*======================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + const char* str) /* in: string */ +{ + pars_info_add_literal(info, name, str, strlen(str), + DATA_VARCHAR, DATA_ENGLISH); +} + +/******************************************************************** +Equivalent to: + +char buf[4]; +mach_write_to_4(buf, val); +pars_info_add_literal(info, name, buf, 4, DATA_INT, 0); + +except that the buffer is dynamically allocated from the info struct's +heap. */ + +void +pars_info_add_int4_literal( +/*=======================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + lint val) /* in: value */ +{ + byte* buf = mem_heap_alloc(info->heap, 4); + + mach_write_to_4(buf, val); + pars_info_add_literal(info, name, buf, 4, DATA_INT, 0); +} + +/******************************************************************** +Equivalent to: + +char buf[8]; +mach_write_to_8(buf, val); +pars_info_add_literal(info, name, buf, 8, DATA_FIXBINARY, 0); + +except that the buffer is dynamically allocated from the info struct's +heap. */ + +void +pars_info_add_dulint_literal( +/*=========================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: name */ + dulint val) /* in: value */ +{ + byte* buf = mem_heap_alloc(info->heap, 8); + + mach_write_to_8(buf, val); + + pars_info_add_literal(info, name, buf, 8, DATA_FIXBINARY, 0); +} + +/******************************************************************** +Add user function. */ + +void +pars_info_add_function( +/*===================*/ + pars_info_t* info, /* in: info struct */ + const char* name, /* in: function name */ + pars_user_func_cb_t func, /* in: function address */ + void* arg) /* in: user-supplied argument */ +{ + pars_user_func_t* puf; + + ut_ad(!pars_info_get_user_func(info, name)); + + puf = mem_heap_alloc(info->heap, sizeof(*puf)); + + puf->name = name; + puf->func = func; + puf->arg = arg; + + if (!info->funcs) { + info->funcs = ib_vector_create(info->heap, 8); + } + + ib_vector_push(info->funcs, puf); +} + +/******************************************************************** +Get user function with the given name.*/ + +pars_user_func_t* +pars_info_get_user_func( +/*====================*/ + /* out: user func, or NULL if not + found */ + pars_info_t* info, /* in: info struct */ + const char* name) /* in: function name to find*/ +{ + ulint i; + ib_vector_t* vec; + + if (!info || !info->funcs) { + return(NULL); + } + + vec = info->funcs; + + for (i = 0; i < ib_vector_size(vec); i++) { + pars_user_func_t* puf = ib_vector_get(vec, i); + + if (strcmp(puf->name, name) == 0) { + return(puf); + } + } + + return(NULL); +} + +/******************************************************************** +Get bound literal with the given name.*/ + +pars_bound_lit_t* +pars_info_get_bound_lit( +/*====================*/ + /* out: bound literal, or NULL if + not found */ + pars_info_t* info, /* in: info struct */ + const char* name) /* in: bound literal name to find */ +{ + ulint i; + ib_vector_t* vec; + + if (!info || !info->bound_lits) { + return(NULL); + } + + vec = info->bound_lits; + + for (i = 0; i < ib_vector_size(vec); i++) { + pars_bound_lit_t* pbl = ib_vector_get(vec, i); + + if (strcmp(pbl->name, name) == 0) { + return(pbl); + } + } + + return(NULL); +} diff --git a/storage/innobase/pars/pars0sym.c b/storage/innobase/pars/pars0sym.c index d8025998f9a..79a1e555b06 100644 --- a/storage/innobase/pars/pars0sym.c +++ b/storage/innobase/pars/pars0sym.c @@ -15,6 +15,7 @@ Created 12/15/1997 Heikki Tuuri #include "mem0mem.h" #include "data0type.h" #include "data0data.h" +#include "pars0grm.h" #include "pars0pars.h" #include "que0que.h" #include "eval0eval.h" @@ -165,6 +166,74 @@ sym_tab_add_str_lit( return(node); } +/********************************************************************** +Add a bound literal to a symbol table. */ + +sym_node_t* +sym_tab_add_bound_lit( +/*==================*/ + /* out: symbol table node */ + sym_tab_t* sym_tab, /* in: symbol table */ + const char* name, /* in: name of bound literal */ + ulint* lit_type) /* out: type of literal (PARS_*_LIT) */ +{ + sym_node_t* node; + pars_bound_lit_t* blit; + ulint len = 0; + + blit = pars_info_get_bound_lit(sym_tab->info, name); + ut_a(blit); + + node = mem_heap_alloc(sym_tab->heap, sizeof(sym_node_t)); + + node->common.type = QUE_NODE_SYMBOL; + + node->resolved = TRUE; + node->token_type = SYM_LIT; + + node->indirection = NULL; + + switch (blit->type) { + case DATA_FIXBINARY: + len = blit->length; + *lit_type = PARS_FIXBINARY_LIT; + break; + + case DATA_BLOB: + *lit_type = PARS_BLOB_LIT; + break; + + case DATA_VARCHAR: + *lit_type = PARS_STR_LIT; + break; + + case DATA_INT: + ut_a(blit->length > 0); + ut_a(blit->length <= 8); + + len = blit->length; + *lit_type = PARS_INT_LIT; + break; + + default: + ut_error; + } + + dtype_set(&(node->common.val.type), blit->type, blit->prtype, len, 0); + + dfield_set_data(&(node->common.val), blit->address, blit->length); + + node->common.val_buf_size = 0; + node->prefetch_buf = NULL; + node->cursor_def = NULL; + + UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node); + + node->sym_table = sym_tab; + + return(node); +} + /********************************************************************** Adds an SQL null literal to a symbol table. */ @@ -220,7 +289,7 @@ sym_tab_add_id( node->resolved = FALSE; node->indirection = NULL; - node->name = mem_heap_strdupl(sym_tab->heap, (char*) name, len + 1); + node->name = mem_heap_strdupl(sym_tab->heap, (char*) name, len); node->name_len = len; UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node); diff --git a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c index e048b94cdc5..59d90eb7e29 100644 --- a/storage/innobase/que/que0que.c +++ b/storage/innobase/que/que0que.c @@ -25,6 +25,7 @@ Created 5/27/1996 Heikki Tuuri #include "log0log.h" #include "eval0proc.h" #include "eval0eval.h" +#include "pars0types.h" #define QUE_PARALLELIZE_LIMIT (64 * 256 * 256 * 256) #define QUE_ROUND_ROBIN_LIMIT (64 * 256 * 256 * 256) @@ -36,6 +37,50 @@ ibool que_trace_on = FALSE; ibool que_always_false = FALSE; +/* Short introduction to query graphs + ================================== + +A query graph consists of nodes linked to each other in various ways. The +execution starts at que_run_threads() which takes a que_thr_t parameter. +que_thr_t contains two fields that control query graph execution: run_node +and prev_node. run_node is the next node to execute and prev_node is the +last node executed. + +Each node has a pointer to a 'next' statement, i.e., its brother, and a +pointer to its parent node. The next pointer is NULL in the last statement +of a block. + +Loop nodes contain a link to the first statement of the enclosed statement +list. While the loop runs, que_thr_step() checks if execution to the loop +node came from its parent or from one of the statement nodes in the loop. If +it came from the parent of the loop node it starts executing the first +statement node in the loop. If it came from one of the statement nodes in +the loop, then it checks if the statement node has another statement node +following it, and runs it if so. + +To signify loop ending, the loop statements (see e.g. while_step()) set +que_thr_t->run_node to the loop node's parent node. This is noticed on the +next call of que_thr_step() and execution proceeds to the node pointed to by +the loop node's 'next' pointer. + +For example, the code: + +X := 1; +WHILE X < 5 LOOP + X := X + 1; + X := X + 1; +X := 5 + +will result in the following node hierarchy, with the X-axis indicating +'next' links and the Y-axis indicating parent/child links: + +A - W - A + | + | + A - A + +A = assign_node_t, W = while_node_t. */ + /* How a stored procedure containing COMMIT or ROLLBACK commands is executed? @@ -128,6 +173,7 @@ que_fork_create( UT_LIST_INIT(fork->thrs); fork->sym_tab = NULL; + fork->info = NULL; fork->heap = heap; @@ -583,6 +629,7 @@ que_graph_free_recursive( break; case QUE_NODE_ASSIGNMENT: + case QUE_NODE_EXIT: case QUE_NODE_RETURN: case QUE_NODE_COMMIT: case QUE_NODE_ROLLBACK: @@ -626,6 +673,10 @@ que_graph_free( sym_tab_free_private(graph->sym_tab); } + if (graph->info && graph->info->graph_owns_us) { + pars_info_free(graph->info); + } + que_graph_free_recursive(graph); mem_heap_free(graph->heap); @@ -1040,6 +1091,37 @@ que_thr_stop_for_mysql_no_error( trx->n_active_thrs--; } +/******************************************************************** +Get the first containing loop node (e.g. while_node_t or for_node_t) for the +given node, or NULL if the node is not within a loop. */ + +que_node_t* +que_node_get_containing_loop_node( +/*==============================*/ + /* out: containing loop node, or NULL. */ + que_node_t* node) /* in: node */ +{ + ut_ad(node); + + for (;;) { + ulint type; + + node = que_node_get_parent(node); + + if (!node) { + break; + } + + type = que_node_get_type(node); + + if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) { + break; + } + } + + return(node); +} + /************************************************************************** Prints info of an SQL query graph node. */ @@ -1093,6 +1175,8 @@ que_node_print_info( str = "FOR LOOP"; } else if (type == QUE_NODE_RETURN) { str = "RETURN"; + } else if (type == QUE_NODE_EXIT) { + str = "EXIT"; } else { str = "UNKNOWN NODE TYPE"; } @@ -1120,8 +1204,8 @@ que_thr_step( thr->resource++; - type = que_node_get_type(thr->run_node); node = thr->run_node; + type = que_node_get_type(node); old_thr = thr; @@ -1160,6 +1244,8 @@ que_thr_step( proc_step(thr); } else if (type == QUE_NODE_WHILE) { while_step(thr); + } else { + ut_error; } } else if (type == QUE_NODE_ASSIGNMENT) { assign_step(thr); @@ -1192,6 +1278,8 @@ que_thr_step( thr = row_purge_step(thr); } else if (type == QUE_NODE_RETURN) { thr = return_step(thr); + } else if (type == QUE_NODE_EXIT) { + thr = exit_step(thr); } else if (type == QUE_NODE_ROLLBACK) { thr = trx_rollback_step(thr); } else if (type == QUE_NODE_CREATE_TABLE) { @@ -1204,7 +1292,11 @@ que_thr_step( ut_error; } - old_thr->prev_node = node; + if (type == QUE_NODE_EXIT) { + old_thr->prev_node = que_node_get_containing_loop_node(node); + } else { + old_thr->prev_node = node; + } return(thr); } @@ -1274,3 +1366,33 @@ loop: goto loop; } + +/************************************************************************* +Evaluate the given SQL */ + +ulint +que_eval_sql( +/*=========*/ + pars_info_t* info, /* out: error code or DB_SUCCESS */ + const char* sql, /* in: info struct, or NULL */ + trx_t* trx) /* in: trx */ +{ + que_thr_t* thr; + que_t* graph; + + graph = pars_sql(info, sql); + ut_a(graph); + + graph->trx = trx; + trx->graph = NULL; + + graph->fork_type = QUE_FORK_MYSQL_INTERFACE; + + ut_a(thr = que_fork_start_command(graph)); + + que_run_threads(thr); + + que_graph_free(graph); + + return(trx->error_state); +} diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index c80a61cc729..e47d6a621a7 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -28,6 +28,7 @@ Created 4/20/1996 Heikki Tuuri #include "eval0eval.h" #include "data0data.h" #include "usr0sess.h" +#include "buf0lru.h" #define ROW_INS_PREV 1 #define ROW_INS_NEXT 2 @@ -139,7 +140,6 @@ row_ins_alloc_sys_fields( mem_heap_t* heap; dict_col_t* col; dfield_t* dfield; - ulint len; byte* ptr; row = node->row; @@ -161,21 +161,6 @@ row_ins_alloc_sys_fields( node->row_id_buf = ptr; - if (table->type == DICT_TABLE_CLUSTER_MEMBER) { - - /* 2. Fill in the dfield for mix id */ - - col = dict_table_get_sys_col(table, DATA_MIX_ID); - - dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); - - len = mach_dulint_get_compressed_size(table->mix_id); - ptr = mem_heap_alloc(heap, DATA_MIX_ID_LEN); - - mach_dulint_write_compressed(ptr, table->mix_id); - dfield_set_data(dfield, ptr, len); - } - /* 3. Allocate buffer for trx id */ col = dict_table_get_sys_col(table, DATA_TRX_ID); @@ -279,10 +264,17 @@ row_ins_sec_index_entry_by_modify( } } else { ut_a(mode == BTR_MODIFY_TREE); + if (buf_LRU_buf_pool_running_out()) { + + err = DB_LOCK_TABLE_FULL; + + goto func_exit; + } + err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor, &dummy_big_rec, update, 0, thr, mtr); } - +func_exit: mem_heap_free(heap); return(err); @@ -344,10 +336,16 @@ row_ins_clust_index_entry_by_modify( } } else { ut_a(mode == BTR_MODIFY_TREE); + if (buf_LRU_buf_pool_running_out()) { + + err = DB_LOCK_TABLE_FULL; + + goto func_exit; + } err = btr_cur_pessimistic_update(0, cursor, big_rec, update, 0, thr, mtr); } - +func_exit: mem_heap_free(heap); return(err); @@ -1882,7 +1880,6 @@ row_ins_duplicate_error_in_clust( err = DB_DUPLICATE_KEY; goto func_exit; } - mem_heap_free(heap); } ut_a(!(cursor->index->type & DICT_CLUSTERED)); @@ -1891,6 +1888,9 @@ row_ins_duplicate_error_in_clust( err = DB_SUCCESS; func_exit: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } return(err); #else /* UNIV_HOTBACKUP */ /* This function depends on MySQL code that is not included in @@ -2091,6 +2091,12 @@ row_ins_index_entry_low( &insert_rec, &big_rec, thr, &mtr); } else { ut_a(mode == BTR_MODIFY_TREE); + if (buf_LRU_buf_pool_running_out()) { + + err = DB_LOCK_TABLE_FULL; + + goto function_exit; + } err = btr_cur_pessimistic_insert(0, &cursor, entry, &insert_rec, &big_rec, thr, &mtr); } @@ -2429,7 +2435,15 @@ row_ins_step( /* If this is the first time this node is executed (or when execution resumes after wait for the table IX lock), set an - IX lock on the table and reset the possible select node. */ + IX lock on the table and reset the possible select node. MySQL's + partitioned table code may also call an insert within the same + SQL statement AFTER it has used this table handle to do a search. + This happens, for example, when a row update moves it to another + partition. In that case, we have already set the IX lock on the + table during the search operation, and there is no need to set + it again here. But we must write trx->id to node->trx_id_buf. */ + + trx_write_trx_id(node->trx_id_buf, trx->id); if (node->state == INS_NODE_SET_IX_LOCK) { @@ -2437,13 +2451,11 @@ row_ins_step( its transaction, or it has been committed: */ if (UT_DULINT_EQ(trx->id, node->trx_id)) { - /* No need to do IX-locking or write trx id to buf */ + /* No need to do IX-locking */ goto same_trx; } - trx_write_trx_id(node->trx_id_buf, trx->id); - err = lock_table(0, node->table, LOCK_IX, thr); if (err != DB_SUCCESS) { diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 4dbe5128974..56574618f9a 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -85,9 +85,11 @@ row_mysql_is_system_table( system table name */ const char* name) { - if (memcmp(name, "mysql/", 6)) { + if (strncmp(name, "mysql/", 6) != 0) { + return(FALSE); } + return(0 == strcmp(name + 6, "host") || 0 == strcmp(name + 6, "user") || 0 == strcmp(name + 6, "db")); @@ -1435,7 +1437,8 @@ run_again: } /************************************************************************* -This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before +This can only be used when srv_locks_unsafe_for_binlog is TRUE or +this session is using a READ COMMITTED isolation level. Before calling this function we must use trx_reset_new_rec_lock_info() and trx_register_new_rec_lock() to store the information which new record locks really were set. This function removes a newly set lock under prebuilt->pcur, @@ -1466,11 +1469,13 @@ row_unlock_for_mysql( ut_ad(prebuilt && trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); - if (!srv_locks_unsafe_for_binlog) { + if (!(srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED)) { fprintf(stderr, "InnoDB: Error: calling row_unlock_for_mysql though\n" -"InnoDB: srv_locks_unsafe_for_binlog is FALSE.\n"); +"InnoDB: srv_locks_unsafe_for_binlog is FALSE and\n" +"InnoDB: this session is not using READ COMMITTED isolation level.\n"); return(DB_SUCCESS); } @@ -1670,7 +1675,9 @@ row_mysql_recover_tmp_table( if (!ptr) { /* table name does not begin with "/rsql" */ + dict_mem_table_free(table); trx_commit_for_mysql(trx); + return(DB_ERROR); } else { @@ -1782,6 +1789,7 @@ row_create_table_for_mysql( const char* table_name; ulint table_name_len; ulint err; + ulint i; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); #ifdef UNIV_SYNC_DEBUG @@ -1799,6 +1807,7 @@ row_create_table_for_mysql( "InnoDB: with raw, and innodb_force_... is removed.\n", stderr); + dict_mem_table_free(table); trx_commit_for_mysql(trx); return(DB_ERROR); @@ -1813,11 +1822,25 @@ row_create_table_for_mysql( "InnoDB: MySQL system tables must be of the MyISAM type!\n", table->name); + dict_mem_table_free(table); trx_commit_for_mysql(trx); return(DB_ERROR); } + /* Check that no reserved column names are used. */ + for (i = 0; i < dict_table_get_n_user_cols(table); i++) { + dict_col_t* col = dict_table_get_nth_col(table, i); + + if (dict_col_name_is_reserved(col->name)) { + + dict_mem_table_free(table); + trx_commit_for_mysql(trx); + + return(DB_ERROR); + } + } + trx_start_if_not_started(trx); if (row_mysql_is_recovered_tmp_table(table->name)) { @@ -2361,11 +2384,9 @@ row_discard_tablespace_for_mysql( dict_foreign_t* foreign; dulint new_id; dict_table_t* table; - que_thr_t* thr; - que_t* graph = NULL; ibool success; ulint err; - char* buf; + pars_info_t* info = NULL; /* How do we prevent crashes caused by ongoing operations on the table? Old operations could try to access non-existent pages. @@ -2387,36 +2408,6 @@ discard ongoing operations. 5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we do not allow the discard. We also reserve the data dictionary latch. */ - static const char discard_tablespace_proc1[] = - "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n" - "old_id CHAR;\n" - "new_id CHAR;\n" - "new_id_low INT;\n" - "new_id_high INT;\n" - "table_name CHAR;\n" - "BEGIN\n" - "table_name := '"; - static const char discard_tablespace_proc2[] = - "';\n" - "new_id_high := %lu;\n" - "new_id_low := %lu;\n" - "new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n" - "SELECT ID INTO old_id\n" - "FROM SYS_TABLES\n" - "WHERE NAME = table_name;\n" - "IF (SQL %% NOTFOUND) THEN\n" - " COMMIT WORK;\n" - " RETURN;\n" - "END IF;\n" - "UPDATE SYS_TABLES SET ID = new_id\n" - "WHERE ID = old_id;\n" - "UPDATE SYS_COLUMNS SET TABLE_ID = new_id\n" - "WHERE TABLE_ID = old_id;\n" - "UPDATE SYS_INDEXES SET TABLE_ID = new_id\n" - "WHERE TABLE_ID = old_id;\n" - "COMMIT WORK;\n" - "END;\n"; - ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); trx->op_info = "discarding tablespace"; @@ -2496,35 +2487,34 @@ do not allow the discard. We also reserve the data dictionary latch. */ new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); - buf = mem_alloc((sizeof discard_tablespace_proc1) + - (sizeof discard_tablespace_proc2) + - 20 + ut_strlenq(name, '\'')); - - memcpy(buf, discard_tablespace_proc1, sizeof discard_tablespace_proc1); - sprintf(ut_strcpyq(buf + (sizeof discard_tablespace_proc1 - 1), - '\'', name), - discard_tablespace_proc2, - (ulong) ut_dulint_get_high(new_id), - (ulong) ut_dulint_get_low(new_id)); - - graph = pars_sql(buf); - - ut_a(graph); - /* Remove any locks there are on the table or its records */ - lock_reset_all_on_table(table); - graph->trx = trx; - trx->graph = NULL; + info = pars_info_create(); - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; + pars_info_add_str_literal(info, "table_name", name); + pars_info_add_dulint_literal(info, "new_id", new_id); - ut_a(thr = que_fork_start_command(graph)); - - que_run_threads(thr); - - err = trx->error_state; + err = que_eval_sql(info, + "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n" + "old_id CHAR;\n" + "BEGIN\n" + "SELECT ID INTO old_id\n" + "FROM SYS_TABLES\n" + "WHERE NAME = :table_name;\n" + "IF (SQL % NOTFOUND) THEN\n" + " COMMIT WORK;\n" + " RETURN;\n" + "END IF;\n" + "UPDATE SYS_TABLES SET ID = :new_id\n" + " WHERE ID = old_id;\n" + "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n" + " WHERE TABLE_ID = old_id;\n" + "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n" + " WHERE TABLE_ID = old_id;\n" + "COMMIT WORK;\n" + "END;\n" + , trx); if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; @@ -2548,13 +2538,10 @@ do not allow the discard. We also reserve the data dictionary latch. */ table->ibd_file_missing = TRUE; } } + funct_exit: row_mysql_unlock_data_dictionary(trx); - if (graph) { - que_graph_free(graph); - } - trx_commit_for_mysql(trx); trx->op_info = ""; @@ -2715,9 +2702,7 @@ row_truncate_table_for_mysql( btr_pcur_t pcur; mtr_t mtr; dulint new_id; - char* sql; - que_thr_t* thr; - que_t* graph = NULL; + pars_info_t* info = NULL; /* How do we prevent crashes caused by ongoing operations on the table? Old operations could try to access non-existent pages. @@ -2745,30 +2730,6 @@ by DISCARD TABLESPACE.) 5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we do not allow the TRUNCATE. We also reserve the data dictionary latch. */ - static const char renumber_tablespace_proc[] = - "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n" - "old_id CHAR;\n" - "new_id CHAR;\n" - "old_id_low INT;\n" - "old_id_high INT;\n" - "new_id_low INT;\n" - "new_id_high INT;\n" - "BEGIN\n" - "old_id_high := %lu;\n" - "old_id_low := %lu;\n" - "new_id_high := %lu;\n" - "new_id_low := %lu;\n" - "old_id := CONCAT(TO_BINARY(old_id_high, 4), TO_BINARY(old_id_low, 4));\n" - "new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n" - "UPDATE SYS_TABLES SET ID = new_id\n" - "WHERE ID = old_id;\n" - "UPDATE SYS_COLUMNS SET TABLE_ID = new_id\n" - "WHERE TABLE_ID = old_id;\n" - "UPDATE SYS_INDEXES SET TABLE_ID = new_id\n" - "WHERE TABLE_ID = old_id;\n" - "COMMIT WORK;\n" - "END;\n"; - ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(table); @@ -2929,35 +2890,27 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */ btr_pcur_close(&pcur); mtr_commit(&mtr); - new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); - - mem_heap_empty(heap); - sql = mem_heap_alloc(heap, (sizeof renumber_tablespace_proc) + 40); - sprintf(sql, renumber_tablespace_proc, - (ulong) ut_dulint_get_high(table->id), - (ulong) ut_dulint_get_low(table->id), - (ulong) ut_dulint_get_high(new_id), - (ulong) ut_dulint_get_low(new_id)); - - graph = pars_sql(sql); - - ut_a(graph); - mem_heap_free(heap); - graph->trx = trx; - trx->graph = NULL; + new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; + info = pars_info_create(); - thr = que_fork_start_command(graph); - ut_a(thr); + pars_info_add_dulint_literal(info, "old_id", table->id); + pars_info_add_dulint_literal(info, "new_id", new_id); - que_run_threads(thr); - - que_graph_free(graph); - - err = trx->error_state; + err = que_eval_sql(info, + "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n" + "BEGIN\n" + "UPDATE SYS_TABLES SET ID = :new_id\n" + " WHERE ID = :old_id;\n" + "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n" + " WHERE TABLE_ID = :old_id;\n" + "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n" + " WHERE TABLE_ID = :old_id;\n" + "COMMIT WORK;\n" + "END;\n" + , trx); if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; @@ -3007,83 +2960,13 @@ row_drop_table_for_mysql( dict_foreign_t* foreign; dict_table_t* table; ulint space_id; - que_thr_t* thr; - que_t* graph; ulint err; const char* table_name; ulint namelen; char* dir_path_of_temp_table = NULL; ibool success; ibool locked_dictionary = FALSE; - char* quoted_name; - char* sql; - - /* We use the private SQL parser of Innobase to generate the - query graphs needed in deleting the dictionary data from system - tables in Innobase. Deleting a row from SYS_INDEXES table also - frees the file segments of the B-tree associated with the index. */ - - static const char str1[] = - "PROCEDURE DROP_TABLE_PROC () IS\n" - "table_name CHAR;\n" - "sys_foreign_id CHAR;\n" - "table_id CHAR;\n" - "index_id CHAR;\n" - "foreign_id CHAR;\n" - "found INT;\n" - "BEGIN\n" - "table_name := "; - static const char str2[] = - ";\n" - "SELECT ID INTO table_id\n" - "FROM SYS_TABLES\n" - "WHERE NAME = table_name;\n" - "IF (SQL % NOTFOUND) THEN\n" - " COMMIT WORK;\n" - " RETURN;\n" - "END IF;\n" - "found := 1;\n" - "SELECT ID INTO sys_foreign_id\n" - "FROM SYS_TABLES\n" - "WHERE NAME = 'SYS_FOREIGN';\n" - "IF (SQL % NOTFOUND) THEN\n" - " found := 0;\n" - "END IF;\n" - "IF (table_name = 'SYS_FOREIGN') THEN\n" - " found := 0;\n" - "END IF;\n" - "IF (table_name = 'SYS_FOREIGN_COLS') THEN\n" - " found := 0;\n" - "END IF;\n" - "WHILE found = 1 LOOP\n" - " SELECT ID INTO foreign_id\n" - " FROM SYS_FOREIGN\n" - " WHERE FOR_NAME = table_name\n" - " AND TO_BINARY(FOR_NAME) = TO_BINARY(table_name);\n" - " IF (SQL % NOTFOUND) THEN\n" - " found := 0;\n" - " ELSE" - " DELETE FROM SYS_FOREIGN_COLS WHERE ID = foreign_id;\n" - " DELETE FROM SYS_FOREIGN WHERE ID = foreign_id;\n" - " END IF;\n" - "END LOOP;\n" - "found := 1;\n" - "WHILE found = 1 LOOP\n" - " SELECT ID INTO index_id\n" - " FROM SYS_INDEXES\n" - " WHERE TABLE_ID = table_id;\n" - " IF (SQL % NOTFOUND) THEN\n" - " found := 0;\n" - " ELSE" - " DELETE FROM SYS_FIELDS WHERE INDEX_ID = index_id;\n" - " DELETE FROM SYS_INDEXES WHERE ID = index_id\n" - " AND TABLE_ID = table_id;\n" - " END IF;\n" - "END LOOP;\n" - "DELETE FROM SYS_COLUMNS WHERE TABLE_ID = table_id;\n" - "DELETE FROM SYS_TABLES WHERE ID = table_id;\n" - "COMMIT WORK;\n" - "END;\n"; + pars_info_t* info = NULL; ut_a(name != NULL); @@ -3138,14 +3021,6 @@ row_drop_table_for_mysql( srv_print_innodb_table_monitor = FALSE; } - quoted_name = mem_strdupq(name, '\''); - namelen = strlen(quoted_name); - sql = mem_alloc((sizeof str1) + (sizeof str2) - 2 + 1 + namelen); - memcpy(sql, str1, (sizeof str1) - 1); - memcpy(sql + (sizeof str1) - 1, quoted_name, namelen); - memcpy(sql + (sizeof str1) - 1 + namelen, str2, sizeof str2); - mem_free(quoted_name); - /* Serialize data dictionary operations with dictionary mutex: no deadlocks can occur then in these operations */ @@ -3163,16 +3038,6 @@ row_drop_table_for_mysql( ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - graph = pars_sql(sql); - - ut_a(graph); - mem_free(sql); - - graph->trx = trx; - trx->graph = NULL; - - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - table = dict_table_get_low(name); if (!table) { @@ -3296,18 +3161,80 @@ fputs(" InnoDB: You are trying to drop table ", stderr); trx->dict_operation = TRUE; trx->table_id = table->id; - ut_a(thr = que_fork_start_command(graph)); + /* We use the private SQL parser of Innobase to generate the + query graphs needed in deleting the dictionary data from system + tables in Innobase. Deleting a row from SYS_INDEXES table also + frees the file segments of the B-tree associated with the index. */ - que_run_threads(thr); + info = pars_info_create(); - err = trx->error_state; + pars_info_add_str_literal(info, "table_name", name); + + err = que_eval_sql(info, + "PROCEDURE DROP_TABLE_PROC () IS\n" + "sys_foreign_id CHAR;\n" + "table_id CHAR;\n" + "index_id CHAR;\n" + "foreign_id CHAR;\n" + "found INT;\n" + "BEGIN\n" + "SELECT ID INTO table_id\n" + "FROM SYS_TABLES\n" + "WHERE NAME = :table_name;\n" + "IF (SQL % NOTFOUND) THEN\n" + " COMMIT WORK;\n" + " RETURN;\n" + "END IF;\n" + "found := 1;\n" + "SELECT ID INTO sys_foreign_id\n" + "FROM SYS_TABLES\n" + "WHERE NAME = 'SYS_FOREIGN';\n" + "IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + "END IF;\n" + "IF (:table_name = 'SYS_FOREIGN') THEN\n" + " found := 0;\n" + "END IF;\n" + "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n" + " found := 0;\n" + "END IF;\n" + "WHILE found = 1 LOOP\n" + " SELECT ID INTO foreign_id\n" + " FROM SYS_FOREIGN\n" + " WHERE FOR_NAME = :table_name\n" + " AND TO_BINARY(FOR_NAME) = TO_BINARY(:table_name);\n" + " IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + " ELSE" + " DELETE FROM SYS_FOREIGN_COLS WHERE ID = foreign_id;\n" + " DELETE FROM SYS_FOREIGN WHERE ID = foreign_id;\n" + " END IF;\n" + "END LOOP;\n" + "found := 1;\n" + "WHILE found = 1 LOOP\n" + " SELECT ID INTO index_id\n" + " FROM SYS_INDEXES\n" + " WHERE TABLE_ID = table_id;\n" + " IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + " ELSE" + " DELETE FROM SYS_FIELDS WHERE INDEX_ID = index_id;\n" + " DELETE FROM SYS_INDEXES WHERE ID = index_id\n" + " AND TABLE_ID = table_id;\n" + " END IF;\n" + "END LOOP;\n" + "DELETE FROM SYS_COLUMNS WHERE TABLE_ID = table_id;\n" + "DELETE FROM SYS_TABLES WHERE ID = table_id;\n" + "COMMIT WORK;\n" + "END;\n" + , trx); if (err != DB_SUCCESS) { ut_a(err == DB_OUT_OF_FILE_SPACE); err = DB_MUST_GET_MORE_FILE_SPACE; - row_mysql_handle_errors(&err, trx, thr, NULL); + row_mysql_handle_errors(&err, trx, NULL, NULL); ut_error; } else { @@ -3385,8 +3312,6 @@ funct_exit: mem_free(dir_path_of_temp_table); } - que_graph_free(graph); - trx_commit_for_mysql(trx); trx->op_info = ""; @@ -3491,6 +3416,62 @@ row_is_mysql_tmp_table_name( return(strstr(name, "/@0023sql") != NULL); } +/******************************************************************** +Delete a single constraint. */ +static +int +row_delete_constraint_low( +/*======================*/ + /* out: error code or DB_SUCCESS */ + const char* id, /* in: constraint id */ + trx_t* trx) /* in: transaction handle */ +{ + pars_info_t* info = pars_info_create(); + + pars_info_add_str_literal(info, "id", id); + + return(que_eval_sql(info, + "PROCEDURE DELETE_CONSTRAINT () IS\n" + "BEGIN\n" + "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n" + "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n" + "END;\n" + , trx)); +} + +/******************************************************************** +Delete a single constraint. */ +static +int +row_delete_constraint( +/*==================*/ + /* out: error code or DB_SUCCESS */ + const char* id, /* in: constraint id */ + const char* database_name, /* in: database name, with the + trailing '/' */ + mem_heap_t* heap, /* in: memory heap */ + trx_t* trx) /* in: transaction handle */ +{ + ulint err; + + /* New format constraints have ids /. */ + err = row_delete_constraint_low( + mem_heap_strcat(heap, database_name, id), trx); + + if ((err == DB_SUCCESS) && !strchr(id, '/')) { + /* Old format < 4.0.18 constraints have constraint ids + _. We only try deleting them if the + constraint name does not contain a '/' character, otherwise + deleting a new format constraint named 'foo/bar' from + database 'baz' would remove constraint 'bar' from database + 'foo', if it existed. */ + + err = row_delete_constraint_low(id, trx); + } + + return(err); +} + /************************************************************************* Renames a table for MySQL. */ @@ -3503,100 +3484,13 @@ row_rename_table_for_mysql( trx_t* trx) /* in: transaction handle */ { dict_table_t* table; - que_thr_t* thr; - que_t* graph = NULL; ulint err; - /* We use the private SQL parser of Innobase to generate the - query graphs needed in deleting the dictionary data from system - tables in Innobase. Deleting a row from SYS_INDEXES table also - frees the file segments of the B-tree associated with the index. */ - static const char str1[] = - "PROCEDURE RENAME_TABLE_PROC () IS\n" - "new_table_name CHAR;\n" - "old_table_name CHAR;\n" - "gen_constr_prefix CHAR;\n" - "new_db_name CHAR;\n" - "foreign_id CHAR;\n" - "new_foreign_id CHAR;\n" - "old_db_name_len INT;\n" - "old_t_name_len INT;\n" - "new_db_name_len INT;\n" - "id_len INT;\n" - "found INT;\n" - "BEGIN\n" - "new_table_name := '"; - static const char str2[] = - "';\nold_table_name := '"; - static const char str3[] = - "';\n" - "UPDATE SYS_TABLES SET NAME = new_table_name\n" - "WHERE NAME = old_table_name;\n"; - static const char str4a1[] = /* drop some constraints of tmp tables */ - "DELETE FROM SYS_FOREIGN_COLS WHERE ID = '"; - static const char str4a2[] = "';\n" - "DELETE FROM SYS_FOREIGN WHERE ID = '"; - static const char str4a3[] = "';\n"; - static const char str4b[] = /* rename all constraints */ - "found := 1;\n" - "old_db_name_len := INSTR(old_table_name, '/') - 1;\n" - "new_db_name_len := INSTR(new_table_name, '/') - 1;\n" - "new_db_name := SUBSTR(new_table_name, 0, new_db_name_len);\n" - "old_t_name_len := LENGTH(old_table_name);\n" - "gen_constr_prefix := CONCAT(old_table_name, '_ibfk_');\n" - "WHILE found = 1 LOOP\n" - " SELECT ID INTO foreign_id\n" - " FROM SYS_FOREIGN\n" - " WHERE FOR_NAME = old_table_name\n" - " AND TO_BINARY(FOR_NAME) = TO_BINARY(old_table_name);\n" - " IF (SQL % NOTFOUND) THEN\n" - " found := 0;\n" - " ELSE\n" - " UPDATE SYS_FOREIGN\n" - " SET FOR_NAME = new_table_name\n" - " WHERE ID = foreign_id;\n" - " id_len := LENGTH(foreign_id);\n" - " IF (INSTR(foreign_id, '/') > 0) THEN\n" - " IF (INSTR(foreign_id,\n" - " gen_constr_prefix) > 0)\n" - " THEN\n" - " new_foreign_id :=\n" - " CONCAT(new_table_name,\n" - " SUBSTR(foreign_id, old_t_name_len,\n" - " id_len - old_t_name_len));\n" - " ELSE\n" - " new_foreign_id :=\n" - " CONCAT(new_db_name,\n" - " SUBSTR(foreign_id,\n" - " old_db_name_len,\n" - " id_len - old_db_name_len));\n" - " END IF;\n" - " UPDATE SYS_FOREIGN\n" - " SET ID = new_foreign_id\n" - " WHERE ID = foreign_id;\n" - " UPDATE SYS_FOREIGN_COLS\n" - " SET ID = new_foreign_id\n" - " WHERE ID = foreign_id;\n" - " END IF;\n" - " END IF;\n" - "END LOOP;\n" - "UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n" - "WHERE REF_NAME = old_table_name\n" - " AND TO_BINARY(REF_NAME) = TO_BINARY(old_table_name);\n"; - static const char str5[] = - "END;\n"; - mem_heap_t* heap = NULL; const char** constraints_to_drop = NULL; ulint n_constraints_to_drop = 0; ibool recovering_temp_table = FALSE; ibool old_is_tmp, new_is_tmp; - ulint len; - ulint i; - ibool success; - /* length of database name; 0 if not renaming to a temporary table */ - ulint db_name_len; - char* sql; - char* sqlend; + pars_info_t* info = NULL; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_a(old_name != NULL); @@ -3674,13 +3568,7 @@ row_rename_table_for_mysql( goto funct_exit; } - /* calculate the length of the SQL string */ - len = (sizeof str1) + (sizeof str2) + (sizeof str3) + (sizeof str5) - 4 - + ut_strlenq(new_name, '\'') + ut_strlenq(old_name, '\''); - if (new_is_tmp) { - db_name_len = dict_get_db_name_len(old_name) + 1; - /* MySQL is doing an ALTER TABLE command and it renames the original table to a temporary table name. We want to preserve the original foreign key constraint definitions despite the @@ -3690,110 +3578,124 @@ row_rename_table_for_mysql( heap = mem_heap_create(100); err = dict_foreign_parse_drop_constraints(heap, trx, - table, - &n_constraints_to_drop, - &constraints_to_drop); + table, &n_constraints_to_drop, &constraints_to_drop); + if (err != DB_SUCCESS) { goto funct_exit; } - - /* reserve space for all database names */ - len += 2 * n_constraints_to_drop - * (ut_strlenq(old_name, '\'') - - ut_strlenq(old_name + db_name_len, '\'')); - - for (i = 0; i < n_constraints_to_drop; i++) { - ulint addlen - = 2 * ut_strlenq(constraints_to_drop[i], '\'') - + ((sizeof str4a1) + (sizeof str4a2) - + (sizeof str4a3) - 3); - if (!strchr(constraints_to_drop[i], '/')) { - addlen *= 2; - } - len += addlen; - } - } else { - db_name_len = 0; - len += (sizeof str4b) - 1; } - sql = sqlend = mem_alloc(len + 1); - memcpy(sql, str1, (sizeof str1) - 1); - sqlend += (sizeof str1) - 1; - sqlend = ut_strcpyq(sqlend, '\'', new_name); - memcpy(sqlend, str2, (sizeof str2) - 1); - sqlend += (sizeof str2) - 1; - sqlend = ut_strcpyq(sqlend, '\'', old_name); - memcpy(sqlend, str3, (sizeof str3) - 1); - sqlend += (sizeof str3) - 1; + /* We use the private SQL parser of Innobase to generate the query + graphs needed in deleting the dictionary data from system tables in + Innobase. Deleting a row from SYS_INDEXES table also frees the file + segments of the B-tree associated with the index. */ - if (db_name_len) { - /* Internally, old format < 4.0.18 constraints have as the - constraint id _, while new format constraints - have /. */ + info = pars_info_create(); + + pars_info_add_str_literal(info, "new_table_name", new_name); + pars_info_add_str_literal(info, "old_table_name", old_name); + + err = que_eval_sql(info, + "PROCEDURE RENAME_TABLE () IS\n" + "BEGIN\n" + "UPDATE SYS_TABLES SET NAME = :new_table_name\n" + " WHERE NAME = :old_table_name;\n" + "END;\n" + , trx); + + if (err != DB_SUCCESS) { + + goto end; + } + + if (!new_is_tmp) { + /* Rename all constraints. */ + + info = pars_info_create(); + + pars_info_add_str_literal(info, "new_table_name", new_name); + pars_info_add_str_literal(info, "old_table_name", old_name); + + err = que_eval_sql(info, + "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n" + "gen_constr_prefix CHAR;\n" + "new_db_name CHAR;\n" + "foreign_id CHAR;\n" + "new_foreign_id CHAR;\n" + "old_db_name_len INT;\n" + "old_t_name_len INT;\n" + "new_db_name_len INT;\n" + "id_len INT;\n" + "found INT;\n" + "BEGIN\n" + "found := 1;\n" + "old_db_name_len := INSTR(:old_table_name, '/') - 1;\n" + "new_db_name_len := INSTR(:new_table_name, '/') - 1;\n" + "new_db_name := SUBSTR(:new_table_name, 0, new_db_name_len);\n" + "old_t_name_len := LENGTH(:old_table_name);\n" + "gen_constr_prefix := CONCAT(:old_table_name, '_ibfk_');\n" + "WHILE found = 1 LOOP\n" + " SELECT ID INTO foreign_id\n" + " FROM SYS_FOREIGN\n" + " WHERE FOR_NAME = :old_table_name\n" + " AND TO_BINARY(FOR_NAME) = TO_BINARY(:old_table_name);\n" + " IF (SQL % NOTFOUND) THEN\n" + " found := 0;\n" + " ELSE\n" + " UPDATE SYS_FOREIGN\n" + " SET FOR_NAME = :new_table_name\n" + " WHERE ID = foreign_id;\n" + " id_len := LENGTH(foreign_id);\n" + " IF (INSTR(foreign_id, '/') > 0) THEN\n" + " IF (INSTR(foreign_id,\n" + " gen_constr_prefix) > 0)\n" + " THEN\n" + " new_foreign_id :=\n" + " CONCAT(:new_table_name,\n" + " SUBSTR(foreign_id, old_t_name_len,\n" + " id_len - old_t_name_len));\n" + " ELSE\n" + " new_foreign_id :=\n" + " CONCAT(new_db_name,\n" + " SUBSTR(foreign_id,\n" + " old_db_name_len,\n" + " id_len - old_db_name_len));\n" + " END IF;\n" + " UPDATE SYS_FOREIGN\n" + " SET ID = new_foreign_id\n" + " WHERE ID = foreign_id;\n" + " UPDATE SYS_FOREIGN_COLS\n" + " SET ID = new_foreign_id\n" + " WHERE ID = foreign_id;\n" + " END IF;\n" + " END IF;\n" + "END LOOP;\n" + "UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n" + "WHERE REF_NAME = :old_table_name\n" + " AND TO_BINARY(REF_NAME) = TO_BINARY(:old_table_name);\n" + "END;\n" + , trx); + + } else if (n_constraints_to_drop > 0) { + /* Drop some constraints of tmp tables. */ + + ulint db_name_len = dict_get_db_name_len(old_name) + 1; + char* db_name = mem_heap_strdupl(heap, old_name, + db_name_len); + ulint i; for (i = 0; i < n_constraints_to_drop; i++) { - memcpy(sqlend, str4a1, (sizeof str4a1) - 1); - sqlend += (sizeof str4a1) - 1; - sqlend = ut_memcpyq(sqlend, '\'', - old_name, db_name_len); - sqlend = ut_strcpyq(sqlend, '\'', - constraints_to_drop[i]); - memcpy(sqlend, str4a2, (sizeof str4a2) - 1); - sqlend += (sizeof str4a2) - 1; - sqlend = ut_memcpyq(sqlend, '\'', - old_name, db_name_len); - sqlend = ut_strcpyq(sqlend, '\'', - constraints_to_drop[i]); - memcpy(sqlend, str4a3, (sizeof str4a3) - 1); - sqlend += (sizeof str4a3) - 1; + err = row_delete_constraint(constraints_to_drop[i], + db_name, heap, trx); - if (!strchr(constraints_to_drop[i], '/')) { - /* If this happens to be an old format - constraint, let us delete it. Since all new - format constraints contain '/', it does no - harm to run these DELETEs anyway. */ - - memcpy(sqlend, str4a1, (sizeof str4a1) - 1); - sqlend += (sizeof str4a1) - 1; - sqlend = ut_strcpyq(sqlend, '\'', - constraints_to_drop[i]); - memcpy(sqlend, str4a2, (sizeof str4a2) - 1); - sqlend += (sizeof str4a2) - 1; - sqlend = ut_strcpyq(sqlend, '\'', - constraints_to_drop[i]); - memcpy(sqlend, str4a3, (sizeof str4a3) - 1); - sqlend += (sizeof str4a3) - 1; + if (err != DB_SUCCESS) { + break; } } } - else { - memcpy(sqlend, str4b, (sizeof str4b) - 1); - sqlend += (sizeof str4b) - 1; - } - - memcpy(sqlend, str5, sizeof str5); - sqlend += sizeof str5; - - ut_a(sqlend == sql + len + 1); - - graph = pars_sql(sql); - - ut_a(graph); - mem_free(sql); - - graph->trx = trx; - trx->graph = NULL; - - graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - - ut_a(thr = que_fork_start_command(graph)); - - que_run_threads(thr); - - err = trx->error_state; +end: if (err != DB_SUCCESS) { if (err == DB_DUPLICATE_KEY) { ut_print_timestamp(stderr); @@ -3830,8 +3732,9 @@ row_rename_table_for_mysql( /* The following call will also rename the .ibd data file if the table is stored in a single-table tablespace */ - success = dict_table_rename_in_cache(table, new_name, + ibool success = dict_table_rename_in_cache(table, new_name, !new_is_tmp); + if (!success) { trx->error_state = DB_SUCCESS; trx_general_rollback_for_mysql(trx, FALSE, NULL); @@ -3879,20 +3782,16 @@ row_rename_table_for_mysql( ut_a(dict_table_rename_in_cache(table, old_name, FALSE)); trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, - NULL); + trx_general_rollback_for_mysql(trx, FALSE, NULL); trx->error_state = DB_SUCCESS; } } + funct_exit: if (!recovering_temp_table) { row_mysql_unlock_data_dictionary(trx); } - if (graph) { - que_graph_free(graph); - } - if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 0809d2872a5..c0f906f4ed7 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -710,12 +710,17 @@ row_sel_get_clust_rec( if (!node->read_view) { /* Try to place a lock on the index record */ - /* If innodb_locks_unsafe_for_binlog option is used, + /* If innodb_locks_unsafe_for_binlog option is used + or this session is using READ COMMITTED isolation level we lock only the record, i.e., next-key locking is not used. */ ulint lock_type; + trx_t* trx; - if (srv_locks_unsafe_for_binlog) { + trx = thr_get_trx(thr); + + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { lock_type = LOCK_REC_NOT_GAP; } else { lock_type = LOCK_ORDINARY; @@ -1307,16 +1312,22 @@ rec_loop: if (!consistent_read) { - /* If innodb_locks_unsafe_for_binlog option is used, - we lock only the record, i.e., next-key locking is - not used. */ + /* If innodb_locks_unsafe_for_binlog option is used + or this session is using READ COMMITTED isolation + level, we lock only the record, i.e., next-key + locking is not used. */ rec_t* next_rec = page_rec_get_next(rec); ulint lock_type; + trx_t* trx; + + trx = thr_get_trx(thr); + offsets = rec_get_offsets(next_rec, index, offsets, ULINT_UNDEFINED, &heap); - if (srv_locks_unsafe_for_binlog) { + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { lock_type = LOCK_REC_NOT_GAP; } else { lock_type = LOCK_ORDINARY; @@ -1350,15 +1361,21 @@ rec_loop: if (!consistent_read) { /* Try to place a lock on the index record */ - /* If innodb_locks_unsafe_for_binlog option is used, + /* If innodb_locks_unsafe_for_binlog option is used + or this session is using READ COMMITTED isolation level, we lock only the record, i.e., next-key locking is not used. */ ulint lock_type; + trx_t* trx; + offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); - if (srv_locks_unsafe_for_binlog) { + trx = thr_get_trx(thr); + + if (srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) { lock_type = LOCK_REC_NOT_GAP; } else { lock_type = LOCK_ORDINARY; @@ -1413,14 +1430,6 @@ rec_loop: /* Ok, no need to test end_conds or mix id */ - } else if (plan->mixed_index) { - /* We have to check if the record in a mixed cluster belongs - to this table */ - - if (!dict_is_mixed_table_rec(plan->table, rec)) { - - goto next_rec; - } } /* We are ready to look at a possible new index entry in the result @@ -1958,7 +1967,18 @@ fetch_step( if (sel_node->state != SEL_NODE_NO_MORE_ROWS) { - sel_assign_into_var_values(node->into_list, sel_node); + if (node->into_list) { + sel_assign_into_var_values(node->into_list, + sel_node); + } else { + void* ret = (*node->func->func)(sel_node, + node->func->arg); + + if (!ret) { + sel_node->state = + SEL_NODE_NO_MORE_ROWS; + } + } } thr->run_node = que_node_get_parent(node); @@ -1974,8 +1994,8 @@ fetch_step( sel_node->common.parent = node; if (sel_node->state == SEL_NODE_CLOSED) { - /* SQL error detected */ - fprintf(stderr, "SQL error %lu\n", (ulong)DB_ERROR); + fprintf(stderr, + "InnoDB: Error: fetch called on a closed cursor\n"); que_thr_handle_error(thr, DB_ERROR, NULL, 0); @@ -1987,6 +2007,76 @@ fetch_step( return(thr); } +/******************************************************************** +Sample callback function for fetch that prints each row.*/ + +void* +row_fetch_print( +/*============*/ + /* out: always returns non-NULL */ + void* row, /* in: sel_node_t* */ + void* user_arg) /* in: not used */ +{ + sel_node_t* node = row; + que_node_t* exp; + ulint i = 0; + + UT_NOT_USED(user_arg); + + fprintf(stderr, "row_fetch_print: row %p\n", row); + + exp = node->select_list; + + while (exp) { + dfield_t* dfield = que_node_get_val(exp); + dtype_t* type = dfield_get_type(dfield); + + fprintf(stderr, " column %lu:\n", (ulong)i); + + dtype_print(type); + fprintf(stderr, "\n"); + + ut_print_buf(stderr, dfield_get_data(dfield), + dfield_get_len(dfield)); + fprintf(stderr, "\n"); + + exp = que_node_get_next(exp); + i++; + } + + return((void*)42); +} + +/******************************************************************** +Callback function for fetch that stores an unsigned 4 byte integer to the +location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length += 4. */ + +void* +row_fetch_store_uint4( +/*==================*/ + /* out: always returns NULL */ + void* row, /* in: sel_node_t* */ + void* user_arg) /* in: data pointer */ +{ + sel_node_t* node = row; + ib_uint32_t* val = user_arg; + ulint tmp; + + dfield_t* dfield = que_node_get_val(node->select_list); + dtype_t* type = dfield_get_type(dfield); + ulint len = dfield_get_len(dfield); + + ut_a(dtype_get_mtype(type) == DATA_INT); + ut_a(dtype_get_prtype(type) & DATA_UNSIGNED); + ut_a(len == 4); + + tmp = mach_read_from_4(dfield_get_data(dfield)); + *val = tmp; + + return(NULL); +} + /*************************************************************** Prints a row in a select result. */ @@ -2397,18 +2487,16 @@ row_sel_field_store_in_mysql_format( } else if (templ->type == DATA_MYSQL) { memcpy(dest, data, len); -#if defined(UNIV_RELEASE_NOT_YET_STABLE) || defined(UNIV_DEBUG) - ut_a(templ->mysql_col_len >= len); - ut_a(templ->mbmaxlen >= templ->mbminlen); + ut_ad(templ->mysql_col_len >= len); + ut_ad(templ->mbmaxlen >= templ->mbminlen); - ut_a(templ->mbmaxlen > templ->mbminlen + ut_ad(templ->mbmaxlen > templ->mbminlen || templ->mysql_col_len == len); - ut_a(len * templ->mbmaxlen >= templ->mysql_col_len); -#endif /* UNIV_RELEASE_NOT_YET_STABLE || UNIV_DEBUG */ /* The following assertion would fail for old tables containing UTF-8 ENUM columns due to Bug #9526. */ ut_ad(!templ->mbmaxlen || !(templ->mysql_col_len % templ->mbmaxlen)); + ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len); if (templ->mbminlen != templ->mbmaxlen) { /* Pad with spaces. This undoes the stripping @@ -2418,15 +2506,13 @@ row_sel_field_store_in_mysql_format( memset(dest + len, 0x20, templ->mysql_col_len - len); } } else { -#if defined(UNIV_RELEASE_NOT_YET_STABLE) || defined(UNIV_DEBUG) - ut_a(templ->type == DATA_CHAR + ut_ad(templ->type == DATA_CHAR || templ->type == DATA_FIXBINARY /*|| templ->type == DATA_SYS_CHILD || templ->type == DATA_SYS*/ || templ->type == DATA_FLOAT || templ->type == DATA_DOUBLE || templ->type == DATA_DECIMAL); -#endif /* UNIV_RELEASE_NOT_YET_STABLE || UNIV_DEBUG */ ut_ad(templ->mysql_col_len == len); memcpy(dest, data, len); @@ -3210,11 +3296,13 @@ stderr); } /* Reset the new record lock info if srv_locks_unsafe_for_binlog - is set. Then we are able to remove the record locks set here on an - individual row. */ + is set or session is using a READ COMMITED isolation level. Then + we are able to remove the record locks set here on an individual + row. */ - if (srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE) { + if ((srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { trx_reset_new_rec_lock_info(trx); } @@ -3582,13 +3670,15 @@ rec_loop: if (page_rec_is_supremum(rec)) { if (set_also_gap_locks - && !srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE) { + && !(srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a lock on the index record */ - /* If innodb_locks_unsafe_for_binlog option is used, - we do not lock gaps. Supremum record is really + /* If innodb_locks_unsafe_for_binlog option is used + or this session is using a READ COMMITTED isolation + level we do not lock gaps. Supremum record is really a gap and therefore we do not set locks there. */ offsets = rec_get_offsets(rec, index, offsets, @@ -3708,12 +3798,14 @@ wrong_offs: if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) { if (set_also_gap_locks - && !srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE) { + && !(srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a gap lock on the index record only if innodb_locks_unsafe_for_binlog - option is not set */ + option is not set or this session is not + using a READ COMMITTED isolation level. */ err = sel_set_rec_lock(rec, index, offsets, prebuilt->select_lock_type, @@ -3739,12 +3831,14 @@ wrong_offs: if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) { if (set_also_gap_locks - && !srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE) { + && !(srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a gap lock on the index record only if innodb_locks_unsafe_for_binlog - option is not set */ + option is not set or this session is not + using a READ COMMITTED isolation level. */ err = sel_set_rec_lock(rec, index, offsets, prebuilt->select_lock_type, @@ -3775,16 +3869,18 @@ wrong_offs: is a non-delete marked record, then it is enough to lock its existence with LOCK_REC_NOT_GAP. */ - /* If innodb_locks_unsafe_for_binlog option is used, - we lock only the record, i.e., next-key locking is + /* If innodb_locks_unsafe_for_binlog option is used + or this session is using a READ COMMITED isolation + level we lock only the record, i.e., next-key locking is not used. */ ulint lock_type; if (!set_also_gap_locks - || srv_locks_unsafe_for_binlog - || (unique_search && !UNIV_UNLIKELY( - rec_get_deleted_flag(rec, comp)))) { + || srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED + || (unique_search + && !UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp)))) { goto no_gap_lock; } else { @@ -3943,9 +4039,10 @@ no_gap_lock: /* The record is delete-marked: we can skip it */ - if (srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE - && !did_semi_consistent_read) { + if ((srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE + && !did_semi_consistent_read) { /* No need to keep a lock on a delete-marked record if we do not want to use next-key locking. */ @@ -3996,8 +4093,9 @@ requires_clust_rec: /* The record is delete marked: we can skip it */ - if (srv_locks_unsafe_for_binlog - && prebuilt->select_lock_type != LOCK_NONE) { + if ((srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { /* No need to keep a lock on a delete-marked record if we do not want to use next-key @@ -4117,8 +4215,9 @@ next_rec: } did_semi_consistent_read = FALSE; - if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog) - && prebuilt->select_lock_type != LOCK_NONE) { + if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && prebuilt->select_lock_type != LOCK_NONE) { trx_reset_new_rec_lock_info(trx); } @@ -4206,7 +4305,11 @@ lock_wait_or_error: sel_restore_position_for_mysql(&same_user_rec, BTR_SEARCH_LEAF, pcur, moves_up, &mtr); - if (srv_locks_unsafe_for_binlog && !same_user_rec) { + + if ((srv_locks_unsafe_for_binlog + || trx->isolation_level == TRX_ISO_READ_COMMITTED) + && !same_user_rec) { + /* Since we were not able to restore the cursor on the same user record, we cannot use row_unlock_for_mysql() to unlock any records, and diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 23be601a17b..4023283a60c 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -28,6 +28,7 @@ Created 12/27/1996 Heikki Tuuri #include "log0log.h" #include "pars0sym.h" #include "eval0eval.h" +#include "buf0lru.h" /* What kind of latch and lock can we assume when the control comes to @@ -869,6 +870,10 @@ row_upd_index_replace_new_col_vals_index_pos( upd_t* update, /* in: an update vector built for the index so that the field number in an upd_field is the index position */ + ibool order_only, + /* in: if TRUE, limit the replacement to + ordering fields of index; note that this + does not work for non-clustered indexes. */ mem_heap_t* heap) /* in: memory heap to which we allocate and copy the new values, set this as NULL if you do not want allocation */ @@ -879,13 +884,20 @@ row_upd_index_replace_new_col_vals_index_pos( dfield_t* new_val; ulint j; ulint i; + ulint n_fields; dtype_t* cur_type; ut_ad(index); dtuple_set_info_bits(entry, update->info_bits); - for (j = 0; j < dict_index_get_n_fields(index); j++) { + if (order_only) { + n_fields = dict_index_get_n_unique(index); + } else { + n_fields = dict_index_get_n_fields(index); + } + + for (j = 0; j < n_fields; j++) { field = dict_index_get_nth_field(index, j); @@ -1530,6 +1542,10 @@ row_upd_clust_rec( return(err); } + if (buf_LRU_buf_pool_running_out()) { + + return(DB_LOCK_TABLE_FULL); + } /* We may have to modify the tree structure: do a pessimistic descent down the index tree */ diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 1256dd21c87..fe1eeab9c3f 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -1713,6 +1713,8 @@ srv_printf_innodb_monitor( "; in additional pool allocated " ULINTPF "\n", ut_total_allocated_memory, mem_pool_get_reserved(mem_comm_pool)); + fprintf(file, "Dictionary memory allocated " ULINTPF "\n", + dict_sys->size); if (srv_use_awe) { fprintf(file, diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c index 1f3d6df0403..fb7ec4cc78b 100644 --- a/storage/innobase/sync/sync0arr.c +++ b/storage/innobase/sync/sync0arr.c @@ -524,7 +524,7 @@ sync_array_cell_print( "Last time reserved in file %s line %lu, " #endif /* UNIV_SYNC_DEBUG */ "waiters flag %lu\n", - mutex, mutex->cfile_name, (ulong) mutex->cline, + (void*) mutex, mutex->cfile_name, (ulong) mutex->cline, (ulong) mutex->lock_word, #ifdef UNIV_SYNC_DEBUG mutex->file_name, (ulong) mutex->line, @@ -539,7 +539,7 @@ sync_array_cell_print( fprintf(file, " RW-latch at %p created in file %s line %lu\n", - rwlock, rwlock->cfile_name, + (void*) rwlock, rwlock->cfile_name, (ulong) rwlock->cline); if (rwlock->writer != RW_LOCK_NOT_LOCKED) { fprintf(file, @@ -670,7 +670,6 @@ sync_array_detect_deadlock( rw_lock_debug_t*debug; ut_a(arr && start && cell); - ut_ad(cell->state == SC_RESERVED); ut_ad(cell->wait_object); ut_ad(os_thread_get_curr_id() == start->thread); ut_ad(depth < 100); @@ -703,7 +702,7 @@ sync_array_detect_deadlock( if (ret) { fprintf(stderr, "Mutex %p owned by thread %lu file %s line %lu\n", - mutex, + (void*) mutex, (ulong) os_thread_pf(mutex->thread_id), mutex->file_name, (ulong) mutex->line); sync_array_cell_print(stderr, cell); @@ -740,7 +739,8 @@ sync_array_detect_deadlock( thread, debug->pass, depth); if (ret) { print: - fprintf(stderr, "rw-lock %p ", lock); + fprintf(stderr, "rw-lock %p ", + (void*) lock); sync_array_cell_print(stderr, cell); rw_lock_debug_print(debug); return(TRUE); diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index b33c1553bae..673e1080d89 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -246,7 +246,7 @@ lock_loop: if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu spin wait rw-s-lock at %p cfile %s cline %lu rnds %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), lock, + (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) lock, lock->cfile_name, (ulong) lock->cline, (ulong) i); } @@ -277,7 +277,8 @@ lock_loop: fprintf(stderr, "Thread %lu OS wait rw-s-lock at %p cfile %s cline %lu\n", os_thread_pf(os_thread_get_curr_id()), - lock, lock->cfile_name, (ulong) lock->cline); + (void*) lock, lock->cfile_name, + (ulong) lock->cline); } rw_s_system_call_count++; @@ -495,8 +496,8 @@ lock_loop: if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu spin wait rw-x-lock at %p cfile %s cline %lu rnds %lu\n", - os_thread_pf(os_thread_get_curr_id()), lock, - lock->cfile_name, (ulong) lock->cline, (ulong) i); + os_thread_pf(os_thread_get_curr_id()), (void*) lock, + lock->cfile_name, (ulong) lock->cline, (ulong) i); } rw_x_spin_wait_count++; @@ -528,8 +529,8 @@ lock_loop: if (srv_print_latch_waits) { fprintf(stderr, "Thread %lu OS wait for rw-x-lock at %p cfile %s cline %lu\n", - os_thread_pf(os_thread_get_curr_id()), lock, - lock->cfile_name, (ulong) lock->cline); + os_thread_pf(os_thread_get_curr_id()), (void*) lock, + lock->cfile_name, (ulong) lock->cline); } rw_x_system_call_count++; @@ -787,7 +788,7 @@ rw_lock_list_print_info(void) || (rw_lock_get_reader_count(lock) != 0) || (rw_lock_get_waiters(lock) != 0)) { - fprintf(stderr, "RW-LOCK: %p ", lock); + fprintf(stderr, "RW-LOCK: %p ", (void*) lock); if (rw_lock_get_waiters(lock)) { fputs(" Waiters for the lock exist\n", stderr); @@ -823,7 +824,7 @@ rw_lock_print( fprintf(stderr, "-------------\n" "RW-LATCH INFO\n" - "RW-LATCH: %p ", lock); + "RW-LATCH: %p ", (void*) lock); if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED) || (rw_lock_get_reader_count(lock) != 0) diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 86fa66d5112..6354830df70 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -423,7 +423,7 @@ spin_loop: #ifdef UNIV_SRV_PRINT_LATCH_WAITS fprintf(stderr, "Thread %lu spin wait mutex at %p cfile %s cline %lu rnds %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), mutex, + (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex, mutex->cfile_name, (ulong) mutex->cline, (ulong) i); #endif @@ -485,7 +485,7 @@ spin_loop: fprintf(stderr, "Thread %lu spin wait succeeds at 2:" " mutex at %p\n", (ulong) os_thread_pf(os_thread_get_curr_id()), - mutex); + (void*) mutex); #endif goto finish_timing; @@ -503,7 +503,7 @@ spin_loop: #ifdef UNIV_SRV_PRINT_LATCH_WAITS fprintf(stderr, "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n", - (ulong) os_thread_pf(os_thread_get_curr_id()), mutex, + (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex, mutex->cfile_name, (ulong) mutex->cline, (ulong) i); #endif @@ -666,7 +666,7 @@ mutex_list_print_info(void) &thread_id); fprintf(stderr, "Locked mutex: addr %p thread %ld file %s line %ld\n", - mutex, os_thread_pf(thread_id), + (void*) mutex, os_thread_pf(thread_id), file_name, line); } @@ -852,10 +852,10 @@ sync_thread_levels_g( fprintf(stderr, "InnoDB: Locked mutex: addr %p thread %ld file %s line %ld\n", - mutex, os_thread_pf(thread_id), file_name, (ulong) line); + (void*) mutex, os_thread_pf(thread_id), file_name, (ulong) line); #else /* UNIV_SYNC_DEBUG */ fprintf(stderr, - "InnoDB: Locked mutex: addr %p\n", mutex); + "InnoDB: Locked mutex: addr %p\n", (void*) mutex); #endif /* UNIV_SYNC_DEBUG */ } else { fputs("Not locked\n", stderr); diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index 90d6d92c09e..a3115e332cd 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -366,8 +366,6 @@ trx_free_for_mysql( /*===============*/ trx_t* trx) /* in, own: trx object */ { - thr_local_free(trx->mysql_thread_id); - mutex_enter(&kernel_mutex); UT_LIST_REMOVE(mysql_trx_list, trx_sys->mysql_trx_list, trx); @@ -1770,6 +1768,9 @@ trx_print( fprintf(f, "%lu lock struct(s), heap size %lu", (ulong) UT_LIST_GET_LEN(trx->trx_locks), (ulong) mem_heap_get_size(trx->lock_heap)); + + fprintf(f, "%lu row lock(s)", + (ulong) lock_number_of_rows_locked(trx)); } if (trx->has_search_latch) { diff --git a/storage/innobase/ut/Makefile.am b/storage/innobase/ut/Makefile.am index 2fdbb99e0f3..c833a6d5a4c 100644 --- a/storage/innobase/ut/Makefile.am +++ b/storage/innobase/ut/Makefile.am @@ -19,6 +19,6 @@ include ../include/Makefile.i noinst_LIBRARIES = libut.a -libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c +libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c ut0vec.c EXTRA_PROGRAMS = diff --git a/storage/innobase/ut/ut0mem.c b/storage/innobase/ut/ut0mem.c index 345c14e00f9..4358edba8c0 100644 --- a/storage/innobase/ut/ut0mem.c +++ b/storage/innobase/ut/ut0mem.c @@ -437,3 +437,96 @@ ut_memcpyq( return(dest); } + +/************************************************************************** +Return the number of times s2 occurs in s1. Overlapping instances of s2 +are only counted once. */ + +ulint +ut_strcount( +/*========*/ + /* out: the number of times s2 occurs in s1 */ + const char* s1, /* in: string to search in */ + const char* s2) /* in: string to search for */ +{ + ulint count = 0; + ulint len = strlen(s2); + + if (len == 0) { + + return(0); + } + + for (;;) { + s1 = strstr(s1, s2); + + if (!s1) { + + break; + } + + count++; + s1 += len; + } + + return(count); +} + +/************************************************************************** +Replace every occurrence of s1 in str with s2. Overlapping instances of s1 +are only replaced once. */ + +char * +ut_strreplace( +/*==========*/ + /* out, own: modified string, must be + freed with mem_free() */ + const char* str, /* in: string to operate on */ + const char* s1, /* in: string to replace */ + const char* s2) /* in: string to replace s1 with */ +{ + char* new_str; + char* ptr; + const char* str_end; + ulint str_len = strlen(str); + ulint s1_len = strlen(s1); + ulint s2_len = strlen(s2); + ulint count = 0; + int len_delta = (int)s2_len - (int)s1_len; + + str_end = str + str_len; + + if (len_delta <= 0) { + len_delta = 0; + } else { + count = ut_strcount(str, s1); + } + + new_str = mem_alloc(str_len + count * len_delta + 1); + ptr = new_str; + + while (str) { + const char* next = strstr(str, s1); + + if (!next) { + next = str_end; + } + + memcpy(ptr, str, next - str); + ptr += next - str; + + if (next == str_end) { + + break; + } + + memcpy(ptr, s2, s2_len); + ptr += s2_len; + + str = next + s1_len; + } + + *ptr = '\0'; + + return(new_str); +} diff --git a/storage/innobase/ut/ut0vec.c b/storage/innobase/ut/ut0vec.c new file mode 100644 index 00000000000..3f61c8c8386 --- /dev/null +++ b/storage/innobase/ut/ut0vec.c @@ -0,0 +1,54 @@ +#include "ut0vec.h" +#ifdef UNIV_NONINL +#include "ut0vec.ic" +#endif +#include + +/******************************************************************** +Create a new vector with the given initial size. */ + +ib_vector_t* +ib_vector_create( +/*=============*/ + /* out: vector */ + mem_heap_t* heap, /* in: heap */ + ulint size) /* in: initial size */ +{ + ib_vector_t* vec; + + ut_a(size > 0); + + vec = mem_heap_alloc(heap, sizeof(*vec)); + + vec->heap = heap; + vec->data = mem_heap_alloc(heap, sizeof(void*) * size); + vec->used = 0; + vec->total = size; + + return(vec); +} + +/******************************************************************** +Push a new element to the vector, increasing its size if necessary. */ + +void +ib_vector_push( +/*===========*/ + ib_vector_t* vec, /* in: vector */ + void* elem) /* in: data element */ +{ + if (vec->used >= vec->total) { + void** new_data; + ulint new_total = vec->total * 2; + + new_data = mem_heap_alloc(vec->heap, + sizeof(void*) * new_total); + memcpy(new_data, vec->data, sizeof(void*) * vec->total); + + vec->data = new_data; + vec->total = new_total; + } + + vec->data[vec->used] = elem; + vec->used++; +} diff --git a/storage/myisam/mi_dynrec.c b/storage/myisam/mi_dynrec.c index 36d88bd362a..9d76a1fb9a5 100644 --- a/storage/myisam/mi_dynrec.c +++ b/storage/myisam/mi_dynrec.c @@ -67,6 +67,11 @@ static int _mi_cmp_buffer(File file, const byte *buff, my_off_t filepos, my_bool mi_dynmap_file(MI_INFO *info, my_off_t size) { DBUG_ENTER("mi_dynmap_file"); + if (size > (my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN) + { + DBUG_PRINT("warning", ("File is too large for mmap")); + DBUG_RETURN(1); + } info->s->file_map= (byte*) my_mmap(0, (size_t)(size + MEMMAP_EXTRA_MARGIN), info->s->mode==O_RDONLY ? PROT_READ : diff --git a/storage/ndb/home/bin/Linuxmkisofs b/storage/ndb/home/bin/Linuxmkisofs deleted file mode 100755 index a531f4cca7b..00000000000 Binary files a/storage/ndb/home/bin/Linuxmkisofs and /dev/null differ diff --git a/storage/ndb/home/bin/Solarismkisofs b/storage/ndb/home/bin/Solarismkisofs deleted file mode 100755 index b239eaed6ad..00000000000 Binary files a/storage/ndb/home/bin/Solarismkisofs and /dev/null differ diff --git a/storage/ndb/home/bin/cvs2cl.pl b/storage/ndb/home/bin/cvs2cl.pl deleted file mode 100755 index 9e6da5acf5b..00000000000 --- a/storage/ndb/home/bin/cvs2cl.pl +++ /dev/null @@ -1,1865 +0,0 @@ -#!/bin/sh -exec perl -w -x $0 ${1+"$@"} # -*- mode: perl; perl-indent-level: 2; -*- -#!perl -w - -############################################################## -### ### -### cvs2cl.pl: produce ChangeLog(s) from `cvs log` output. ### -### ### -############################################################## - -## $Revision: 2.38 $ -## $Date: 2001/02/12 19:54:35 $ -## $Author: kfogel $ -## -## (C) 1999 Karl Fogel , under the GNU GPL. -## -## (Extensively hacked on by Melissa O'Neill .) -## -## cvs2cl.pl is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2, or (at your option) -## any later version. -## -## cvs2cl.pl is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You may have received a copy of the GNU General Public License -## along with cvs2cl.pl; see the file COPYING. If not, write to the -## Free Software Foundation, Inc., 59 Temple Place - Suite 330, -## Boston, MA 02111-1307, USA. - - - -use strict; -use Text::Wrap; -use Time::Local; -use File::Basename; - - -# The Plan: -# -# Read in the logs for multiple files, spit out a nice ChangeLog that -# mirrors the information entered during `cvs commit'. -# -# The problem presents some challenges. In an ideal world, we could -# detect files with the same author, log message, and checkin time -- -# each would be a changelog entry. -# We'd sort them; and spit them out. Unfortunately, CVS is *not atomic* -# so checkins can span a range of times. Also, the directory structure -# could be hierarchical. -# -# Another question is whether we really want to have the ChangeLog -# exactly reflect commits. An author could issue two related commits, -# with different log entries, reflecting a single logical change to the -# source. GNU style ChangeLogs group these under a single author/date. -# We try to do the same. -# -# So, we parse the output of `cvs log', storing log messages in a -# multilevel hash that stores the mapping: -# directory => author => time => message => filelist -# As we go, we notice "nearby" commit times and store them together -# (i.e., under the same timestamp), so they appear in the same log -# entry. -# -# When we've read all the logs, we twist this mapping into -# a time => author => message => filelist mapping for each directory. -# -# If we're not using the `--distributed' flag, the directory is always -# considered to be `./', even as descend into subdirectories. - - -############### Globals ################ - - -# What we run to generate it: -my $Log_Source_Command = "cvs log"; - -# In case we have to print it out: -my $VERSION = '$Revision: 2.38 $'; -$VERSION =~ s/\S+\s+(\S+)\s+\S+/$1/; - -## Vars set by options: - -# Print debugging messages? -my $Debug = 0; - -# Just show version and exit? -my $Print_Version = 0; - -# Just print usage message and exit? -my $Print_Usage = 0; - -# Single top-level ChangeLog, or one per subdirectory? -my $Distributed = 0; - -# What file should we generate (defaults to "ChangeLog")? -my $Log_File_Name = "ChangeLog"; - -# Grab most recent entry date from existing ChangeLog file, just add -# to that ChangeLog. -my $Cumulative = 0; - -# Expand usernames to email addresses based on a map file? -my $User_Map_File = ""; - -# Output to a file or to stdout? -my $Output_To_Stdout = 0; - -# Eliminate empty log messages? -my $Prune_Empty_Msgs = 0; - -# Don't call Text::Wrap on the body of the message -my $No_Wrap = 0; - -# Separates header from log message. Code assumes it is either " " or -# "\n\n", so if there's ever an option to set it to something else, -# make sure to go through all conditionals that use this var. -my $After_Header = " "; - -# Format more for programs than for humans. -my $XML_Output = 0; - -# Do some special tweaks for log data that was written in FSF -# ChangeLog style. -my $FSF_Style = 0; - -# Show times in UTC instead of local time -my $UTC_Times = 0; - -# Show day of week in output? -my $Show_Day_Of_Week = 0; - -# Show revision numbers in output? -my $Show_Revisions = 0; - -# Show tags (symbolic names) in output? -my $Show_Tags = 0; - -# Show branches by symbolic name in output? -my $Show_Branches = 0; - -# Show only revisions on these branches or their ancestors. -my @Follow_Branches; - -# Don't bother with files matching this regexp. -my @Ignore_Files; - -# How exactly we match entries. We definitely want "o", -# and user might add "i" by using --case-insensitive option. -my $Case_Insensitive = 0; - -# Maybe only show log messages matching a certain regular expression. -my $Regexp_Gate = ""; - -# Pass this global option string along to cvs, to the left of `log': -my $Global_Opts = ""; - -# Pass this option string along to the cvs log subcommand: -my $Command_Opts = ""; - -# Read log output from stdin instead of invoking cvs log? -my $Input_From_Stdin = 0; - -# Don't show filenames in output. -my $Hide_Filenames = 0; - -# Max checkin duration. CVS checkin is not atomic, so we may have checkin -# times that span a range of time. We assume that checkins will last no -# longer than $Max_Checkin_Duration seconds, and that similarly, no -# checkins will happen from the same users with the same message less -# than $Max_Checkin_Duration seconds apart. -my $Max_Checkin_Duration = 180; - -# What to put at the front of [each] ChangeLog. -my $ChangeLog_Header = ""; - -## end vars set by options. - -# In 'cvs log' output, one long unbroken line of equal signs separates -# files: -my $file_separator = "=======================================" - . "======================================"; - -# In 'cvs log' output, a shorter line of dashes separates log messages -# within a file: -my $logmsg_separator = "----------------------------"; - - -############### End globals ############ - - - - -&parse_options (); -&derive_change_log (); - - - -### Everything below is subroutine definitions. ### - -# If accumulating, grab the boundary date from pre-existing ChangeLog. -sub maybe_grab_accumulation_date () -{ - if (! $Cumulative) { - return ""; - } - - # else - - open (LOG, "$Log_File_Name") - or die ("trouble opening $Log_File_Name for reading ($!)"); - - my $boundary_date; - while () - { - if (/^(\d\d\d\d-\d\d-\d\d\s+\d\d:\d\d)/) - { - $boundary_date = "$1"; - last; - } - } - - close (LOG); - return $boundary_date; -} - - -# Fills up a ChangeLog structure in the current directory. -sub derive_change_log () -{ - # See "The Plan" above for a full explanation. - - my %grand_poobah; - - my $file_full_path; - my $time; - my $revision; - my $author; - my $msg_txt; - my $detected_file_separator; - - # Might be adding to an existing ChangeLog - my $accumulation_date = &maybe_grab_accumulation_date (); - if ($accumulation_date) { - $Log_Source_Command .= " -d\'>${accumulation_date}\'"; - } - - # We might be expanding usernames - my %usermap; - - # In general, it's probably not very maintainable to use state - # variables like this to tell the loop what it's doing at any given - # moment, but this is only the first one, and if we never have more - # than a few of these, it's okay. - my $collecting_symbolic_names = 0; - my %symbolic_names; # Where tag names get stored. - my %branch_names; # We'll grab branch names while we're at it. - my %branch_numbers; # Save some revisions for @Follow_Branches - my @branch_roots; # For showing which files are branch ancestors. - - # Bleargh. Compensate for a deficiency of custom wrapping. - if (($After_Header ne " ") and $FSF_Style) - { - $After_Header .= "\t"; - } - - if (! $Input_From_Stdin) { - open (LOG_SOURCE, "$Log_Source_Command |") - or die "unable to run \"${Log_Source_Command}\""; - } - else { - open (LOG_SOURCE, "-") or die "unable to open stdin for reading"; - } - - %usermap = &maybe_read_user_map_file (); - - while () - { - # If on a new file and don't see filename, skip until we find it, and - # when we find it, grab it. - if ((! (defined $file_full_path)) and /^Working file: (.*)/) - { - $file_full_path = $1; - if (@Ignore_Files) - { - my $base; - ($base, undef, undef) = fileparse ($file_full_path); - # Ouch, I wish trailing operators in regexps could be - # evaluated on the fly! - if ($Case_Insensitive) { - if (grep ($file_full_path =~ m|$_|i, @Ignore_Files)) { - undef $file_full_path; - } - } - elsif (grep ($file_full_path =~ m|$_|, @Ignore_Files)) { - undef $file_full_path; - } - } - next; - } - - # Just spin wheels if no file defined yet. - next if (! $file_full_path); - - # Collect tag names in case we're asked to print them in the output. - if (/^symbolic names:$/) { - $collecting_symbolic_names = 1; - next; # There's no more info on this line, so skip to next - } - if ($collecting_symbolic_names) - { - # All tag names are listed with whitespace in front in cvs log - # output; so if see non-whitespace, then we're done collecting. - if (/^\S/) { - $collecting_symbolic_names = 0; - } - else # we're looking at a tag name, so parse & store it - { - # According to the Cederqvist manual, in node "Tags", tag - # names must start with an uppercase or lowercase letter and - # can contain uppercase and lowercase letters, digits, `-', - # and `_'. However, it's not our place to enforce that, so - # we'll allow anything CVS hands us to be a tag: - /^\s+([^:]+): ([\d.]+)$/; - my $tag_name = $1; - my $tag_rev = $2; - - # A branch number either has an odd number of digit sections - # (and hence an even number of dots), or has ".0." as the - # second-to-last digit section. Test for these conditions. - my $real_branch_rev = ""; - if (($tag_rev =~ /^(\d+\.\d+\.)+\d+$/) # Even number of dots... - and (! ($tag_rev =~ /^(1\.)+1$/))) # ...but not "1.[1.]1" - { - $real_branch_rev = $tag_rev; - } - elsif ($tag_rev =~ /(\d+\.(\d+\.)+)0.(\d+)/) # Has ".0." - { - $real_branch_rev = $1 . $3; - } - # If we got a branch, record its number. - if ($real_branch_rev) - { - $branch_names{$real_branch_rev} = $tag_name; - if (@Follow_Branches) { - if (grep ($_ eq $tag_name, @Follow_Branches)) { - $branch_numbers{$tag_name} = $real_branch_rev; - } - } - } - else { - # Else it's just a regular (non-branch) tag. - push (@{$symbolic_names{$tag_rev}}, $tag_name); - } - } - } - # End of code for collecting tag names. - - # If have file name, but not revision, and see revision, then grab - # it. (We collect unconditionally, even though we may or may not - # ever use it.) - if ((! (defined $revision)) and (/^revision (\d+\.[\d.]+)/)) - { - $revision = $1; - - if (@Follow_Branches) - { - foreach my $branch (@Follow_Branches) - { - # Special case for following trunk revisions - if (($branch =~ /^trunk$/i) and ($revision =~ /^[0-9]+\.[0-9]+$/)) - { - goto dengo; - } - - my $branch_number = $branch_numbers{$branch}; - if ($branch_number) - { - # Are we on one of the follow branches or an ancestor of - # same? - # - # If this revision is a prefix of the branch number, or - # possibly is less in the minormost number, OR if this - # branch number is a prefix of the revision, then yes. - # Otherwise, no. - # - # So below, we determine if any of those conditions are - # met. - - # Trivial case: is this revision on the branch? - # (Compare this way to avoid regexps that screw up Emacs - # indentation, argh.) - if ((substr ($revision, 0, ((length ($branch_number)) + 1))) - eq ($branch_number . ".")) - { - goto dengo; - } - # Non-trivial case: check if rev is ancestral to branch - elsif ((length ($branch_number)) > (length ($revision))) - { - $revision =~ /^((?:\d+\.)+)(\d+)$/; - my $r_left = $1; # still has the trailing "." - my $r_end = $2; - - $branch_number =~ /^((?:\d+\.)+)(\d+)\.\d+$/; - my $b_left = $1; # still has trailing "." - my $b_mid = $2; # has no trailing "." - - if (($r_left eq $b_left) - && ($r_end <= $b_mid)) - { - goto dengo; - } - } - } - } - } - else # (! @Follow_Branches) - { - next; - } - - # Else we are following branches, but this revision isn't on the - # path. So skip it. - undef $revision; - dengo: - next; - } - - # If we don't have a revision right now, we couldn't possibly - # be looking at anything useful. - if (! (defined ($revision))) { - $detected_file_separator = /^$file_separator$/o; - if ($detected_file_separator) { - # No revisions for this file; can happen, e.g. "cvs log -d DATE" - goto CLEAR; - } - else { - next; - } - } - - # If have file name but not date and author, and see date or - # author, then grab them: - unless (defined $time) - { - if (/^date: .*/) - { - ($time, $author) = &parse_date_and_author ($_); - if (defined ($usermap{$author}) and $usermap{$author}) { - $author = $usermap{$author}; - } - } - else { - $detected_file_separator = /^$file_separator$/o; - if ($detected_file_separator) { - # No revisions for this file; can happen, e.g. "cvs log -d DATE" - goto CLEAR; - } - } - # If the date/time/author hasn't been found yet, we couldn't - # possibly care about anything we see. So skip: - next; - } - - # A "branches: ..." line here indicates that one or more branches - # are rooted at this revision. If we're showing branches, then we - # want to show that fact as well, so we collect all the branches - # that this is the latest ancestor of and store them in - # @branch_roots. Just for reference, the format of the line we're - # seeing at this point is: - # - # branches: 1.5.2; 1.5.4; ...; - # - # Okay, here goes: - - if (/^branches:\s+(.*);$/) - { - if ($Show_Branches) - { - my $lst = $1; - $lst =~ s/(1\.)+1;|(1\.)+1$//; # ignore the trivial branch 1.1.1 - if ($lst) { - @branch_roots = split (/;\s+/, $lst); - } - else { - undef @branch_roots; - } - next; - } - else - { - # Ugh. This really bothers me. Suppose we see a log entry - # like this: - # - # ---------------------------- - # revision 1.1 - # date: 1999/10/17 03:07:38; author: jrandom; state: Exp; - # branches: 1.1.2; - # Intended first line of log message begins here. - # ---------------------------- - # - # The question is, how we can tell the difference between that - # log message and a *two*-line log message whose first line is - # - # "branches: 1.1.2;" - # - # See the problem? The output of "cvs log" is inherently - # ambiguous. - # - # For now, we punt: we liberally assume that people don't - # write log messages like that, and just toss a "branches:" - # line if we see it but are not showing branches. I hope no - # one ever loses real log data because of this. - next; - } - } - - # If have file name, time, and author, then we're just grabbing - # log message texts: - $detected_file_separator = /^$file_separator$/o; - if ($detected_file_separator && ! (defined $revision)) { - # No revisions for this file; can happen, e.g. "cvs log -d DATE" - goto CLEAR; - } - unless ($detected_file_separator || /^$logmsg_separator$/o) - { - $msg_txt .= $_; # Normally, just accumulate the message... - next; - } - # ... until a msg separator is encountered: - # Ensure the message contains something: - if ((! $msg_txt) - || ($msg_txt =~ /^\s*\.\s*$|^\s*$/) - || ($msg_txt =~ /\*\*\* empty log message \*\*\*/)) - { - if ($Prune_Empty_Msgs) { - goto CLEAR; - } - # else - $msg_txt = "[no log message]\n"; - } - - ### Store it all in the Grand Poobah: - { - my $dir_key; # key into %grand_poobah - my %qunk; # complicated little jobbie, see below - - # Each revision of a file has a little data structure (a `qunk') - # associated with it. That data structure holds not only the - # file's name, but any additional information about the file - # that might be needed in the output, such as the revision - # number, tags, branches, etc. The reason to have these things - # arranged in a data structure, instead of just appending them - # textually to the file's name, is that we may want to do a - # little rearranging later as we write the output. For example, - # all the files on a given tag/branch will go together, followed - # by the tag in parentheses (so trunk or otherwise non-tagged - # files would go at the end of the file list for a given log - # message). This rearrangement is a lot easier to do if we - # don't have to reparse the text. - # - # A qunk looks like this: - # - # { - # filename => "hello.c", - # revision => "1.4.3.2", - # time => a timegm() return value (moment of commit) - # tags => [ "tag1", "tag2", ... ], - # branch => "branchname" # There should be only one, right? - # branchroots => [ "branchtag1", "branchtag2", ... ] - # } - - if ($Distributed) { - # Just the basename, don't include the path. - ($qunk{'filename'}, $dir_key, undef) = fileparse ($file_full_path); - } - else { - $dir_key = "./"; - $qunk{'filename'} = $file_full_path; - } - - # This may someday be used in a more sophisticated calculation - # of what other files are involved in this commit. For now, we - # don't use it, because the common-commit-detection algorithm is - # hypothesized to be "good enough" as it stands. - $qunk{'time'} = $time; - - # We might be including revision numbers and/or tags and/or - # branch names in the output. Most of the code from here to - # loop-end deals with organizing these in qunk. - - $qunk{'revision'} = $revision; - - # Grab the branch, even though we may or may not need it: - $qunk{'revision'} =~ /((?:\d+\.)+)\d+/; - my $branch_prefix = $1; - $branch_prefix =~ s/\.$//; # strip off final dot - if ($branch_names{$branch_prefix}) { - $qunk{'branch'} = $branch_names{$branch_prefix}; - } - - # If there's anything in the @branch_roots array, then this - # revision is the root of at least one branch. We'll display - # them as branch names instead of revision numbers, the - # substitution for which is done directly in the array: - if (@branch_roots) { - my @roots = map { $branch_names{$_} } @branch_roots; - $qunk{'branchroots'} = \@roots; - } - - # Save tags too. - if (defined ($symbolic_names{$revision})) { - $qunk{'tags'} = $symbolic_names{$revision}; - delete $symbolic_names{$revision}; - } - - # Add this file to the list - # (We use many spoonfuls of autovivication magic. Hashes and arrays - # will spring into existence if they aren't there already.) - - &debug ("(pushing log msg for ${dir_key}$qunk{'filename'})\n"); - - # Store with the files in this commit. Later we'll loop through - # again, making sure that revisions with the same log message - # and nearby commit times are grouped together as one commit. - push (@{$grand_poobah{$dir_key}{$author}{$time}{$msg_txt}}, \%qunk); - } - - CLEAR: - # Make way for the next message - undef $msg_txt; - undef $time; - undef $revision; - undef $author; - undef @branch_roots; - - # Maybe even make way for the next file: - if ($detected_file_separator) { - undef $file_full_path; - undef %branch_names; - undef %branch_numbers; - undef %symbolic_names; - } - } - - close (LOG_SOURCE); - - ### Process each ChangeLog - - while (my ($dir,$authorhash) = each %grand_poobah) - { - &debug ("DOING DIR: $dir\n"); - - # Here we twist our hash around, from being - # author => time => message => filelist - # in %$authorhash to - # time => author => message => filelist - # in %changelog. - # - # This is also where we merge entries. The algorithm proceeds - # through the timeline of the changelog with a sliding window of - # $Max_Checkin_Duration seconds; within that window, entries that - # have the same log message are merged. - # - # (To save space, we zap %$authorhash after we've copied - # everything out of it.) - - my %changelog; - while (my ($author,$timehash) = each %$authorhash) - { - my $lasttime; - my %stamptime; - foreach my $time (sort {$main::a <=> $main::b} (keys %$timehash)) - { - my $msghash = $timehash->{$time}; - while (my ($msg,$qunklist) = each %$msghash) - { - my $stamptime = $stamptime{$msg}; - if ((defined $stamptime) - and (($time - $stamptime) < $Max_Checkin_Duration) - and (defined $changelog{$stamptime}{$author}{$msg})) - { - push(@{$changelog{$stamptime}{$author}{$msg}}, @$qunklist); - } - else { - $changelog{$time}{$author}{$msg} = $qunklist; - $stamptime{$msg} = $time; - } - } - } - } - undef (%$authorhash); - - ### Now we can write out the ChangeLog! - - my ($logfile_here, $logfile_bak, $tmpfile); - - if (! $Output_To_Stdout) { - $logfile_here = $dir . $Log_File_Name; - $logfile_here =~ s/^\.\/\//\//; # fix any leading ".//" problem - $tmpfile = "${logfile_here}.cvs2cl$$.tmp"; - $logfile_bak = "${logfile_here}.bak"; - - open (LOG_OUT, ">$tmpfile") or die "Unable to open \"$tmpfile\""; - } - else { - open (LOG_OUT, ">-") or die "Unable to open stdout for writing"; - } - - print LOG_OUT $ChangeLog_Header; - - if ($XML_Output) { - print LOG_OUT "\n\n" - . "\n\n"; - } - - foreach my $time (sort {$main::b <=> $main::a} (keys %changelog)) - { - my $authorhash = $changelog{$time}; - while (my ($author,$mesghash) = each %$authorhash) - { - # If XML, escape in outer loop to avoid compound quoting: - if ($XML_Output) { - $author = &xml_escape ($author); - } - - while (my ($msg,$qunklist) = each %$mesghash) - { - my $files = &pretty_file_list ($qunklist); - my $header_line; # date and author - my $body; # see below - my $wholething; # $header_line + $body - - # Set up the date/author line. - # kff todo: do some more XML munging here, on the header - # part of the entry: - my ($ignore,$min,$hour,$mday,$mon,$year,$wday) - = $UTC_Times ? gmtime($time) : localtime($time); - - # XML output includes everything else, we might as well make - # it always include Day Of Week too, for consistency. - if ($Show_Day_Of_Week or $XML_Output) { - $wday = ("Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday")[$wday]; - $wday = ($XML_Output) ? "${wday}\n" : " $wday"; - } - else { - $wday = ""; - } - - if ($XML_Output) { - $header_line = - sprintf ("%4u-%02u-%02u\n" - . "${wday}" - . "\n" - . "%s\n", - $year+1900, $mon+1, $mday, $hour, $min, $author); - } - else { - $header_line = - sprintf ("%4u-%02u-%02u${wday} %02u:%02u %s\n\n", - $year+1900, $mon+1, $mday, $hour, $min, $author); - } - - # Reshape the body according to user preferences. - if ($XML_Output) - { - $msg = &preprocess_msg_text ($msg); - $body = $files . $msg; - } - elsif ($No_Wrap) - { - $msg = &preprocess_msg_text ($msg); - $files = wrap ("\t", " ", "$files"); - $msg =~ s/\n(.*)/\n\t$1/g; - unless ($After_Header eq " ") { - $msg =~ s/^(.*)/\t$1/g; - } - $body = $files . $After_Header . $msg; - } - else # do wrapping, either FSF-style or regular - { - if ($FSF_Style) - { - $files = wrap ("\t", " ", "$files"); - - my $files_last_line_len = 0; - if ($After_Header eq " ") - { - $files_last_line_len = &last_line_len ($files); - $files_last_line_len += 1; # for $After_Header - } - - $msg = &wrap_log_entry - ($msg, "\t", 69 - $files_last_line_len, 69); - $body = $files . $After_Header . $msg; - } - else # not FSF-style - { - $msg = &preprocess_msg_text ($msg); - $body = $files . $After_Header . $msg; - $body = wrap ("\t", " ", "$body"); - } - } - - $wholething = $header_line . $body; - - if ($XML_Output) { - $wholething = "\n${wholething}\n"; - } - - # One last check: make sure it passes the regexp test, if the - # user asked for that. We have to do it here, so that the - # test can match against information in the header as well - # as in the text of the log message. - - # How annoying to duplicate so much code just because I - # can't figure out a way to evaluate scalars on the trailing - # operator portion of a regular expression. Grrr. - if ($Case_Insensitive) { - unless ($Regexp_Gate && ($wholething !~ /$Regexp_Gate/oi)) { - print LOG_OUT "${wholething}\n"; - } - } - else { - unless ($Regexp_Gate && ($wholething !~ /$Regexp_Gate/o)) { - print LOG_OUT "${wholething}\n"; - } - } - } - } - } - - if ($XML_Output) { - print LOG_OUT "\n"; - } - - close (LOG_OUT); - - if (! $Output_To_Stdout) - { - # If accumulating, append old data to new before renaming. But - # don't append the most recent entry, since it's already in the - # new log due to CVS's idiosyncratic interpretation of "log -d". - if ($Cumulative && -f $logfile_here) - { - open (NEW_LOG, ">>$tmpfile") - or die "trouble appending to $tmpfile ($!)"; - - open (OLD_LOG, "<$logfile_here") - or die "trouble reading from $logfile_here ($!)"; - - my $started_first_entry = 0; - my $passed_first_entry = 0; - while () - { - if (! $passed_first_entry) - { - if ((! $started_first_entry) - && /^(\d\d\d\d-\d\d-\d\d\s+\d\d:\d\d)/) { - $started_first_entry = 1; - } - elsif (/^(\d\d\d\d-\d\d-\d\d\s+\d\d:\d\d)/) { - $passed_first_entry = 1; - print NEW_LOG $_; - } - } - else { - print NEW_LOG $_; - } - } - - close (NEW_LOG); - close (OLD_LOG); - } - - if (-f $logfile_here) { - rename ($logfile_here, $logfile_bak); - } - rename ($tmpfile, $logfile_here); - } - } -} - - -sub parse_date_and_author () -{ - # Parses the date/time and author out of a line like: - # - # date: 1999/02/19 23:29:05; author: apharris; state: Exp; - - my $line = shift; - - my ($year, $mon, $mday, $hours, $min, $secs, $author) = $line =~ - m#(\d+)/(\d+)/(\d+)\s+(\d+):(\d+):(\d+);\s+author:\s+([^;]+);# - or die "Couldn't parse date ``$line''"; - die "Bad date or Y2K issues" unless ($year > 1969 and $year < 2258); - # Kinda arbitrary, but useful as a sanity check - my $time = timegm($secs,$min,$hours,$mday,$mon-1,$year-1900); - - return ($time, $author); -} - - -# Here we take a bunch of qunks and convert them into printed -# summary that will include all the information the user asked for. -sub pretty_file_list () -{ - if ($Hide_Filenames and (! $XML_Output)) { - return ""; - } - - my $qunksref = shift; - my @qunkrefs = @$qunksref; - my @filenames; - my $beauty = ""; # The accumulating header string for this entry. - my %non_unanimous_tags; # Tags found in a proper subset of qunks - my %unanimous_tags; # Tags found in all qunks - my %all_branches; # Branches found in any qunk - my $common_dir = undef; # Dir prefix common to all files ("" if none) - my $fbegun = 0; # Did we begin printing filenames yet? - - # First, loop over the qunks gathering all the tag/branch names. - # We'll put them all in non_unanimous_tags, and take out the - # unanimous ones later. - foreach my $qunkref (@qunkrefs) - { - # Keep track of whether all the files in this commit were in the - # same directory, and memorize it if so. We can make the output a - # little more compact by mentioning the directory only once. - if ((scalar (@qunkrefs)) > 1) - { - if (! (defined ($common_dir))) - { - my ($base, $dir); - ($base, $dir, undef) = fileparse ($$qunkref{'filename'}); - - if ((! (defined ($dir))) # this first case is sheer paranoia - or ($dir eq "") - or ($dir eq "./") - or ($dir eq ".\\")) - { - $common_dir = ""; - } - else - { - $common_dir = $dir; - } - } - elsif ($common_dir ne "") - { - # Already have a common dir prefix, so how much of it can we preserve? - $common_dir = &common_path_prefix ($$qunkref{'filename'}, $common_dir); - } - } - else # only one file in this entry anyway, so common dir not an issue - { - $common_dir = ""; - } - - if (defined ($$qunkref{'branch'})) { - $all_branches{$$qunkref{'branch'}} = 1; - } - if (defined ($$qunkref{'tags'})) { - foreach my $tag (@{$$qunkref{'tags'}}) { - $non_unanimous_tags{$tag} = 1; - } - } - } - - # Any tag held by all qunks will be printed specially... but only if - # there are multiple qunks in the first place! - if ((scalar (@qunkrefs)) > 1) { - foreach my $tag (keys (%non_unanimous_tags)) { - my $everyone_has_this_tag = 1; - foreach my $qunkref (@qunkrefs) { - if ((! (defined ($$qunkref{'tags'}))) - or (! (grep ($_ eq $tag, @{$$qunkref{'tags'}})))) { - $everyone_has_this_tag = 0; - } - } - if ($everyone_has_this_tag) { - $unanimous_tags{$tag} = 1; - delete $non_unanimous_tags{$tag}; - } - } - } - - if ($XML_Output) - { - # If outputting XML, then our task is pretty simple, because we - # don't have to detect common dir, common tags, branch prefixing, - # etc. We just output exactly what we have, and don't worry about - # redundancy or readability. - - foreach my $qunkref (@qunkrefs) - { - my $filename = $$qunkref{'filename'}; - my $revision = $$qunkref{'revision'}; - my $tags = $$qunkref{'tags'}; - my $branch = $$qunkref{'branch'}; - my $branchroots = $$qunkref{'branchroots'}; - - $filename = &xml_escape ($filename); # probably paranoia - $revision = &xml_escape ($revision); # definitely paranoia - - $beauty .= "\n"; - $beauty .= "${filename}\n"; - $beauty .= "${revision}\n"; - if ($branch) { - $branch = &xml_escape ($branch); # more paranoia - $beauty .= "${branch}\n"; - } - foreach my $tag (@$tags) { - $tag = &xml_escape ($tag); # by now you're used to the paranoia - $beauty .= "${tag}\n"; - } - foreach my $root (@$branchroots) { - $root = &xml_escape ($root); # which is good, because it will continue - $beauty .= "${root}\n"; - } - $beauty .= "\n"; - } - - # Theoretically, we could go home now. But as long as we're here, - # let's print out the common_dir and utags, as a convenience to - # the receiver (after all, earlier code calculated that stuff - # anyway, so we might as well take advantage of it). - - if ((scalar (keys (%unanimous_tags))) > 1) { - foreach my $utag ((keys (%unanimous_tags))) { - $utag = &xml_escape ($utag); # the usual paranoia - $beauty .= "${utag}\n"; - } - } - if ($common_dir) { - $common_dir = &xml_escape ($common_dir); - $beauty .= "${common_dir}\n"; - } - - # That's enough for XML, time to go home: - return $beauty; - } - - # Else not XML output, so complexly compactify for chordate - # consumption. At this point we have enough global information - # about all the qunks to organize them non-redundantly for output. - - if ($common_dir) { - # Note that $common_dir still has its trailing slash - $beauty .= "$common_dir: "; - } - - if ($Show_Branches) - { - # For trailing revision numbers. - my @brevisions; - - foreach my $branch (keys (%all_branches)) - { - foreach my $qunkref (@qunkrefs) - { - if ((defined ($$qunkref{'branch'})) - and ($$qunkref{'branch'} eq $branch)) - { - if ($fbegun) { - # kff todo: comma-delimited in XML too? Sure. - $beauty .= ", "; - } - else { - $fbegun = 1; - } - my $fname = substr ($$qunkref{'filename'}, length ($common_dir)); - $beauty .= $fname; - $$qunkref{'printed'} = 1; # Just setting a mark bit, basically - - if ($Show_Tags && (defined @{$$qunkref{'tags'}})) { - my @tags = grep ($non_unanimous_tags{$_}, @{$$qunkref{'tags'}}); - if (@tags) { - $beauty .= " (tags: "; - $beauty .= join (', ', @tags); - $beauty .= ")"; - } - } - - if ($Show_Revisions) { - # Collect the revision numbers' last components, but don't - # print them -- they'll get printed with the branch name - # later. - $$qunkref{'revision'} =~ /.+\.([\d]+)$/; - push (@brevisions, $1); - - # todo: we're still collecting branch roots, but we're not - # showing them anywhere. If we do show them, it would be - # nifty to just call them revision "0" on a the branch. - # Yeah, that's the ticket. - } - } - } - $beauty .= " ($branch"; - if (@brevisions) { - if ((scalar (@brevisions)) > 1) { - $beauty .= ".["; - $beauty .= (join (',', @brevisions)); - $beauty .= "]"; - } - else { - $beauty .= ".$brevisions[0]"; - } - } - $beauty .= ")"; - } - } - - # Okay; any qunks that were done according to branch are taken care - # of, and marked as printed. Now print everyone else. - - foreach my $qunkref (@qunkrefs) - { - next if (defined ($$qunkref{'printed'})); # skip if already printed - - if ($fbegun) { - $beauty .= ", "; - } - else { - $fbegun = 1; - } - $beauty .= substr ($$qunkref{'filename'}, length ($common_dir)); - # todo: Shlomo's change was this: - # $beauty .= substr ($$qunkref{'filename'}, - # (($common_dir eq "./") ? "" : length ($common_dir))); - $$qunkref{'printed'} = 1; # Set a mark bit. - - if ($Show_Revisions || $Show_Tags) - { - my $started_addendum = 0; - - if ($Show_Revisions) { - $started_addendum = 1; - $beauty .= " ("; - $beauty .= "$$qunkref{'revision'}"; - } - if ($Show_Tags && (defined $$qunkref{'tags'})) { - my @tags = grep ($non_unanimous_tags{$_}, @{$$qunkref{'tags'}}); - if ((scalar (@tags)) > 0) { - if ($started_addendum) { - $beauty .= ", "; - } - else { - $beauty .= " (tags: "; - } - $beauty .= join (', ', @tags); - $started_addendum = 1; - } - } - if ($started_addendum) { - $beauty .= ")"; - } - } - } - - # Unanimous tags always come last. - if ($Show_Tags && %unanimous_tags) - { - $beauty .= " (utags: "; - $beauty .= join (', ', keys (%unanimous_tags)); - $beauty .= ")"; - } - - # todo: still have to take care of branch_roots? - - $beauty = "* $beauty:"; - - return $beauty; -} - - -sub common_path_prefix () -{ - my $path1 = shift; - my $path2 = shift; - - my ($dir1, $dir2); - (undef, $dir1, undef) = fileparse ($path1); - (undef, $dir2, undef) = fileparse ($path2); - - # Transmogrify Windows filenames to look like Unix. - # (It is far more likely that someone is running cvs2cl.pl under - # Windows than that they would genuinely have backslashes in their - # filenames.) - $dir1 =~ tr#\\#/#; - $dir2 =~ tr#\\#/#; - - my $accum1 = ""; - my $accum2 = ""; - my $last_common_prefix = ""; - - while ($accum1 eq $accum2) - { - $last_common_prefix = $accum1; - last if ($accum1 eq $dir1); - my ($tmp1) = split (/\//, (substr ($dir1, length ($accum1)))); - my ($tmp2) = split (/\//, (substr ($dir2, length ($accum2)))); - $accum1 .= "$tmp1/" if ((defined ($tmp1)) and $tmp1); - $accum2 .= "$tmp2/" if ((defined ($tmp2)) and $tmp2); - } - - return $last_common_prefix; -} - - -sub preprocess_msg_text () -{ - my $text = shift; - - # Strip out carriage returns (as they probably result from DOSsy editors). - $text =~ s/\r\n/\n/g; - - # If it *looks* like two newlines, make it *be* two newlines: - $text =~ s/\n\s*\n/\n\n/g; - - if ($XML_Output) - { - $text = &xml_escape ($text); - $text = "${text}\n"; - } - elsif (! $No_Wrap) - { - # Strip off lone newlines, but only for lines that don't begin with - # whitespace or a mail-quoting character, since we want to preserve - # that kind of formatting. Also don't strip newlines that follow a - # period; we handle those specially next. And don't strip - # newlines that precede an open paren. - 1 while ($text =~ s/(^|\n)([^>\s].*[^.\n])\n([^>\n])/$1$2 $3/g); - - # If a newline follows a period, make sure that when we bring up the - # bottom sentence, it begins with two spaces. - 1 while ($text =~ s/(^|\n)([^>\s].*)\n([^>\n])/$1$2 $3/g); - } - - return $text; -} - - -sub last_line_len () -{ - my $files_list = shift; - my @lines = split (/\n/, $files_list); - my $last_line = pop (@lines); - return length ($last_line); -} - - -# A custom wrap function, sensitive to some common constructs used in -# log entries. -sub wrap_log_entry () -{ - my $text = shift; # The text to wrap. - my $left_pad_str = shift; # String to pad with on the left. - - # These do NOT take left_pad_str into account: - my $length_remaining = shift; # Amount left on current line. - my $max_line_length = shift; # Amount left for a blank line. - - my $wrapped_text = ""; # The accumulating wrapped entry. - my $user_indent = ""; # Inherited user_indent from prev line. - - my $first_time = 1; # First iteration of the loop? - my $suppress_line_start_match = 0; # Set to disable line start checks. - - my @lines = split (/\n/, $text); - while (@lines) # Don't use `foreach' here, it won't work. - { - my $this_line = shift (@lines); - chomp $this_line; - - if ($this_line =~ /^(\s+)/) { - $user_indent = $1; - } - else { - $user_indent = ""; - } - - # If it matches any of the line-start regexps, print a newline now... - if ($suppress_line_start_match) - { - $suppress_line_start_match = 0; - } - elsif (($this_line =~ /^(\s*)\*\s+[a-zA-Z0-9]/) - || ($this_line =~ /^(\s*)\* [a-zA-Z0-9_\.\/\+-]+/) - || ($this_line =~ /^(\s*)\([a-zA-Z0-9_\.\/\+-]+(\)|,\s*)/) - || ($this_line =~ /^(\s+)(\S+)/) - || ($this_line =~ /^(\s*)- +/) - || ($this_line =~ /^()\s*$/) - || ($this_line =~ /^(\s*)\*\) +/) - || ($this_line =~ /^(\s*)[a-zA-Z0-9](\)|\.|\:) +/)) - { - # Make a line break immediately, unless header separator is set - # and this line is the first line in the entry, in which case - # we're getting the blank line for free already and shouldn't - # add an extra one. - unless (($After_Header ne " ") and ($first_time)) - { - if ($this_line =~ /^()\s*$/) { - $suppress_line_start_match = 1; - $wrapped_text .= "\n${left_pad_str}"; - } - - $wrapped_text .= "\n${left_pad_str}"; - } - - $length_remaining = $max_line_length - (length ($user_indent)); - } - - # Now that any user_indent has been preserved, strip off leading - # whitespace, so up-folding has no ugly side-effects. - $this_line =~ s/^\s*//; - - # Accumulate the line, and adjust parameters for next line. - my $this_len = length ($this_line); - if ($this_len == 0) - { - # Blank lines should cancel any user_indent level. - $user_indent = ""; - $length_remaining = $max_line_length; - } - elsif ($this_len >= $length_remaining) # Line too long, try breaking it. - { - # Walk backwards from the end. At first acceptable spot, break - # a new line. - my $idx = $length_remaining - 1; - if ($idx < 0) { $idx = 0 }; - while ($idx > 0) - { - if (substr ($this_line, $idx, 1) =~ /\s/) - { - my $line_now = substr ($this_line, 0, $idx); - my $next_line = substr ($this_line, $idx); - $this_line = $line_now; - - # Clean whitespace off the end. - chomp $this_line; - - # The current line is ready to be printed. - $this_line .= "\n${left_pad_str}"; - - # Make sure the next line is allowed full room. - $length_remaining = $max_line_length - (length ($user_indent)); - - # Strip next_line, but then preserve any user_indent. - $next_line =~ s/^\s*//; - - # Sneak a peek at the user_indent of the upcoming line, so - # $next_line (which will now precede it) can inherit that - # indent level. Otherwise, use whatever user_indent level - # we currently have, which might be none. - my $next_next_line = shift (@lines); - if ((defined ($next_next_line)) && ($next_next_line =~ /^(\s+)/)) { - $next_line = $1 . $next_line if (defined ($1)); - # $length_remaining = $max_line_length - (length ($1)); - $next_next_line =~ s/^\s*//; - } - else { - $next_line = $user_indent . $next_line; - } - if (defined ($next_next_line)) { - unshift (@lines, $next_next_line); - } - unshift (@lines, $next_line); - - # Our new next line might, coincidentally, begin with one of - # the line-start regexps, so we temporarily turn off - # sensitivity to that until we're past the line. - $suppress_line_start_match = 1; - - last; - } - else - { - $idx--; - } - } - - if ($idx == 0) - { - # We bottomed out because the line is longer than the - # available space. But that could be because the space is - # small, or because the line is longer than even the maximum - # possible space. Handle both cases below. - - if ($length_remaining == ($max_line_length - (length ($user_indent)))) - { - # The line is simply too long -- there is no hope of ever - # breaking it nicely, so just insert it verbatim, with - # appropriate padding. - $this_line = "\n${left_pad_str}${this_line}"; - } - else - { - # Can't break it here, but may be able to on the next round... - unshift (@lines, $this_line); - $length_remaining = $max_line_length - (length ($user_indent)); - $this_line = "\n${left_pad_str}"; - } - } - } - else # $this_len < $length_remaining, so tack on what we can. - { - # Leave a note for the next iteration. - $length_remaining = $length_remaining - $this_len; - - if ($this_line =~ /\.$/) - { - $this_line .= " "; - $length_remaining -= 2; - } - else # not a sentence end - { - $this_line .= " "; - $length_remaining -= 1; - } - } - - # Unconditionally indicate that loop has run at least once. - $first_time = 0; - - $wrapped_text .= "${user_indent}${this_line}"; - } - - # One last bit of padding. - $wrapped_text .= "\n"; - - return $wrapped_text; -} - - -sub xml_escape () -{ - my $txt = shift; - $txt =~ s/&/&/g; - $txt =~ s//>/g; - return $txt; -} - - -sub maybe_read_user_map_file () -{ - my %expansions; - - if ($User_Map_File) - { - open (MAPFILE, "<$User_Map_File") - or die ("Unable to open $User_Map_File ($!)"); - - while () - { - next if /^\s*#/; # Skip comment lines. - next if not /:/; # Skip lines without colons. - - # It is now safe to split on ':'. - my ($username, $expansion) = split ':'; - chomp $expansion; - $expansion =~ s/^'(.*)'$/$1/; - $expansion =~ s/^"(.*)"$/$1/; - - # If it looks like the expansion has a real name already, then - # we toss the username we got from CVS log. Otherwise, keep - # it to use in combination with the email address. - - if ($expansion =~ /^\s*<{0,1}\S+@.*/) { - # Also, add angle brackets if none present - if (! ($expansion =~ /<\S+@\S+>/)) { - $expansions{$username} = "$username <$expansion>"; - } - else { - $expansions{$username} = "$username $expansion"; - } - } - else { - $expansions{$username} = $expansion; - } - } - - close (MAPFILE); - } - - return %expansions; -} - - -sub parse_options () -{ - # Check this internally before setting the global variable. - my $output_file; - - # If this gets set, we encountered unknown options and will exit at - # the end of this subroutine. - my $exit_with_admonishment = 0; - - while (my $arg = shift (@ARGV)) - { - if ($arg =~ /^-h$|^-help$|^--help$|^--usage$|^-?$/) { - $Print_Usage = 1; - } - elsif ($arg =~ /^--debug$/) { # unadvertised option, heh - $Debug = 1; - } - elsif ($arg =~ /^--version$/) { - $Print_Version = 1; - } - elsif ($arg =~ /^-g$|^--global-opts$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - # Don't assume CVS is called "cvs" on the user's system: - $Log_Source_Command =~ s/(^\S*)/$1 $narg/; - } - elsif ($arg =~ /^-l$|^--log-opts$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $Log_Source_Command .= " $narg"; - } - elsif ($arg =~ /^-f$|^--file$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $output_file = $narg; - } - elsif ($arg =~ /^--accum$/) { - $Cumulative = 1; - } - elsif ($arg =~ /^--fsf$/) { - $FSF_Style = 1; - } - elsif ($arg =~ /^-U$|^--usermap$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $User_Map_File = $narg; - } - elsif ($arg =~ /^-W$|^--window$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $Max_Checkin_Duration = $narg; - } - elsif ($arg =~ /^-I$|^--ignore$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - push (@Ignore_Files, $narg); - } - elsif ($arg =~ /^-C$|^--case-insensitive$/) { - $Case_Insensitive = 1; - } - elsif ($arg =~ /^-R$|^--regexp$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $Regexp_Gate = $narg; - } - elsif ($arg =~ /^--stdout$/) { - $Output_To_Stdout = 1; - } - elsif ($arg =~ /^--version$/) { - $Print_Version = 1; - } - elsif ($arg =~ /^-d$|^--distributed$/) { - $Distributed = 1; - } - elsif ($arg =~ /^-P$|^--prune$/) { - $Prune_Empty_Msgs = 1; - } - elsif ($arg =~ /^-S$|^--separate-header$/) { - $After_Header = "\n\n"; - } - elsif ($arg =~ /^--no-wrap$/) { - $No_Wrap = 1; - } - elsif ($arg =~ /^--gmt$|^--utc$/) { - $UTC_Times = 1; - } - elsif ($arg =~ /^-w$|^--day-of-week$/) { - $Show_Day_Of_Week = 1; - } - elsif ($arg =~ /^-r$|^--revisions$/) { - $Show_Revisions = 1; - } - elsif ($arg =~ /^-t$|^--tags$/) { - $Show_Tags = 1; - } - elsif ($arg =~ /^-b$|^--branches$/) { - $Show_Branches = 1; - } - elsif ($arg =~ /^-F$|^--follow$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - push (@Follow_Branches, $narg); - } - elsif ($arg =~ /^--stdin$/) { - $Input_From_Stdin = 1; - } - elsif ($arg =~ /^--header$/) { - my $narg = shift (@ARGV) || die "$arg needs argument.\n"; - $ChangeLog_Header = &slurp_file ($narg); - if (! defined ($ChangeLog_Header)) { - $ChangeLog_Header = ""; - } - } - elsif ($arg =~ /^--xml$/) { - $XML_Output = 1; - } - elsif ($arg =~ /^--hide-filenames$/) { - $Hide_Filenames = 1; - $After_Header = ""; - } - else { - # Just add a filename as argument to the log command - $Log_Source_Command .= " $arg"; - } - } - - ## Check for contradictions... - - if ($Output_To_Stdout && $Distributed) { - print STDERR "cannot pass both --stdout and --distributed\n"; - $exit_with_admonishment = 1; - } - - if ($Output_To_Stdout && $output_file) { - print STDERR "cannot pass both --stdout and --file\n"; - $exit_with_admonishment = 1; - } - - if ($XML_Output && $Cumulative) { - print STDERR "cannot pass both --xml and --accum\n"; - $exit_with_admonishment = 1; - } - - # Or if any other error message has already been printed out, we - # just leave now: - if ($exit_with_admonishment) { - &usage (); - exit (1); - } - elsif ($Print_Usage) { - &usage (); - exit (0); - } - elsif ($Print_Version) { - &version (); - exit (0); - } - - ## Else no problems, so proceed. - - if ($output_file) { - $Log_File_Name = $output_file; - } -} - - -sub slurp_file () -{ - my $filename = shift || die ("no filename passed to slurp_file()"); - my $retstr; - - open (SLURPEE, "<${filename}") or die ("unable to open $filename ($!)"); - my $saved_sep = $/; - undef $/; - $retstr = ; - $/ = $saved_sep; - close (SLURPEE); - return $retstr; -} - - -sub debug () -{ - if ($Debug) { - my $msg = shift; - print STDERR $msg; - } -} - - -sub version () -{ - print "cvs2cl.pl version ${VERSION}; distributed under the GNU GPL.\n"; -} - - -sub usage () -{ - &version (); - print <<'END_OF_INFO'; -Generate GNU-style ChangeLogs in CVS working copies. - -Notes about the output format(s): - - The default output of cvs2cl.pl is designed to be compact, formally - unambiguous, but still easy for humans to read. It is largely - self-explanatory, I hope; the one abbreviation that might not be - obvious is "utags". That stands for "universal tags" -- a - universal tag is one held by all the files in a given change entry. - - If you need output that's easy for a program to parse, use the - --xml option. Note that with XML output, just about all available - information is included with each change entry, whether you asked - for it or not, on the theory that your parser can ignore anything - it's not looking for. - -Notes about the options and arguments (the actual options are listed -last in this usage message): - - * The -I and -F options may appear multiple times. - - * To follow trunk revisions, use "-F trunk" ("-F TRUNK" also works). - This is okay because no would ever, ever be crazy enough to name a - branch "trunk", right? Right. - - * For the -U option, the UFILE should be formatted like - CVSROOT/users. That is, each line of UFILE looks like this - jrandom:jrandom@red-bean.com - or maybe even like this - jrandom:'Jesse Q. Random ' - Don't forget to quote the portion after the colon if necessary. - - * Many people want to filter by date. To do so, invoke cvs2cl.pl - like this: - cvs2cl.pl -l "-d'DATESPEC'" - where DATESPEC is any date specification valid for "cvs log -d". - (Note that CVS 1.10.7 and below requires there be no space between - -d and its argument). - -Options/Arguments: - - -h, -help, --help, or -? Show this usage and exit - --version Show version and exit - -r, --revisions Show revision numbers in output - -b, --branches Show branch names in revisions when possible - -t, --tags Show tags (symbolic names) in output - --stdin Read from stdin, don't run cvs log - --stdout Output to stdout not to ChangeLog - -d, --distributed Put ChangeLogs in subdirs - -f FILE, --file FILE Write to FILE instead of "ChangeLog" - --fsf Use this if log data is in FSF ChangeLog style - -W SECS, --window SECS Window of time within which log entries unify - -U UFILE, --usermap UFILE Expand usernames to email addresses from UFILE - -R REGEXP, --regexp REGEXP Include only entries that match REGEXP - -I REGEXP, --ignore REGEXP Ignore files whose names match REGEXP - -C, --case-insensitive Any regexp matching is done case-insensitively - -F BRANCH, --follow BRANCH Show only revisions on or ancestral to BRANCH - -S, --separate-header Blank line between each header and log message - --no-wrap Don't auto-wrap log message (recommend -S also) - --gmt, --utc Show times in GMT/UTC instead of local time - --accum Add to an existing ChangeLog (incompat w/ --xml) - -w, --day-of-week Show day of week - --header FILE Get ChangeLog header from FILE ("-" means stdin) - --xml Output XML instead of ChangeLog format - --hide-filenames Don't show filenames (ignored for XML output) - -P, --prune Don't show empty log messages - -g OPTS, --global-opts OPTS Invoke like this "cvs OPTS log ..." - -l OPTS, --log-opts OPTS Invoke like this "cvs ... log OPTS" - FILE1 [FILE2 ...] Show only log information for the named FILE(s) - -See http://www.red-bean.com/cvs2cl for maintenance and bug info. -END_OF_INFO -} - -__END__ - -=head1 NAME - -cvs2cl.pl - produces GNU-style ChangeLogs in CVS working copies, by - running "cvs log" and parsing the output. Shared log entries are - unified in an intuitive way. - -=head1 DESCRIPTION - -This script generates GNU-style ChangeLog files from CVS log -information. Basic usage: just run it inside a working copy and a -ChangeLog will appear. It requires repository access (i.e., 'cvs log' -must work). Run "cvs2cl.pl --help" to see more advanced options. - -See http://www.red-bean.com/cvs2cl for updates, and for instructions -on getting anonymous CVS access to this script. - -Maintainer: Karl Fogel -Please report bugs to . - -=head1 README - -This script generates GNU-style ChangeLog files from CVS log -information. Basic usage: just run it inside a working copy and a -ChangeLog will appear. It requires repository access (i.e., 'cvs log' -must work). Run "cvs2cl.pl --help" to see more advanced options. - -See http://www.red-bean.com/cvs2cl for updates, and for instructions -on getting anonymous CVS access to this script. - -Maintainer: Karl Fogel -Please report bugs to . - -=head1 PREREQUISITES - -This script requires C, C, and -C. -It also seems to require C or higher. - -=pod OSNAMES - -any - -=pod SCRIPT CATEGORIES - -Version_Control/CVS - -=cut - - --*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- - -Note about a bug-slash-opportunity: ------------------------------------ - -There's a bug in Text::Wrap, which affects cvs2cl. This script -reveals it: - - #!/usr/bin/perl -w - - use Text::Wrap; - - my $test_text = - "This script demonstrates a bug in Text::Wrap. The very long line - following this paragraph will be relocated relative to the surrounding - text: - - ==================================================================== - - See? When the bug happens, we'll get the line of equal signs below - this paragraph, even though it should be above."; - - - # Print out the test text with no wrapping: - print "$test_text"; - print "\n"; - print "\n"; - - # Now print it out wrapped, and see the bug: - print wrap ("\t", " ", "$test_text"); - print "\n"; - print "\n"; - -If the line of equal signs were one shorter, then the bug doesn't -happen. Interesting. - -Anyway, rather than fix this in Text::Wrap, we might as well write a -new wrap() which has the following much-needed features: - -* initial indentation, like current Text::Wrap() -* subsequent line indentation, like current Text::Wrap() -* user chooses among: force-break long words, leave them alone, or die()? -* preserve existing indentation: chopped chunks from an indented line - are indented by same (like this line, not counting the asterisk!) -* optional list of things to preserve on line starts, default ">" - -Note that the last two are essentially the same concept, so unify in -implementation and give a good interface to controlling them. - -And how about: - -Optionally, when encounter a line pre-indented by same as previous -line, then strip the newline and refill, but indent by the same. -Yeah... diff --git a/storage/ndb/home/bin/fix-cvs-root b/storage/ndb/home/bin/fix-cvs-root deleted file mode 100755 index 2c4f158f825..00000000000 --- a/storage/ndb/home/bin/fix-cvs-root +++ /dev/null @@ -1,17 +0,0 @@ -#! /bin/sh - -# change all CVS/Root to current CVSROOT - -[ "$CVSROOT" ] || { echo "no CVSROOT in environment" >&2; exit 1; } - -echo "changing all CVS/Root files under `pwd`" -sleep 1 - -find . -path '*/CVS/Root' -print | -while read file; do - echo "$file" - chmod +w $file || exit 1 - echo $CVSROOT >$file || exit 1 -done - -echo "done" diff --git a/storage/ndb/home/bin/import-from-bk.sh b/storage/ndb/home/bin/import-from-bk.sh deleted file mode 100755 index 4e3957be6d5..00000000000 --- a/storage/ndb/home/bin/import-from-bk.sh +++ /dev/null @@ -1,158 +0,0 @@ -#! /bin/sh - -# XXX does not delete files -# XXX does not handle nested new dirs -# this script screams for perl, no time now -# look for bk2cvs on the net - -PATH=/usr/local/bin:$PATH; export PATH -LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH - -batch=n -if [ "$1" = "-batch" ]; then - batch=y - shift -fi - -say() { - echo "$*" -} - -die() { - case $# in - 0) set -- "command failed" ;; - esac - say "$* -- aborted" >&2 - exit 1 -} - -usage() { - die "usage: $0 [-batch] top -- copy from mysql/ndb to another NDB_TOP" -} - -doit() { - cmd="$*" - if [ $batch = n ]; then - echo -n "$cmd [y]" - read junk - sh -c "$cmd" - return 0 - else - echo "$cmd" - sh -c "$cmd" - return $? - fi -} - -say "======================" -say "`date`" - -case $# in -1) [ -d $1/src/CVS ] || die "$1 is not an NDB_TOP" - top=$1 ;; -*) usage ;; -esac - -if ! fgrep ndb_kernel_version.h $top/include/kernel/CVS/Entries >/dev/null 2>&1; then - die "$top is not an NDB_TOP" -fi - -if find $top -path '*/CVS/Tag' -print | grep . >/dev/null; then - die "$top: contains CVS/Tag files, not accepted" -fi - -if [ ! -f include/SCCS/s.ndb_version.h ]; then - die "current dir ($PWD) is not an NDB_TOP" -fi - -doit "bk pull" || exit 1 -doit "bk -r clean" -doit "bk -r get -q" - -files=`bk -r. sfiles -g | - fgrep -v ' ' | - fgrep -v /.cvsignore` - -n=0 -files2= -for f in $files; do - if [ ! -f $f ]; then - die "$f: no such file" - fi - if [ -w $f ]; then - say "$f: is writable, accept anyway" - fi - files2="$files2 $f" - n=$((n+1)) -done -files=$files2 -say "$n files..." - -adddirs= addfiles= updfiles= -for f in $files; do - d=`dirname $f` - b=`basename $f` - if [ ! -f $top/$d/CVS/Entries ]; then - found=n - for x in $adddirs; do - if [ $x = $d ]; then found=y; break; fi - done - if [ $found = n ]; then - say "$d: to create dir" - adddirs="$adddirs $d" - fi - addfiles="$addfiles $f" - say "$f: to create" - elif ! fgrep "/$b/" $top/$d/CVS/Entries >/dev/null; then - addfiles="$addfiles $f" - say "$f: to create" - else - cmp $f $top/$f >/dev/null - case $? in - 0) continue ;; - 1) ;; - *) die "$f: unknown error" ;; - esac - updfiles="$updfiles $f" - say "$f: to update" - fi -done - -for d in $adddirs; do - doit "cd $top && mkdir -p $d" || die -done - -for f in $addfiles $updfiles; do - doit "cp -fp $f $top/$f" || die -done - -for d in $adddirs; do - # fix 1 level up - d2=`dirname $d` - if [ ! -d $top/$d2/CVS ]; then - doit "cd $top && cvs add $d2" || die - fi - doit "cd $top && cvs add $d" || die -done - -for f in $addfiles; do - kb= - if echo $f | perl -nle "print(-B $_)" | grep 1 >/dev/null; then - kb="-kb" - fi - doit "cd $top && cvs add $kb $f" || die -done - -tag=import_bk_`date +%Y_%m_%d` - -doit "cd $top && cvs commit -m $tag" || die -doit "cd $top && cvs tag -F $tag" || die - -env="NDB_TOP=$top; export NDB_TOP" -env="$env; USER_FLAGS='-DAPI_TRACE -fmessage-length=0'; export USER_FLAGS" -doit "$env; cd $top && ./configure" -doit "$env; cd $top && sh config/GuessConfig.sh" -doit "$env; cd $top && make clean nuke-deps vim-tags" -doit "$env; cd $top && make" || die - -say "imported ok" diff --git a/storage/ndb/home/bin/ndb_deploy b/storage/ndb/home/bin/ndb_deploy deleted file mode 100755 index 773fc9b8fd7..00000000000 --- a/storage/ndb/home/bin/ndb_deploy +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -if [ $# -eq 0 ] -then - for i in $DEPLOY_DST - do - rsync -r -v --exclude '*.a' $NDB_TOP/bin $NDB_TOP/lib $i/ - done -else - while [ $# -gt 0 ] - do - arg=$1 - shift; - if [ `echo $arg | grep -c lib` -eq 0 ] - then - dst=bin/ - else - dst=lib/ - fi - - for i in $DEPLOY_DST - do - rsync -v $arg $i/$dst - done - done -fi - diff --git a/storage/ndb/home/bin/ndbdoxy.pl b/storage/ndb/home/bin/ndbdoxy.pl deleted file mode 100755 index 89b7de8440e..00000000000 --- a/storage/ndb/home/bin/ndbdoxy.pl +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/local/bin/perl -# -# ndbdoxy.pl Executes doxygen on a checked out version of NDB Cluster -# -# Written by Lars Thalmann, 2003. - -use strict; -umask 000; - -# ----------------------------------------------------------------------------- -# Settings -# ----------------------------------------------------------------------------- - -my $root = "/home/elathal/public_html/cvsdoxy"; - -$ENV{LD_LIBRARY_PATH} = "/usr/local/lib:/opt/as/local/lib"; -$ENV{LD_LIBRARY_PATH} = $ENV{LD_LIBRARY_PATH} . ":/opt/as/forte6/SUNWspro/lib"; -$ENV{PATH} = $ENV{PATH} . ":/usr/local/bin:/opt/as/local/bin"; -$ENV{PATH} = $ENV{PATH} . ":/opt/as/local/teTeX/bin/sparc-sun-solaris2.8"; - -my $DOXYGEN = "doxygen"; -my $PDFLATEX = "pdflatex"; -my $MAKEINDEX = "makeindex"; - -# ----------------------------------------------------------------------------- -# Argument handling -# ----------------------------------------------------------------------------- - -if (@ARGV != 3) { - print< <version> - - where - <module> is cvsdoxy module to doxgenify - <title> is title of report - <version> is version of NDB Cluster -END - exit; -} -my $module = $ARGV[0]; -my $title = $ARGV[1]; -my $version = $ARGV[2]; -my $destdir = "."; - -# ----------------------------------------------------------------------------- -# Execute Doxygen -g -# ----------------------------------------------------------------------------- - -if (-r "${root}/doxyfiles/${module}.doxyfile") { - system("cd ${destdir}; \ - cp ${root}/doxyfiles/${module}.doxyfile Doxyfile"); -} elsif (-r "${root}/doxyfiles/default.doxyfile") { - system("cd ${destdir}; \ - cp ${root}/doxyfiles/default.doxyfile Doxyfile"); -} else { - system("cd ${destdir}; $DOXYGEN -g"); -} - -# ----------------------------------------------------------------------------- -# HTML Footer -# ----------------------------------------------------------------------------- - -if (-r "${root}/doxyfiles/htmlfooter") { - system("cd ${destdir}; \ - cp ${root}/doxyfiles/htmlfooter footer.html"); - - open (INFILE, "< ${destdir}/footer.html") - or die "Error opening ${destdir}/footer.html.\n"; - open (OUTFILE, "> ${destdir}/footer.html.new") - or die "Error opening ${destdir}/footer.html.new.\n"; - while (<INFILE>) { - if (/(.*)DATE(.*)$/) { - print OUTFILE $1 . localtime() . $2; - } else { - print OUTFILE; - } - } - close INFILE; - close OUTFILE; - - system("mv ${destdir}/footer.html.new ${destdir}/footer.html"); -} else { - print("Warning: No ${root}/doxyfiles/${module}.htmlfooter"); -} - -# ----------------------------------------------------------------------------- -# Execute Doxygen -# ----------------------------------------------------------------------------- - -system("cd ${destdir}; $DOXYGEN"); - -# ----------------------------------------------------------------------------- -# Change a little in refman.tex -# ----------------------------------------------------------------------------- - -open (INFILE, "< ${destdir}/latex/refman.tex") - or die "Error opening ${destdir}/latex/refman.tex.\n"; -open (OUTFILE, "> ${destdir}/latex/refman.tex.new") - or die "Error opening ${destdir}/latex/refman.tex.new.\n"; - -while (<INFILE>) -{ - if (/(.*)Reference Manual(.*)$/) { - print OUTFILE $1 . - "\\mbox{}\\vspace{-3cm}\\mbox{}" . - "\\hrule\\bigskip\\bigskip\\bigskip\\bigskip" . - "\\Huge{" . $title . "}" . $2; - } elsif (/(.*)Generated by Doxygen 1.2.1[0-9](.*)$/) { - print OUTFILE $1 . - "\\begin{center}" . - "\\LARGE{MySQL AB}" . - "\\end{center}". - "\\hfill\\bigskip\\bigskip\\bigskip\\hrule" . - "\\bigskip\\bigskip\\bigskip\\bigskip\\bigskip" . - "\\bigskip\\bigskip\\bigskip\\bigskip\\bigskip" . - "\\bigskip\\bigskip NDB Cluster Release " . $version . - "\\bigskip\\bigskip\\bigskip\\bigskip\\bigskip\\hfill" . - $2; - } elsif (/\\chapter\{File Index\}/) { - print OUTFILE "\%\\chapter{File Index}\n"; - } elsif (/\\input{files}/) { - print OUTFILE "\%\\input{files}\n"; - } elsif (/\\chapter\{Page Index\}/) { - print OUTFILE "\%\\chapter{Page Index}\n"; - } elsif (/\\input{pages}/) { - print OUTFILE "\%\\input{pages}\n"; - } else { - print OUTFILE; - } -} - -close INFILE; -close OUTFILE; - -system("mv ${destdir}/latex/refman.tex.new ${destdir}/latex/refman.tex"); - -# ----------------------------------------------------------------------------- -# Change a little in doxygen.sty -# ----------------------------------------------------------------------------- - -open (INFILE, "< ${destdir}/latex/doxygen.sty") - or die "Error opening INFILE.\n"; -open (OUTFILE, "> ${destdir}/latex/doxygen.sty.new") - or die "Error opening OUTFILE.\n"; - -while (<INFILE>) -{ - if (/\\rfoot/) { - print OUTFILE "\\rfoot[\\fancyplain{}{\\bfseries\\small \\copyright~Copyright 2003 MySQL AB\\hfill support-cluster\@mysql.com}]{}\n"; - } elsif (/\\lfoot/) { - print OUTFILE "\\lfoot[]{\\fancyplain{}{\\bfseries\\small support-cluster\@mysql.com\\hfill \\copyright~Copyright 2003 MySQL AB}}\n"; - } else { - print OUTFILE; - } -} - -close INFILE; -close OUTFILE; - -system("mv ${destdir}/latex/doxygen.sty.new ${destdir}/latex/doxygen.sty"); - -# ----------------------------------------------------------------------------- -# Other -# ----------------------------------------------------------------------------- - -#system("cd ${root}/tmp/${module}; \ -# mkdir html.tar; \ -# cd html.tar; \ -# cp -r ../html ${module}; \ -# tar cf ${module}.html.tar ${module}; \ -# /usr/local/bin/gzip ${module}.html.tar; \ -# /bin/rm -rf ${root}/tmp/${module}/html.tar/${module}"); - -#system("cd ${destdir}/latex/; \ -# $PDFLATEX refman.tex \ -# $MAKEINDEX refman.idx \ -# $PDFLATEX refman.tex \ -# mv -f refman.pdf ${module}.pdf"); - -print<<END; -Execute: - latex refman; makeindex refman; latex refman -END diff --git a/storage/ndb/home/bin/ngcalc b/storage/ndb/home/bin/ngcalc deleted file mode 100755 index a289d384db9..00000000000 --- a/storage/ndb/home/bin/ngcalc +++ /dev/null @@ -1,78 +0,0 @@ -#! /usr/local/bin/perl - -use strict; -use Getopt::Long; - -sub usage { - print <<END; -ngcalc -- calculate node groups and table fragments -usage: ngcalc [ options ] f1 f2 ... --g num number of node groups (default 2) --r num number of replicas (default 2) --n list comma-separated list of db nodes (default 1,2,...) -fX number of fragments per node group in table X (e.g. 1,2,8) - (all replicas count as same fragment) -END - exit(1); -}; - -use vars qw($cnoOfNodeGroups $cnoReplicas $nodeArray); - -$cnoOfNodeGroups = 2; -$cnoReplicas = 2; -GetOptions( - "g=i" => \$cnoOfNodeGroups, - "r=i" => \$cnoReplicas, - "n=s" => \$nodeArray, -) or &usage; - -my @tableList = @ARGV; - -$cnoOfNodeGroups > 0 or &usage; -$cnoReplicas > 0 or &usage; -if (! defined($nodeArray)) { - $nodeArray = join(',', 1..($cnoOfNodeGroups*$cnoReplicas)); -} -$nodeArray =~ /^\d+(,\d+)*$/ or &usage; -my @nodeArray = split(/,/, $nodeArray); -@nodeArray == $cnoOfNodeGroups*$cnoReplicas or &usage; - -my @nodeGroupRecord; -for (my $i = 0; $i < $cnoOfNodeGroups; $i++) { - my $rec = {}; - my $nodes = []; - for (my $j = 0; $j < $cnoReplicas; $j++) { - push(@$nodes, $nodeArray[$i * $cnoReplicas + $j]); - } - $rec->{nodesInGroup} = $nodes; - $rec->{nodeCount} = $cnoReplicas; - $rec->{nextReplicaNode} = 0; - $nodeGroupRecord[$i] = $rec; - print "NG $i: ", join(" ", @{$rec->{nodesInGroup}}), "\n"; -} - -# see Dbdih::execCREATE_FRAGMENTATION_REQ - -my $c_nextNodeGroup = 0; -for (my $t = 0; $t < @tableList; $t++) { - use integer; - my $f = $tableList[$t]; - my $ng = $c_nextNodeGroup++; - $c_nextNodeGroup = 0 if $c_nextNodeGroup == $cnoOfNodeGroups; - my $noOfFragments = $f * $cnoOfNodeGroups; - my @fragments; - for (my $fragNo = 0; $fragNo < $noOfFragments; $fragNo++) { - my $rec = $nodeGroupRecord[$ng]; - my $max = $rec->{nodeCount}; - my $ind = $rec->{nextReplicaNode}; - $rec->{nextReplicaNode} = ($ind + 1 >= $max ? 0 : $ind + 1); - for (my $replicaNo = 0; $replicaNo < $cnoReplicas; $replicaNo++) { - my $nodeId = $rec->{nodesInGroup}[$ind++]; - push(@fragments, $nodeId); - $ind = ($ind == $max ? 0 : $ind); - } - $ng++; - $ng = ($ng == $cnoOfNodeGroups ? 0 : $ng); - } - printf "%02d %s\n", $t, join(" ", @fragments); -} diff --git a/storage/ndb/home/bin/parseConfigFile.awk b/storage/ndb/home/bin/parseConfigFile.awk deleted file mode 100644 index 6903949156c..00000000000 --- a/storage/ndb/home/bin/parseConfigFile.awk +++ /dev/null @@ -1,98 +0,0 @@ -BEGIN{ - where=0; - n_hosts=0; - n_api=0; - n_ndb=0; - n_mgm=0; - n_ports=0; -} -/COMPUTERS/ { - where=1; -} -/\[[ \t]*COMPUTER[ \t]*\]/ { - where=1; -} -/PROCESSES/ { - where=2; -} -/Type: MGMT/ { - if(where!=1){ - where=2; - n_mgm++; - } -} -/\[[ \t]*MGM[ \t]*\]/ { - where=2; - n_mgm++; -} -/Type: DB/ { - if(where!=1){ - where=3; - n_ndb++; - } -} -/\[[ \t]*DB[ \t]*\]/ { - where=3; - n_ndb++; -} -/Type: API/ { - if(where!=1){ - where=4; - n_api++; - } -} -/\[[ \t]*API[ \t]*\]/ { - where=4; - n_api++; -} -/HostName:/ { - host_names[host_ids[n_hosts]]=$2; -} - -/FileSystemPath:/ { - if (where==3){ - ndb_fs[ndb_ids[n_ndb]]=$2; - } -} - -/Id:/{ - if(where==1){ - n_hosts++; - host_ids[n_hosts]=$2; - } - if(where==2){ - mgm_ids[n_mgm]=$2; - } - if(where==3){ - ndb_ids[n_ndb]=$2; - } - if(where==4){ - api_ids[n_api]=$2; - } -} -/ExecuteOnComputer:/{ - if(where==2){ - mgm_hosts[mgm_ids[n_mgm]]=host_names[$2]; - } - if(where==3){ - ndb_hosts[ndb_ids[n_ndb]]=host_names[$2]; - } - if(where==4){ - api_hosts[api_ids[n_api]]=host_names[$2]; - } -} -END { - for(i=1; i<=n_mgm; i++){ - printf("mgm_%d=%s\n", mgm_ids[i], mgm_hosts[mgm_ids[i]]); - } - for(i=1; i<=n_ndb; i++){ - printf("ndb_%d=%s\n", ndb_ids[i], ndb_hosts[ndb_ids[i]]); - printf("ndbfs_%d=%s\n", ndb_ids[i], ndb_fs[ndb_ids[i]]); - } - for(i=1; i<=n_api; i++){ - printf("api_%d=%s\n", api_ids[i], api_hosts[api_ids[i]]); - } - printf("mgm_nodes=%d\n", n_mgm); - printf("ndb_nodes=%d\n", n_ndb); - printf("api_nodes=%d\n", n_api); -} diff --git a/storage/ndb/home/bin/setup-test.sh b/storage/ndb/home/bin/setup-test.sh deleted file mode 100755 index 61097c30027..00000000000 --- a/storage/ndb/home/bin/setup-test.sh +++ /dev/null @@ -1,272 +0,0 @@ -#!/bin/sh - -# NAME -# run-test.sh - Run a test program -# -# SYNOPSIS -# setup-test.sh [ -n <ndb dir>] [ -r <run dir>] -# -# DESCRIPTION -# run a test -# -# OPTIONS -# -# EXAMPLES -# -# ENVIRONMENT -# NDB_PROJ_HOME Home dir for ndb -# -# FILES -# $NDB_PROJ_HOME/lib/funcs.sh shell script functions -# -# DIAGNOSTICTS -# -# VERSION -# 1.01 -# -# AUTHOR -# Jonas Oreland -# -# - -progname=`basename $0` -synopsis="setup-test.sh [-x xterm] [ -n <ndb dir>] [ -r <run dir>]" - -: ${NDB_PROJ_HOME:?} # If undefined, exit with error message - -: ${RUN_NDB_NODE_OPTIONS:=--} # If undef, set to --. Keeps getopts happy. - # You may have to experiment a bit - # to get quoting right (if you need it). - - -. $NDB_PROJ_HOME/lib/funcs.sh # Load some good stuff - -# defaults for options related variables -# - -verbose=yes -options="" -ndb_dir=$NDB_TOP -if [ -z "$ndb_dir" ] -then - ndb_dir=`pwd` -fi - -local_dir=`pwd` -own_host=`hostname` -uniq_id=$$.$$ - -_xterm=$XTERM -_rlogin="ssh -X" - -# used if error when parsing the options environment variable -# -env_opterr="options environment variable: <<$options>>" - - -# Option parsing, for the options variable as well as the command line. -# -# We want to be able to set options in an environment variable, -# as well as on the command line. In order not to have to repeat -# the same getopts information twice, we loop two times over the -# getopts while loop. The first time, we process options from -# the options environment variable, the second time we process -# options from the command line. -# -# The things to change are the actual options and what they do. -# -# -for optstring in "$options" "" # 1. options variable 2. cmd line -do - while getopts n:r:x: i $optstring # optstring empty => no arg => cmd line - do - case $i in - - n) ndb_dir=$OPTARG;; # Ndb dir - r) run_dir=$OPTARG;; # Run dir - x) _xterm=$OPTARG;; - \?) syndie $env_opterr;; # print synopsis and exit - - esac - done - - [ -n "$optstring" ] && OPTIND=1 # Reset for round 2, cmdline options - - env_opterr= # Round 2 should not use the value - -done -shift `expr $OPTIND - 1` - -# --- option parsing done --- - -ndb_dir=`abspath $ndb_dir` -run_dir=`abspath $run_dir` - -trace "Verifying arguments" - -if [ ! -d $ndb_dir/bin ] || [ ! -d $ndb_dir/lib ] -then - msg "Ndb home path seems incorrect either $ndb_dir/bin or $ndb_dir/lib not found" - exit 1004 -fi - -ndb_bin=$ndb_dir/bin/ndb -mgm_bin=$ndb_dir/bin/mgmtsrvr -api_lib=$ndb_dir/lib/libNDB_API.so - -if [ ! -x $ndb_bin ] -then - msg "Ndb path seems incorrect ndb binary not found: $ndb_bin" - exit 1004 -fi - -if [ ! -x $mgm_bin ] -then - msg "Ndb path seems incorrect management server binary not found: $mgm_bin" - exit 1004 -fi - -init_config=$run_dir/mgm.1/initconfig.txt -local_config=$run_dir/mgm.1/localcfg.txt -if [ ! -r $init_config ] || [ ! -r $local_config ] -then - msg "Run path seems incorrect $init_config or $local_config not found" - exit 1004 -fi - -trace "Parsing $init_config" -awk -f $NDB_PROJ_HOME/bin/parseConfigFile.awk $init_config > /tmp/run-test.$uniq_id -. /tmp/run-test.$uniq_id -cat /tmp/run-test.$uniq_id -rm -f /tmp/run-test.$uniq_id - -trace "Parsing $local_config" -MgmPort=`grep -v "OwnProcessId" $local_config | cut -d " " -f 2` - -trace "Verifying that mgm port is empty" -telnet $mgm_1 $MgmPort > /tmp/mgm_port.$uniq_id 2>&1 <<EOF -EOF - -if [ 0 -lt `grep -c -i connected /tmp/mgm_port.$uniq_id` ] -then - rm /tmp/mgm_port.$uniq_id - msg "There is already something using port $mgm_1:$MgmPort" - exit 1003 -fi -rm /tmp/mgm_port.$uniq_id - -fixhost(){ - if [ "$1" != localhost ] - then - echo $1 - else - uname -n - fi -} - -do_xterm(){ - title=$1 - shift - xterm -fg black -title "$title" -e $* -} - -save_profile(){ - cp $HOME/.profile /tmp/.profile.$uniq_id -} - -wait_restore_profile(){ - while [ -r /tmp/.profile.$uniq_id ] - do - sleep 1 - done -} - -start_mgm(){ - trace "Starting Management server on: $mgm_1" - save_profile - mgm_1=`fixhost $mgm_1` - - ( - echo "PATH=$ndb_dir/bin:\$PATH" - echo "LD_LIBRARY_PATH=$ndb_dir/lib:\$LD_LIBRARY_PATH" - echo "export PATH LD_LIBRARY_PATH" - echo "cd $run_dir/mgm.1" - echo "ulimit -Sc unlimited" - echo "mv /tmp/.profile.$uniq_id $HOME/.profile" - ) >> $HOME/.profile - do_xterm "Mmg on $mgm_1" ${_rlogin} $mgm_1 & - wait_restore_profile -} - -start_ndb_node(){ - node_id=$1 - dir=$run_dir/ndb.$1 - ndb_host=`eval echo "\$"ndb_$node_id` - ndb_host=`fixhost $ndb_host` - ndb_fs=`eval echo "\$"ndbfs_$node_id` - - trace "Starting Ndb node $node_id on $ndb_host" - save_profile - - ( - echo "PATH=$ndb_dir/bin:\$PATH" - echo "LD_LIBRARY_PATH=$ndb_dir/lib:\$LD_LIBRARY_PATH" - echo "mkdir -p $ndb_fs" - echo "export PATH LD_LIBRARY_PATH" - echo "cd $dir" - echo "ulimit -Sc unlimited" - echo "mv /tmp/.profile.$uniq_id $HOME/.profile" - ) >> $HOME/.profile - do_xterm "Ndb: $node_id on $ndb_host" ${_rlogin} $ndb_host & - wait_restore_profile -} - -start_api_node(){ - node_id=$1 - dir=$run_dir/api.$1 - api_host=`eval echo "\$"api_$node_id` - api_host=`fixhost $api_host` - - trace "Starting api node $node_id on $api_host" - save_profile - - ( - echo "PATH=$ndb_dir/bin:\$PATH" - echo "LD_LIBRARY_PATH=$ndb_dir/lib:\$LD_LIBRARY_PATH" - echo "export PATH LD_LIBRARY_PATH NDB_PROJ_HOME" - echo "cd $dir" - echo "ulimit -Sc unlimited" - echo "mv /tmp/.profile.$uniq_id $HOME/.profile" - ) >> $HOME/.profile - do_xterm "API: $node_id on $api_host" ${_rlogin} $api_host & - wait_restore_profile -} - -for_each_ndb_node(){ - i=1 - j=`expr $mgm_nodes + 1` - while [ $i -le $ndb_nodes ] - do - $* $j - j=`expr $j + 1` - i=`expr $i + 1` - done -} - -for_each_api_node(){ - i=1 - j=`expr $mgm_nodes + $ndb_nodes + 1` - while [ $i -le $api_nodes ] - do - $* $j - j=`expr $j + 1` - i=`expr $i + 1` - done -} - -start_mgm -for_each_ndb_node start_ndb_node -for_each_api_node start_api_node - -exit 0 - diff --git a/storage/ndb/home/bin/signallog2html.lib/signallog2list.awk b/storage/ndb/home/bin/signallog2html.lib/signallog2list.awk deleted file mode 100644 index 9839f314556..00000000000 --- a/storage/ndb/home/bin/signallog2html.lib/signallog2list.awk +++ /dev/null @@ -1,102 +0,0 @@ -BEGIN{ - PRINT=0; - SIGNAL_ARRAY[0]=""; - BLOCK_ID=0; - SIGNAL_ID=-22; -} -{ - SIGNAL_ARRAY[SIGNAL_ID]=SIGNAL_ID; -} - -/^---- Send ----- Signal ----------------/ { - DIRECTION="S"; - SENDER=""; - SENDPROCESS=""; - RECEIVER=""; - RECPROCESS=""; - SIGNAL=""; - RECSIGID="?"; - SIGID="?"; - DELAY="N/A"; -} - -/^---- Send delay Signal/ { - DIRECTION="SD"; - SENDER=""; - SENDPROCESS=""; - RECEIVER=""; - RECPROCESS=""; - SIGNAL=""; - RECSIGID="?"; - SIGID="?"; - DELAY=$5; - - LEN=length(DELAY); - DELAY=substr(DELAY,2,LEN); -} - -/^---- Received - Signal ----------------/ { - DIRECTION="R"; - SENDER=""; - SENDPROCESS=""; - RECEIVER=""; - RECPROCESS=""; - SIGNAL=""; - RECSIGID="?"; - SIGID="?"; - DELAY="N/A"; -} - -/r.bn:/{ - - RECEIVER=$3; - RECPROCESS=$5; - - if(DIRECTION == "R"){ - SIGNAL=$10; - RECSIGID=$7; - } - else - SIGNAL=$8; -} - -/s.bn:/{ - - SENDER=$3; - SIGID=$7; - - if(SIGID == SIGNAL_ARRAY[SIGID]){ - PRINT=1; - if(DIRECTION == "R"){ - SIGNAL_ARRAY[RECSIGID]=RECSIGID; - }; - } - - SENDPROCESS=$5; - - LEN=length(RECEIVER); - RECEIVER=substr(RECEIVER,2,LEN-3); - - if(BLOCK_ID == "ALL" || RECEIVER==BLOCK_ID){PRINT=1; } - - LEN=length(SENDER); - SENDER=substr(SENDER,2,LEN-3); - if(BLOCK_ID == "ALL" || SENDER == BLOCK_ID){ PRINT=1;} - - LEN=length(SIGNAL); - SIGNAL=substr(SIGNAL,2,LEN-2); - - LEN=length(SENDPROCESS); - SENDPROCESS=substr(SENDPROCESS,1,LEN-1); - - LEN=length(RECPROCESS); - RECPROCESS=substr(RECPROCESS,1,LEN-1); - - if( PRINT == 1){ - print DIRECTION" "SENDPROCESS" "SENDER" "RECPROCESS" "RECEIVER" "SIGNAL" "SIGID" "RECSIGID" "DELAY; - } - - PRINT=0; -} - - diff --git a/storage/ndb/home/bin/signallog2html.lib/uniq_blocks.awk b/storage/ndb/home/bin/signallog2html.lib/uniq_blocks.awk deleted file mode 100644 index 43f48d1cde1..00000000000 --- a/storage/ndb/home/bin/signallog2html.lib/uniq_blocks.awk +++ /dev/null @@ -1,29 +0,0 @@ -BEGIN{ - NAMES[""]=""; - ORDER[0]=""; - NUM=0; -} - -{ - if(NAMES[$2$3]!=$2$3){ - NAMES[$2$3]=$2$3; - ORDER[NUM]=$2$3; - NUM++; - } - - if(NAMES[$4$5]!=$4$5){ - NAMES[$4$5]=$4$5; - ORDER[NUM]=$4$5; - NUM++; - } - - -} -END{ - for(i=0; i<NUM; i++){ - LIST=ORDER[i]" "LIST; - - } - print LIST; -} - diff --git a/storage/ndb/home/bin/signallog2html.sh b/storage/ndb/home/bin/signallog2html.sh deleted file mode 100755 index 5665275807c..00000000000 --- a/storage/ndb/home/bin/signallog2html.sh +++ /dev/null @@ -1,349 +0,0 @@ -#!/bin/sh -# NAME -# signallog2html.sh -# -# SYNOPSIS -# signallog2html.sh [ -b <block_name | ALL> ] [ -s <signal_id> ] -f signal_log_file -# -# DESCRIPTION -# Creates a signal sequence diagram in HTML format that can be -# viewed from a web browser. The HTML file is created from a signal -# log file and it contains a big table with jpeg files in every -# table cell. Every row in the table is a signal. The block_name -# could be one of the following: CMVMI MISSRA NDBFS NDBCNTR DBACC -# DBDICT DBLQH DBDIH DBTC DBTUP QMGR ALL. The signal_id is a -# number. If no block_name or signal_id is given the default -# block_name "ALL" is used. -# -# -# -# OPTIONS -# -# EXAMPLES -# -# -# ENVIRONMENT -# NDB_PROJ_HOME Home dir for ndb -# -# FILES -# $NDB_PROJ_HOME/lib/funcs.sh General shell script functions. -# uniq_blocks.awk Creates a list of unique blocks -# in the signal_log_file. -# signallog2list.awk Creates a list file from the signal_log_file. -# empty.JPG Jpeg file, must exist in the HTML file -# directory for viewing. -# left_line.JPG -# line.JPG -# right_line.JPG -# self_line.JPG -# -# -# SEE ALSO -# -# DIAGNOSTICTS -# -# VERSION -# 1.0 -# -# DATE -# 011029 -# -# AUTHOR -# Jan Markborg -# - -progname=`basename $0` -synopsis="signallog2html.sh [ -b <block_name | ALL> ] [ -s <signal_id> ] -f signal_log_file" -block_name="" -signal_id="" -verbose=yes -signal_log_file="" - -: ${NDB_PROJ_HOME:?} # If undefined, exit with error message - -: ${NDB_LOCAL_BUILD_OPTIONS:=--} # If undef, set to --. Keeps getopts happy. - # You may have to experiment a bit - # to get quoting right (if you need it). - - -. $NDB_PROJ_HOME/lib/funcs.sh # Load some good stuff - -# defaults for options related variables -# -report_date=`date '+%Y-%m-%d'` - -# Option parsing for the the command line. -# - -while getopts f:b:s: i -do - case $i in - f) signal_log_file=$OPTARG;; - b) block_name=$OPTARG;; - s) signal_id=$OPTARG;; - \?) syndie ;; # print synopsis and exit - esac -done - -# -- Verify -trace "Verifying signal_log_file $signal_log_file" - -if [ x$signal_log_file = "x" ] -then - syndie "Invalid signal_log_file name: $signal_log_file not found" -fi - - -if [ ! -r $signal_log_file ] -then - syndie "Invalid signal_log_file name: $signal_log_file not found" -fi - - - -if [ blocknameSET = 1 ] -then - - trace "Verifying block_name" - case $block_name in - CMVMI| MISSRA| NDBFS| NDBCNTR| DBACC| DBDICT| DBLQH| DBDIH| DBTC| DBTUP| QMGR);; - ALL) trace "Signals to/from every block will be traced!";; - *) syndie "Unknown block name: $block_name";; - esac -fi - -if [ block_name="" -a signal_id="" ] -then - block_name=ALL - trace "block_name = $block_name" -fi - -trace "Arguments OK" - -### -# -# General html functions -header(){ - cat <<EOF -<html><head><title>$* - -EOF -} - -footer(){ - cat < -EOF -} - -heading(){ - h=$1; shift - cat <$* -EOF -} - -table(){ - echo "" -} - -table_header(){ - echo "" -} - -end_table(){ - echo "
$*
" -} - -row(){ - echo "" -} - -end_row(){ - echo "" -} - -c_column(){ - cat <$* -EOF -} - -bold(){ - cat <$* -EOF -} - -column(){ - cat <$* -EOF -} - -para(){ - cat <

-EOF -} - -hr(){ - cat < -EOF -} - -img_column(){ - cat <
<$* height=100% width=100%>
-EOF -} - -# Check the direction of arrow. -# arrowDirection(){ $columnarray $sendnode$sendblock $recnode$recblock -arrowDirection(){ -if [ $2 = $3 ] -then - arrow=SELF - return; -else - for x in $1 - do - if [ $x = $2 ] - then - arrow=RIGHT - break - elif [ $x = $3 ] - then - arrow=LEFT - break - fi - done -fi -} - -drawImages(){ -for x in $columnarray -do - case $arrow in - SELF) - if [ $x = $sendnode$sendblock ] - then - img_column img SRC=\"self_line.JPG\" - else - img_column img SRC=\"empty.JPG\" - fi;; - - RIGHT) - if [ $x = $recnode$recblock ] - then - img_column img SRC=\"right_line.JPG\" - weHavePassedRec=1 - elif [ $x = $sendnode$sendblock ] - then - img_column img SRC=\"empty.JPG\" - weHavePassedSen=1 - elif [ $weHavePassedRec = 1 -o $weHavePassedSen = 0 ] - then - img_column img SRC=\"empty.JPG\" - elif [ $weHavePassedRec = 0 -a $weHavePassedSen = 1 ] - then - img_column img SRC=\"line.JPG\" - fi;; - - LEFT) - if [ $x = $recnode$recblock ] - then - img_column img SRC=\"empty.JPG\" - weHaveJustPassedRec=1 - weHavePassedRec=1 - continue - fi - if [ $x = $sendnode$sendblock -a $weHaveJustPassedRec = 1 ] - then - img_column img SRC=\"left_line.JPG\" - weHaveJustPassedRec=0 - weHavePassedSen=1 - continue - fi - if [ $x = $sendnode$sendblock ] - then - img_column img SRC=\"line.JPG\" - weHavePassedSen=1 - continue - fi - if [ $weHaveJustPassedRec = 1 ] - then - img_column img SRC=\"left_line.JPG\" - weHaveJustPassedRec=0 - continue - fi - if [ $weHavePassedSen = 1 -o $weHavePassedRec = 0 ] - then - img_column img SRC=\"empty.JPG\" - continue - fi - - if [ $weHavePassedRec = 1 -a $weHavePassedSen = 0 ] - then - img_column img SRC=\"line.JPG\" - continue - - fi - column ERROR;; - - *) - echo ERROR;; - esac -done -column $signal -} - -### Main -trace "Making HTML file" -( - header "Signal sequence diagram $report_date" - heading 1 "Signal sequence diagram $report_date" - - trace "Making list file" - #make a signal list file from the signal log file. - `awk -f /home/ndb/bin/signallog2html.lib/signallog2list.awk SIGNAL_ID=$signal_id BLOCK_ID=$block_name $signal_log_file > $signal_log_file.list` - - COLUMNS=`awk -f /home/ndb/bin/signallog2html.lib/uniq_blocks.awk $signal_log_file.list | wc -w` - - table "border=0 cellspacing=0 cellpadding=0 cols=`expr $COLUMNS + 1`" - - columnarray=`awk -f /home/ndb/bin/signallog2html.lib/uniq_blocks.awk $signal_log_file.list` - - row - column #make an empty first column! - for col in $columnarray - do - table_header $col - done - - grep "" $signal_log_file.list | \ - while read direction sendnode sendblock recnode recblock signal sigid recsigid delay - do - if [ $direction = "R" ] - then - row - weHavePassedRec=0 - weHavePassedSen=0 - weHaveJustPassedRec=0 - arrow="" - - # calculate the direction of the arrow. - arrowDirection "$columnarray" "$sendnode$sendblock" "$recnode$recblock" - - # Draw the arrow images. - drawImages - end_row - fi - done - end_table - - footer -) > $signal_log_file.html - -exit 0 diff --git a/storage/ndb/home/bin/stripcr b/storage/ndb/home/bin/stripcr deleted file mode 100755 index 540418f88cf..00000000000 --- a/storage/ndb/home/bin/stripcr +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/sh - - -# NAME -# stripcr - a program for removing carriage return chars from dos-files. -# -# SYNOPSIS -# stripcr [file...] -# -# DESCRIPTION -# stripcr deletes all CR characters from the given files. -# The files are edited in place. -# If no files are given, stdin and stdout are used instead. -# -# OPTIONS -# -s extension Make a copy of the original of each file, and -# give it the given extension (.bak, .orig, -bak, ...). -# -# EXAMPLES -# stripcr file.txt innerloop.cc -# stripcr -i.bak *.cc -# -# ENVIRONMENT -# NDB_PROJ_HOME Home dir for ndb -# -# FILES -# $NDB_PROJ_HOME/lib/funcs.sh Some userful functions for safe execution -# of commands, printing, and tracing. -# -# VERSION -# 1.0 -# -# AUTHOR -# Jonas Mls -# - - -progname=`basename $0` -synopsis="stripcr [-s extension] [file...]" - - -: ${NDB_PROJ_HOME:?} # If undefined, exit with error message - -: ${STRIPCR_OPTIONS:=--} # If undefined, set to --, to keep getopts happy. - # You may have to experiment, to get quoting right. - -. $NDB_PROJ_HOME/lib/funcs.sh - - -# defaults for options related variables -# -extension= -options="$STRIPCR_OPTIONS" - -# used if error when parsing the options environment variable -# -env_opterr="options environment variable: <<$options>>" - - - -# We want to be able to set options in an environment variable, -# as well as on the command line. In order not to have to repeat -# the same getopts information twice, we loop two times over the -# getopts while loop. The first time, we process options from -# the options environment variable, the second time we process -# options from the command line. -# -# The things to change are the actual options and what they do. -# -# -for optstring in "$options" "" # 1. options variable 2. cmd line -do - while getopts s: i $optstring # optstring empty => no arg => cmd line - do - case $i in - - s) extension="$OPTARG";; - \?) syndie $env_opterr;; # print synopsis and exit - - esac - done - - [ -n "$optstring" ] && OPTIND=1 # Reset for round 2, cmd line options - - env_opterr= # Round 2 should not use the value -done -shift `expr $OPTIND - 1` - - -safe perl -i$extension -lpe 'tr/\r//d' $* diff --git a/storage/ndb/home/lib/funcs.sh b/storage/ndb/home/lib/funcs.sh deleted file mode 100644 index b7d8914035e..00000000000 --- a/storage/ndb/home/lib/funcs.sh +++ /dev/null @@ -1,294 +0,0 @@ -# NAME -# safe, safe_eval, die, rawdie, syndie, msg, errmsg, -# rawmsg, rawerrmsg, trace, errtrace, is_wordmatch -# - functions for safe execution and convenient printing and tracing -# -# abspath - make a path absolute -# -# SYNOPSIS -# . funcs.sh -# -# is_wordmatch requires perl. -# -# DESCRIPTION -# Funcs.sh is a collection of somewhat related functions. -# The main categories and their respective functions are: -# Controlled execution - safe, safe_eval -# Exiting with a message - die, rawdie, syndie -# Printing messages - msg, errmsg, rawmsg, rawerrmsg -# Tracing - trace, errtrace -# Pattern matching - is_wordmatch -# -# -# ENVIRONMENT -# These variables are not exported, but they are still visible -# to, and used by, these functions. -# -# progname basename of $0 -# verbose empty or non-emtpy, used for tracing -# synopsis string describing the syntax of $progname -# -# VERSION -# 2.0 -# -# AUTHOR -# Jonas Mvlsd -# Jonas Oreland - added abspath - - - - - -# Safely executes the given command and exits -# with the given commands exit code if != 0, -# else the return value ("the functions exit -# code") is 0. Eg: safely cd $install_dir -# -safely () -{ - "$@" - safely_code__=$? - [ $safely_code__ -ne 0 ] && - { errmsg "Command failed: $@. Exit code: $safely_code__."; - exit $safely_code__; } - - : # return "exit code" 0 from function -} - - - - -# Safely_eval executes "eval command" and exits -# with the given commands exit code if != 0, -# else the return value (the functions "exit -# code") is 0. -# -# Safely_eval is just like like safely, but safely_eval does -# "eval command" instead of just "command" -# -# Safely_eval even works with pipes etc., but you have to quote -# the special characters. Eg: safely_eval ls \| wc \> tst.txt 2\>\&1 -# -# -safely_eval () -{ - eval "$@" - safely_eval_code__=$? - [ $safely_eval_code__ -ne 0 ] && - { errmsg "Command failed: $@. Exit code: $safely_eval_code__."; - exit $safely_eval_code__; } - - : # return "exit code" 0 from function -} - - - - - - -# -# safe and safe_eval are deprecated, use safely and safely_eval instead -# - -# Safe executes the given command and exits -# with the given commands exit code if != 0, -# else the return value ("the functions exit -# code") is 0. -# -safe () -{ - "$@" - safe_code__=$? - [ $safe_code__ -ne 0 ] && - { errmsg "Command failed: $@. Exit code: $safe_code__."; - exit $safe_code__; } - - : # return "exit code" 0 from function -} - - - - -# Safe_eval executes "eval command" and exits -# with the given commands exit code if != 0, -# else the return value (the functions "exit -# code") is 0. -# -# Safe_eval is just like like safe, but safe_eval does -# "eval command" instead of just "command" -# -# Safe_eval even works with pipes etc., but you have to quote -# the special characters. Eg: safe_eval ls \| wc \> tst.txt 2\>\&1 -# -# -safe_eval () -{ - eval "$@" - safe_eval_code__=$? - [ $safe_eval_code__ -ne 0 ] && - { errmsg "Command failed: $@. Exit code: $safe_eval_code__."; - exit $safe_eval_code__; } - - : # return "exit code" 0 from function -} - - - - - - -# die prints the supplied message to stderr, -# prefixed with the program name, and exits -# with the exit code given by "-e num" or -# 1, if no -e option is present. -# -die () -{ - die_code__=1 - [ "X$1" = X-e ] && { die_code__=$2; shift 2; } - [ "X$1" = X-- ] && shift - errmsg "$@" - exit $die_code__ -} - - - -# rawdie prints the supplied message to stderr. -# It then exits with the exit code given with "-e num" -# or 1, if no -e option is present. -# -rawdie () -{ - rawdie_code__=1 - [ "X$1" = X-e ] && { rawdie_code__=$2; shift 2; } - [ "X$1" = X-- ] && shift - rawerrmsg "$@" - exit $rawdie_code__ -} - - - - -# Syndie prints the supplied message (if present) to stderr, -# prefixed with the program name, on the first line. -# On the second line, it prints $synopsis. -# It then exits with the exit code given with "-e num" -# or 1, if no -e option is present. -# -syndie () -{ - syndie_code__=1 - [ "X$1" = X-e ] && { syndie_code__=$2; shift 2; } - [ "X$1" = X-- ] && shift - [ -n "$*" ] && msg "$*" - rawdie -e $syndie_code__ "Synopsis: $synopsis" -} - - - - -# msg prints the supplied message to stdout, -# prefixed with the program name. -# -msg () -{ - echo "${progname:-}:" "$@" -} - - - -# msg prints the supplied message to stderr, -# prefixed with the program name. -# -errmsg () -{ - echo "${progname:-}:" "$@" >&2 -} - - - -rawmsg () { echo "$*"; } # print the supplied message to stdout -rawerrmsg () { echo "$*" >&2; } # print the supplied message to stderr - - - -# trace prints the supplied message to stdout if verbose is non-null -# -trace () -{ - [ -n "$verbose" ] && msg "$@" -} - - -# errtrace prints the supplied message to stderr if verbose is non-null -# -errtrace () -{ - [ -n "$verbose" ] && msg "$@" >&2 -} - - - -# SYNTAX -# is_wordmatch candidatelist wordlist -# -# DESCRIPTION -# is_wordmatch returns true if any of the words (candidates) -# in candidatelist is present in wordlist, otherwise it -# returns false. -# -# EXAMPLES -# is_wordmatch "tuareg nixdorf low content" "xx yy zz low fgj turn roff sd" -# returns true, since "low" in candidatelist is present in wordlist. -# -# is_wordmatch "tuareg nixdorf low content" "xx yy zz slow fgj turn roff sd" -# returns false, since none of the words in candidatelist occurs in wordlist. -# -# is_wordmatch "tuareg nixdorf low content" "xx yy zz low fgj tuareg roff" -# returns true, since "low" and "tuareg" in candidatelist occurs in wordlist. -# -is_wordmatch () -{ - is_wordmatch_pattern__=`echo $1 | - sed 's/^/\\\\b/; - s/[ ][ ]*/\\\\b|\\\\b/g; - s/$/\\\\b/;'` - shift - echo "$*" | - perl -lne "m/$is_wordmatch_pattern__/ || exit 1" -} - -# -# abspath -# -# Stolen from http://oase-shareware.org/shell/shelltips/script_programmer.html -# -abspath() -{ - __abspath_D=`dirname "$1"` - __abspath_B=`basename "$1"` - echo "`cd \"$__abspath_D\" 2>/dev/null && pwd || echo \"$__abspath_D\"`/$__abspath_B" -} - -# -# -# NdbExit -# -# -NdbExit() -{ - echo "NdbExit: $1" - exit $1 -} - -NdbGetExitCode() -{ - __res__=`echo $* | awk '{if($1=="NdbExit:") print $2;}'` - if [ -n $__res__ ] - then - echo $__res__ - else - echo 255 - fi -} - diff --git a/storage/ndb/include/kernel/signaldata/DropFilegroup.hpp b/storage/ndb/include/kernel/signaldata/DropFilegroup.hpp index 7cf275b1f9e..c1dbc95380c 100644 --- a/storage/ndb/include/kernel/signaldata/DropFilegroup.hpp +++ b/storage/ndb/include/kernel/signaldata/DropFilegroup.hpp @@ -150,6 +150,7 @@ struct DropFileRef { enum ErrorCode { NoError = 0, Busy = 701, + NotMaster = 702, NoSuchFile = 766, DropUndoFileNotSupported = 769, InvalidSchemaObjectVersion = 774 diff --git a/storage/ndb/include/util/ndb_opts.h b/storage/ndb/include/util/ndb_opts.h index 787c32f06fd..08ab4a2e9df 100644 --- a/storage/ndb/include/util/ndb_opts.h +++ b/storage/ndb/include/util/ndb_opts.h @@ -84,7 +84,10 @@ const char *opt_debug= 0; 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ { "core-file", OPT_WANT_CORE, "Write core on errors.",\ (gptr*) &opt_core, (gptr*) &opt_core, 0,\ - GET_BOOL, NO_ARG, OPT_WANT_CORE_DEFAULT, 0, 0, 0, 0, 0} + GET_BOOL, NO_ARG, OPT_WANT_CORE_DEFAULT, 0, 0, 0, 0, 0},\ + {"character-sets-dir", OPT_CHARSETS_DIR,\ + "Directory where character sets are.", (gptr*) &charsets_dir,\ + (gptr*) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}\ #ifndef DBUG_OFF #define NDB_STD_OPTS(prog_name) \ @@ -111,6 +114,7 @@ enum ndb_std_options { OPT_WANT_CORE, OPT_NDB_MGMD, OPT_NDB_NODEID, + OPT_CHARSETS_DIR, NDB_STD_OPTIONS_LAST /* should always be last in this enum */ }; diff --git a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index 87bd1d7c53b..57aa9890f24 100644 --- a/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -13396,6 +13396,24 @@ Dbdict::execCREATE_FILE_REQ(Signal* signal){ Uint32 requestInfo = req->requestInfo; do { + if(getOwnNodeId() != c_masterNodeId){ + jam(); + ref->errorCode = CreateFileRef::NotMaster; + ref->status = 0; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + + if (c_blockState != BS_IDLE){ + jam(); + ref->errorCode = CreateFileRef::Busy; + ref->status = 0; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + Ptr trans_ptr; if (! c_Trans.seize(trans_ptr)){ ref->errorCode = CreateFileRef::Busy; @@ -13455,6 +13473,9 @@ Dbdict::execCREATE_FILE_REQ(Signal* signal){ tmp.init(rg, GSN_CREATE_OBJ_REF, trans_key); sendSignal(rg, GSN_CREATE_OBJ_REQ, signal, CreateObjReq::SignalLength, JBB); + + c_blockState = BS_CREATE_TAB; + return; } while(0); @@ -13480,15 +13501,6 @@ Dbdict::execCREATE_FILEGROUP_REQ(Signal* signal){ Uint32 type = req->objType; do { - Ptr trans_ptr; - if (! c_Trans.seize(trans_ptr)){ - ref->errorCode = CreateFilegroupRef::Busy; - ref->status = 0; - ref->errorKey = 0; - ref->errorLine = __LINE__; - break; - } - if(getOwnNodeId() != c_masterNodeId){ jam(); ref->errorCode = CreateFilegroupRef::NotMaster; @@ -13506,6 +13518,15 @@ Dbdict::execCREATE_FILEGROUP_REQ(Signal* signal){ ref->errorLine = __LINE__; break; } + + Ptr trans_ptr; + if (! c_Trans.seize(trans_ptr)){ + ref->errorCode = CreateFilegroupRef::Busy; + ref->status = 0; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } const Uint32 trans_key = ++c_opRecordSequence; trans_ptr.p->key = trans_key; @@ -13554,6 +13575,9 @@ Dbdict::execCREATE_FILEGROUP_REQ(Signal* signal){ tmp.init(rg, GSN_CREATE_OBJ_REF, trans_key); sendSignal(rg, GSN_CREATE_OBJ_REQ, signal, CreateObjReq::SignalLength, JBB); + + c_blockState = BS_CREATE_TAB; + return; } while(0); @@ -13581,6 +13605,22 @@ Dbdict::execDROP_FILE_REQ(Signal* signal) Uint32 version = req->file_version; do { + if(getOwnNodeId() != c_masterNodeId){ + jam(); + ref->errorCode = DropFileRef::NotMaster; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + + if (c_blockState != BS_IDLE){ + jam(); + ref->errorCode = DropFileRef::Busy; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + Ptr file_ptr; if (!c_file_hash.find(file_ptr, objId)) { @@ -13636,6 +13676,9 @@ Dbdict::execDROP_FILE_REQ(Signal* signal) tmp.init(rg, GSN_DROP_OBJ_REF, trans_key); sendSignal(rg, GSN_DROP_OBJ_REQ, signal, DropObjReq::SignalLength, JBB); + + c_blockState = BS_CREATE_TAB; + return; } while(0); @@ -13663,6 +13706,22 @@ Dbdict::execDROP_FILEGROUP_REQ(Signal* signal) Uint32 version = req->filegroup_version; do { + if(getOwnNodeId() != c_masterNodeId){ + jam(); + ref->errorCode = DropFilegroupRef::NotMaster; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + + if (c_blockState != BS_IDLE){ + jam(); + ref->errorCode = DropFilegroupRef::Busy; + ref->errorKey = 0; + ref->errorLine = __LINE__; + break; + } + Ptr filegroup_ptr; if (!c_filegroup_hash.find(filegroup_ptr, objId)) { @@ -13718,6 +13777,9 @@ Dbdict::execDROP_FILEGROUP_REQ(Signal* signal) tmp.init(rg, GSN_DROP_OBJ_REF, trans_key); sendSignal(rg, GSN_DROP_OBJ_REQ, signal, DropObjReq::SignalLength, JBB); + + c_blockState = BS_CREATE_TAB; + return; } while(0); @@ -13892,6 +13954,7 @@ Dbdict::trans_commit_complete_done(Signal* signal, //@todo check api failed sendSignal(trans_ptr.p->m_senderRef, GSN_CREATE_FILEGROUP_CONF, signal, CreateFilegroupConf::SignalLength, JBB); + break; } case GSN_CREATE_FILE_REQ:{ @@ -13935,6 +13998,7 @@ Dbdict::trans_commit_complete_done(Signal* signal, } c_Trans.release(trans_ptr); + ndbrequire(c_blockState == BS_CREATE_TAB); c_blockState = BS_IDLE; return; } @@ -14047,6 +14111,7 @@ Dbdict::trans_abort_complete_done(Signal* signal, } c_Trans.release(trans_ptr); + ndbrequire(c_blockState == BS_CREATE_TAB); c_blockState = BS_IDLE; return; } diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp index 4e507d1b690..273ccb9e1e6 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp @@ -170,7 +170,6 @@ void Dbtup::execTUP_ABORTREQ(Signal* signal) /** * Aborting last operation that performed ALLOC */ - ndbout_c("clearing ALLOC"); tuple_ptr->m_header_bits &= ~(Uint32)Tuple_header::ALLOC; tuple_ptr->m_header_bits |= Tuple_header::FREED; } diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp index 782679eac18..fc3419e694a 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp @@ -473,13 +473,16 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) ptrCheckGuard(regTabPtr, no_of_tablerec, tablerec); PagePtr page; - Tuple_header* tuple_ptr= 0; + Tuple_header* tuple_ptr= (Tuple_header*) + get_ptr(&page, ®OperPtr.p->m_tuple_location, regTabPtr.p); + + bool get_page = false; if(regOperPtr.p->op_struct.m_load_diskpage_on_commit) { + Page_cache_client::Request req; ndbassert(regOperPtr.p->is_first_operation() && regOperPtr.p->is_last_operation()); - Page_cache_client::Request req; /** * Check for page */ @@ -490,15 +493,33 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) memcpy(&req.m_page, tmp->get_disk_ref_ptr(regTabPtr.p), sizeof(Local_key)); + + if (unlikely(regOperPtr.p->op_struct.op_type == ZDELETE && + tmp->m_header_bits & Tuple_header::DISK_ALLOC)) + { + jam(); + /** + * Insert+Delete + */ + regOperPtr.p->op_struct.m_load_diskpage_on_commit = 0; + regOperPtr.p->op_struct.m_wait_log_buffer = 0; + disk_page_abort_prealloc(signal, regFragPtr.p, + &req.m_page, req.m_page.m_page_idx); + + c_lgman->free_log_space(regFragPtr.p->m_logfile_group_id, + regOperPtr.p->m_undo_buffer_space); + ndbout_c("insert+delete"); + goto skip_disk; + } } else { // initial delete ndbassert(regOperPtr.p->op_struct.op_type == ZDELETE); - tuple_ptr= (Tuple_header*) - get_ptr(&page, ®OperPtr.p->m_tuple_location, regTabPtr.p); memcpy(&req.m_page, tuple_ptr->get_disk_ref_ptr(regTabPtr.p), sizeof(Local_key)); + + ndbassert(tuple_ptr->m_header_bits & Tuple_header::DISK_PART); } req.m_callback.m_callbackData= regOperPtr.i; req.m_callback.m_callbackFunction = @@ -522,6 +543,7 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) ndbrequire("NOT YET IMPLEMENTED" == 0); break; } + get_page = true; disk_page_set_dirty(*(Ptr*)&m_pgman.m_ptr); regOperPtr.p->m_commit_disk_callback_page= res; regOperPtr.p->op_struct.m_load_diskpage_on_commit= 0; @@ -555,6 +577,7 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) tuple_ptr = (Tuple_header*) get_ptr(&page, ®OperPtr.p->m_tuple_location,regTabPtr.p); } +skip_disk: req_struct.m_tuple_ptr = tuple_ptr; if(get_tuple_state(regOperPtr.p) == TUPLE_PREPARED) @@ -599,6 +622,8 @@ void Dbtup::execTUP_COMMITREQ(Signal* signal) else { removeActiveOpList(regOperPtr.p, tuple_ptr); + if (get_page) + ndbassert(tuple_ptr->m_header_bits & Tuple_header::DISK_PART); dealloc_tuple(signal, gci, page.p, tuple_ptr, regOperPtr.p, regFragPtr.p, regTabPtr.p); } diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp index d74e4b6811e..ec3231f55f5 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp @@ -1053,6 +1053,7 @@ Dbtup::disk_page_abort_prealloc_callback(Signal* signal, Ptr fragPtr; getFragmentrec(fragPtr, pagePtr.p->m_fragment_id, tabPtr.p); + disk_page_set_dirty(pagePtr); disk_page_abort_prealloc_callback_1(signal, fragPtr.p, pagePtr, sz); } @@ -1074,6 +1075,13 @@ Dbtup::disk_page_abort_prealloc_callback_1(Signal* signal, ddassert(alloc.calc_page_free_bits(free - used) == old_idx); Uint32 new_idx = alloc.calc_page_free_bits(free - used + sz); +#ifdef VM_TRACE + Local_key key; + key.m_page_no = pagePtr.p->m_page_no; + key.m_file_no = pagePtr.p->m_file_no; + ndbout << "disk_page_abort_prealloc_callback_1" << key << endl; +#endif + Ptr extentPtr; c_extent_pool.getPtr(extentPtr, ext); if (old_idx != new_idx) diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index 7305827b6ac..ff917c8482d 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -1382,8 +1382,9 @@ int Dbtup::handleInsertReq(Signal* signal, regOperPtr.p->userpointer, ®OperPtr.p->m_tuple_location); - ((Tuple_header*)ptr)->m_operation_ptr_i= regOperPtr.i; - ((Tuple_header*)ptr)->m_header_bits= Tuple_header::ALLOC | + base = (Tuple_header*)ptr; + base->m_operation_ptr_i= regOperPtr.i; + base->m_header_bits= Tuple_header::ALLOC | (varsize ? Tuple_header::CHAINED_ROW : 0); regOperPtr.p->m_tuple_location.m_page_no = real_page_id; } @@ -1407,6 +1408,8 @@ int Dbtup::handleInsertReq(Signal* signal, } req_struct->m_use_rowid = false; base->m_header_bits &= ~(Uint32)Tuple_header::FREE; + base->m_header_bits |= Tuple_header::ALLOC & + (regOperPtr.p->is_first_operation() ? ~0 : 1); } else { @@ -1415,6 +1418,8 @@ int Dbtup::handleInsertReq(Signal* signal, { ndbout_c("no mem insert but rowid (same)"); base->m_header_bits &= ~(Uint32)Tuple_header::FREE; + base->m_header_bits |= Tuple_header::ALLOC & + (regOperPtr.p->is_first_operation() ? ~0 : 1); } else { @@ -1467,7 +1472,7 @@ int Dbtup::handleInsertReq(Signal* signal, size_change_error: jam(); terrorCode = ZMEM_NOMEM_ERROR; - goto disk_prealloc_error; + goto exit_error; undo_buffer_error: jam(); @@ -1501,9 +1506,13 @@ update_error: regOperPtr.p->op_struct.in_active_list = false; regOperPtr.p->m_tuple_location.setNull(); } -disk_prealloc_error: +exit_error: tupkeyErrorLab(signal); return -1; + +disk_prealloc_error: + base->m_header_bits |= Tuple_header::FREED; + goto exit_error; } /* ---------------------------------------------------------------- */ diff --git a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp index c7ef439e193..4808d22b9e0 100644 --- a/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -4410,7 +4410,7 @@ NdbDictInterface::create_file(const NdbFileImpl & file, ptr[0].p = (Uint32*)m_buffer.get_data(); ptr[0].sz = m_buffer.length() / 4; - int err[] = { CreateFileRef::Busy, 0}; + int err[] = { CreateFileRef::Busy, CreateFileRef::NotMaster, 0}; /* Send signal without time-out since creating files can take a very long time if the file is very big. @@ -4454,7 +4454,7 @@ NdbDictInterface::drop_file(const NdbFileImpl & file){ req->file_id = file.m_id; req->file_version = file.m_version; - int err[] = { DropFileRef::Busy, 0}; + int err[] = { DropFileRef::Busy, DropFileRef::NotMaster, 0}; DBUG_RETURN(dictSignal(&tSignal, 0, 0, 0, // master WAIT_CREATE_INDX_REQ, diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp index 25fc62937c4..36037fba9ed 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -46,7 +46,7 @@ #include extern EventLogger g_eventLogger; -static Gci_container g_empty_gci_container; +static Gci_container_pod g_empty_gci_container; static const Uint32 ACTIVE_GCI_DIRECTORY_SIZE = 4; static const Uint32 ACTIVE_GCI_MASK = ACTIVE_GCI_DIRECTORY_SIZE - 1; @@ -1223,12 +1223,22 @@ operator<<(NdbOut& out, const Gci_container& gci) return out; } +static +NdbOut& +operator<<(NdbOut& out, const Gci_container_pod& gci) +{ + Gci_container* ptr = (Gci_container*)&gci; + out << *ptr; + return out; +} + + static Gci_container* -find_bucket_chained(Vector * active, Uint64 gci) +find_bucket_chained(Vector * active, Uint64 gci) { Uint32 pos = (gci & ACTIVE_GCI_MASK); - Gci_container *bucket= active->getBase() + pos; + Gci_container *bucket= ((Gci_container*)active->getBase()) + pos; if(gci > bucket->m_gci) { @@ -1237,8 +1247,9 @@ find_bucket_chained(Vector * active, Uint64 gci) do { active->fill(move_pos, g_empty_gci_container); - bucket = active->getBase() + pos; // Needs to recomputed after fill - move = active->getBase() + move_pos; + // Needs to recomputed after fill + bucket = ((Gci_container*)active->getBase()) + pos; + move = ((Gci_container*)active->getBase()) + move_pos; if(move->m_gcp_complete_rep_count == 0) { memcpy(move, bucket, sizeof(Gci_container)); @@ -1269,10 +1280,10 @@ find_bucket_chained(Vector * active, Uint64 gci) inline Gci_container* -find_bucket(Vector * active, Uint64 gci) +find_bucket(Vector * active, Uint64 gci) { Uint32 pos = (gci & ACTIVE_GCI_MASK); - Gci_container *bucket= active->getBase() + pos; + Gci_container *bucket= ((Gci_container*)active->getBase()) + pos; if(likely(gci == bucket->m_gci)) return bucket; @@ -1370,7 +1381,8 @@ NdbEventBuffer::execSUB_GCP_COMPLETE_REP(const SubGcpCompleteRep * const rep) { /** out of order something */ ndbout_c("out of order bucket: %d gci: %lld m_latestGCI: %lld", - bucket-m_active_gci.getBase(), gci, m_latestGCI); + bucket-(Gci_container*)m_active_gci.getBase(), + gci, m_latestGCI); bucket->m_state = Gci_container::GC_COMPLETE; bucket->m_gcp_complete_rep_count = 1; // Prevent from being reused m_latest_complete_GCI = gci; @@ -1387,7 +1399,7 @@ NdbEventBuffer::complete_outof_order_gcis() Uint64 stop_gci = m_latest_complete_GCI; const Uint32 size = m_active_gci.size(); - Gci_container* array= m_active_gci.getBase(); + Gci_container* array= (Gci_container*)m_active_gci.getBase(); ndbout_c("complete_outof_order_gcis"); for(Uint32 i = 0; i; +template class Vector; template class Vector; diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp index bffc2174be5..8d413cc8d14 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp @@ -272,6 +272,11 @@ struct Gci_container EventBufData_hash m_data_hash; }; +struct Gci_container_pod +{ + char data[sizeof(Gci_container)]; +}; + class NdbEventOperationImpl : public NdbEventOperation { public: NdbEventOperationImpl(NdbEventOperation &f, @@ -365,7 +370,7 @@ public: ~NdbEventBuffer(); const Uint32 &m_system_nodes; - Vector m_active_gci; + Vector m_active_gci; NdbEventOperation *createEventOperation(const char* eventName, NdbError &); NdbEventOperationImpl *createEventOperation(NdbEventImpl& evnt, diff --git a/storage/ndb/test/ndbapi/bank/Bank.cpp b/storage/ndb/test/ndbapi/bank/Bank.cpp index 5ef01533e07..80edbef7e74 100644 --- a/storage/ndb/test/ndbapi/bank/Bank.cpp +++ b/storage/ndb/test/ndbapi/bank/Bank.cpp @@ -22,7 +22,8 @@ Bank::Bank(Ndb_cluster_connection& con, bool _init, const char * dbase): m_ndb(&con, dbase), m_maxAccount(-1), - m_initialized(false) + m_initialized(false), + m_skip_create(false) { if(_init) init(); diff --git a/storage/ndb/test/ndbapi/bank/Bank.hpp b/storage/ndb/test/ndbapi/bank/Bank.hpp index 60ec7745b59..494f39930eb 100644 --- a/storage/ndb/test/ndbapi/bank/Bank.hpp +++ b/storage/ndb/test/ndbapi/bank/Bank.hpp @@ -29,6 +29,7 @@ public: Bank(Ndb_cluster_connection&, bool init = true, const char *dbase="BANK"); + int setSkipCreate(bool skip) { m_skip_create = skip; } int createAndLoadBank(bool overWrite, bool disk= false, int num_accounts=10); int dropBank(); @@ -140,6 +141,7 @@ private: Ndb m_ndb; int m_maxAccount; bool m_initialized; + bool m_skip_create; }; #endif diff --git a/storage/ndb/test/ndbapi/bank/BankLoad.cpp b/storage/ndb/test/ndbapi/bank/BankLoad.cpp index 45d6a860a3d..5a81a4d2498 100644 --- a/storage/ndb/test/ndbapi/bank/BankLoad.cpp +++ b/storage/ndb/test/ndbapi/bank/BankLoad.cpp @@ -58,7 +58,7 @@ int Bank::createAndLoadBank(bool ovrWrt, bool disk, int num_accounts){ m_ndb.init(); if (m_ndb.waitUntilReady() != 0) return NDBT_FAILED; - + const NdbDictionary::Table* pSysValTab = m_ndb.getDictionary()->getTable("SYSTEM_VALUES"); if (pSysValTab != NULL){ @@ -69,7 +69,7 @@ int Bank::createAndLoadBank(bool ovrWrt, bool disk, int num_accounts){ } } - if (createTables(disk) != NDBT_OK) + if (!m_skip_create && createTables(disk) != NDBT_OK) return NDBT_FAILED; if (clearTables() != NDBT_OK) diff --git a/storage/ndb/test/ndbapi/bank/bankCreator.cpp b/storage/ndb/test/ndbapi/bank/bankCreator.cpp index 39e4920867f..30c024d799c 100644 --- a/storage/ndb/test/ndbapi/bank/bankCreator.cpp +++ b/storage/ndb/test/ndbapi/bank/bankCreator.cpp @@ -31,10 +31,12 @@ int main(int argc, const char** argv){ int _help = 0; char * _database = "BANK"; int disk = 0; + int skip_create = 0; struct getargs args[] = { { "database", 'd', arg_string, &_database, "Database name", ""}, { "disk", 0, arg_flag, &disk, "Use disk tables", "" }, + { "skip-create", 0, arg_flag, &skip_create, "Skip create", "" }, { "usage", '?', arg_flag, &_help, "Print help", "" } }; int num_args = sizeof(args) / sizeof(args[0]); @@ -55,6 +57,7 @@ int main(int argc, const char** argv){ Bank bank(con,_database); int overWriteExisting = true; + bank.setSkipCreate(skip_create); if (bank.createAndLoadBank(overWriteExisting, disk) != NDBT_OK) return NDBT_ProgramExit(NDBT_FAILED); return NDBT_ProgramExit(NDBT_OK); diff --git a/storage/ndb/test/ndbapi/testBasic.cpp b/storage/ndb/test/ndbapi/testBasic.cpp index 879a4979220..69f3d8daef6 100644 --- a/storage/ndb/test/ndbapi/testBasic.cpp +++ b/storage/ndb/test/ndbapi/testBasic.cpp @@ -1034,6 +1034,38 @@ runMassiveRollback2(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int +runMassiveRollback3(NDBT_Context* ctx, NDBT_Step* step){ + + int result = NDBT_OK; + HugoOperations hugoOps(*ctx->getTab()); + Ndb* pNdb = GETNDB(step); + + const Uint32 BATCH = 10; + const Uint32 OPS_TOTAL = 20; + const Uint32 LOOPS = 100; + + for(Uint32 loop = 0; loop> 2) - 1); - LogE * logE= 0; - Uint32 len= ~0; const Uint32 stopGCP = m_metaData.getStopGCP(); - NdbAutoPtr ap1; + Uint32 tableId; + Uint32 triggerEvent; + Uint32 frag_id; + Uint32 *attr_data; + Uint32 attr_data_len; do { + Uint32 len; + Uint32 *logEntryPtr; if (buffer_read_ahead(&len, sizeof(Uint32), 1) != 1){ res= -1; return 0; @@ -977,7 +977,7 @@ RestoreLogIterator::getNextLogEntry(int & res) { len= ntohl(len); Uint32 data_len = sizeof(Uint32) + len*4; - if (buffer_get_ptr((void **)(&logE), 1, data_len) != data_len) { + if (buffer_get_ptr((void **)(&logEntryPtr), 1, data_len) != data_len) { res= -2; return 0; } @@ -986,7 +986,8 @@ RestoreLogIterator::getNextLogEntry(int & res) { res= 0; return 0; } - if (m_metaData.getFileHeader().NdbVersion < NDBD_FRAGID_VERSION) + + if (unlikely(m_metaData.getFileHeader().NdbVersion < NDBD_FRAGID_VERSION)) { /* FragId was introduced in LogEntry in version @@ -994,48 +995,38 @@ RestoreLogIterator::getNextLogEntry(int & res) { We set FragId to 0 in older versions (these versions do not support restore of user defined partitioned tables. - - These log entries miss one Uint32 FragId, hence missing_len=1 - - Reconstruct a new log entry with old. */ - const Uint32 missing_len= 1; - assert((offsetof(LogE, Data) - offsetof(LogE_no_fragid, Data)) >> 2 == - missing_len); - LogE_no_fragid * logE_no_fragid= (LogE_no_fragid *)logE; - - int i; - LogE *tmpLogE= (LogE*)NdbMem_Allocate(data_len + missing_len*4); - if (!tmpLogE) - { - res = -2; - return 0; - } - ap1.reset((char*)tmpLogE); - bzero(tmpLogE, data_len + missing_len*4); - /* correct len to reflect new logEntry version length */ - len+= missing_len; - tmpLogE->Length = logE_no_fragid->Length; - tmpLogE->TableId = logE_no_fragid->TableId; - tmpLogE->TriggerEvent = logE_no_fragid->TriggerEvent; - for (i = 0; i < len - offset; i++) - tmpLogE->Data[i] = logE_no_fragid->Data[i]; - logE= tmpLogE; + typedef BackupFormat::LogFile::LogEntry_no_fragid LogE_no_fragid; + LogE_no_fragid * logE_no_fragid= (LogE_no_fragid *)logEntryPtr; + tableId= ntohl(logE_no_fragid->TableId); + triggerEvent= ntohl(logE_no_fragid->TriggerEvent); + frag_id= 0; + attr_data= &logE_no_fragid->Data[0]; + attr_data_len= len - ((offsetof(LogE_no_fragid, Data) >> 2) - 1); + } + else /* normal case */ + { + typedef BackupFormat::LogFile::LogEntry LogE; + LogE * logE= (LogE *)logEntryPtr; + tableId= ntohl(logE->TableId); + triggerEvent= ntohl(logE->TriggerEvent); + frag_id= ntohl(logE->FragId); + attr_data= &logE->Data[0]; + attr_data_len= len - ((offsetof(LogE, Data) >> 2) - 1); } - logE->TableId= ntohl(logE->TableId); - logE->TriggerEvent= ntohl(logE->TriggerEvent); - - const bool hasGcp= (logE->TriggerEvent & 0x10000) != 0; - logE->TriggerEvent &= 0xFFFF; + const bool hasGcp= (triggerEvent & 0x10000) != 0; + triggerEvent &= 0xFFFF; + if(hasGcp){ - len--; - m_last_gci = ntohl(logE->Data[len-offset]); + // last attr_data is gci info + attr_data_len--; + m_last_gci = ntohl(*(attr_data + attr_data_len)); } } while(m_last_gci > stopGCP + 1); - - m_logEntry.m_table = m_metaData.getTable(logE->TableId); - switch(logE->TriggerEvent){ + + m_logEntry.m_table = m_metaData.getTable(tableId); + switch(triggerEvent){ case TriggerEvent::TE_INSERT: m_logEntry.m_type = LogEntry::LE_INSERT; break; @@ -1053,10 +1044,10 @@ RestoreLogIterator::getNextLogEntry(int & res) { const TableS * tab = m_logEntry.m_table; m_logEntry.clear(); - AttributeHeader * ah = (AttributeHeader *)&logE->Data[0]; - AttributeHeader *end = (AttributeHeader *)&logE->Data[len - offset]; + AttributeHeader * ah = (AttributeHeader *)attr_data; + AttributeHeader *end = (AttributeHeader *)(attr_data + attr_data_len); AttributeS * attr; - m_logEntry.m_frag_id = ntohl(logE->FragId); + m_logEntry.m_frag_id = frag_id; while(ah < end){ attr= m_logEntry.add_attr(); if(attr == NULL) { @@ -1065,6 +1056,9 @@ RestoreLogIterator::getNextLogEntry(int & res) { return 0; } + if(unlikely(!m_hostByteOrder)) + *(Uint32*)ah = Twiddle32(*(Uint32*)ah); + attr->Desc = (* tab)[ah->getAttributeId()]; assert(attr->Desc != 0);