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;
- $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<
-
- where
- is cvsdoxy module to doxgenify
- is title of report
- 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 () {
- 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 ()
-{
- 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 ()
-{
- 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< \$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 ] [ -r ]
-#
-# 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 ] [ -r ]"
-
-: ${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 <> $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 ] [ -s ] -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 ] [ -s ] -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
-}
-
-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);