summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin H. Johnson <robbat2@gentoo.org>2005-09-05 20:11:43 +0000
committerRobin H. Johnson <robbat2@gentoo.org>2005-09-05 20:11:43 +0000
commitfbfb494a3860b810caff74535280a9ffb614fb1a (patch)
treedf02916d0a86cd360027c907658a3465c3d3fe0e
downloadmysql-extras-fbfb494a3860b810caff74535280a9ffb614fb1a.tar.gz
mysql-extras-fbfb494a3860b810caff74535280a9ffb614fb1a.tar.bz2
mysql-extras-fbfb494a3860b810caff74535280a9ffb614fb1a.zip
Imported from /home/gentoo/distfiles/mysql-extras-20050904.tar.bz2.mysql-extras-20050904
-rw-r--r--005_all_tmp-5.1.patch11
-rw-r--r--010_all_my-print-defaults-r0.patch15
-rw-r--r--010_all_my-print-defaults-r1.patch29
-rw-r--r--010_all_my-print-defaults-r2.patch42
-rw-r--r--020_all_gentoo-nptl.patch18
-rw-r--r--030_all_thrssl-r0.patch17
-rw-r--r--030_all_thrssl-r1.patch28
-rw-r--r--035_x86_asm-pic-fixes-r0.patch99
-rw-r--r--035_x86_asm-pic-fixes-r1.patch159
-rw-r--r--035_x86_asm-pic-fixes-r2.patch343
-rw-r--r--035_x86_asm-pic-fixes-r3.patch365
-rw-r--r--035_x86_asm-pic-fixes-r4.patch365
-rw-r--r--035_x86_asm-pic-fixes-r6.patch333
-rw-r--r--035_x86_asm-pic-fixes-r7.patch32
-rw-r--r--040_all_tcpd-vars-fix-r1.patch14
-rw-r--r--040_all_tcpd-vars-fix.patch14
-rw-r--r--050_all_mysql-create_system_tables.patch12
-rw-r--r--060_all_myxml_by_Alexander_Barkov.patch6170
-rw-r--r--070_all_make-test.patch14
-rw-r--r--701_all_test-myisam-geometry.patch26
-rw-r--r--703_all_test-rpl_rotate_logs.patch18
-rw-r--r--705_all_view_geometry.patch71
22 files changed, 8195 insertions, 0 deletions
diff --git a/005_all_tmp-5.1.patch b/005_all_tmp-5.1.patch
new file mode 100644
index 0000000..6694c55
--- /dev/null
+++ b/005_all_tmp-5.1.patch
@@ -0,0 +1,11 @@
+###MY_VER_RANGE [5.1.0_alpha,mysql-5.1.0_alpha20050606)
+--- mysql-5.1.0-alpha-nightly-20050531/sql/Makefile.am 2005-05-31 08:39:53.000000000 +0200
++++ mysql-5.1.0-bitvector/sql/Makefile.am 2005-06-02 13:15:49.000000000 +0200
+@@ -91,7 +91,6 @@
+ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
+ slave.cc sql_repl.cc rpl_filter.cc \
+ sql_union.cc sql_derived.cc \
+- bitvector.cc \
+ client.c sql_client.cc mini_client_errors.c pack.c\
+ stacktrace.c repl_failsafe.h repl_failsafe.cc \
+ sql_olap.cc sql_view.cc \
diff --git a/010_all_my-print-defaults-r0.patch b/010_all_my-print-defaults-r0.patch
new file mode 100644
index 0000000..890f3f8
--- /dev/null
+++ b/010_all_my-print-defaults-r0.patch
@@ -0,0 +1,15 @@
+###MY_VER_RANGE [4.0_alpha,5.0_alpha) [5.0_alpha,5.0.5_beta)
+
+# for correct hardcoded sysconf directory
+
+--- mysql-4.1.8/mysys/default.c 2004-12-14 13:40:36.000000000 +0100
++++ bbb/mysys/default.c 2005-01-09 17:57:00.407231408 +0100
+@@ -48,7 +48,7 @@
+ #elif defined(__NETWARE__)
+ "sys:/etc/",
+ #else
+-"/etc/",
++"/etc/mysql/",
+ #endif
+ #ifdef DATADIR
+ DATADIR,
diff --git a/010_all_my-print-defaults-r1.patch b/010_all_my-print-defaults-r1.patch
new file mode 100644
index 0000000..831e6c8
--- /dev/null
+++ b/010_all_my-print-defaults-r1.patch
@@ -0,0 +1,29 @@
+###MY_VER_RANGE [5.0.5_beta,5.0.6_beta)
++++ mysql/mysys/default.c 2005-05-09 14:29:29.783506560 +0200
+@@ -844,25 +844,8 @@
+ {
+ const char *env, **ptr= default_directories;
+
+-#ifdef __WIN__
+- *ptr++= "C:/";
++ *ptr++= "/etc/mysql/";
+
+- if (GetWindowsDirectory(system_dir,sizeof(system_dir)))
+- *ptr++= &system_dir;
+- /* Only add shared system directory if different from default. */
+- if (GetSystemWindowsDirectory(shared_system_dir,sizeof(shared_system_dir)) &&
+- strcmp(system_dir, shared_system_dir))
+- *ptr++= &shared_system_dir;
+-
+-#elif defined(__NETWARE__)
+- *ptr++= "sys:/etc/";
+-#else
+-#if defined(__EMX__) || defined(OS2)
+- if ((env= getenv("ETC")))
+- *ptr++= env;
+-#endif
+- *ptr++= "/etc/";
+-#endif
+ if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV))))
+ *ptr++= env;
+ *ptr++= ""; /* Place for defaults_extra_file */
diff --git a/010_all_my-print-defaults-r2.patch b/010_all_my-print-defaults-r2.patch
new file mode 100644
index 0000000..656930d
--- /dev/null
+++ b/010_all_my-print-defaults-r2.patch
@@ -0,0 +1,42 @@
+###MY_VER_RANGE [5.0.6_beta,)
+--- mysql.old/mysys/default.c 2005-05-22 02:35:25.000000000 +0200
++++ mysql/mysys/default.c 2005-05-22 02:36:17.000000000 +0200
+@@ -823,19 +823,19 @@
+ 5. ""
+
+ On Novell NetWare, this is:
+- 1. sys:/etc/
++ 1. sys:/etc/mysql/
+ 2. getenv(DEFAULT_HOME_ENV)
+ 3. ""
+
+ On OS/2, this is:
+ 1. getenv(ETC)
+- 2. /etc/
++ 2. /etc/mysql/
+ 3. getenv(DEFAULT_HOME_ENV)
+ 4. ""
+ 5. "~/"
+
+ Everywhere else, this is:
+- 1. /etc/
++ 1. /etc/mysql/
+ 2. getenv(DEFAULT_HOME_ENV)
+ 3. ""
+ 4. "~/"
+@@ -860,13 +860,13 @@
+ #endif
+
+ #elif defined(__NETWARE__)
+- *ptr++= "sys:/etc/";
++ *ptr++= "sys:/etc/mysql/";
+ #else
+ #if defined(__EMX__) || defined(OS2)
+ if ((env= getenv("ETC")))
+ *ptr++= env;
+ #endif
+- *ptr++= "/etc/";
++ *ptr++= "/etc/mysql/";
+ #endif
+ if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV))))
+ *ptr++= env;
diff --git a/020_all_gentoo-nptl.patch b/020_all_gentoo-nptl.patch
new file mode 100644
index 0000000..6432d9a
--- /dev/null
+++ b/020_all_gentoo-nptl.patch
@@ -0,0 +1,18 @@
+###MY_VER_RANGE [4.0.18,4.1.12) [5.0.0_alpha,5.0.4_beta)
+
+# NPTL support
+
+--- mysql-4.1.8/configure.in 2004-12-14 13:40:38.000000000 +0100
++++ bbb/configure.in 2005-01-09 17:57:57.451559352 +0100
+@@ -1269,7 +1269,10 @@
+ then
+ # Look for LinuxThreads.
+ AC_MSG_CHECKING("LinuxThreads")
+- res=`grep Linuxthreads /usr/include/pthread.h 2>/dev/null | wc -l`
++ # res=`grep Linuxthreads /usr/include/pthread.h 2>/dev/null | wc -l`
++ # All gentoo systems support this stuff, and this is an improper detection
++ # for LinuxThreads anyhow, always set the result to 1
++ res=1
+ if test "$res" -gt 0
+ then
+ AC_MSG_RESULT("Found")
diff --git a/030_all_thrssl-r0.patch b/030_all_thrssl-r0.patch
new file mode 100644
index 0000000..a4db917
--- /dev/null
+++ b/030_all_thrssl-r0.patch
@@ -0,0 +1,17 @@
+###MY_VER_RANGE [4.0.21,4.1.11_alpha20050215) [5.0_alpha,5.0.3_alpha)
+
+# attempt to get libmysqlclient_r linked against ssl if USE="ssl" enabled
+# i would really prefer to fix this at the Makefile.am level, but can't
+# get the software to autoreconf as distributed - too many missing files
+
+--- mysql-4.1.8/libmysql_r/Makefile.in 2004-12-14 13:41:13.000000000 +0100
++++ bbb/libmysql_r/Makefile.in 2005-01-09 17:57:27.156164952 +0100
+@@ -242,7 +242,7 @@
+ LIBDL = @LIBDL@
+ LIBEDIT_LOBJECTS = @LIBEDIT_LOBJECTS@
+ LIBOBJS = @LIBOBJS@
+-LIBS = @LIBS@ @openssl_libs@
++LIBS = @CLIENT_LIBS@ @openssl_libs@
+ LIBTOOL = @LIBTOOL@
+ LIB_EXTRA_CCFLAGS = @LIB_EXTRA_CCFLAGS@
+ LM_CFLAGS = @LM_CFLAGS@
diff --git a/030_all_thrssl-r1.patch b/030_all_thrssl-r1.patch
new file mode 100644
index 0000000..adbd84d
--- /dev/null
+++ b/030_all_thrssl-r1.patch
@@ -0,0 +1,28 @@
+###MY_VER_RANGE [4.1.11_alpha20050215,5.0_alpha) [5.0.3_alpha,5.0.4_beta)
+
+# attempt to get libmysqlclient_r linked against ssl if USE="ssl" enabled
+# i would really prefer to fix this at the Makefile.am level, but can't
+# get the software to autoreconf as distributed - too many missing files
+
+--- mysql-4.1.11_alpha20050216.orig/libmysql_r/Makefile.am 2005-02-19 15:58:34.000000000 +0100
++++ mysql-4.1.10/libmysql_r/Makefile.am 2005-02-19 15:59:02.000000000 +0100
+@@ -22,7 +22,7 @@
+
+ target = libmysqlclient_r.la
+ target_defs = -DDONT_USE_RAID -DMYSQL_CLIENT @LIB_EXTRA_CCFLAGS@
+-LIBS = @LIBS@ @ZLIB_LIBS@ @openssl_libs@
++LIBS = @CLIENT_LIBS@ @ZLIB_LIBS@ @openssl_libs@
+
+ INCLUDES = @MT_INCLUDES@ \
+ -I$(top_srcdir)/include $(openssl_includes) @ZLIB_INCLUDES@
+--- mysql-4.1.11_alpha20050216.orig/libmysql_r/Makefile.in 2005-02-19 15:58:34.000000000 +0100
++++ mysql-4.1.10/libmysql_r/Makefile.in 2005-02-19 15:59:24.000000000 +0100
+@@ -243,7 +243,7 @@
+ LIBDL = @LIBDL@
+ LIBEDIT_LOBJECTS = @LIBEDIT_LOBJECTS@
+ LIBOBJS = @LIBOBJS@
+-LIBS = @LIBS@ @ZLIB_LIBS@ @openssl_libs@
++LIBS = @CLIENT_LIBS@ @ZLIB_LIBS@ @openssl_libs@
+ LIBTOOL = @LIBTOOL@
+ LIB_EXTRA_CCFLAGS = @LIB_EXTRA_CCFLAGS@
+ LM_CFLAGS = @LM_CFLAGS@
diff --git a/035_x86_asm-pic-fixes-r0.patch b/035_x86_asm-pic-fixes-r0.patch
new file mode 100644
index 0000000..300756f
--- /dev/null
+++ b/035_x86_asm-pic-fixes-r0.patch
@@ -0,0 +1,99 @@
+###MY_VER_RANGE [4.0.24,4.1_alpha)
+--- mysql-4.0.24/strings/longlong2str-x86.s 2005-03-05 00:38:14.000000000 +0000
++++ mysql-4.0.24-fixed/strings/longlong2str-x86.s 2005-05-17 01:37:52.000000000 +0100
+@@ -19,6 +19,13 @@
+ .file "longlong2str.s"
+ .version "1.01"
+
++ .section .rodata
++ .align 32
++ .type _dig_vec, @object
++ .size _dig_vec, 37
++_dig_vec:
++ .string "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++
+ .text
+ .align 4
+
+@@ -31,11 +38,14 @@ longlong2str:
+ pushl %esi
+ pushl %edi
+ pushl %ebx
++
++ call __i686.get_pc_thunk.bx
++ addl $_GLOBAL_OFFSET_TABLE_,%ebx
++
+ movl 100(%esp),%esi # Lower part of val
+ movl 104(%esp),%ebp # Higher part of val
+ movl 108(%esp),%edi # get dst
+- movl 112(%esp),%ebx # Radix
+- movl %ebx,%eax
++ movl 112(%esp),%eax # Radix
+ testl %eax,%eax
+ jge .L144
+
+@@ -50,7 +60,7 @@ longlong2str:
+ adcl $0,%ebp
+ negl %ebp
+ .L146:
+- negl %ebx # Change radix to positive
++ negl 112(%esp) # Change radix to positive
+ jmp .L148
+ .align 4
+ .L144:
+@@ -77,12 +87,12 @@ longlong2str:
+
+ movl %ebp,%eax # High part of value
+ xorl %edx,%edx
+- divl %ebx
++ divl 112(%esp)
+ movl %eax,%ebp
+ movl %esi,%eax
+- divl %ebx
++ divl 112(%esp)
+ movl %eax,%esi # quotent in ebp:esi
+- movb _dig_vec(%edx),%al # al is faster than dl
++ movb _dig_vec@GOTOFF(%ebx,%edx),%al # al is faster than dl
+ decl %ecx
+ movb %al,(%ecx) # store value in buff
+ .align 4
+@@ -93,14 +103,13 @@ longlong2str:
+ jl .L153
+ je .L160 # Ready
+ movl %esi,%eax
+- movl $_dig_vec,%ebp
+ .align 4
+
+ .L154: # Do rest with integer precision
+ cltd
+- divl %ebx
++ divl 112(%esp)
+ decl %ecx
+- movb (%edx,%ebp),%dl # bh is always zero as ebx=radix < 36
++ movb _dig_vec@GOTOFF(%ebx,%edx),%dl
+ testl %eax,%eax
+ movb %dl,(%ecx)
+ jne .L154
+@@ -138,3 +147,13 @@ longlong10_to_str:
+
+ .L10end:
+ .size longlong10_to_str,.L10end-longlong10_to_str
++
++ .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
++.globl __i686.get_pc_thunk.bx
++ .hidden __i686.get_pc_thunk.bx
++ .type __i686.get_pc_thunk.bx, @function
++__i686.get_pc_thunk.bx:
++ movl (%esp), %ebx
++ ret
++
++ .section .note.GNU-stack,"",@progbits
+diff -Nurp mysql-4.0.24/strings/strings-x86.s mysql-4.0.24-fixed/strings/strings-x86.s
+--- mysql-4.0.24/strings/strings-x86.s 2005-03-05 00:38:15.000000000 +0000
++++ mysql-4.0.24-fixed/strings/strings-x86.s 2005-05-17 01:37:47.000000000 +0100
+@@ -403,3 +403,5 @@ next_str:
+ ret
+ .strxmov_end:
+ .size strxmov,.strxmov_end-strxmov
++
++ .section .note.GNU-stack,"",@progbits
diff --git a/035_x86_asm-pic-fixes-r1.patch b/035_x86_asm-pic-fixes-r1.patch
new file mode 100644
index 0000000..6d6293d
--- /dev/null
+++ b/035_x86_asm-pic-fixes-r1.patch
@@ -0,0 +1,159 @@
+###MY_VER_RANGE [4.1,4.1.13-r1)
+diff -Nurp mysql/strings/longlong2str-x86.s mysql-fixed/strings/longlong2str-x86.s
+--- mysql/strings/longlong2str-x86.s 2005-05-13 12:32:11.000000000 +0100
++++ mysql-fixed/strings/longlong2str-x86.s 2005-05-25 01:19:32.000000000 +0100
+@@ -19,6 +19,13 @@
+ .file "longlong2str.s"
+ .version "1.01"
+
++ .section .rodata
++ .align 32
++ .type _dig_vec_upper, @object
++ .size _dig_vec_upper, 37
++_dig_vec_upper:
++ .string "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
++
+ .text
+ .align 4
+
+@@ -31,11 +38,14 @@ longlong2str:
+ pushl %esi
+ pushl %edi
+ pushl %ebx
++
++ call __i686.get_pc_thunk.bx
++ addl $_GLOBAL_OFFSET_TABLE_,%ebx
++
+ movl 100(%esp),%esi # Lower part of val
+ movl 104(%esp),%ebp # Higher part of val
+ movl 108(%esp),%edi # get dst
+- movl 112(%esp),%ebx # Radix
+- movl %ebx,%eax
++ movl 112(%esp),%eax # Radix
+ testl %eax,%eax
+ jge .L144
+
+@@ -50,7 +60,7 @@ longlong2str:
+ adcl $0,%ebp
+ negl %ebp
+ .L146:
+- negl %ebx # Change radix to positive
++ negl 112(%esp) # Change radix to positive
+ jmp .L148
+ .align 4
+ .L144:
+@@ -77,13 +87,13 @@ longlong2str:
+
+ movl %ebp,%eax # High part of value
+ xorl %edx,%edx
+- divl %ebx
++ divl 112(%esp)
+ movl %eax,%ebp
+ movl %esi,%eax
+- divl %ebx
++ divl 112(%esp)
+ decl %ecx
+ movl %eax,%esi # quotent in ebp:esi
+- movb _dig_vec_upper(%edx),%al # al is faster than dl
++ movb _dig_vec_upper@GOTOFF(%ebx,%edx),%al # al is faster than dl
+ movb %al,(%ecx) # store value in buff
+ .align 4
+ .L155:
+@@ -93,14 +103,13 @@ longlong2str:
+ jl .L153
+ je .L10_mov # Ready
+ movl %esi,%eax
+- movl $_dig_vec_upper,%ebp
+ .align 4
+
+ .L154: # Do rest with integer precision
+ cltd
+- divl %ebx
++ divl 112(%esp)
+ decl %ecx
+- movb (%edx,%ebp),%dl # bh is always zero as ebx=radix < 36
++ movb _dig_vec_upper@GOTOFF(%ebx,%edx),%dl
+ testl %eax,%eax
+ movb %dl,(%ecx)
+ jne .L154
+@@ -137,9 +146,6 @@ longlong2str:
+ #
+
+ .align 4
+-.Ltmp:
+- .long 0xcccccccd
+- .align 4
+
+ .globl longlong10_to_str
+ .type longlong10_to_str,@function
+@@ -202,7 +208,7 @@ longlong10_to_str:
+
+ # The following code uses some tricks to change division by 10 to
+ # multiplication and shifts
+- movl .Ltmp,%esi # set %esi to 0xcccccccd
++ movl $0xcccccccd,%esi # set %esi to 0xcccccccd
+
+ .L10_40:
+ movl %ebx,%eax
+@@ -221,3 +227,13 @@ longlong10_to_str:
+
+ .L10end:
+ .size longlong10_to_str,.L10end-longlong10_to_str
++
++ .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
++.globl __i686.get_pc_thunk.bx
++ .hidden __i686.get_pc_thunk.bx
++ .type __i686.get_pc_thunk.bx, @function
++__i686.get_pc_thunk.bx:
++ movl (%esp), %ebx
++ ret
++
++ .section .note.GNU-stack,"",@progbits
+diff -Nurp mysql/strings/my_strtoll10-x86.s mysql-fixed/strings/my_strtoll10-x86.s
+--- mysql/strings/my_strtoll10-x86.s 2005-05-13 12:32:22.000000000 +0100
++++ mysql-fixed/strings/my_strtoll10-x86.s 2005-05-25 01:13:23.000000000 +0100
+@@ -18,7 +18,7 @@
+
+ .file "my_strtoll10-x86.s"
+ .version "01.01"
+-.data
++.section .rodata
+ .align 32
+ .type lfactor,@object
+ .size lfactor,36
+@@ -315,7 +315,11 @@ my_strtoll10:
+ .Lend_i_and_j:
+ movl %esi,%ecx
+ subl -12(%ebp),%ecx # ecx= number of digits in second part
+- movl lfactor(,%ecx,4),%eax
++
++ call __i686.get_pc_thunk.bx
++ addl $_GLOBAL_OFFSET_TABLE_,%ebx
++
++ movl lfactor@GOTOFF(%ebx,%ecx,4),%eax
+ jmp .L523
+
+ # Return -8(%ebp) * $1000000000 + edi
+@@ -400,3 +404,13 @@ my_strtoll10:
+ .comm end_ptr,120,32
+ .comm error,120,32
+ .ident "Monty"
++
++ .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
++.globl __i686.get_pc_thunk.bx
++ .hidden __i686.get_pc_thunk.bx
++ .type __i686.get_pc_thunk.bx, @function
++__i686.get_pc_thunk.bx:
++ movl (%esp), %ebx
++ ret
++
++ .section .note.GNU-stack,"",@progbits
+diff -Nurp mysql/strings/strings-x86.s mysql-fixed/strings/strings-x86.s
+--- mysql/strings/strings-x86.s 2005-05-13 12:32:40.000000000 +0100
++++ mysql-fixed/strings/strings-x86.s 2005-05-23 23:19:13.000000000 +0100
+@@ -415,3 +415,5 @@ next_str:
+ ret
+ .strxmov_end:
+ .size strxmov,.strxmov_end-strxmov
++
++ .section .note.GNU-stack,"",@progbits
diff --git a/035_x86_asm-pic-fixes-r2.patch b/035_x86_asm-pic-fixes-r2.patch
new file mode 100644
index 0000000..4a089a3
--- /dev/null
+++ b/035_x86_asm-pic-fixes-r2.patch
@@ -0,0 +1,343 @@
+###MY_VER_RANGE [4.1.13-r1,4.1.13-r1] [5.0.9_beta-r2,5.0.9_beta-r2]
+diff -aur mysql.orig/strings/longlong2str-x86.s mysql.notextrel/strings/longlong2str-x86.s
+--- mysql.orig/strings/longlong2str-x86.s 2005-07-26 17:52:18.000000000 +0200
++++ mysql.notextrel/strings/longlong2str-x86.s 2005-07-26 19:29:23.000000000 +0200
+@@ -13,8 +13,9 @@
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+-# Optimized longlong2str function for Intel 80x86 (gcc/gas syntax)
+-# Some set sequences are optimized for pentuimpro II
++# longlong2str function for Intel 80x86 (gcc/gas syntax)
++
++# See longlong2str(dst,radix,val) description in longlong2str.c.
+
+ .file "longlong2str.s"
+ .version "1.01"
+@@ -24,99 +25,88 @@
+
+ .globl longlong2str
+ .type longlong2str,@function
+-
++
+ longlong2str:
+- subl $80,%esp
++ subl $80,%esp # Temporary buffer for up to 64 radix-2 digits
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+- movl 100(%esp),%esi # Lower part of val
+- movl 104(%esp),%ebp # Higher part of val
+- movl 108(%esp),%edi # get dst
+- movl 112(%esp),%ebx # Radix
+- movl %ebx,%eax
+- testl %eax,%eax
+- jge .L144
+-
+- addl $36,%eax
+- cmpl $34,%eax
+- ja .Lerror # Wrong radix
++
++ movl 100(%esp),%esi # esi = Lower part of val
++ movl 112(%esp),%ebx # ebx = Radix
++ movl 104(%esp),%ebp # ebp = Higher part of val
++ movl 108(%esp),%edi # edi -> dst
++
++ testl %ebx,%ebx
++ jge .L144 # (Radix >= 0)
++
+ testl %ebp,%ebp
+- jge .L146
+- movb $45,(%edi) # Add sign
+- incl %edi # Change sign of val
+- negl %esi
+- adcl $0,%ebp
+- negl %ebp
++ jge .L146 # (Higher part of val >= 0)
++ movb $45,(%edi) # Add '-' sign
++ incl %edi
++ negl %esi # Change val to positive
++ adcl $0,%ebp
++ negl %ebp
+ .L146:
+- negl %ebx # Change radix to positive
+- jmp .L148
+- .align 4
++ negl %ebx # Change radix to positive
+ .L144:
+- addl $-2,%eax
+- cmpl $34,%eax
+- ja .Lerror # Radix in range
++ cmpl $36,%ebx # Radix must be between 2 and 36
++ ja .Lerror # (Radix not in range)
++ cmpl $2,%ebx
++ jb .Lerror # (Radix not in range)
++
++ movl %esi,%eax # eax = lower part of val ...
++ orl %ebp,%eax # and it stays thus if ebp=0
++ je Lzero # (Treat zero as special case)
+
+-.L148:
+- movl %esi,%eax # Test if zero (for easy loop)
+- orl %ebp,%eax
+- jne .L150
+- movb $48,(%edi)
+- incl %edi
+- jmp .L10_end
+- .align 4
+-
+-.L150:
+- leal 92(%esp),%ecx # End of buffer
+- jmp .L155
+- .align 4
+-
+-.L153:
+- # val is stored in in ebp:esi
+-
+- movl %ebp,%eax # High part of value
+- xorl %edx,%edx
+- divl %ebx
+- movl %eax,%ebp
+- movl %esi,%eax
+- divl %ebx
+- decl %ecx
+- movl %eax,%esi # quotent in ebp:esi
+- movb _dig_vec_upper(%edx),%al # al is faster than dl
+- movb %al,(%ecx) # store value in buff
+- .align 4
+-.L155:
++ leal 92(%esp),%ecx # ecx -> End of temporary buffer
++
+ testl %ebp,%ebp
+- ja .L153
+- testl %esi,%esi # rest value
+- jl .L153
+- je .L10_mov # Ready
+- movl %esi,%eax
+- movl $_dig_vec_upper,%ebp
+- .align 4
+-
+-.L154: # Do rest with integer precision
+- cltd
+- divl %ebx
+- decl %ecx
+- movb (%edx,%ebp),%dl # bh is always zero as ebx=radix < 36
+- testl %eax,%eax
+- movb %dl,(%ecx)
+- jne .L154
+-
+-.L10_mov:
+- movl %ecx,%esi
+- leal 92(%esp),%ecx # End of buffer
+- subl %esi,%ecx
+- rep
+- movsb
+-
+-.L10_end:
+- movl %edi,%eax # Pointer to end null
+- movb $0,(%edi) # Store the end null
+-
+-.L165:
++ je Llow # (Higher part of val = 0)
++
++Lhigh:
++ #val in ebp:esi. div the high part by the radix,
++ #then div remainder + low part by the radix.
++ movl %ebp,%eax # edx=0,eax=high(from ebp)
++ xorl %edx,%edx
++ decl %ecx
++ divl %ebx
++ movl %eax,%ebp # edx=result of last, eax=low(from esi)
++ movl %esi,%eax
++ divl %ebx
++ movl %eax,%esi # ebp:esi = quotient
++ movb %dl,(%ecx) # store byte in temporary buffer
++ testl %ebp,%ebp
++ jne Lhigh # (Higher part of val still > 0)
++
++Llow:
++ #val in 0:eax. div 0 + low part by the radix.
++ xorl %edx,%edx
++ decl %ecx
++ divl %ebx
++ movb %dl,(%ecx) # store byte in temporary buffer
++ testl %eax,%eax
++ jne Llow # (Lower part of val still <> 0)
++
++ leal 92(%esp),%esi # esi -> End of temporary buffer
++
++Lmov:
++ movb (%ecx),%dl # dl = byte from temporary buffer
++ movb $-1,%bl
++ cmpb $10,%dl # add 7 if dl > '9'
++ adcb $0,%bl
++ addb $48,%dl # add '0'
++ andb $7,%bl
++ addb %bl,%dl
++ incl %ecx
++ movb %dl,(%edi) # put dl in dst
++ incl %edi
++ cmpl %ecx,%esi
++ ja Lmov # (more bytes exist in temporary buffer)
++ movb $0,(%edi) # trailing '\0' in dst
++ movl %edi,%eax # eax = return value = pointer to '\0'
++.Lret:
+ popl %ebx
+ popl %edi
+ popl %esi
+@@ -126,20 +116,28 @@
+
+ .Lerror:
+ xorl %eax,%eax # Wrong radix
+- jmp .L165
++ jmp .Lret
+
+-.Lfe3:
+- .size longlong2str,.Lfe3-longlong2str
++Lzero:
++ # Treat 0 as a special case. Unnecessary but we
++ # expect 0 will be frequent.
++ movl 108(%esp),%eax # eax = dst
++ popl %ebx
++ movb $48,(%eax) # '0'
++ popl %edi
++ incl %eax
++ popl %esi
++ popl %ebp
++ addl $80,%esp
++ movb $0,(%eax) # '\0'
++ ret
+
+ #
+ # This is almost equal to the above, except that we can do the final
+ # loop much more efficient
+-#
++#
+
+ .align 4
+-.Ltmp:
+- .long 0xcccccccd
+- .align 4
+
+ .globl longlong10_to_str
+ .type longlong10_to_str,@function
+@@ -202,7 +200,7 @@
+
+ # The following code uses some tricks to change division by 10 to
+ # multiplication and shifts
+- movl .Ltmp,%esi # set %esi to 0xcccccccd
++ movl $0xcccccccd,%esi # set %esi to 0xcccccccd
+
+ .L10_40:
+ movl %ebx,%eax
+@@ -217,7 +215,30 @@
+ movl %edx,%ebx
+ testl %ebx,%ebx
+ jne .L10_40
+- jmp .L10_mov # Shared end with longlong10_to_str
++# jmp .L10_mov # Shared end with longlong10_to_str
++
+
++.L10_mov:
++ movl %ecx,%esi
++ leal 92(%esp),%ecx # End of buffer
++ subl %esi,%ecx
++ rep
++ movsb
++
++.L10_end:
++ movl %edi,%eax # Pointer to end null
++ movb $0,(%edi) # Store the end null
++
++.L165:
++ popl %ebx
++ popl %edi
++ popl %esi
++ popl %ebp
++ addl $80,%esp
++ ret
++
+ .L10end:
+ .size longlong10_to_str,.L10end-longlong10_to_str
++
++ .section .note.GNU-stack,"",@progbits
++
+diff -aur mysql.orig/strings/my_strtoll10-x86.s mysql.notextrel/strings/my_strtoll10-x86.s
+--- mysql.orig/strings/my_strtoll10-x86.s 2005-07-26 17:52:18.000000000 +0200
++++ mysql.notextrel/strings/my_strtoll10-x86.s 2005-07-26 19:29:33.000000000 +0200
+@@ -18,20 +18,7 @@
+
+ .file "my_strtoll10-x86.s"
+ .version "01.01"
+-.data
+- .align 32
+- .type lfactor,@object
+- .size lfactor,36
+-lfactor:
+- .long 1
+- .long 10
+- .long 100
+- .long 1000
+- .long 10000
+- .long 100000
+- .long 1000000
+- .long 10000000
+- .long 100000000
++
+ .text
+ .align 4
+
+@@ -315,9 +302,32 @@
+ .Lend_i_and_j:
+ movl %esi,%ecx
+ subl -12(%ebp),%ecx # ecx= number of digits in second part
+- movl lfactor(,%ecx,4),%eax
+- jmp .L523
+-
++ movl $1,%eax
++ cmpb $0,%cl
++ je .L523 # 0 so 1
++ movl $10,%eax
++ cmpb $1,%cl
++ je .L523 # 1 so 10
++ movl $100,%eax
++ cmpb $2,%cl
++ je .L523 # 2 so 100
++ movl $1000,%eax
++ cmpb $3,%cl
++ je .L523 # 3 so 1000
++ movl $10000,%eax
++ cmpb $4,%cl
++ je .L523 # 4 so 10000
++ movl $100000,%eax
++ cmpb $5,%cl
++ je .L523 # 5 so 100000
++ movl $1000000,%eax
++ cmpb $6,%cl
++ je .L523 # 6 so 1000000
++ movl $10000000,%eax
++ cmpb $7,%cl
++ je .L523 # 7 so 10000000
++ movl $100000000,%eax
++ jmp .L523 # 8 so 100000000
+ # Return -8(%ebp) * $1000000000 + edi
+ .p2align 4,,7
+ .Lend3:
+@@ -400,3 +410,6 @@
+ .comm end_ptr,120,32
+ .comm error,120,32
+ .ident "Monty"
++
++ .section .note.GNU-stack,"",@progbits
++
+diff -aur mysql.orig/strings/strings-x86.s mysql.notextrel/strings/strings-x86.s
+--- mysql.orig/strings/strings-x86.s 2005-07-26 17:52:18.000000000 +0200
++++ mysql.notextrel/strings/strings-x86.s 2005-07-26 19:29:42.000000000 +0200
+@@ -415,3 +415,6 @@
+ ret
+ .strxmov_end:
+ .size strxmov,.strxmov_end-strxmov
++
++ .section .note.GNU-stack,"",@progbits
++
diff --git a/035_x86_asm-pic-fixes-r3.patch b/035_x86_asm-pic-fixes-r3.patch
new file mode 100644
index 0000000..a6836d0
--- /dev/null
+++ b/035_x86_asm-pic-fixes-r3.patch
@@ -0,0 +1,365 @@
+###MY_VER_RANGE [4.1.13-r2,4.1.14_alpha20050816)
+
+FOLLOWING THE ORIGINAL PATCH COMMIT COMMENTS:
+
+ChangeSet
+ 1.2356 05/08/08 13:18:18 monty@mishka.local +6 -0
+ Fix for BUG #11642: [Patch]es x86 Assembler and text relocations
+ Changed assembler functions to not access global variables or variables in text segement
+ Added wrapper function in C to longlong2str() to pass _dig_vec_upper as an argument
+
+ strings/longlong2str_asm.c
+ 1.1 05/08/08 13:18:12 monty@mishka.local +33 -0
+ New BitKeeper file ``strings/longlong2str_asm.c''
+
+ strings/my_strtoll10-x86.s
+ 1.4 05/08/08 13:18:12 monty@mishka.local +39 -23
+ Removd array lfactor by calculating the value in code
+ (this is to to make the code position independent)
+
+ strings/longlong2str_asm.c
+ 1.0 05/08/08 13:18:12 monty@mishka.local +0 -0
+ BitKeeper file /home/my/mysql-4.1/strings/longlong2str_asm.c
+
+ strings/longlong2str-x86.s
+ 1.11 05/08/08 13:18:12 monty@mishka.local +18 -17
+ Changed functions to not access variables in text segment
+ Fixed this by adding global variable '_dig_vec_upper' as an argument to longlong2str_with_dig_vector()
+
+ strings/Makefile.am
+ 1.43 05/08/08 13:18:12 monty@mishka.local +2 -2
+ Added longlong2str_asm.c
+
+ mysql-test/t/bigint.test
+ 1.24 05/08/08 13:18:11 monty@mishka.local +3 -0
+ More tests for parsing of bigint's
+ More tests for different values to conv()
+
+ mysql-test/r/bigint.result
+ 1.25 05/08/08 13:18:11 monty@mishka.local +9 -0
+ More tests for parsing of bigint's
+ More tests for different values to conv()
+
+REAPPLIED PATCH FROM HERE:
+PLUS ".section .note.GNU-stack,"",@progbits"
+
+diff -Naur mysql.orig/mysql-test/r/bigint.result mysql.new/mysql-test/r/bigint.result
+--- mysql.orig/mysql-test/r/bigint.result 2005-07-15 12:50:20.000000000 +0200
++++ mysql.new/mysql-test/r/bigint.result 2005-08-08 22:21:46.000000000 +0200
+@@ -17,6 +17,15 @@
+ select -(0-3),round(-(0-3)), round(9999999999999999999);
+ -(0-3) round(-(0-3)) round(9999999999999999999)
+ 3 3 10000000000000000000
++select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001;
++1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001
++1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001
++select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001;
++-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000001
++-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000000
++select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16);
++conv(1,10,16) conv((1<<2)-1,10,16) conv((1<<10)-2,10,16) conv((1<<16)-3,10,16) conv((1<<25)-4,10,16) conv((1<<31)-5,10,16) conv((1<<36)-6,10,16) conv((1<<47)-7,10,16) conv((1<<48)-8,10,16) conv((1<<55)-9,10,16) conv((1<<56)-10,10,16) conv((1<<63)-11,10,16)
++1 3 3FE FFFD 1FFFFFC 7FFFFFFB FFFFFFFFA 7FFFFFFFFFF9 FFFFFFFFFFF8 7FFFFFFFFFFFF7 FFFFFFFFFFFFF6 7FFFFFFFFFFFFFF5
+ create table t1 (a bigint unsigned not null, primary key(a));
+ insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE), (18446744073709551613), (18446744073709551612);
+ select * from t1;
+diff -Naur mysql.orig/mysql-test/t/bigint.test mysql.new/mysql-test/t/bigint.test
+--- mysql.orig/mysql-test/t/bigint.test 2005-07-15 12:50:20.000000000 +0200
++++ mysql.new/mysql-test/t/bigint.test 2005-08-08 22:21:46.000000000 +0200
+@@ -14,6 +14,9 @@
+ select cast(9223372036854775808 as unsigned)+1;
+ select 9223372036854775808+1;
+ select -(0-3),round(-(0-3)), round(9999999999999999999);
++select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001;
++select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000001;
++select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16);
+
+ #
+ # In 3.23 we have to disable the test of column to bigint as
+diff -Naur mysql.orig/strings/Makefile.am mysql.new/strings/Makefile.am
+--- mysql.orig/strings/Makefile.am 2005-07-15 12:39:35.000000000 +0200
++++ mysql.new/strings/Makefile.am 2005-08-08 22:21:46.000000000 +0200
+@@ -23,7 +23,7 @@
+ # Exact one of ASSEMBLER_X
+ if ASSEMBLER_x86
+ ASRCS = strings-x86.s longlong2str-x86.s my_strtoll10-x86.s
+-CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c
++CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c longlong2str_asm.c
+ else
+ if ASSEMBLER_sparc32
+ # These file MUST all be on the same line!! Otherwise automake
+@@ -46,7 +46,7 @@
+ ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-utf8.c \
+ ctype-ucs2.c ctype-uca.c ctype-tis620.c ctype-ujis.c \
+ xml.c strto.c strings-x86.s \
+- longlong2str.c longlong2str-x86.s \
++ longlong2str.c longlong2str-x86.s longlong2str_asm.c \
+ my_strtoll10.c my_strtoll10-x86.s \
+ strxmov.c bmove_upp.c strappend.c strcont.c strend.c \
+ strfill.c strcend.c is_prefix.c strstr.c strinstr.c \
+diff -Naur mysql.orig/strings/longlong2str-x86.s mysql.new/strings/longlong2str-x86.s
+--- mysql.orig/strings/longlong2str-x86.s 2005-07-15 12:39:33.000000000 +0200
++++ mysql.new/strings/longlong2str-x86.s 2005-08-08 22:52:38.000000000 +0200
+@@ -16,26 +16,26 @@
+ # Optimized longlong2str function for Intel 80x86 (gcc/gas syntax)
+ # Some set sequences are optimized for pentuimpro II
+
+- .file "longlong2str.s"
+- .version "1.01"
++ .file "longlong2str-x86.s"
++ .version "1.02"
+
+ .text
+ .align 4
+
+-.globl longlong2str
+- .type longlong2str,@function
++.globl longlong2str_with_dig_vector
++ .type longlong2str_with_dig_vector,@function
+
+-longlong2str:
++longlong2str_with_dig_vector:
+ subl $80,%esp
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 100(%esp),%esi # Lower part of val
+- movl 104(%esp),%ebp # Higher part of val
+- movl 108(%esp),%edi # get dst
+ movl 112(%esp),%ebx # Radix
++ movl 104(%esp),%ebp # Higher part of val
+ movl %ebx,%eax
++ movl 108(%esp),%edi # get dst
+ testl %eax,%eax
+ jge .L144
+
+@@ -69,6 +69,8 @@
+
+ .L150:
+ leal 92(%esp),%ecx # End of buffer
++ movl %edi, 108(%esp) # Store possible modified dest
++ movl 116(%esp), %edi # dig_vec_upper
+ jmp .L155
+ .align 4
+
+@@ -83,7 +85,7 @@
+ divl %ebx
+ decl %ecx
+ movl %eax,%esi # quotent in ebp:esi
+- movb _dig_vec_upper(%edx),%al # al is faster than dl
++ movb (%edx,%edi),%al # al is faster than dl
+ movb %al,(%ecx) # store value in buff
+ .align 4
+ .L155:
+@@ -91,20 +93,22 @@
+ ja .L153
+ testl %esi,%esi # rest value
+ jl .L153
+- je .L10_mov # Ready
++ je .L160 # Ready
+ movl %esi,%eax
+- movl $_dig_vec_upper,%ebp
+ .align 4
+
+ .L154: # Do rest with integer precision
+ cltd
+ divl %ebx
+ decl %ecx
+- movb (%edx,%ebp),%dl # bh is always zero as ebx=radix < 36
++ movb (%edx,%edi),%dl # bh is always zero as ebx=radix < 36
+ testl %eax,%eax
+ movb %dl,(%ecx)
+ jne .L154
+
++.L160:
++ movl 108(%esp),%edi # get dst
++
+ .L10_mov:
+ movl %ecx,%esi
+ leal 92(%esp),%ecx # End of buffer
+@@ -129,7 +133,7 @@
+ jmp .L165
+
+ .Lfe3:
+- .size longlong2str,.Lfe3-longlong2str
++ .size longlong2str_with_dig_vector,.Lfe3-longlong2str_with_dig_vector
+
+ #
+ # This is almost equal to the above, except that we can do the final
+@@ -137,9 +141,6 @@
+ #
+
+ .align 4
+-.Ltmp:
+- .long 0xcccccccd
+- .align 4
+
+ .globl longlong10_to_str
+ .type longlong10_to_str,@function
+@@ -202,8 +203,8 @@
+
+ # The following code uses some tricks to change division by 10 to
+ # multiplication and shifts
+- movl .Ltmp,%esi # set %esi to 0xcccccccd
+-
++ movl $0xcccccccd,%esi
++
+ .L10_40:
+ movl %ebx,%eax
+ mull %esi
+@@ -221,3 +222,6 @@
+
+ .L10end:
+ .size longlong10_to_str,.L10end-longlong10_to_str
++
++ .section .note.GNU-stack,"",@progbits
++
+diff -Naur mysql.orig/strings/longlong2str_asm.c mysql.new/strings/longlong2str_asm.c
+--- mysql.orig/strings/longlong2str_asm.c 1970-01-01 01:00:00.000000000 +0100
++++ mysql.new/strings/longlong2str_asm.c 2005-08-08 22:23:33.000000000 +0200
+@@ -0,0 +1,34 @@
++/* Copyright (C) 2000 MySQL AB
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program 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 should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++/*
++ * Wrapper for longlong2str.s
++ *
++ * We need this because the assembler code can't access the local variable
++ * _dig_vector in a portable manner.
++ */
++
++#include <my_global.h>
++#include "m_string.h"
++
++extern char *longlong2str_with_dig_vector(longlong val,char *dst,int radix,
++ const char *dig_vector);
++
++char *longlong2str(longlong val,char *dst,int radix)
++{
++ return longlong2str_with_dig_vector(val, dst, radix, _dig_vec_upper);
++}
++
+diff -Naur mysql.orig/strings/my_strtoll10-x86.s mysql.new/strings/my_strtoll10-x86.s
+--- mysql.orig/strings/my_strtoll10-x86.s 2005-07-15 12:39:34.000000000 +0200
++++ mysql.new/strings/my_strtoll10-x86.s 2005-08-08 22:52:51.000000000 +0200
+@@ -17,21 +17,8 @@
+ # For documentation, check my_strtoll.c
+
+ .file "my_strtoll10-x86.s"
+- .version "01.01"
+-.data
+- .align 32
+- .type lfactor,@object
+- .size lfactor,36
+-lfactor:
+- .long 1
+- .long 10
+- .long 100
+- .long 1000
+- .long 10000
+- .long 100000
+- .long 1000000
+- .long 10000000
+- .long 100000000
++ .version "01.02"
++
+ .text
+ .align 4
+
+@@ -209,14 +196,16 @@
+ jne .L500
+ cmpl -36(%ebp),%esi # Test if string is less than 18 digits
+ jne .Lend_i_and_j
+- jmp .Lend3 # 18 digit string
++.L499:
++ movl $1000000000,%eax
++ jmp .Lgot_factor # 18 digit string
+
+ # Handle the possible next to last digit and store in ecx
+ .L500:
+ movb (%esi),%al
+ addb $-48,%al
+ cmpb $9,%al
+- ja .Lend3
++ ja .L499 # 18 digit string
+
+ incl %esi
+ movzbl %al,%ecx
+@@ -315,14 +304,41 @@
+ .Lend_i_and_j:
+ movl %esi,%ecx
+ subl -12(%ebp),%ecx # ecx= number of digits in second part
+- movl lfactor(,%ecx,4),%eax
+- jmp .L523
+
+- # Return -8(%ebp) * $1000000000 + edi
++ # Calculate %eax= 10 ** %cl, where %cl <= 8
++ # With an array one could do this with:
++ # movl 10_factor_table(,%ecx,4),%eax
++ # We calculate the table here to avoid problems in
++ # position independent code (gcc -pic)
++
++ cmpb $3,%cl
++ ja .L4_to_8
++ movl $1000, %eax
++ je .Lgot_factor # %cl=3, eax= 1000
++ movl $10, %eax
++ cmpb $1,%cl # %cl is here 0 - 2
++ je .Lgot_factor # %cl=1, eax= 10
++ movl $100, %eax
++ ja .Lgot_factor # %cl=2, eax=100
++ movl $1, %eax
++ jmp .Lgot_factor # %cl=0, eax=1
++
++.L4_to_8: # %cl is here 4-8
++ cmpb $5,%cl
++ movl $100000, %eax
++ je .Lgot_factor # %cl=5, eax=100000
++ movl $10000, %eax
++ jbe .Lgot_factor # %cl=4, eax=10000
++ movl $10000000, %eax
++ cmpb $7,%cl
++ je .Lgot_factor # %cl=7, eax=10000000
++ movl $100000000, %eax
++ ja .Lgot_factor # %cl=8, eax=100000000
++ movl $1000000, %eax # %cl=6, eax=1000000
++
++ # Return -8(%ebp) * %eax + edi
+ .p2align 4,,7
+-.Lend3:
+- movl $1000000000,%eax
+-.L523:
++.Lgot_factor:
+ mull -8(%ebp)
+ addl %edi,%eax
+ adcl $0,%edx
+@@ -400,3 +416,6 @@
+ .comm end_ptr,120,32
+ .comm error,120,32
+ .ident "Monty"
++
++ .section .note.GNU-stack,"",@progbits
++
+diff -Naur mysql.orig/strings/strings-x86.s mysql.new/strings/strings-x86.s
+--- mysql.orig/strings/strings-x86.s 2005-07-15 12:39:36.000000000 +0200
++++ mysql.new/strings/strings-x86.s 2005-08-08 22:53:00.000000000 +0200
+@@ -415,3 +415,6 @@
+ ret
+ .strxmov_end:
+ .size strxmov,.strxmov_end-strxmov
++
++ .section .note.GNU-stack,"",@progbits
++
diff --git a/035_x86_asm-pic-fixes-r4.patch b/035_x86_asm-pic-fixes-r4.patch
new file mode 100644
index 0000000..308b6e5
--- /dev/null
+++ b/035_x86_asm-pic-fixes-r4.patch
@@ -0,0 +1,365 @@
+###MY_VER_RANGE [5.0.10_beta-r1,5.0.10_beta-r1]
+
+FOLLOWING THE ORIGINAL PATCH COMMIT COMMENTS:
+
+ChangeSet
+ 1.2356 05/08/08 13:18:18 monty@mishka.local +6 -0
+ Fix for BUG #11642: [Patch]es x86 Assembler and text relocations
+ Changed assembler functions to not access global variables or variables in text segement
+ Added wrapper function in C to longlong2str() to pass _dig_vec_upper as an argument
+
+ strings/longlong2str_asm.c
+ 1.1 05/08/08 13:18:12 monty@mishka.local +33 -0
+ New BitKeeper file ``strings/longlong2str_asm.c''
+
+ strings/my_strtoll10-x86.s
+ 1.4 05/08/08 13:18:12 monty@mishka.local +39 -23
+ Removd array lfactor by calculating the value in code
+ (this is to to make the code position independent)
+
+ strings/longlong2str_asm.c
+ 1.0 05/08/08 13:18:12 monty@mishka.local +0 -0
+ BitKeeper file /home/my/mysql-4.1/strings/longlong2str_asm.c
+
+ strings/longlong2str-x86.s
+ 1.11 05/08/08 13:18:12 monty@mishka.local +18 -17
+ Changed functions to not access variables in text segment
+ Fixed this by adding global variable '_dig_vec_upper' as an argument to longlong2str_with_dig_vector()
+
+ strings/Makefile.am
+ 1.43 05/08/08 13:18:12 monty@mishka.local +2 -2
+ Added longlong2str_asm.c
+
+ mysql-test/t/bigint.test
+ 1.24 05/08/08 13:18:11 monty@mishka.local +3 -0
+ More tests for parsing of bigint's
+ More tests for different values to conv()
+
+ mysql-test/r/bigint.result
+ 1.25 05/08/08 13:18:11 monty@mishka.local +9 -0
+ More tests for parsing of bigint's
+ More tests for different values to conv()
+
+REAPPLIED PATCH FROM HERE:
+PLUS ".section .note.GNU-stack,"",@progbits"
+
+
+diff -Naur mysql.orig/mysql-test/t/bigint.test mysql.new/mysql-test/t/bigint.test
+--- mysql.orig/mysql-test/t/bigint.test 2005-08-08 22:39:10.000000000 +0200
++++ mysql.new/mysql-test/t/bigint.test 2005-08-08 22:41:29.000000000 +0200
+@@ -14,6 +14,9 @@
+ select cast(9223372036854775808 as unsigned)+1;
+ select 9223372036854775808+1;
+ select -(0-3),round(-(0-3)), round(9999999999999999999);
++select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001;
++select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000000;
++select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16);
+
+ #
+ # In 3.23 we have to disable the test of column to bigint as
+diff -Naur mysql.orig/strings/Makefile.am mysql.new/strings/Makefile.am
+--- mysql.orig/strings/Makefile.am 2005-08-08 22:39:10.000000000 +0200
++++ mysql.new/strings/Makefile.am 2005-08-08 22:41:29.000000000 +0200
+@@ -22,7 +22,7 @@
+ # Exact one of ASSEMBLER_X
+ if ASSEMBLER_x86
+ ASRCS = strings-x86.s longlong2str-x86.s my_strtoll10-x86.s
+-CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c
++CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c longlong2str_asm.c
+ else
+ if ASSEMBLER_sparc32
+ # These file MUST all be on the same line!! Otherwise automake
+@@ -45,7 +45,7 @@
+ ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-utf8.c \
+ ctype-ucs2.c ctype-uca.c ctype-tis620.c ctype-ujis.c \
+ xml.c decimal.c strto.c strings-x86.s \
+- longlong2str.c longlong2str-x86.s \
++ longlong2str.c longlong2str-x86.s longlong2str_asm.c \
+ my_strtoll10.c my_strtoll10-x86.s \
+ strxmov.c bmove_upp.c strappend.c strcont.c strend.c \
+ strfill.c strcend.c is_prefix.c strstr.c strinstr.c \
+diff -Naur mysql.orig/strings/longlong2str-x86.s mysql.new/strings/longlong2str-x86.s
+--- mysql.orig/strings/longlong2str-x86.s 2005-08-08 22:39:10.000000000 +0200
++++ mysql.new/strings/longlong2str-x86.s 2005-08-08 22:44:14.000000000 +0200
+@@ -16,26 +16,26 @@
+ # Optimized longlong2str function for Intel 80x86 (gcc/gas syntax)
+ # Some set sequences are optimized for pentuimpro II
+
+- .file "longlong2str.s"
+- .version "1.01"
++ .file "longlong2str-x86.s"
++ .version "1.02"
+
+ .text
+ .align 4
+
+-.globl longlong2str
+- .type longlong2str,@function
++.globl longlong2str_with_dig_vector
++ .type longlong2str_with_dig_vector,@function
+
+-longlong2str:
++longlong2str_with_dig_vector:
+ subl $80,%esp
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 100(%esp),%esi # Lower part of val
+- movl 104(%esp),%ebp # Higher part of val
+- movl 108(%esp),%edi # get dst
+ movl 112(%esp),%ebx # Radix
++ movl 104(%esp),%ebp # Higher part of val
+ movl %ebx,%eax
++ movl 108(%esp),%edi # get dst
+ testl %eax,%eax
+ jge .L144
+
+@@ -69,6 +69,8 @@
+
+ .L150:
+ leal 92(%esp),%ecx # End of buffer
++ movl %edi, 108(%esp) # Store possible modified dest
++ movl 116(%esp), %edi # dig_vec_upper
+ jmp .L155
+ .align 4
+
+@@ -83,7 +85,7 @@
+ divl %ebx
+ decl %ecx
+ movl %eax,%esi # quotent in ebp:esi
+- movb _dig_vec_upper(%edx),%al # al is faster than dl
++ movb (%edx,%edi),%al # al is faster than dl
+ movb %al,(%ecx) # store value in buff
+ .align 4
+ .L155:
+@@ -91,20 +93,22 @@
+ ja .L153
+ testl %esi,%esi # rest value
+ jl .L153
+- je .L10_mov # Ready
++ je .L160 # Ready
+ movl %esi,%eax
+- movl $_dig_vec_upper,%ebp
+ .align 4
+
+ .L154: # Do rest with integer precision
+ cltd
+ divl %ebx
+ decl %ecx
+- movb (%edx,%ebp),%dl # bh is always zero as ebx=radix < 36
++ movb (%edx,%edi),%dl # bh is always zero as ebx=radix < 36
+ testl %eax,%eax
+ movb %dl,(%ecx)
+ jne .L154
+
++.L160:
++ movl 108(%esp),%edi # get dst
++
+ .L10_mov:
+ movl %ecx,%esi
+ leal 92(%esp),%ecx # End of buffer
+@@ -129,7 +133,7 @@
+ jmp .L165
+
+ .Lfe3:
+- .size longlong2str,.Lfe3-longlong2str
++ .size longlong2str_with_dig_vector,.Lfe3-longlong2str_with_dig_vector
+
+ #
+ # This is almost equal to the above, except that we can do the final
+@@ -137,9 +141,6 @@
+ #
+
+ .align 4
+-.Ltmp:
+- .long 0xcccccccd
+- .align 4
+
+ .globl longlong10_to_str
+ .type longlong10_to_str,@function
+@@ -202,8 +203,8 @@
+
+ # The following code uses some tricks to change division by 10 to
+ # multiplication and shifts
+- movl .Ltmp,%esi # set %esi to 0xcccccccd
+-
++ movl $0xcccccccd,%esi
++
+ .L10_40:
+ movl %ebx,%eax
+ mull %esi
+@@ -221,3 +222,6 @@
+
+ .L10end:
+ .size longlong10_to_str,.L10end-longlong10_to_str
++
++ .section .note.GNU-stack,"",@progbits
++
+diff -Naur mysql.orig/strings/longlong2str_asm.c mysql.new/strings/longlong2str_asm.c
+--- mysql.orig/strings/longlong2str_asm.c 1970-01-01 01:00:00.000000000 +0100
++++ mysql.new/strings/longlong2str_asm.c 2005-08-08 22:39:10.000000000 +0200
+@@ -0,0 +1,34 @@
++/* Copyright (C) 2000 MySQL AB
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program 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 should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++/*
++ * Wrapper for longlong2str.s
++ *
++ * We need this because the assembler code can't access the local variable
++ * _dig_vector in a portable manner.
++ */
++
++#include <my_global.h>
++#include "m_string.h"
++
++extern char *longlong2str_with_dig_vector(longlong val,char *dst,int radix,
++ const char *dig_vector);
++
++char *longlong2str(longlong val,char *dst,int radix)
++{
++ return longlong2str_with_dig_vector(val, dst, radix, _dig_vec_upper);
++}
++
+diff -Naur mysql.orig/strings/my_strtoll10-x86.s mysql.new/strings/my_strtoll10-x86.s
+--- mysql.orig/strings/my_strtoll10-x86.s 2005-08-08 22:39:10.000000000 +0200
++++ mysql.new/strings/my_strtoll10-x86.s 2005-08-08 22:44:23.000000000 +0200
+@@ -17,21 +17,8 @@
+ # For documentation, check my_strtoll.c
+
+ .file "my_strtoll10-x86.s"
+- .version "01.01"
+-.data
+- .align 32
+- .type lfactor,@object
+- .size lfactor,36
+-lfactor:
+- .long 1
+- .long 10
+- .long 100
+- .long 1000
+- .long 10000
+- .long 100000
+- .long 1000000
+- .long 10000000
+- .long 100000000
++ .version "01.02"
++
+ .text
+ .align 4
+
+@@ -209,14 +196,16 @@
+ jne .L500
+ cmpl -36(%ebp),%esi # Test if string is less than 18 digits
+ jne .Lend_i_and_j
+- jmp .Lend3 # 18 digit string
++.L499:
++ movl $1000000000,%eax
++ jmp .Lgot_factor # 18 digit string
+
+ # Handle the possible next to last digit and store in ecx
+ .L500:
+ movb (%esi),%al
+ addb $-48,%al
+ cmpb $9,%al
+- ja .Lend3
++ ja .L499 # 18 digit string
+
+ incl %esi
+ movzbl %al,%ecx
+@@ -315,14 +304,41 @@
+ .Lend_i_and_j:
+ movl %esi,%ecx
+ subl -12(%ebp),%ecx # ecx= number of digits in second part
+- movl lfactor(,%ecx,4),%eax
+- jmp .L523
+
+- # Return -8(%ebp) * $1000000000 + edi
++ # Calculate %eax= 10 ** %cl, where %cl <= 8
++ # With an array one could do this with:
++ # movl 10_factor_table(,%ecx,4),%eax
++ # We calculate the table here to avoid problems in
++ # position independent code (gcc -pic)
++
++ cmpb $3,%cl
++ ja .L4_to_8
++ movl $1000, %eax
++ je .Lgot_factor # %cl=3, eax= 1000
++ movl $10, %eax
++ cmpb $1,%cl # %cl is here 0 - 2
++ je .Lgot_factor # %cl=1, eax= 10
++ movl $100, %eax
++ ja .Lgot_factor # %cl=2, eax=100
++ movl $1, %eax
++ jmp .Lgot_factor # %cl=0, eax=1
++
++.L4_to_8: # %cl is here 4-8
++ cmpb $5,%cl
++ movl $100000, %eax
++ je .Lgot_factor # %cl=5, eax=100000
++ movl $10000, %eax
++ jbe .Lgot_factor # %cl=4, eax=10000
++ movl $10000000, %eax
++ cmpb $7,%cl
++ je .Lgot_factor # %cl=7, eax=10000000
++ movl $100000000, %eax
++ ja .Lgot_factor # %cl=8, eax=100000000
++ movl $1000000, %eax # %cl=6, eax=1000000
++
++ # Return -8(%ebp) * %eax + edi
+ .p2align 4,,7
+-.Lend3:
+- movl $1000000000,%eax
+-.L523:
++.Lgot_factor:
+ mull -8(%ebp)
+ addl %edi,%eax
+ adcl $0,%edx
+@@ -400,3 +416,6 @@
+ .comm end_ptr,120,32
+ .comm error,120,32
+ .ident "Monty"
++
++ .section .note.GNU-stack,"",@progbits
++
+diff -Naur mysql.orig/strings/strings-x86.s mysql.new/strings/strings-x86.s
+--- mysql.orig/strings/strings-x86.s 2005-08-08 22:39:10.000000000 +0200
++++ mysql.new/strings/strings-x86.s 2005-08-08 22:44:29.000000000 +0200
+@@ -415,3 +415,6 @@
+ ret
+ .strxmov_end:
+ .size strxmov,.strxmov_end-strxmov
++
++ .section .note.GNU-stack,"",@progbits
++
+--- mysql.orig/mysql-test/r/bigint.result 2005-08-10 23:28:13.000000000 +0200
++++ mysql.new/mysql-test/r/bigint.result 2005-08-10 23:27:41.000000000 +0200
+@@ -17,6 +17,15 @@
+ select -(0-3),round(-(0-3)), round(9999999999999999999);
+ -(0-3) round(-(0-3)) round(9999999999999999999)
+ 3 3 9999999999999999999
++select 1,11,101,1001,10001,100001,1000001,10000001,100000001,1000000001,10000000001,100000000001,1000000000001,10000000000001,100000000000001,1000000000000001,10000000000000001,100000000000000001,1000000000000000001,10000000000000000001;
++1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001
++1 11 101 1001 10001 100001 1000001 10000001 100000001 1000000001 10000000001 100000000001 1000000000001 10000000000001 100000000000001 1000000000000001 10000000000000001 100000000000000001 1000000000000000001 10000000000000000001
++select -1,-11,-101,-1001,-10001,-100001,-1000001,-10000001,-100000001,-1000000001,-10000000001,-100000000001,-1000000000001,-10000000000001,-100000000000001,-1000000000000001,-10000000000000001,-100000000000000001,-1000000000000000001,-10000000000000000000;
++-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000000
++-1 -11 -101 -1001 -10001 -100001 -1000001 -10000001 -100000001 -1000000001 -10000000001 -100000000001 -1000000000001 -10000000000001 -100000000000001 -1000000000000001 -10000000000000001 -100000000000000001 -1000000000000000001 -10000000000000000000
++select conv(1,10,16),conv((1<<2)-1,10,16),conv((1<<10)-2,10,16),conv((1<<16)-3,10,16),conv((1<<25)-4,10,16),conv((1<<31)-5,10,16),conv((1<<36)-6,10,16),conv((1<<47)-7,10,16),conv((1<<48)-8,10,16),conv((1<<55)-9,10,16),conv((1<<56)-10,10,16),conv((1<<63)-11,10,16);
++conv(1,10,16) conv((1<<2)-1,10,16) conv((1<<10)-2,10,16) conv((1<<16)-3,10,16) conv((1<<25)-4,10,16) conv((1<<31)-5,10,16) conv((1<<36)-6,10,16) conv((1<<47)-7,10,16) conv((1<<48)-8,10,16) conv((1<<55)-9,10,16) conv((1<<56)-10,10,16) conv((1<<63)-11,10,16)
++1 3 3FE FFFD 1FFFFFC 7FFFFFFB FFFFFFFFA 7FFFFFFFFFF9 FFFFFFFFFFF8 7FFFFFFFFFFFF7 FFFFFFFFFFFFF6 7FFFFFFFFFFFFFF5
+ create table t1 (a bigint unsigned not null, primary key(a));
+ insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE), (18446744073709551613), (18446744073709551612);
+ select * from t1;
diff --git a/035_x86_asm-pic-fixes-r6.patch b/035_x86_asm-pic-fixes-r6.patch
new file mode 100644
index 0000000..5430bc6
--- /dev/null
+++ b/035_x86_asm-pic-fixes-r6.patch
@@ -0,0 +1,333 @@
+###MY_VER_RANGE [5.0.11_beta,5.0.12_alpha) [5.1,5.1.2_alpha)
+
+FOLLOWING THE ORIGINAL PATCH COMMIT COMMENTS:
+
+ChangeSet
+ 1.2356 05/08/08 13:18:18 monty@mishka.local +6 -0
+ Fix for BUG #11642: [Patch]es x86 Assembler and text relocations
+ Changed assembler functions to not access global variables or variables in text segement
+ Added wrapper function in C to longlong2str() to pass _dig_vec_upper as an argument
+
+ strings/longlong2str_asm.c
+ 1.1 05/08/08 13:18:12 monty@mishka.local +33 -0
+ New BitKeeper file ``strings/longlong2str_asm.c''
+
+ strings/my_strtoll10-x86.s
+ 1.4 05/08/08 13:18:12 monty@mishka.local +39 -23
+ Removd array lfactor by calculating the value in code
+ (this is to to make the code position independent)
+
+ strings/longlong2str_asm.c
+ 1.0 05/08/08 13:18:12 monty@mishka.local +0 -0
+ BitKeeper file /home/my/mysql-4.1/strings/longlong2str_asm.c
+
+ strings/longlong2str-x86.s
+ 1.11 05/08/08 13:18:12 monty@mishka.local +18 -17
+ Changed functions to not access variables in text segment
+ Fixed this by adding global variable '_dig_vec_upper' as an argument to longlong2str_with_dig_vector()
+
+ strings/Makefile.am
+ 1.43 05/08/08 13:18:12 monty@mishka.local +2 -2
+ Added longlong2str_asm.c
+
+# mysql-test/t/bigint.test
+# 1.24 05/08/08 13:18:11 monty@mishka.local +3 -0
+# More tests for parsing of bigint's
+# More tests for different values to conv()
+#
+# mysql-test/r/bigint.result
+# 1.25 05/08/08 13:18:11 monty@mishka.local +9 -0
+# More tests for parsing of bigint's
+# More tests for different values to conv()
+
+REAPPLIED PATCH FROM HERE:
+PLUS ".section .note.GNU-stack,"",@progbits"
+
+diff -Naur mysql.orig/strings/Makefile.am mysql.new/strings/Makefile.am
+--- mysql.orig/strings/Makefile.am 2005-08-08 22:57:13.000000000 +0200
++++ mysql.new/strings/Makefile.am 2005-08-08 22:57:45.000000000 +0200
+@@ -22,7 +22,7 @@
+ # Exact one of ASSEMBLER_X
+ if ASSEMBLER_x86
+ ASRCS = strings-x86.s longlong2str-x86.s my_strtoll10-x86.s
+-CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c str_alloc.c
++CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c decimal.c ctype-extra.c str_alloc.c longlong2str_asm.c
+ else
+ if ASSEMBLER_sparc32
+ # These file MUST all be on the same line!! Otherwise automake
+@@ -45,7 +45,7 @@
+ ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-utf8.c \
+ ctype-ucs2.c ctype-uca.c ctype-tis620.c ctype-ujis.c \
+ xml.c decimal.c strto.c strings-x86.s \
+- longlong2str.c longlong2str-x86.s \
++ longlong2str.c longlong2str-x86.s longlong2str_asm.c \
+ my_strtoll10.c my_strtoll10-x86.s \
+ strxmov.c bmove_upp.c strappend.c strcont.c strend.c \
+ strfill.c strcend.c is_prefix.c strstr.c strinstr.c \
+diff -Naur mysql.orig/strings/longlong2str-x86.s mysql.new/strings/longlong2str-x86.s
+--- mysql.orig/strings/longlong2str-x86.s 2005-08-08 22:57:13.000000000 +0200
++++ mysql.new/strings/longlong2str-x86.s 2005-08-08 22:58:23.000000000 +0200
+@@ -16,26 +16,26 @@
+ # Optimized longlong2str function for Intel 80x86 (gcc/gas syntax)
+ # Some set sequences are optimized for pentuimpro II
+
+- .file "longlong2str.s"
+- .version "1.01"
++ .file "longlong2str-x86.s"
++ .version "1.02"
+
+ .text
+ .align 4
+
+-.globl longlong2str
+- .type longlong2str,@function
++.globl longlong2str_with_dig_vector
++ .type longlong2str_with_dig_vector,@function
+
+-longlong2str:
++longlong2str_with_dig_vector:
+ subl $80,%esp
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 100(%esp),%esi # Lower part of val
+- movl 104(%esp),%ebp # Higher part of val
+- movl 108(%esp),%edi # get dst
+ movl 112(%esp),%ebx # Radix
++ movl 104(%esp),%ebp # Higher part of val
+ movl %ebx,%eax
++ movl 108(%esp),%edi # get dst
+ testl %eax,%eax
+ jge .L144
+
+@@ -69,6 +69,8 @@
+
+ .L150:
+ leal 92(%esp),%ecx # End of buffer
++ movl %edi, 108(%esp) # Store possible modified dest
++ movl 116(%esp), %edi # dig_vec_upper
+ jmp .L155
+ .align 4
+
+@@ -83,7 +85,7 @@
+ divl %ebx
+ decl %ecx
+ movl %eax,%esi # quotent in ebp:esi
+- movb _dig_vec_upper(%edx),%al # al is faster than dl
++ movb (%edx,%edi),%al # al is faster than dl
+ movb %al,(%ecx) # store value in buff
+ .align 4
+ .L155:
+@@ -91,20 +93,22 @@
+ ja .L153
+ testl %esi,%esi # rest value
+ jl .L153
+- je .L10_mov # Ready
++ je .L160 # Ready
+ movl %esi,%eax
+- movl $_dig_vec_upper,%ebp
+ .align 4
+
+ .L154: # Do rest with integer precision
+ cltd
+ divl %ebx
+ decl %ecx
+- movb (%edx,%ebp),%dl # bh is always zero as ebx=radix < 36
++ movb (%edx,%edi),%dl # bh is always zero as ebx=radix < 36
+ testl %eax,%eax
+ movb %dl,(%ecx)
+ jne .L154
+
++.L160:
++ movl 108(%esp),%edi # get dst
++
+ .L10_mov:
+ movl %ecx,%esi
+ leal 92(%esp),%ecx # End of buffer
+@@ -129,7 +133,7 @@
+ jmp .L165
+
+ .Lfe3:
+- .size longlong2str,.Lfe3-longlong2str
++ .size longlong2str_with_dig_vector,.Lfe3-longlong2str_with_dig_vector
+
+ #
+ # This is almost equal to the above, except that we can do the final
+@@ -137,9 +141,6 @@
+ #
+
+ .align 4
+-.Ltmp:
+- .long 0xcccccccd
+- .align 4
+
+ .globl longlong10_to_str
+ .type longlong10_to_str,@function
+@@ -202,8 +203,8 @@
+
+ # The following code uses some tricks to change division by 10 to
+ # multiplication and shifts
+- movl .Ltmp,%esi # set %esi to 0xcccccccd
+-
++ movl $0xcccccccd,%esi
++
+ .L10_40:
+ movl %ebx,%eax
+ mull %esi
+@@ -221,3 +222,6 @@
+
+ .L10end:
+ .size longlong10_to_str,.L10end-longlong10_to_str
++
++ .section .note.GNU-stack,"",@progbits
++
+diff -Naur mysql.orig/strings/longlong2str_asm.c mysql.new/strings/longlong2str_asm.c
+--- mysql.orig/strings/longlong2str_asm.c 1970-01-01 01:00:00.000000000 +0100
++++ mysql.new/strings/longlong2str_asm.c 2005-08-08 22:57:17.000000000 +0200
+@@ -0,0 +1,34 @@
++/* Copyright (C) 2000 MySQL AB
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program 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 should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++/*
++ * Wrapper for longlong2str.s
++ *
++ * We need this because the assembler code can't access the local variable
++ * _dig_vector in a portable manner.
++ */
++
++#include <my_global.h>
++#include "m_string.h"
++
++extern char *longlong2str_with_dig_vector(longlong val,char *dst,int radix,
++ const char *dig_vector);
++
++char *longlong2str(longlong val,char *dst,int radix)
++{
++ return longlong2str_with_dig_vector(val, dst, radix, _dig_vec_upper);
++}
++
+diff -Naur mysql.orig/strings/my_strtoll10-x86.s mysql.new/strings/my_strtoll10-x86.s
+--- mysql.orig/strings/my_strtoll10-x86.s 2005-08-08 22:57:13.000000000 +0200
++++ mysql.new/strings/my_strtoll10-x86.s 2005-08-08 22:58:30.000000000 +0200
+@@ -17,21 +17,8 @@
+ # For documentation, check my_strtoll.c
+
+ .file "my_strtoll10-x86.s"
+- .version "01.01"
+-.data
+- .align 32
+- .type lfactor,@object
+- .size lfactor,36
+-lfactor:
+- .long 1
+- .long 10
+- .long 100
+- .long 1000
+- .long 10000
+- .long 100000
+- .long 1000000
+- .long 10000000
+- .long 100000000
++ .version "01.02"
++
+ .text
+ .align 4
+
+@@ -209,14 +196,16 @@
+ jne .L500
+ cmpl -36(%ebp),%esi # Test if string is less than 18 digits
+ jne .Lend_i_and_j
+- jmp .Lend3 # 18 digit string
++.L499:
++ movl $1000000000,%eax
++ jmp .Lgot_factor # 18 digit string
+
+ # Handle the possible next to last digit and store in ecx
+ .L500:
+ movb (%esi),%al
+ addb $-48,%al
+ cmpb $9,%al
+- ja .Lend3
++ ja .L499 # 18 digit string
+
+ incl %esi
+ movzbl %al,%ecx
+@@ -315,14 +304,41 @@
+ .Lend_i_and_j:
+ movl %esi,%ecx
+ subl -12(%ebp),%ecx # ecx= number of digits in second part
+- movl lfactor(,%ecx,4),%eax
+- jmp .L523
+
+- # Return -8(%ebp) * $1000000000 + edi
++ # Calculate %eax= 10 ** %cl, where %cl <= 8
++ # With an array one could do this with:
++ # movl 10_factor_table(,%ecx,4),%eax
++ # We calculate the table here to avoid problems in
++ # position independent code (gcc -pic)
++
++ cmpb $3,%cl
++ ja .L4_to_8
++ movl $1000, %eax
++ je .Lgot_factor # %cl=3, eax= 1000
++ movl $10, %eax
++ cmpb $1,%cl # %cl is here 0 - 2
++ je .Lgot_factor # %cl=1, eax= 10
++ movl $100, %eax
++ ja .Lgot_factor # %cl=2, eax=100
++ movl $1, %eax
++ jmp .Lgot_factor # %cl=0, eax=1
++
++.L4_to_8: # %cl is here 4-8
++ cmpb $5,%cl
++ movl $100000, %eax
++ je .Lgot_factor # %cl=5, eax=100000
++ movl $10000, %eax
++ jbe .Lgot_factor # %cl=4, eax=10000
++ movl $10000000, %eax
++ cmpb $7,%cl
++ je .Lgot_factor # %cl=7, eax=10000000
++ movl $100000000, %eax
++ ja .Lgot_factor # %cl=8, eax=100000000
++ movl $1000000, %eax # %cl=6, eax=1000000
++
++ # Return -8(%ebp) * %eax + edi
+ .p2align 4,,7
+-.Lend3:
+- movl $1000000000,%eax
+-.L523:
++.Lgot_factor:
+ mull -8(%ebp)
+ addl %edi,%eax
+ adcl $0,%edx
+@@ -400,3 +416,6 @@
+ .comm end_ptr,120,32
+ .comm error,120,32
+ .ident "Monty"
++
++ .section .note.GNU-stack,"",@progbits
++
+diff -Naur mysql.orig/strings/strings-x86.s mysql.new/strings/strings-x86.s
+--- mysql.orig/strings/strings-x86.s 2005-08-08 22:57:13.000000000 +0200
++++ mysql.new/strings/strings-x86.s 2005-08-08 22:58:40.000000000 +0200
+@@ -415,3 +415,6 @@
+ ret
+ .strxmov_end:
+ .size strxmov,.strxmov_end-strxmov
++
++ .section .note.GNU-stack,"",@progbits
++
diff --git a/035_x86_asm-pic-fixes-r7.patch b/035_x86_asm-pic-fixes-r7.patch
new file mode 100644
index 0000000..d7d2b58
--- /dev/null
+++ b/035_x86_asm-pic-fixes-r7.patch
@@ -0,0 +1,32 @@
+###MY_VER_RANGE [5.0.12_beta,5.0.12_beta]
+
+diff -Naur mysql.old/strings/longlong2str-x86.s mysql.new/strings/longlong2str-x86.s
+--- mysql.old/strings/longlong2str-x86.s 2005-08-27 22:33:11.000000000 +0200
++++ mysql.new/strings/longlong2str-x86.s 2005-09-05 18:46:04.000000000 +0200
+@@ -222,3 +222,6 @@
+
+ .L10end:
+ .size longlong10_to_str,.L10end-longlong10_to_str
++
++ .section .note.GNU-stack,"",@progbits
++
+diff -Naur mysql.old/strings/my_strtoll10-x86.s mysql.new/strings/my_strtoll10-x86.s
+--- mysql.old/strings/my_strtoll10-x86.s 2005-08-27 22:33:19.000000000 +0200
++++ mysql.new/strings/my_strtoll10-x86.s 2005-09-05 18:46:10.000000000 +0200
+@@ -416,3 +416,6 @@
+ .comm end_ptr,120,32
+ .comm error,120,32
+ .ident "Monty"
++
++ .section .note.GNU-stack,"",@progbits
++
+diff -Naur mysql.old/strings/strings-x86.s mysql.new/strings/strings-x86.s
+--- mysql.old/strings/strings-x86.s 2005-08-27 22:33:36.000000000 +0200
++++ mysql.new/strings/strings-x86.s 2005-09-05 18:46:22.000000000 +0200
+@@ -415,3 +415,6 @@
+ ret
+ .strxmov_end:
+ .size strxmov,.strxmov_end-strxmov
++
++ .section .note.GNU-stack,"",@progbits
++
diff --git a/040_all_tcpd-vars-fix-r1.patch b/040_all_tcpd-vars-fix-r1.patch
new file mode 100644
index 0000000..20a3798
--- /dev/null
+++ b/040_all_tcpd-vars-fix-r1.patch
@@ -0,0 +1,14 @@
+###MY_VER_RANGE [5.0.11_beta,)
+--- mysql-old/sql/mysqld.cc 2005-08-06 03:39:41.000000000 +0200
++++ mysql-new/sql/mysqld.cc 2005-08-30 23:40:44.000000000 +0200
+@@ -126,8 +126,8 @@
+ #ifdef NEED_SYS_SYSLOG_H
+ #include <sys/syslog.h>
+ #endif /* NEED_SYS_SYSLOG_H */
+-int allow_severity = LOG_INFO;
+-int deny_severity = LOG_WARNING;
++//int allow_severity = LOG_INFO;
++//int deny_severity = LOG_WARNING;
+
+ #endif /* HAVE_LIBWRAP */
+
diff --git a/040_all_tcpd-vars-fix.patch b/040_all_tcpd-vars-fix.patch
new file mode 100644
index 0000000..156e368
--- /dev/null
+++ b/040_all_tcpd-vars-fix.patch
@@ -0,0 +1,14 @@
+###MY_VER_RANGE [4.0.14-r1,5.0_alpha]
+--- mysql-4.1.8/sql/mysqld.cc 2004-12-14 13:40:36.000000000 +0100
++++ bbb/sql/mysqld.cc 2005-01-09 17:57:47.829022200 +0100
+@@ -133,8 +133,8 @@
+ #ifdef NEED_SYS_SYSLOG_H
+ #include <sys/syslog.h>
+ #endif /* NEED_SYS_SYSLOG_H */
+-int allow_severity = LOG_INFO;
+-int deny_severity = LOG_WARNING;
++//int allow_severity = LOG_INFO;
++//int deny_severity = LOG_WARNING;
+
+ #ifdef __STDC__
+ #define my_fromhost(A) fromhost(A)
diff --git a/050_all_mysql-create_system_tables.patch b/050_all_mysql-create_system_tables.patch
new file mode 100644
index 0000000..9440c77
--- /dev/null
+++ b/050_all_mysql-create_system_tables.patch
@@ -0,0 +1,12 @@
+###MY_VER_RANGE [5.0_alpha,5.0.10_beta)
+--- mysql.old/scripts/mysql_create_system_tables.sh 2005-04-19 12:08:40.000000000 +0200
++++ mysql-5.0.4-beta/scripts/mysql_create_system_tables.sh 2005-04-19 12:09:18.000000000 +0200
+@@ -714,7 +714,7 @@
+ c_p="$c_p 'TRADITIONAL',"
+ c_p="$c_p 'NO_AUTO_CREATE_USER',"
+ c_p="$c_p 'HIGH_NOT_PRECEDENCE'"
+- c_p="$c_p ) DEFAULT 0 NOT NULL,"
++ c_p="$c_p ) DEFAULT '' NOT NULL,"
+ c_p="$c_p comment char(64) binary DEFAULT '' NOT NULL,"
+ c_p="$c_p PRIMARY KEY (db,name,type)"
+ c_p="$c_p ) comment='Stored Procedures';"
diff --git a/060_all_myxml_by_Alexander_Barkov.patch b/060_all_myxml_by_Alexander_Barkov.patch
new file mode 100644
index 0000000..3dffe00
--- /dev/null
+++ b/060_all_myxml_by_Alexander_Barkov.patch
@@ -0,0 +1,6170 @@
+###MY_VER_RANGE [5.0.6_beta,)
+###MY_USE_FLAG barkov-xml
+diff -Naur mysql.orig/include/my_xml.h mysql.xml/include/my_xml.h
+--- mysql.orig/include/my_xml.h 2005-05-15 06:16:51.000000000 +0200
++++ mysql.xml/include/my_xml.h 2005-05-20 15:19:29.000000000 +0200
+@@ -26,8 +26,31 @@
+ #define MY_XML_OK 0
+ #define MY_XML_ERROR 1
+
++/*
++ A flag whether to use absolute tag names in call-back functions,
++ like "a", "a.b" and "a.b.c" (used in character set file parser),
++ or relative names like "a", "b" and "c".
++*/
++#define MY_XML_FLAG_RELATIVE_NAMES 1
++
++/*
++ A flag whether to skip normilization of text values before calling
++ call-back functions: i.e. skip leading/trailing spaces,
++ \r, \n, \t characters.
++*/
++#define MY_XML_FLAG_SKIP_TEXT_NORMALIZATION 2
++
++enum my_xml_node_type
++{
++ MY_XML_NODE_TAG, /* can have TAG, ATTR and TEXT children */
++ MY_XML_NODE_ATTR, /* can have TEXT children */
++ MY_XML_NODE_TEXT /* cannot have children */
++};
++
+ typedef struct xml_stack_st
+ {
++ int flags;
++ enum my_xml_node_type current_node_type;
+ char errstr[128];
+ char attr[128];
+ char *attrend;
+diff -Naur mysql.orig/mysql-test/r/xml.result mysql.xml/mysql-test/r/xml.result
+--- mysql.orig/mysql-test/r/xml.result 1970-01-01 01:00:00.000000000 +0100
++++ mysql.xml/mysql-test/r/xml.result 2005-04-13 09:17:23.000000000 +0200
+@@ -0,0 +1,522 @@
++SET @xml='<a aa1="aa1" aa2="aa2">a1<b ba1="ba1">b1<c>c1</c>b2</b>a2</a>';
++SELECT extractValue(@xml,'/a');
++extractValue(@xml,'/a')
++a1 a2
++SELECT extractValue(@xml,'/a/b');
++extractValue(@xml,'/a/b')
++b1 b2
++SELECT extractValue(@xml,'/a/b/c');
++extractValue(@xml,'/a/b/c')
++c1
++SELECT extractValue(@xml,'/a/@aa1');
++extractValue(@xml,'/a/@aa1')
++aa1
++SELECT extractValue(@xml,'/a/@aa2');
++extractValue(@xml,'/a/@aa2')
++aa2
++SELECT extractValue(@xml,'/a/@*');
++extractValue(@xml,'/a/@*')
++aa1 aa2
++SELECT extractValue(@xml,'//@ba1');
++extractValue(@xml,'//@ba1')
++ba1
++SELECT extractValue(@xml,'//a');
++extractValue(@xml,'//a')
++a1 a2
++SELECT extractValue(@xml,'//b');
++extractValue(@xml,'//b')
++b1 b2
++SELECT extractValue(@xml,'//c');
++extractValue(@xml,'//c')
++c1
++SELECT extractValue(@xml,'/a//b');
++extractValue(@xml,'/a//b')
++b1 b2
++SELECT extractValue(@xml,'/a//c');
++extractValue(@xml,'/a//c')
++c1
++SELECT extractValue(@xml,'//*');
++extractValue(@xml,'//*')
++a1 b1 c1 b2 a2
++SELECT extractValue(@xml,'/a//*');
++extractValue(@xml,'/a//*')
++b1 c1 b2
++SELECT extractValue(@xml,'/./a');
++extractValue(@xml,'/./a')
++a1 a2
++SELECT extractValue(@xml,'/a/b/.');
++extractValue(@xml,'/a/b/.')
++b1 b2
++SELECT extractValue(@xml,'/a/b/..');
++extractValue(@xml,'/a/b/..')
++a1 a2
++SELECT extractValue(@xml,'/a/b/../@aa1');
++extractValue(@xml,'/a/b/../@aa1')
++aa1
++SELECT extractValue(@xml,'/*');
++extractValue(@xml,'/*')
++a1 a2
++SELECT extractValue(@xml,'/*/*');
++extractValue(@xml,'/*/*')
++b1 b2
++SELECT extractValue(@xml,'/*/*/*');
++extractValue(@xml,'/*/*/*')
++c1
++SELECT extractValue(@xml,'/a/child::*');
++extractValue(@xml,'/a/child::*')
++b1 b2
++SELECT extractValue(@xml,'/a/descendant::*');
++extractValue(@xml,'/a/descendant::*')
++b1 c1 b2
++SELECT extractValue(@xml,'/a/descendant-or-self::*');
++extractValue(@xml,'/a/descendant-or-self::*')
++a1 b1 c1 b2 a2
++SELECT extractValue(@xml,'/a/attribute::*');
++extractValue(@xml,'/a/attribute::*')
++aa1 aa2
++SELECT extractValue(@xml,'/a/b/c/parent::*');
++extractValue(@xml,'/a/b/c/parent::*')
++b1 b2
++SELECT extractValue(@xml,'/a/b/c/ancestor::*');
++extractValue(@xml,'/a/b/c/ancestor::*')
++a1 b1 b2 a2
++SELECT extractValue(@xml,'/a/b/c/ancestor-or-self::*');
++extractValue(@xml,'/a/b/c/ancestor-or-self::*')
++a1 b1 c1 b2 a2
++SELECT extractValue(@xml,'/descendant-or-self::*');
++extractValue(@xml,'/descendant-or-self::*')
++a1 b1 c1 b2 a2
++SET @xml='<a>a11<b ba="ba11" ba="ba12">b11</b><b ba="ba21" ba="ba22">b21<c>c1</c>b22</b>a12</a>';
++SELECT extractValue(@xml,'/a/b/c/ancestor-or-self::*');
++extractValue(@xml,'/a/b/c/ancestor-or-self::*')
++a11 b21 c1 b22 a12
++SELECT extractValue(@xml,'//@ba');
++extractValue(@xml,'//@ba')
++ba11 ba12 ba21 ba22
++SET @xml='<a><b>b</b><c>c</c></a>';
++SELECT extractValue(@xml,'/a/b');
++extractValue(@xml,'/a/b')
++b
++SELECT extractValue(@xml,'/a/c');
++extractValue(@xml,'/a/c')
++c
++SELECT extractValue(@xml,'/a/child::b');
++extractValue(@xml,'/a/child::b')
++b
++SELECT extractValue(@xml,'/a/child::c');
++extractValue(@xml,'/a/child::c')
++c
++SET @xml='<a><b>b1</b><c>c1</c><b>b2</b><c>c2</c></a>';
++SELECT extractValue(@xml,'/a/b[1]');
++extractValue(@xml,'/a/b[1]')
++b1
++SELECT extractValue(@xml,'/a/b[2]');
++extractValue(@xml,'/a/b[2]')
++b2
++SELECT extractValue(@xml,'/a/c[1]');
++extractValue(@xml,'/a/c[1]')
++c1
++SELECT extractValue(@xml,'/a/c[2]');
++extractValue(@xml,'/a/c[2]')
++c2
++SET @xml='<a><b x="xb1" x="xb2"/><c x="xc1" x="xc2"/></a>';
++SELECT extractValue(@xml,'/a//@x');
++extractValue(@xml,'/a//@x')
++xb1 xb2 xc1 xc2
++SELECT extractValue(@xml,'/a//@x[1]');
++extractValue(@xml,'/a//@x[1]')
++xb1 xc1
++SELECT extractValue(@xml,'/a//@x[2]');
++extractValue(@xml,'/a//@x[2]')
++xb2 xc2
++SET @xml='<a><b>b1</b><b>b2</b><c><b>c1b1</b><b>c1b2</b></c><c><b>c2b1</c></b>/a>';
++SELECT extractValue(@xml,'//b[1]');
++extractValue(@xml,'//b[1]')
++b1 c1b1 c2b1
++SELECT extractValue(@xml,'/descendant::b[1]');
++extractValue(@xml,'/descendant::b[1]')
++b1
++SET @xml='<a><b>b1</b><b>b2</b></a>';
++SELECT extractValue(@xml,'/a/b[1+0]');
++extractValue(@xml,'/a/b[1+0]')
++b1
++SELECT extractValue(@xml,'/a/b[1*1]');
++extractValue(@xml,'/a/b[1*1]')
++b1
++SELECT extractValue(@xml,'/a/b[--1]');
++extractValue(@xml,'/a/b[--1]')
++b1
++SELECT extractValue(@xml,'/a/b[2*1-1]');
++extractValue(@xml,'/a/b[2*1-1]')
++b1
++SELECT extractValue(@xml,'/a/b[1+1]');
++extractValue(@xml,'/a/b[1+1]')
++b2
++SELECT extractValue(@xml,'/a/b[1*2]');
++extractValue(@xml,'/a/b[1*2]')
++b2
++SELECT extractValue(@xml,'/a/b[--2]');
++extractValue(@xml,'/a/b[--2]')
++b2
++SELECT extractValue(@xml,'/a/b[1*(3-1)]');
++extractValue(@xml,'/a/b[1*(3-1)]')
++b2
++SELECT extractValue(@xml,'//*[1=1]');
++extractValue(@xml,'//*[1=1]')
++b1 b2
++SELECT extractValue(@xml,'//*[1!=1]');
++extractValue(@xml,'//*[1!=1]')
++
++SELECT extractValue(@xml,'//*[1>1]');
++extractValue(@xml,'//*[1>1]')
++
++SELECT extractValue(@xml,'//*[2>1]');
++extractValue(@xml,'//*[2>1]')
++b1 b2
++SELECT extractValue(@xml,'//*[1>2]');
++extractValue(@xml,'//*[1>2]')
++
++SELECT extractValue(@xml,'//*[1>=1]');
++extractValue(@xml,'//*[1>=1]')
++b1 b2
++SELECT extractValue(@xml,'//*[2>=1]');
++extractValue(@xml,'//*[2>=1]')
++b1 b2
++SELECT extractValue(@xml,'//*[1>=2]');
++extractValue(@xml,'//*[1>=2]')
++
++SELECT extractValue(@xml,'//*[1<1]');
++extractValue(@xml,'//*[1<1]')
++
++SELECT extractValue(@xml,'//*[2<1]');
++extractValue(@xml,'//*[2<1]')
++
++SELECT extractValue(@xml,'//*[1<2]');
++extractValue(@xml,'//*[1<2]')
++b1 b2
++SELECT extractValue(@xml,'//*[1<=1]');
++extractValue(@xml,'//*[1<=1]')
++b1 b2
++SELECT extractValue(@xml,'//*[2<=1]');
++extractValue(@xml,'//*[2<=1]')
++
++SELECT extractValue(@xml,'//*[1<=2]');
++extractValue(@xml,'//*[1<=2]')
++b1 b2
++SET @xml='<a><b>b11<c>c11</c></b><b>b21<c>c21</c></b></a>';
++SELECT extractValue(@xml,'/a/b[c="c11"]');
++extractValue(@xml,'/a/b[c="c11"]')
++b11
++SELECT extractValue(@xml,'/a/b[c="c21"]');
++extractValue(@xml,'/a/b[c="c21"]')
++b21
++SET @xml='<a><b c="c11">b11</b><b c="c21">b21</b></a>';
++SELECT extractValue(@xml,'/a/b[@c="c11"]');
++extractValue(@xml,'/a/b[@c="c11"]')
++b11
++SELECT extractValue(@xml,'/a/b[@c="c21"]');
++extractValue(@xml,'/a/b[@c="c21"]')
++b21
++SET @xml='<a>a1<b c="c11">b11<d>d11</d></b><b c="c21">b21<d>d21</d></b></a>';
++SELECT extractValue(@xml, '/a/b[@c="c11"]/d');
++extractValue(@xml, '/a/b[@c="c11"]/d')
++d11
++SELECT extractValue(@xml, '/a/b[@c="c21"]/d');
++extractValue(@xml, '/a/b[@c="c21"]/d')
++d21
++SELECT extractValue(@xml, '/a/b[d="d11"]/@c');
++extractValue(@xml, '/a/b[d="d11"]/@c')
++c11
++SELECT extractValue(@xml, '/a/b[d="d21"]/@c');
++extractValue(@xml, '/a/b[d="d21"]/@c')
++c21
++SELECT extractValue(@xml, '/a[b="b11"]');
++extractValue(@xml, '/a[b="b11"]')
++a1
++SELECT extractValue(@xml, '/a[b/@c="c11"]');
++extractValue(@xml, '/a[b/@c="c11"]')
++a1
++SELECT extractValue(@xml, '/a[b/d="d11"]');
++extractValue(@xml, '/a[b/d="d11"]')
++a1
++SELECT extractValue(@xml, '/a[/a/b="b11"]');
++extractValue(@xml, '/a[/a/b="b11"]')
++a1
++SELECT extractValue(@xml, '/a[/a/b/@c="c11"]');
++extractValue(@xml, '/a[/a/b/@c="c11"]')
++a1
++SELECT extractValue(@xml, '/a[/a/b/d="d11"]');
++extractValue(@xml, '/a[/a/b/d="d11"]')
++a1
++SELECT extractValue('<a>a</a>', '/a[false()]');
++extractValue('<a>a</a>', '/a[false()]')
++
++SELECT extractValue('<a>a</a>', '/a[true()]');
++extractValue('<a>a</a>', '/a[true()]')
++a
++SELECT extractValue('<a>a</a>', '/a[not(false())]');
++extractValue('<a>a</a>', '/a[not(false())]')
++a
++SELECT extractValue('<a>a</a>', '/a[not(true())]');
++extractValue('<a>a</a>', '/a[not(true())]')
++
++SELECT extractValue('<a>a</a>', '/a[true() and true()]');
++extractValue('<a>a</a>', '/a[true() and true()]')
++a
++SELECT extractValue('<a>a</a>', '/a[true() and false()]');
++extractValue('<a>a</a>', '/a[true() and false()]')
++
++SELECT extractValue('<a>a</a>', '/a[false()and false()]');
++extractValue('<a>a</a>', '/a[false()and false()]')
++
++SELECT extractValue('<a>a</a>', '/a[false()and true()]');
++extractValue('<a>a</a>', '/a[false()and true()]')
++
++SELECT extractValue('<a>a</a>', '/a[true() or true()]');
++extractValue('<a>a</a>', '/a[true() or true()]')
++a
++SELECT extractValue('<a>a</a>', '/a[true() or false()]');
++extractValue('<a>a</a>', '/a[true() or false()]')
++a
++SELECT extractValue('<a>a</a>', '/a[false()or false()]');
++extractValue('<a>a</a>', '/a[false()or false()]')
++
++SELECT extractValue('<a>a</a>', '/a[false()or true()]');
++extractValue('<a>a</a>', '/a[false()or true()]')
++a
++SET @xml='<a>ab<b c="c" c="e">b1</b><b c="d">b2</b><b c="f" c="e">b3</b></a>';
++select extractValue(@xml,'/a/b[@c="c"]');
++extractValue(@xml,'/a/b[@c="c"]')
++b1
++select extractValue(@xml,'/a/b[@c="d"]');
++extractValue(@xml,'/a/b[@c="d"]')
++b2
++select extractValue(@xml,'/a/b[@c="e"]');
++extractValue(@xml,'/a/b[@c="e"]')
++b1 b3
++select extractValue(@xml,'/a/b[not(@c="e")]');
++extractValue(@xml,'/a/b[not(@c="e")]')
++b2
++select extractValue(@xml,'/a/b[@c!="e"]');
++extractValue(@xml,'/a/b[@c!="e"]')
++b1 b2 b3
++select extractValue(@xml,'/a/b[@c="c" or @c="d"]');
++extractValue(@xml,'/a/b[@c="c" or @c="d"]')
++b1 b2
++select extractValue(@xml,'/a/b[@c="c" and @c="e"]');
++extractValue(@xml,'/a/b[@c="c" and @c="e"]')
++b1
++SET @xml='<a><b c="c" d="d">b1</b><b d="d" e="e">b2</b></a>';
++select extractValue(@xml,'/a/b[@c]');
++extractValue(@xml,'/a/b[@c]')
++b1
++select extractValue(@xml,'/a/b[@d]');
++extractValue(@xml,'/a/b[@d]')
++b1 b2
++select extractValue(@xml,'/a/b[@e]');
++extractValue(@xml,'/a/b[@e]')
++b2
++select extractValue(@xml,'/a/b[not(@c)]');
++extractValue(@xml,'/a/b[not(@c)]')
++b2
++select extractValue(@xml,'/a/b[not(@d)]');
++extractValue(@xml,'/a/b[not(@d)]')
++
++select extractValue(@xml,'/a/b[not(@e)]');
++extractValue(@xml,'/a/b[not(@e)]')
++b1
++select extractValue(@xml, '/a/b[boolean(@c) or boolean(@d)]');
++extractValue(@xml, '/a/b[boolean(@c) or boolean(@d)]')
++b1 b2
++select extractValue(@xml, '/a/b[boolean(@c) or boolean(@e)]');
++extractValue(@xml, '/a/b[boolean(@c) or boolean(@e)]')
++b1 b2
++select extractValue(@xml, '/a/b[boolean(@d) or boolean(@e)]');
++extractValue(@xml, '/a/b[boolean(@d) or boolean(@e)]')
++b1 b2
++select extractValue(@xml, '/a/b[boolean(@c) and boolean(@d)]');
++extractValue(@xml, '/a/b[boolean(@c) and boolean(@d)]')
++b1
++select extractValue(@xml, '/a/b[boolean(@c) and boolean(@e)]');
++extractValue(@xml, '/a/b[boolean(@c) and boolean(@e)]')
++
++select extractValue(@xml, '/a/b[boolean(@d) and boolean(@e)]');
++extractValue(@xml, '/a/b[boolean(@d) and boolean(@e)]')
++b2
++select extractValue(@xml, '/a/b[@c or @d]');
++extractValue(@xml, '/a/b[@c or @d]')
++b1 b2
++select extractValue(@xml, '/a/b[@c or @e]');
++extractValue(@xml, '/a/b[@c or @e]')
++b1 b2
++select extractValue(@xml, '/a/b[@d or @e]');
++extractValue(@xml, '/a/b[@d or @e]')
++b1 b2
++select extractValue(@xml, '/a/b[@c and @d]');
++extractValue(@xml, '/a/b[@c and @d]')
++b1
++select extractValue(@xml, '/a/b[@c and @e]');
++extractValue(@xml, '/a/b[@c and @e]')
++
++select extractValue(@xml, '/a/b[@d and @e]');
++extractValue(@xml, '/a/b[@d and @e]')
++b2
++SET @xml='<a><b c="c">b1</b><b>b2</b></a>';
++SELECT extractValue(@xml,'/a/b[@*]');
++extractValue(@xml,'/a/b[@*]')
++b1
++SELECT extractValue(@xml,'/a/b[not(@*)]');
++extractValue(@xml,'/a/b[not(@*)]')
++b2
++SELECT extractValue('<a>a</a>', '/a[ceiling(3.1)=4]');
++extractValue('<a>a</a>', '/a[ceiling(3.1)=4]')
++a
++SELECT extractValue('<a>a</a>', '/a[floor(3.1)=3]');
++extractValue('<a>a</a>', '/a[floor(3.1)=3]')
++a
++SELECT extractValue('<a>a</a>', '/a[round(3.1)=3]');
++extractValue('<a>a</a>', '/a[round(3.1)=3]')
++a
++SELECT extractValue('<a>a</a>', '/a[round(3.8)=4]');
++extractValue('<a>a</a>', '/a[round(3.8)=4]')
++a
++SELECT extractValue('<a><b>b</b><c>c</c></a>', '/a/b | /a/c');
++extractValue('<a><b>b</b><c>c</c></a>', '/a/b | /a/c')
++b c
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=1]');
++extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=1]')
++b1
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=2]');
++extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=2]')
++b2
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3]');
++extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3]')
++b3
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[1=position()]');
++extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[1=position()]')
++b1
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2=position()]');
++extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2=position()]')
++b2
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[3=position()]');
++extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[3=position()]')
++b3
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2>=position()]');
++extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2>=position()]')
++b1 b2
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2<=position()]');
++extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2<=position()]')
++b2 b3
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3 or position()=2]');
++extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3 or position()=2]')
++b2 b3
++SELECT extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=0]');
++extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=0]')
++a2
++SELECT extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=1]');
++extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=1]')
++a1
++select extractValue('<a>a1<b ba="1" ba="2">b1</b><b>b2</b>4</a>','/a/b[sum(@ba)=3]');
++extractValue('<a>a1<b ba="1" ba="2">b1</b><b>b2</b>4</a>','/a/b[sum(@ba)=3]')
++b1
++select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[1]');
++extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[1]')
++b1
++select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[boolean(1)]');
++extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[boolean(1)]')
++b1 b2
++select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[true()]');
++extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[true()]')
++b1 b2
++select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[number(true())]');
++extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[number(true())]')
++b1
++select extractValue('<a>ab</a>','/a[contains("abc","b")]');
++extractValue('<a>ab</a>','/a[contains("abc","b")]')
++ab
++select extractValue('<a>ab</a>','/a[contains(.,"a")]');
++extractValue('<a>ab</a>','/a[contains(.,"a")]')
++ab
++select extractValue('<a>ab</a>','/a[contains(.,"b")]');
++extractValue('<a>ab</a>','/a[contains(.,"b")]')
++ab
++select extractValue('<a>ab</a>','/a[contains(.,"c")]');
++extractValue('<a>ab</a>','/a[contains(.,"c")]')
++
++select extractValue('<a b="1">ab</a>','/a[concat(@b,"2")="12"]');
++extractValue('<a b="1">ab</a>','/a[concat(@b,"2")="12"]')
++ab
++SET @xml='<a b="11" b="12" b="21" b="22">ab</a>';
++select extractValue(@xml, '/a/@b[substring(.,2)="1"]');
++extractValue(@xml, '/a/@b[substring(.,2)="1"]')
++11 21
++select extractValue(@xml, '/a/@b[substring(.,2)="2"]');
++extractValue(@xml, '/a/@b[substring(.,2)="2"]')
++12 22
++select extractValue(@xml, '/a/@b[substring(.,1,1)="1"]');
++extractValue(@xml, '/a/@b[substring(.,1,1)="1"]')
++11 12
++select extractValue(@xml, '/a/@b[substring(.,1,1)="2"]');
++extractValue(@xml, '/a/@b[substring(.,1,1)="2"]')
++21 22
++select extractValue(@xml, '/a/@b[substring(.,2,1)="1"]');
++extractValue(@xml, '/a/@b[substring(.,2,1)="1"]')
++11 21
++select extractValue(@xml, '/a/@b[substring(.,2,1)="2"]');
++extractValue(@xml, '/a/@b[substring(.,2,1)="2"]')
++12 22
++SET @xml='<a b="b11" b="b12" b="b21" b="22"/>';
++select extractValue(@xml,'/a/@b');
++extractValue(@xml,'/a/@b')
++b11 b12 b21 22
++select extractValue(@xml,'/a/@b[contains(.,"1")]');
++extractValue(@xml,'/a/@b[contains(.,"1")]')
++b11 b12 b21
++select extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")]');
++extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")]')
++b12 b21
++select extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")][2]');
++extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")][2]')
++b21
++SET @xml='<a>a1<b>b1<c>c1</c>b2</b>a2</a>';
++select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','+++++++++');
++UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','+++++++++')
++<a>a1<b>b1+++++++++b2</b>a2</a>
++select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1>+++++++++</c1>');
++UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1>+++++++++</c1>')
++<a>a1<b>b1<c1>+++++++++</c1>b2</b>a2</a>
++select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1/>');
++UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1/>')
++<a>a1<b>b1<c1/>b2</b>a2</a>
++SET @xml='<a><b>bb</b></a>';
++select UpdateXML(@xml, '/a/b', '<b>ccc</b>');
++UpdateXML(@xml, '/a/b', '<b>ccc</b>')
++<a><b>ccc</b></a>
++SET @xml='<a aa1="aa1" aa2="aa2"><b bb1="bb1" bb2="bb2">bb</b></a>';
++select UpdateXML(@xml, '/a/b', '<b>ccc</b>');
++UpdateXML(@xml, '/a/b', '<b>ccc</b>')
++<a aa1="aa1" aa2="aa2"><b>ccc</b></a>
++select UpdateXML(@xml, '/a/@aa1', '');
++UpdateXML(@xml, '/a/@aa1', '')
++<a aa2="aa2"><b bb1="bb1" bb2="bb2">bb</b></a>
++select UpdateXML(@xml, '/a/@aa1', 'aa3="aa3"');
++UpdateXML(@xml, '/a/@aa1', 'aa3="aa3"')
++<a aa3="aa3" aa2="aa2"><b bb1="bb1" bb2="bb2">bb</b></a>
++select UpdateXML(@xml, '/a/@aa2', '');
++UpdateXML(@xml, '/a/@aa2', '')
++<a aa1="aa1" ><b bb1="bb1" bb2="bb2">bb</b></a>
++select UpdateXML(@xml, '/a/@aa2', 'aa3="aa3"');
++UpdateXML(@xml, '/a/@aa2', 'aa3="aa3"')
++<a aa1="aa1" aa3="aa3"><b bb1="bb1" bb2="bb2">bb</b></a>
++select UpdateXML(@xml, '/a/b/@bb1', '');
++UpdateXML(@xml, '/a/b/@bb1', '')
++<a aa1="aa1" aa2="aa2"><b bb2="bb2">bb</b></a>
++select UpdateXML(@xml, '/a/b/@bb1', 'bb3="bb3"');
++UpdateXML(@xml, '/a/b/@bb1', 'bb3="bb3"')
++<a aa1="aa1" aa2="aa2"><b bb3="bb3" bb2="bb2">bb</b></a>
++select UpdateXML(@xml, '/a/b/@bb2', '');
++UpdateXML(@xml, '/a/b/@bb2', '')
++<a aa1="aa1" aa2="aa2"><b bb1="bb1" >bb</b></a>
++select UpdateXML(@xml, '/a/b/@bb2', 'bb3="bb3"');
++UpdateXML(@xml, '/a/b/@bb2', 'bb3="bb3"')
++<a aa1="aa1" aa2="aa2"><b bb1="bb1" bb3="bb3">bb</b></a>
+diff -Naur mysql.orig/mysql-test/t/xml.test mysql.xml/mysql-test/t/xml.test
+--- mysql.orig/mysql-test/t/xml.test 1970-01-01 01:00:00.000000000 +0100
++++ mysql.xml/mysql-test/t/xml.test 2005-04-13 09:15:03.000000000 +0200
+@@ -0,0 +1,217 @@
++SET @xml='<a aa1="aa1" aa2="aa2">a1<b ba1="ba1">b1<c>c1</c>b2</b>a2</a>';
++SELECT extractValue(@xml,'/a');
++SELECT extractValue(@xml,'/a/b');
++SELECT extractValue(@xml,'/a/b/c');
++SELECT extractValue(@xml,'/a/@aa1');
++SELECT extractValue(@xml,'/a/@aa2');
++SELECT extractValue(@xml,'/a/@*');
++SELECT extractValue(@xml,'//@ba1');
++
++SELECT extractValue(@xml,'//a');
++SELECT extractValue(@xml,'//b');
++SELECT extractValue(@xml,'//c');
++SELECT extractValue(@xml,'/a//b');
++SELECT extractValue(@xml,'/a//c');
++SELECT extractValue(@xml,'//*');
++SELECT extractValue(@xml,'/a//*');
++SELECT extractValue(@xml,'/./a');
++SELECT extractValue(@xml,'/a/b/.');
++SELECT extractValue(@xml,'/a/b/..');
++SELECT extractValue(@xml,'/a/b/../@aa1');
++SELECT extractValue(@xml,'/*');
++SELECT extractValue(@xml,'/*/*');
++SELECT extractValue(@xml,'/*/*/*');
++
++SELECT extractValue(@xml,'/a/child::*');
++SELECT extractValue(@xml,'/a/descendant::*');
++SELECT extractValue(@xml,'/a/descendant-or-self::*');
++SELECT extractValue(@xml,'/a/attribute::*');
++SELECT extractValue(@xml,'/a/b/c/parent::*');
++SELECT extractValue(@xml,'/a/b/c/ancestor::*');
++SELECT extractValue(@xml,'/a/b/c/ancestor-or-self::*');
++SELECT extractValue(@xml,'/descendant-or-self::*');
++
++SET @xml='<a>a11<b ba="ba11" ba="ba12">b11</b><b ba="ba21" ba="ba22">b21<c>c1</c>b22</b>a12</a>';
++SELECT extractValue(@xml,'/a/b/c/ancestor-or-self::*');
++SELECT extractValue(@xml,'//@ba');
++
++SET @xml='<a><b>b</b><c>c</c></a>';
++SELECT extractValue(@xml,'/a/b');
++SELECT extractValue(@xml,'/a/c');
++SELECT extractValue(@xml,'/a/child::b');
++SELECT extractValue(@xml,'/a/child::c');
++
++SET @xml='<a><b>b1</b><c>c1</c><b>b2</b><c>c2</c></a>';
++SELECT extractValue(@xml,'/a/b[1]');
++SELECT extractValue(@xml,'/a/b[2]');
++SELECT extractValue(@xml,'/a/c[1]');
++SELECT extractValue(@xml,'/a/c[2]');
++
++SET @xml='<a><b x="xb1" x="xb2"/><c x="xc1" x="xc2"/></a>';
++SELECT extractValue(@xml,'/a//@x');
++SELECT extractValue(@xml,'/a//@x[1]');
++SELECT extractValue(@xml,'/a//@x[2]');
++
++SET @xml='<a><b>b1</b><b>b2</b><c><b>c1b1</b><b>c1b2</b></c><c><b>c2b1</c></b>/a>';
++SELECT extractValue(@xml,'//b[1]');
++SELECT extractValue(@xml,'/descendant::b[1]');
++
++SET @xml='<a><b>b1</b><b>b2</b></a>';
++SELECT extractValue(@xml,'/a/b[1+0]');
++SELECT extractValue(@xml,'/a/b[1*1]');
++SELECT extractValue(@xml,'/a/b[--1]');
++SELECT extractValue(@xml,'/a/b[2*1-1]');
++
++SELECT extractValue(@xml,'/a/b[1+1]');
++SELECT extractValue(@xml,'/a/b[1*2]');
++SELECT extractValue(@xml,'/a/b[--2]');
++SELECT extractValue(@xml,'/a/b[1*(3-1)]');
++
++SELECT extractValue(@xml,'//*[1=1]');
++SELECT extractValue(@xml,'//*[1!=1]');
++SELECT extractValue(@xml,'//*[1>1]');
++SELECT extractValue(@xml,'//*[2>1]');
++SELECT extractValue(@xml,'//*[1>2]');
++SELECT extractValue(@xml,'//*[1>=1]');
++SELECT extractValue(@xml,'//*[2>=1]');
++SELECT extractValue(@xml,'//*[1>=2]');
++SELECT extractValue(@xml,'//*[1<1]');
++SELECT extractValue(@xml,'//*[2<1]');
++SELECT extractValue(@xml,'//*[1<2]');
++SELECT extractValue(@xml,'//*[1<=1]');
++SELECT extractValue(@xml,'//*[2<=1]');
++SELECT extractValue(@xml,'//*[1<=2]');
++
++SET @xml='<a><b>b11<c>c11</c></b><b>b21<c>c21</c></b></a>';
++SELECT extractValue(@xml,'/a/b[c="c11"]');
++SELECT extractValue(@xml,'/a/b[c="c21"]');
++
++SET @xml='<a><b c="c11">b11</b><b c="c21">b21</b></a>';
++SELECT extractValue(@xml,'/a/b[@c="c11"]');
++SELECT extractValue(@xml,'/a/b[@c="c21"]');
++
++SET @xml='<a>a1<b c="c11">b11<d>d11</d></b><b c="c21">b21<d>d21</d></b></a>';
++SELECT extractValue(@xml, '/a/b[@c="c11"]/d');
++SELECT extractValue(@xml, '/a/b[@c="c21"]/d');
++SELECT extractValue(@xml, '/a/b[d="d11"]/@c');
++SELECT extractValue(@xml, '/a/b[d="d21"]/@c');
++SELECT extractValue(@xml, '/a[b="b11"]');
++SELECT extractValue(@xml, '/a[b/@c="c11"]');
++SELECT extractValue(@xml, '/a[b/d="d11"]');
++SELECT extractValue(@xml, '/a[/a/b="b11"]');
++SELECT extractValue(@xml, '/a[/a/b/@c="c11"]');
++SELECT extractValue(@xml, '/a[/a/b/d="d11"]');
++
++SELECT extractValue('<a>a</a>', '/a[false()]');
++SELECT extractValue('<a>a</a>', '/a[true()]');
++SELECT extractValue('<a>a</a>', '/a[not(false())]');
++SELECT extractValue('<a>a</a>', '/a[not(true())]');
++SELECT extractValue('<a>a</a>', '/a[true() and true()]');
++SELECT extractValue('<a>a</a>', '/a[true() and false()]');
++SELECT extractValue('<a>a</a>', '/a[false()and false()]');
++SELECT extractValue('<a>a</a>', '/a[false()and true()]');
++SELECT extractValue('<a>a</a>', '/a[true() or true()]');
++SELECT extractValue('<a>a</a>', '/a[true() or false()]');
++SELECT extractValue('<a>a</a>', '/a[false()or false()]');
++SELECT extractValue('<a>a</a>', '/a[false()or true()]');
++
++SET @xml='<a>ab<b c="c" c="e">b1</b><b c="d">b2</b><b c="f" c="e">b3</b></a>';
++select extractValue(@xml,'/a/b[@c="c"]');
++select extractValue(@xml,'/a/b[@c="d"]');
++select extractValue(@xml,'/a/b[@c="e"]');
++select extractValue(@xml,'/a/b[not(@c="e")]');
++select extractValue(@xml,'/a/b[@c!="e"]');
++select extractValue(@xml,'/a/b[@c="c" or @c="d"]');
++select extractValue(@xml,'/a/b[@c="c" and @c="e"]');
++
++SET @xml='<a><b c="c" d="d">b1</b><b d="d" e="e">b2</b></a>';
++select extractValue(@xml,'/a/b[@c]');
++select extractValue(@xml,'/a/b[@d]');
++select extractValue(@xml,'/a/b[@e]');
++select extractValue(@xml,'/a/b[not(@c)]');
++select extractValue(@xml,'/a/b[not(@d)]');
++select extractValue(@xml,'/a/b[not(@e)]');
++
++select extractValue(@xml, '/a/b[boolean(@c) or boolean(@d)]');
++select extractValue(@xml, '/a/b[boolean(@c) or boolean(@e)]');
++select extractValue(@xml, '/a/b[boolean(@d) or boolean(@e)]');
++select extractValue(@xml, '/a/b[boolean(@c) and boolean(@d)]');
++select extractValue(@xml, '/a/b[boolean(@c) and boolean(@e)]');
++select extractValue(@xml, '/a/b[boolean(@d) and boolean(@e)]');
++
++select extractValue(@xml, '/a/b[@c or @d]');
++select extractValue(@xml, '/a/b[@c or @e]');
++select extractValue(@xml, '/a/b[@d or @e]');
++select extractValue(@xml, '/a/b[@c and @d]');
++select extractValue(@xml, '/a/b[@c and @e]');
++select extractValue(@xml, '/a/b[@d and @e]');
++
++SET @xml='<a><b c="c">b1</b><b>b2</b></a>';
++SELECT extractValue(@xml,'/a/b[@*]');
++SELECT extractValue(@xml,'/a/b[not(@*)]');
++
++SELECT extractValue('<a>a</a>', '/a[ceiling(3.1)=4]');
++SELECT extractValue('<a>a</a>', '/a[floor(3.1)=3]');
++SELECT extractValue('<a>a</a>', '/a[round(3.1)=3]');
++SELECT extractValue('<a>a</a>', '/a[round(3.8)=4]');
++
++SELECT extractValue('<a><b>b</b><c>c</c></a>', '/a/b | /a/c');
++
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=1]');
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=2]');
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3]');
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[1=position()]');
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2=position()]');
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[3=position()]');
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2>=position()]');
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[2<=position()]');
++select extractValue('<a b="b1" b="b2" b="b3"/>','/a/@b[position()=3 or position()=2]');
++
++SELECT extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=0]');
++SELECT extractValue('<a>a<b>a1<c>c1</c></b><b>a2</b></a>','/a/b[count(c)=1]');
++select extractValue('<a>a1<b ba="1" ba="2">b1</b><b>b2</b>4</a>','/a/b[sum(@ba)=3]');
++
++select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[1]');
++select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[boolean(1)]');
++select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[true()]');
++select extractValue('<a><b>b1</b><b>b2</b></a>','/a/b[number(true())]');
++
++select extractValue('<a>ab</a>','/a[contains("abc","b")]');
++select extractValue('<a>ab</a>','/a[contains(.,"a")]');
++select extractValue('<a>ab</a>','/a[contains(.,"b")]');
++select extractValue('<a>ab</a>','/a[contains(.,"c")]');
++
++select extractValue('<a b="1">ab</a>','/a[concat(@b,"2")="12"]');
++
++SET @xml='<a b="11" b="12" b="21" b="22">ab</a>';
++select extractValue(@xml, '/a/@b[substring(.,2)="1"]');
++select extractValue(@xml, '/a/@b[substring(.,2)="2"]');
++select extractValue(@xml, '/a/@b[substring(.,1,1)="1"]');
++select extractValue(@xml, '/a/@b[substring(.,1,1)="2"]');
++select extractValue(@xml, '/a/@b[substring(.,2,1)="1"]');
++select extractValue(@xml, '/a/@b[substring(.,2,1)="2"]');
++
++SET @xml='<a b="b11" b="b12" b="b21" b="22"/>';
++select extractValue(@xml,'/a/@b');
++select extractValue(@xml,'/a/@b[contains(.,"1")]');
++select extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")]');
++select extractValue(@xml,'/a/@b[contains(.,"1")][contains(.,"2")][2]');
++
++SET @xml='<a>a1<b>b1<c>c1</c>b2</b>a2</a>';
++select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','+++++++++');
++select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1>+++++++++</c1>');
++select UpdateXML('<a>a1<b>b1<c>c1</c>b2</b>a2</a>','/a/b/c','<c1/>');
++
++SET @xml='<a><b>bb</b></a>';
++select UpdateXML(@xml, '/a/b', '<b>ccc</b>');
++
++SET @xml='<a aa1="aa1" aa2="aa2"><b bb1="bb1" bb2="bb2">bb</b></a>';
++select UpdateXML(@xml, '/a/b', '<b>ccc</b>');
++select UpdateXML(@xml, '/a/@aa1', '');
++select UpdateXML(@xml, '/a/@aa1', 'aa3="aa3"');
++select UpdateXML(@xml, '/a/@aa2', '');
++select UpdateXML(@xml, '/a/@aa2', 'aa3="aa3"');
++select UpdateXML(@xml, '/a/b/@bb1', '');
++select UpdateXML(@xml, '/a/b/@bb1', 'bb3="bb3"');
++select UpdateXML(@xml, '/a/b/@bb2', '');
++select UpdateXML(@xml, '/a/b/@bb2', 'bb3="bb3"');
+diff -Naur mysql.orig/sql/Makefile.am mysql.xml/sql/Makefile.am
+--- mysql.orig/sql/Makefile.am 2005-05-15 06:16:51.000000000 +0200
++++ mysql.xml/sql/Makefile.am 2005-05-20 15:19:29.000000000 +0200
+@@ -45,6 +45,7 @@
+ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@
+ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
+ item_strfunc.h item_timefunc.h item_uniq.h \
++ item_xmlfunc.h \
+ item_create.h item_subselect.h item_row.h \
+ mysql_priv.h item_geofunc.h sql_bitmap.h \
+ procedure.h sql_class.h sql_lex.h sql_list.h \
+@@ -68,7 +69,7 @@
+ item.cc item_sum.cc item_buff.cc item_func.cc \
+ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
+ thr_malloc.cc item_create.cc item_subselect.cc \
+- item_row.cc item_geofunc.cc \
++ item_row.cc item_geofunc.cc item_xmlfunc.cc \
+ field.cc strfunc.cc key.cc sql_class.cc sql_list.cc \
+ net_serv.cc protocol.cc sql_state.c \
+ lock.cc my_lock.c \
+diff -Naur mysql.orig/sql/item.h mysql.xml/sql/item.h
+--- mysql.orig/sql/item.h 2005-05-15 06:16:50.000000000 +0200
++++ mysql.xml/sql/item.h 2005-05-20 15:19:29.000000000 +0200
+@@ -241,7 +241,8 @@
+ PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
+ FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,
+ SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,
+- PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM};
++ PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM,
++ XPATH_NODESET, XPATH_NODESET_CMP };
+
+ enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
+
+@@ -391,6 +392,7 @@
+ TRUE value is true (not equal to 0)
+ */
+ virtual bool val_bool();
++ virtual String *val_nodeset(String*) { return 0; }
+ /* Helper functions, see item_sum.cc */
+ String *val_string_from_real(String *str);
+ String *val_string_from_int(String *str);
+@@ -1429,6 +1431,7 @@
+ #include "item_timefunc.h"
+ #include "item_uniq.h"
+ #include "item_subselect.h"
++#include "item_xmlfunc.h"
+
+ class Item_copy_string :public Item
+ {
+diff -Naur mysql.orig/sql/item.h.orig mysql.xml/sql/item.h.orig
+--- mysql.orig/sql/item.h.orig 1970-01-01 01:00:00.000000000 +0100
++++ mysql.xml/sql/item.h.orig 2005-05-15 06:16:50.000000000 +0200
+@@ -0,0 +1,1850 @@
++/* Copyright (C) 2000-2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program 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 should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++
++#ifdef USE_PRAGMA_INTERFACE
++#pragma interface /* gcc class implementation */
++#endif
++
++class Protocol;
++struct st_table_list;
++void item_init(void); /* Init item functions */
++class Item_field;
++
++
++/*
++ "Declared Type Collation"
++ A combination of collation and its derivation.
++*/
++
++enum Derivation
++{
++ DERIVATION_IGNORABLE= 5,
++ DERIVATION_COERCIBLE= 4,
++ DERIVATION_SYSCONST= 3,
++ DERIVATION_IMPLICIT= 2,
++ DERIVATION_NONE= 1,
++ DERIVATION_EXPLICIT= 0
++};
++
++/*
++ Flags for collation aggregation modes:
++ MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset
++ MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value
++ (i.e. constant).
++ MY_COLL_ALLOW_CONV - allow any kind of conversion
++ (combination of the above two)
++ MY_COLL_DISALLOW_NONE - don't allow return DERIVATION_NONE
++ (e.g. when aggregating for comparison)
++ MY_COLL_CMP_CONV - combination of MY_COLL_ALLOW_CONV
++ and MY_COLL_DISALLOW_NONE
++*/
++
++#define MY_COLL_ALLOW_SUPERSET_CONV 1
++#define MY_COLL_ALLOW_COERCIBLE_CONV 2
++#define MY_COLL_ALLOW_CONV 3
++#define MY_COLL_DISALLOW_NONE 4
++#define MY_COLL_CMP_CONV 7
++
++class DTCollation {
++public:
++ CHARSET_INFO *collation;
++ enum Derivation derivation;
++
++ DTCollation()
++ {
++ collation= &my_charset_bin;
++ derivation= DERIVATION_NONE;
++ }
++ DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg)
++ {
++ collation= collation_arg;
++ derivation= derivation_arg;
++ }
++ void set(DTCollation &dt)
++ {
++ collation= dt.collation;
++ derivation= dt.derivation;
++ }
++ void set(CHARSET_INFO *collation_arg, Derivation derivation_arg)
++ {
++ collation= collation_arg;
++ derivation= derivation_arg;
++ }
++ void set(CHARSET_INFO *collation_arg)
++ { collation= collation_arg; }
++ void set(Derivation derivation_arg)
++ { derivation= derivation_arg; }
++ bool aggregate(DTCollation &dt, uint flags= 0);
++ bool set(DTCollation &dt1, DTCollation &dt2, uint flags= 0)
++ { set(dt1); return aggregate(dt2, flags); }
++ const char *derivation_name() const
++ {
++ switch(derivation)
++ {
++ case DERIVATION_IGNORABLE: return "IGNORABLE";
++ case DERIVATION_COERCIBLE: return "COERCIBLE";
++ case DERIVATION_IMPLICIT: return "IMPLICIT";
++ case DERIVATION_SYSCONST: return "SYSCONST";
++ case DERIVATION_EXPLICIT: return "EXPLICIT";
++ case DERIVATION_NONE: return "NONE";
++ default: return "UNKNOWN";
++ }
++ }
++};
++
++
++/*************************************************************************/
++/*
++ A framework to easily handle different return types for hybrid items
++ (hybrid item is an item whose operand can be of any type, e.g. integer,
++ real, decimal).
++*/
++
++struct Hybrid_type_traits;
++
++struct Hybrid_type
++{
++ longlong integer;
++
++ double real;
++ /*
++ Use two decimal buffers interchangeably to speed up += operation
++ which has no native support in decimal library.
++ Hybrid_type+= arg is implemented as dec_buf[1]= dec_buf[0] + arg.
++ The third decimal is used as a handy temporary storage.
++ */
++ my_decimal dec_buf[3];
++ int used_dec_buf_no;
++
++ /*
++ Traits moved to a separate class to
++ a) be able to easily change object traits in runtime
++ b) they work as a differentiator for the union above
++ */
++ const Hybrid_type_traits *traits;
++
++ Hybrid_type() {}
++ /* XXX: add traits->copy() when needed */
++ Hybrid_type(const Hybrid_type &rhs) :traits(rhs.traits) {}
++};
++
++
++/* Hybryd_type_traits interface + default implementation for REAL_RESULT */
++
++struct Hybrid_type_traits
++{
++ virtual Item_result type() const { return REAL_RESULT; }
++
++ virtual void
++ fix_length_and_dec(Item *item, Item *arg) const;
++
++ /* Hybrid_type operations. */
++ virtual void set_zero(Hybrid_type *val) const { val->real= 0.0; }
++ virtual void add(Hybrid_type *val, Field *f) const
++ { val->real+= f->val_real(); }
++ virtual void div(Hybrid_type *val, ulonglong u) const
++ { val->real/= ulonglong2double(u); }
++
++ virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const
++ { return (longlong) val->real; }
++ virtual double val_real(Hybrid_type *val) const { return val->real; }
++ virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const;
++ virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
++ static const Hybrid_type_traits *instance();
++};
++
++
++struct Hybrid_type_traits_decimal: public Hybrid_type_traits
++{
++ virtual Item_result type() const { return DECIMAL_RESULT; }
++
++ virtual void
++ fix_length_and_dec(Item *arg, Item *item) const;
++
++ /* Hybrid_type operations. */
++ virtual void set_zero(Hybrid_type *val) const;
++ virtual void add(Hybrid_type *val, Field *f) const;
++ virtual void div(Hybrid_type *val, ulonglong u) const;
++
++ virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const;
++ virtual double val_real(Hybrid_type *val) const;
++ virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const
++ { return &val->dec_buf[val->used_dec_buf_no]; }
++ virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const;
++ static const Hybrid_type_traits_decimal *instance();
++};
++
++
++struct Hybrid_type_traits_integer: public Hybrid_type_traits
++{
++ virtual Item_result type() const { return INT_RESULT; }
++
++ virtual void
++ fix_length_and_dec(Item *arg, Item *item) const;
++
++ /* Hybrid_type operations. */
++ virtual void set_zero(Hybrid_type *val) const
++ { val->integer= 0; }
++ virtual void add(Hybrid_type *val, Field *f) const
++ { val->integer+= f->val_int(); }
++ virtual void div(Hybrid_type *val, ulonglong u) const
++ { val->integer/= (longlong) u; }
++
++ virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const
++ { return val->integer; }
++ virtual double val_real(Hybrid_type *val) const
++ { return (double) val->integer; }
++ virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const
++ {
++ int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, &val->dec_buf[2]);
++ return &val->dec_buf[2];
++ }
++ virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const
++ { buf->set(val->integer, &my_charset_bin); return buf;}
++ static const Hybrid_type_traits_integer *instance();
++};
++
++/*************************************************************************/
++
++typedef bool (Item::*Item_processor)(byte *arg);
++typedef Item* (Item::*Item_transformer) (byte *arg);
++
++typedef void (*Cond_traverser) (const Item *item, void *arg);
++
++class Item {
++ Item(const Item &); /* Prevent use of these */
++ void operator=(Item &);
++public:
++ static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
++ static void *operator new(size_t size, MEM_ROOT *mem_root)
++ { return (void*) alloc_root(mem_root, (uint) size); }
++ static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
++ static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
++
++ enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM,
++ INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM,
++ COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM,
++ PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
++ FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,
++ SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,
++ PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM};
++
++ enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
++
++ enum traverse_order { POSTFIX, PREFIX };
++
++ /*
++ str_values's main purpose is to be used to cache the value in
++ save_in_field
++ */
++ String str_value;
++ my_string name; /* Name from select */
++ /* Original item name (if it was renamed)*/
++ my_string orig_name;
++ Item *next;
++ uint32 max_length;
++ uint name_length; /* Length of name */
++ uint8 marker, decimals;
++ my_bool maybe_null; /* If item may be null */
++ my_bool null_value; /* if item is null */
++ my_bool unsigned_flag;
++ my_bool with_sum_func;
++ my_bool fixed; /* If item fixed with fix_fields */
++ DTCollation collation;
++
++ // alloc & destruct is done as start of select using sql_alloc
++ Item();
++ /*
++ Constructor used by Item_field, Item_ref & aggregate (sum) functions.
++ Used for duplicating lists in processing queries with temporary
++ tables
++ Also it used for Item_cond_and/Item_cond_or for creating
++ top AND/OR structure of WHERE clause to protect it of
++ optimisation changes in prepared statements
++ */
++ Item(THD *thd, Item *item);
++ virtual ~Item()
++ {
++ name=0;
++ } /*lint -e1509 */
++ void set_name(const char *str,uint length, CHARSET_INFO *cs);
++ void rename(char *new_name);
++ void init_make_field(Send_field *tmp_field,enum enum_field_types type);
++ virtual void cleanup();
++ virtual void make_field(Send_field *field);
++ Field *make_string_field(TABLE *table);
++ virtual bool fix_fields(THD *, struct st_table_list *, Item **);
++ /*
++ should be used in case where we are sure that we do not need
++ complete fix_fields() procedure.
++ */
++ inline void quick_fix_field() { fixed= 1; }
++ /* Function returns 1 on overflow and -1 on fatal errors */
++ int save_in_field_no_warnings(Field *field, bool no_conversions);
++ virtual int save_in_field(Field *field, bool no_conversions);
++ virtual void save_org_in_field(Field *field)
++ { (void) save_in_field(field, 1); }
++ virtual int save_safe_in_field(Field *field)
++ { return save_in_field(field, 1); }
++ virtual bool send(Protocol *protocol, String *str);
++ virtual bool eq(const Item *, bool binary_cmp) const;
++ virtual Item_result result_type() const { return REAL_RESULT; }
++ virtual Item_result cast_to_int_type() const { return result_type(); }
++ virtual enum_field_types field_type() const;
++ virtual enum Type type() const =0;
++ /* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */
++ /*
++ Return double precision floating point representation of item.
++
++ SYNOPSIS
++ val_real()
++
++ RETURN
++ In case of NULL value return 0.0 and set null_value flag to TRUE.
++ If value is not null null_value flag will be reset to FALSE.
++ */
++ virtual double val_real()=0;
++ /*
++ Return integer representation of item.
++
++ SYNOPSIS
++ val_int()
++
++ RETURN
++ In case of NULL value return 0 and set null_value flag to TRUE.
++ If value is not null null_value flag will be reset to FALSE.
++ */
++ virtual longlong val_int()=0;
++ /*
++ Return string representation of this item object.
++
++ SYNOPSIS
++ val_str()
++ str an allocated buffer this or any nested Item object can use to
++ store return value of this method.
++
++ NOTE
++ Buffer passed via argument should only be used if the item itself
++ doesn't have an own String buffer. In case when the item maintains
++ it's own string buffer, it's preferable to return it instead to
++ minimize number of mallocs/memcpys.
++ The caller of this method can modify returned string, but only in case
++ when it was allocated on heap, (is_alloced() is true). This allows
++ the caller to efficiently use a buffer allocated by a child without
++ having to allocate a buffer of it's own. The buffer, given to
++ val_str() as argument, belongs to the caller and is later used by the
++ caller at it's own choosing.
++ A few implications from the above:
++ - unless you return a string object which only points to your buffer
++ but doesn't manages it you should be ready that it will be
++ modified.
++ - even for not allocated strings (is_alloced() == false) the caller
++ can change charset (see Item_func_{typecast/binary}. XXX: is this
++ a bug?
++ - still you should try to minimize data copying and return internal
++ object whenever possible.
++
++ RETURN
++ In case of NULL value return 0 (NULL pointer) and set null_value flag
++ to TRUE.
++ If value is not null null_value flag will be reset to FALSE.
++ */
++ virtual String *val_str(String *str)=0;
++ /*
++ Return decimal representation of item with fixed point.
++
++ SYNOPSIS
++ val_decimal()
++ decimal_buffer buffer which can be used by Item for returning value
++ (but can be not)
++
++ NOTE
++ Returned value should not be changed if it is not the same which was
++ passed via argument.
++
++ RETURN
++ Return pointer on my_decimal (it can be other then passed via argument)
++ if value is not NULL (null_value flag will be reset to FALSE).
++ In case of NULL value it return 0 pointer and set null_value flag
++ to TRUE.
++ */
++ virtual my_decimal *val_decimal(my_decimal *decimal_buffer)= 0;
++ /*
++ Return boolean value of item.
++
++ RETURN
++ FALSE value is false or NULL
++ TRUE value is true (not equal to 0)
++ */
++ virtual bool val_bool();
++ /* Helper functions, see item_sum.cc */
++ String *val_string_from_real(String *str);
++ String *val_string_from_int(String *str);
++ String *val_string_from_decimal(String *str);
++ my_decimal *val_decimal_from_real(my_decimal *decimal_value);
++ my_decimal *val_decimal_from_int(my_decimal *decimal_value);
++ my_decimal *val_decimal_from_string(my_decimal *decimal_value);
++ longlong val_int_from_decimal();
++ double val_real_from_decimal();
++
++ virtual Field *get_tmp_table_field() { return 0; }
++ virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
++ virtual const char *full_name() const { return name ? name : "???"; }
++
++ /*
++ *result* family of methods is analog of *val* family (see above) but
++ return value of result_field of item if it is present. If Item have not
++ result field, it return val(). This methods set null_value flag in same
++ way as *val* methods do it.
++ */
++ virtual double val_result() { return val_real(); }
++ virtual longlong val_int_result() { return val_int(); }
++ virtual String *str_result(String* tmp) { return val_str(tmp); }
++ virtual my_decimal *val_decimal_result(my_decimal *val)
++ { return val_decimal(val); }
++ virtual bool val_bool_result() { return val_bool(); }
++
++ /* bit map of tables used by item */
++ virtual table_map used_tables() const { return (table_map) 0L; }
++ /*
++ Return table map of tables that can't be NULL tables (tables that are
++ used in a context where if they would contain a NULL row generated
++ by a LEFT or RIGHT join, the item would not be true).
++ This expression is used on WHERE item to determinate if a LEFT JOIN can be
++ converted to a normal join.
++ Generally this function should return used_tables() if the function
++ would return null if any of the arguments are null
++ As this is only used in the beginning of optimization, the value don't
++ have to be updated in update_used_tables()
++ */
++ virtual table_map not_null_tables() const { return used_tables(); }
++ /*
++ Returns true if this is a simple constant item like an integer, not
++ a constant expression. Used in the optimizer to propagate basic constants.
++ */
++ virtual bool basic_const_item() const { return 0; }
++ /* cloning of constant items (0 if it is not const) */
++ virtual Item *new_item() { return 0; }
++ virtual cond_result eq_cmp_result() const { return COND_OK; }
++ inline uint float_length(uint decimals_par) const
++ { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}
++ virtual uint decimal_precision() const;
++ inline int decimal_int_part() const
++ { return my_decimal_int_part(decimal_precision(), decimals); }
++ /*
++ Returns true if this is constant (during query execution, i.e. its value
++ will not change until next fix_fields) and its value is known.
++ */
++ virtual bool const_item() const { return used_tables() == 0; }
++ /*
++ Returns true if this is constant but its value may be not known yet.
++ (Can be used for parameters of prep. stmts or of stored procedures.)
++ */
++ virtual bool const_during_execution() const
++ { return (used_tables() & ~PARAM_TABLE_BIT) == 0; }
++ virtual void print(String *str_arg) { str_arg->append(full_name()); }
++ void print_item_w_name(String *);
++ virtual void update_used_tables() {}
++ virtual void split_sum_func(THD *thd, Item **ref_pointer_array,
++ List<Item> &fields) {}
++ /* Called for items that really have to be split */
++ void split_sum_func2(THD *thd, Item **ref_pointer_array, List<Item> &fields,
++ Item **ref);
++ virtual bool get_date(TIME *ltime,uint fuzzydate);
++ virtual bool get_time(TIME *ltime);
++ virtual bool get_date_result(TIME *ltime,uint fuzzydate)
++ { return get_date(ltime,fuzzydate); }
++ /*
++ This function is used only in Item_func_isnull/Item_func_isnotnull
++ (implementations of IS NULL/IS NOT NULL clauses). Item_func_is{not}null
++ calls this method instead of one of val/result*() methods, which
++ normally will set null_value. This allows to determine nullness of
++ a complex expression without fully evaluating it.
++ Any new item which can be NULL must implement this call.
++ */
++ virtual bool is_null() { return 0; }
++ /*
++ it is "top level" item of WHERE clause and we do not need correct NULL
++ handling
++ */
++ virtual void top_level_item() {}
++ /*
++ set field of temporary table for Item which can be switched on temporary
++ table during query processing (grouping and so on)
++ */
++ virtual void set_result_field(Field *field) {}
++ virtual bool is_result_field() { return 0; }
++ virtual bool is_bool_func() { return 0; }
++ virtual void save_in_result_field(bool no_conversions) {}
++ /*
++ set value of aggregate function in case of no rows for grouping were found
++ */
++ virtual void no_rows_in_result() {}
++ virtual Item *copy_or_same(THD *thd) { return this; }
++ virtual Item *copy_andor_structure(THD *thd) { return this; }
++ virtual Item *real_item() { return this; }
++ virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
++
++ static CHARSET_INFO *default_charset();
++ virtual CHARSET_INFO *compare_collation() { return NULL; }
++
++ virtual bool walk(Item_processor processor, byte *arg)
++ {
++ return (this->*processor)(arg);
++ }
++
++ virtual Item* transform(Item_transformer transformer, byte *arg)
++ {
++ return (this->*transformer)(arg);
++ }
++
++ virtual void traverse_cond(Cond_traverser traverser,
++ void *arg, traverse_order order)
++ {
++ (*traverser)(this, arg);
++ }
++
++ virtual bool remove_dependence_processor(byte * arg) { return 0; }
++ virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; }
++ virtual bool cleanup_processor(byte *arg);
++ virtual bool collect_item_field_processor(byte * arg) { return 0; }
++ virtual Item *equal_fields_propagator(byte * arg) { return this; }
++ virtual Item *set_no_const_sub(byte *arg) { return this; }
++ virtual Item *replace_equal_field(byte * arg) { return this; }
++
++ /*
++ For SP local variable returns pointer to Item representing its
++ current value and pointer to current Item otherwise.
++ */
++ virtual Item *this_item() { return this; }
++ /*
++ For SP local variable returns address of pointer to Item representing its
++ current value and pointer passed via parameter otherwise.
++ */
++ virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; }
++ virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */
++
++ // Row emulation
++ virtual uint cols() { return 1; }
++ virtual Item* el(uint i) { return this; }
++ virtual Item** addr(uint i) { return 0; }
++ virtual bool check_cols(uint c);
++ // It is not row => null inside is impossible
++ virtual bool null_inside() { return 0; }
++ // used in row subselects to get value of elements
++ virtual void bring_value() {}
++
++ Field *tmp_table_field_from_field_type(TABLE *table);
++ virtual Item_field *filed_for_view_update() { return 0; }
++
++ virtual Item *neg_transformer(THD *thd) { return NULL; }
++ virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
++ void delete_self()
++ {
++ cleanup();
++ delete this;
++ }
++
++ virtual bool is_splocal() { return 0; } /* Needed for error checking */
++};
++
++
++// A local SP variable (incl. parameters), used in runtime
++class Item_splocal : public Item
++{
++private:
++
++ uint m_offset;
++ LEX_STRING m_name;
++
++public:
++
++ Item_splocal(LEX_STRING name, uint offset)
++ : m_offset(offset), m_name(name)
++ {
++ Item::maybe_null= TRUE;
++ }
++
++ bool is_splocal() { return 1; } /* Needed for error checking */
++
++ Item *this_item();
++ Item **this_item_addr(THD *thd, Item **);
++ Item *this_const_item() const;
++
++ bool fix_fields(THD *, struct st_table_list *, Item **);
++ void cleanup();
++
++ inline uint get_offset()
++ {
++ return m_offset;
++ }
++
++ // Abstract methods inherited from Item. Just defer the call to
++ // the item in the frame
++ enum Type type() const;
++
++ double val_real();
++ longlong val_int();
++ String *val_str(String *sp);
++ my_decimal *val_decimal(my_decimal *);
++ bool is_null();
++ void print(String *str);
++
++ inline void make_field(Send_field *field)
++ {
++ Item *it= this_item();
++
++ if (name)
++ it->set_name(name, strlen(name), system_charset_info);
++ else
++ it->set_name(m_name.str, m_name.length, system_charset_info);
++ it->make_field(field);
++ }
++
++ inline Item_result result_type() const
++ {
++ return this_const_item()->result_type();
++ }
++
++ inline bool const_item() const
++ {
++ return TRUE;
++ }
++
++ inline int save_in_field(Field *field, bool no_conversions)
++ {
++ return this_item()->save_in_field(field, no_conversions);
++ }
++
++ inline bool send(Protocol *protocol, String *str)
++ {
++ return this_item()->send(protocol, str);
++ }
++};
++
++
++class Item_num: public Item
++{
++public:
++ virtual Item_num *neg()= 0;
++};
++
++#define NO_CACHED_FIELD_INDEX ((uint)(-1))
++
++class st_select_lex;
++class Item_ident :public Item
++{
++protected:
++ /*
++ We have to store initial values of db_name, table_name and field_name
++ to be able to restore them during cleanup() because they can be
++ updated during fix_fields() to values from Field object and life-time
++ of those is shorter than life-time of Item_field.
++ */
++ const char *orig_db_name;
++ const char *orig_table_name;
++ const char *orig_field_name;
++public:
++ const char *db_name;
++ const char *table_name;
++ const char *field_name;
++ bool alias_name_used; /* true if item was resolved against alias */
++ /*
++ Cached value of index for this field in table->field array, used by prep.
++ stmts for speeding up their re-execution. Holds NO_CACHED_FIELD_INDEX
++ if index value is not known.
++ */
++ uint cached_field_index;
++ /*
++ Cached pointer to table which contains this field, used for the same reason
++ by prep. stmt. too in case then we have not-fully qualified field.
++ 0 - means no cached value.
++ */
++ TABLE_LIST *cached_table;
++ st_select_lex *depended_from;
++ Item_ident(const char *db_name_par,const char *table_name_par,
++ const char *field_name_par);
++ Item_ident(THD *thd, Item_ident *item);
++ const char *full_name() const;
++ void cleanup();
++ bool remove_dependence_processor(byte * arg);
++ void print(String *str);
++
++ friend bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
++ const char *table_name, List_iterator<Item> *it,
++ bool any_privileges, bool allocate_view_names);
++};
++
++class Item_equal;
++class COND_EQUAL;
++
++class Item_field :public Item_ident
++{
++protected:
++ void set_field(Field *field);
++public:
++ Field *field,*result_field;
++ Item_equal *item_equal;
++ bool no_const_subst;
++ /*
++ if any_privileges set to TRUE then here real effective privileges will
++ be stored
++ */
++ uint have_privileges;
++ /* field need any privileges (for VIEW creation) */
++ bool any_privileges;
++
++ Item_field(const char *db_par,const char *table_name_par,
++ const char *field_name_par)
++ :Item_ident(db_par,table_name_par,field_name_par),
++ field(0), result_field(0), item_equal(0), no_const_subst(0),
++ have_privileges(0), any_privileges(0)
++ { collation.set(DERIVATION_IMPLICIT); }
++ /*
++ Constructor needed to process subselect with temporary tables (see Item)
++ */
++ Item_field(THD *thd, Item_field *item);
++ /*
++ Constructor used inside setup_wild(), ensures that field, table,
++ and database names will live as long as Item_field (this is important
++ in prepared statements).
++ */
++ Item_field(THD *thd, Field *field);
++ /*
++ If this constructor is used, fix_fields() won't work, because
++ db_name, table_name and column_name are unknown. It's necessary to call
++ reset_field() before fix_fields() for all fields created this way.
++ */
++ Item_field(Field *field);
++ enum Type type() const { return FIELD_ITEM; }
++ bool eq(const Item *item, bool binary_cmp) const;
++ double val_real();
++ longlong val_int();
++ my_decimal *val_decimal(my_decimal *);
++ String *val_str(String*);
++ double val_result();
++ longlong val_int_result();
++ String *str_result(String* tmp);
++ my_decimal *val_decimal_result(my_decimal *);
++ bool val_bool_result();
++ bool send(Protocol *protocol, String *str_arg);
++ void reset_field(Field *f);
++ bool fix_fields(THD *, struct st_table_list *, Item **);
++ void make_field(Send_field *tmp_field);
++ int save_in_field(Field *field,bool no_conversions);
++ void save_org_in_field(Field *field);
++ table_map used_tables() const;
++ enum Item_result result_type () const
++ {
++ return field->result_type();
++ }
++ Item_result cast_to_int_type() const
++ {
++ return field->cast_to_int_type();
++ }
++ enum_field_types field_type() const
++ {
++ return field->type();
++ }
++ Field *get_tmp_table_field() { return result_field; }
++ Field *tmp_table_field(TABLE *t_arg) { return result_field; }
++ bool get_date(TIME *ltime,uint fuzzydate);
++ bool get_date_result(TIME *ltime,uint fuzzydate);
++ bool get_time(TIME *ltime);
++ bool is_null() { return field->is_null(); }
++ Item *get_tmp_table_item(THD *thd);
++ bool collect_item_field_processor(byte * arg);
++ void cleanup();
++ Item_equal *find_item_equal(COND_EQUAL *cond_equal);
++ Item *equal_fields_propagator(byte *arg);
++ Item *set_no_const_sub(byte *arg);
++ Item *replace_equal_field(byte *arg);
++ inline uint32 max_disp_length() { return field->max_length(); }
++ Item_field *filed_for_view_update() { return this; }
++ Item *safe_charset_converter(CHARSET_INFO *tocs);
++ friend class Item_default_value;
++ friend class Item_insert_value;
++ friend class st_select_lex_unit;
++};
++
++class Item_null :public Item
++{
++public:
++ Item_null(char *name_par=0)
++ {
++ maybe_null= null_value= TRUE;
++ max_length= 0;
++ name= name_par ? name_par : (char*) "NULL";
++ fixed= 1;
++ collation.set(&my_charset_bin, DERIVATION_IGNORABLE);
++ }
++ enum Type type() const { return NULL_ITEM; }
++ bool eq(const Item *item, bool binary_cmp) const;
++ double val_real();
++ longlong val_int();
++ String *val_str(String *str);
++ my_decimal *val_decimal(my_decimal *);
++ int save_in_field(Field *field, bool no_conversions);
++ int save_safe_in_field(Field *field);
++ bool send(Protocol *protocol, String *str);
++ enum Item_result result_type () const { return STRING_RESULT; }
++ enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
++ /* to prevent drop fixed flag (no need parent cleanup call) */
++ void cleanup() {}
++ bool basic_const_item() const { return 1; }
++ Item *new_item() { return new Item_null(name); }
++ bool is_null() { return 1; }
++ void print(String *str) { str->append("NULL", 4); }
++ Item *safe_charset_converter(CHARSET_INFO *tocs);
++};
++
++class Item_null_result :public Item_null
++{
++public:
++ Field *result_field;
++ Item_null_result() : Item_null(), result_field(0) {}
++ bool is_result_field() { return result_field != 0; }
++ void save_in_result_field(bool no_conversions)
++ {
++ save_in_field(result_field, no_conversions);
++ }
++};
++
++/* Item represents one placeholder ('?') of prepared statement */
++
++class Item_param :public Item
++{
++public:
++ enum enum_item_param_state
++ {
++ NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE,
++ STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE,
++ DECIMAL_VALUE
++ } state;
++
++ /*
++ A buffer for string and long data values. Historically all allocated
++ values returned from val_str() were treated as eligible to
++ modification. I. e. in some cases Item_func_concat can append it's
++ second argument to return value of the first one. Because of that we
++ can't return the original buffer holding string data from val_str(),
++ and have to have one buffer for data and another just pointing to
++ the data. This is the latter one and it's returned from val_str().
++ Can not be declared inside the union as it's not a POD type.
++ */
++ String str_value_ptr;
++ my_decimal decimal_value;
++ union
++ {
++ longlong integer;
++ double real;
++ /*
++ Character sets conversion info for string values.
++ Character sets of client and connection defined at bind time are used
++ for all conversions, even if one of them is later changed (i.e.
++ between subsequent calls to mysql_stmt_execute).
++ */
++ struct CONVERSION_INFO
++ {
++ CHARSET_INFO *character_set_client;
++ /*
++ This points at character set of connection if conversion
++ to it is required (i. e. if placeholder typecode is not BLOB).
++ Otherwise it's equal to character_set_client (to simplify
++ check in convert_str_value()).
++ */
++ CHARSET_INFO *final_character_set_of_str_value;
++ } cs_info;
++ TIME time;
++ } value;
++
++ /* Cached values for virtual methods to save us one switch. */
++ enum Item_result item_result_type;
++ enum Type item_type;
++
++ /*
++ Used when this item is used in a temporary table.
++ This is NOT placeholder metadata sent to client, as this value
++ is assigned after sending metadata (in setup_one_conversion_function).
++ For example in case of 'SELECT ?' you'll get MYSQL_TYPE_STRING both
++ in result set and placeholders metadata, no matter what type you will
++ supply for this placeholder in mysql_stmt_execute.
++ */
++ enum enum_field_types param_type;
++ /*
++ Offset of placeholder inside statement text. Used to create
++ no-placeholders version of this statement for the binary log.
++ */
++ uint pos_in_query;
++
++ Item_param(uint pos_in_query_arg);
++
++ enum Item_result result_type () const { return item_result_type; }
++ enum Type type() const { return item_type; }
++ enum_field_types field_type() const { return param_type; }
++
++ double val_real();
++ longlong val_int();
++ my_decimal *val_decimal(my_decimal*);
++ String *val_str(String*);
++ bool get_time(TIME *tm);
++ bool get_date(TIME *tm, uint fuzzydate);
++ int save_in_field(Field *field, bool no_conversions);
++ bool fix_fields(THD *, struct st_table_list *, Item **);
++
++ void set_null();
++ void set_int(longlong i, uint32 max_length_arg);
++ void set_double(double i);
++ void set_decimal(const char *str, ulong length);
++ bool set_str(const char *str, ulong length);
++ bool set_longdata(const char *str, ulong length);
++ void set_time(TIME *tm, timestamp_type type, uint32 max_length_arg);
++ bool set_from_user_var(THD *thd, const user_var_entry *entry);
++ void reset();
++ /*
++ Assign placeholder value from bind data.
++ Note, that 'len' has different semantics in embedded library (as we
++ don't need to check that packet is not broken there). See
++ sql_prepare.cc for details.
++ */
++ void (*set_param_func)(Item_param *param, uchar **pos, ulong len);
++
++ const String *query_val_str(String *str) const;
++
++ bool convert_str_value(THD *thd);
++
++ /*
++ If value for parameter was not set we treat it as non-const
++ so noone will use parameters value in fix_fields still
++ parameter is constant during execution.
++ */
++ virtual table_map used_tables() const
++ { return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; }
++ void print(String *str);
++ bool is_null()
++ { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; }
++ bool basic_const_item() const;
++ /*
++ This method is used to make a copy of a basic constant item when
++ propagating constants in the optimizer. The reason to create a new
++ item and not use the existing one is not precisely known (2005/04/16).
++ Probably we are trying to preserve tree structure of items, in other
++ words, avoid pointing at one item from two different nodes of the tree.
++ Return a new basic constant item if parameter value is a basic
++ constant, assert otherwise. This method is called only if
++ basic_const_item returned TRUE.
++ */
++ Item *new_item();
++ /*
++ Implement by-value equality evaluation if parameter value
++ is set and is a basic constant (integer, real or string).
++ Otherwise return FALSE.
++ */
++ bool eq(const Item *item, bool binary_cmp) const;
++};
++
++
++class Item_int :public Item_num
++{
++public:
++ longlong value;
++ Item_int(int32 i,uint length=11) :value((longlong) i)
++ { max_length=length; fixed= 1; }
++#ifdef HAVE_LONG_LONG
++ Item_int(longlong i,uint length=21) :value(i)
++ { max_length=length; fixed= 1; }
++#endif
++ Item_int(const char *str_arg,longlong i,uint length) :value(i)
++ { max_length=length; name=(char*) str_arg; fixed= 1; }
++ Item_int(const char *str_arg, uint length=64);
++ enum Type type() const { return INT_ITEM; }
++ enum Item_result result_type () const { return INT_RESULT; }
++ enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
++ longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
++ double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
++ my_decimal *val_decimal(my_decimal *);
++ String *val_str(String*);
++ int save_in_field(Field *field, bool no_conversions);
++ bool basic_const_item() const { return 1; }
++ Item *new_item() { return new Item_int(name,value,max_length); }
++ // to prevent drop fixed flag (no need parent cleanup call)
++ void cleanup() {}
++ void print(String *str);
++ Item_num *neg() { value= -value; return this; }
++ uint decimal_precision() const { return (uint)(max_length - test(value < 0)); }
++ bool eq(const Item *, bool binary_cmp) const;
++};
++
++
++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)
++ {}
++ void print(String *str) { str->append(func_name); }
++};
++
++
++class Item_uint :public Item_int
++{
++public:
++ Item_uint(const char *str_arg, uint length);
++ Item_uint(const char *str_arg, longlong i, uint length);
++ Item_uint(uint32 i) :Item_int((longlong) i, 10)
++ { unsigned_flag= 1; }
++ double val_real()
++ { DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); }
++ String *val_str(String*);
++ Item *new_item() { return new Item_uint(name,max_length); }
++ int save_in_field(Field *field, bool no_conversions);
++ void print(String *str);
++ Item_num *neg ();
++ uint decimal_precision() const { return max_length; }
++};
++
++
++/* decimal (fixed point) constant */
++class Item_decimal :public Item_num
++{
++protected:
++ my_decimal decimal_value;
++public:
++ Item_decimal(const char *str_arg, uint length, CHARSET_INFO *charset);
++ Item_decimal(const char *str, const my_decimal *val_arg,
++ uint decimal_par, uint length);
++ Item_decimal(my_decimal *value_par);
++ Item_decimal(longlong val, bool unsig);
++ Item_decimal(double val, int precision, int scale);
++ Item_decimal(const char *bin, int precision, int scale);
++
++ enum Type type() const { return DECIMAL_ITEM; }
++ enum Item_result result_type () const { return DECIMAL_RESULT; }
++ enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
++ longlong val_int();
++ double val_real();
++ String *val_str(String*);
++ my_decimal *val_decimal(my_decimal *val) { return &decimal_value; }
++ int save_in_field(Field *field, bool no_conversions);
++ bool basic_const_item() const { return 1; }
++ Item *new_item()
++ {
++ return new Item_decimal(name, &decimal_value, decimals, max_length);
++ }
++ // to prevent drop fixed flag (no need parent cleanup call)
++ void cleanup() {}
++ void print(String *str);
++ Item_num *neg()
++ {
++ my_decimal_neg(&decimal_value);
++ unsigned_flag= !decimal_value.sign();
++ return this;
++ }
++ uint decimal_precision() const { return decimal_value.precision(); }
++ bool eq(const Item *, bool binary_cmp) const;
++};
++
++
++class Item_float :public Item_num
++{
++ char *presentation;
++public:
++ double value;
++ // Item_real() :value(0) {}
++ Item_float(const char *str_arg, uint length);
++ Item_float(const char *str,double val_arg,uint decimal_par,uint length)
++ :value(val_arg)
++ {
++ presentation= name=(char*) str;
++ decimals=(uint8) decimal_par;
++ max_length=length;
++ fixed= 1;
++ }
++ Item_float(double value_par) :presentation(0), value(value_par) { fixed= 1; }
++
++ int save_in_field(Field *field, bool no_conversions);
++ enum Type type() const { return REAL_ITEM; }
++ enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
++ double val_real() { DBUG_ASSERT(fixed == 1); return value; }
++ longlong val_int()
++ {
++ DBUG_ASSERT(fixed == 1);
++ return (longlong) (value+(value > 0 ? 0.5 : -0.5));
++ }
++ String *val_str(String*);
++ my_decimal *val_decimal(my_decimal *);
++ bool basic_const_item() const { return 1; }
++ // to prevent drop fixed flag (no need parent cleanup call)
++ void cleanup() {}
++ Item *new_item()
++ { return new Item_float(name, value, decimals, max_length); }
++ Item_num *neg() { value= -value; return this; }
++ void print(String *str);
++ bool eq(const Item *, bool binary_cmp) const;
++};
++
++
++class Item_static_float_func :public Item_float
++{
++ const char *func_name;
++public:
++ Item_static_float_func(const char *str, double val_arg, uint decimal_par,
++ uint length)
++ :Item_float(NullS, val_arg, decimal_par, length), func_name(str)
++ {}
++ void print(String *str) { str->append(func_name); }
++};
++
++
++class Item_string :public Item
++{
++public:
++ Item_string(const char *str,uint length,
++ CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
++ {
++ collation.set(cs, dv);
++ str_value.set_or_copy_aligned(str,length,cs);
++ /*
++ We have to have a different max_length than 'length' here to
++ ensure that we get the right length if we do use the item
++ to create a new table. In this case max_length must be the maximum
++ number of chars for a string of this type because we in create_field::
++ divide the max_length with mbmaxlen).
++ */
++ max_length= str_value.numchars()*cs->mbmaxlen;
++ set_name(str, length, cs);
++ decimals=NOT_FIXED_DEC;
++ // it is constant => can be used without fix_fields (and frequently used)
++ fixed= 1;
++ }
++ Item_string(const char *name_par, const char *str, uint length,
++ CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
++ {
++ collation.set(cs, dv);
++ str_value.set_or_copy_aligned(str,length,cs);
++ max_length= str_value.numchars()*cs->mbmaxlen;
++ set_name(name_par,0,cs);
++ decimals=NOT_FIXED_DEC;
++ // it is constant => can be used without fix_fields (and frequently used)
++ fixed= 1;
++ }
++ enum Type type() const { return STRING_ITEM; }
++ double val_real();
++ longlong val_int();
++ String *val_str(String*)
++ {
++ DBUG_ASSERT(fixed == 1);
++ return (String*) &str_value;
++ }
++ my_decimal *val_decimal(my_decimal *);
++ int save_in_field(Field *field, bool no_conversions);
++ enum Item_result result_type () const { return STRING_RESULT; }
++ enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
++ bool basic_const_item() const { return 1; }
++ bool eq(const Item *item, bool binary_cmp) const;
++ Item *new_item()
++ {
++ return new Item_string(name, str_value.ptr(),
++ str_value.length(), collation.collation);
++ }
++ Item *safe_charset_converter(CHARSET_INFO *tocs);
++ String *const_string() { return &str_value; }
++ inline void append(char *str, uint length) { str_value.append(str, length); }
++ void print(String *str);
++ // to prevent drop fixed flag (no need parent cleanup call)
++ void cleanup() {}
++};
++
++
++class Item_static_string_func :public Item_string
++{
++ const char *func_name;
++public:
++ Item_static_string_func(const char *name_par, const char *str, uint length,
++ CHARSET_INFO *cs,
++ Derivation dv= DERIVATION_COERCIBLE)
++ :Item_string(NullS, str, length, cs, dv), func_name(name_par)
++ {}
++ void print(String *str) { str->append(func_name); }
++};
++
++
++/* for show tables */
++
++class Item_datetime :public Item_string
++{
++public:
++ Item_datetime(const char *item_name): Item_string(item_name,"",0,
++ &my_charset_bin)
++ { max_length=19;}
++ enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
++};
++
++class Item_empty_string :public Item_string
++{
++public:
++ Item_empty_string(const char *header,uint length, CHARSET_INFO *cs= NULL) :
++ Item_string("",0, cs ? cs : &my_charset_bin)
++ { name=(char*) header; max_length= cs ? length * cs->mbmaxlen : length; }
++ void make_field(Send_field *field);
++};
++
++class Item_return_int :public Item_int
++{
++ enum_field_types int_field_type;
++public:
++ Item_return_int(const char *name, uint length,
++ enum_field_types field_type_arg)
++ :Item_int(name, 0, length), int_field_type(field_type_arg)
++ {
++ unsigned_flag=1;
++ }
++ enum_field_types field_type() const { return int_field_type; }
++};
++
++
++class Item_hex_string: public Item
++{
++public:
++ Item_hex_string(): Item() {}
++ Item_hex_string(const char *str,uint str_length);
++ enum Type type() const { return VARBIN_ITEM; }
++ double val_real()
++ { DBUG_ASSERT(fixed == 1); return (double) Item_hex_string::val_int(); }
++ longlong val_int();
++ bool basic_const_item() const { return 1; }
++ String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
++ my_decimal *val_decimal(my_decimal *);
++ int save_in_field(Field *field, bool no_conversions);
++ enum Item_result result_type () const { return STRING_RESULT; }
++ enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
++ // to prevent drop fixed flag (no need parent cleanup call)
++ void cleanup() {}
++ bool eq(const Item *item, bool binary_cmp) const;
++};
++
++
++class Item_bin_string: public Item_hex_string
++{
++public:
++ Item_bin_string(const char *str,uint str_length);
++};
++
++class Item_result_field :public Item /* Item with result field */
++{
++public:
++ Field *result_field; /* Save result here */
++ Item_result_field() :result_field(0) {}
++ // Constructor used for Item_sum/Item_cond_and/or (see Item comment)
++ Item_result_field(THD *thd, Item_result_field *item):
++ Item(thd, item), result_field(item->result_field)
++ {}
++ ~Item_result_field() {} /* Required with gcc 2.95 */
++ Field *get_tmp_table_field() { return result_field; }
++ Field *tmp_table_field(TABLE *t_arg) { return result_field; }
++ table_map used_tables() const { return 1; }
++ virtual void fix_length_and_dec()=0;
++ void set_result_field(Field *field) { result_field= field; }
++ bool is_result_field() { return 1; }
++ void save_in_result_field(bool no_conversions)
++ {
++ save_in_field(result_field, no_conversions);
++ }
++ void cleanup();
++};
++
++
++class Item_ref :public Item_ident
++{
++protected:
++ void set_properties();
++public:
++ Field *result_field; /* Save result here */
++ Item **ref;
++ Item_ref(const char *db_par, const char *table_name_par,
++ const char *field_name_par)
++ :Item_ident(db_par, table_name_par, field_name_par), result_field(0), ref(0) {}
++ /*
++ This constructor is used in two scenarios:
++ A) *item = NULL
++ No initialization is performed, fix_fields() call will be necessary.
++
++ B) *item points to an Item this Item_ref will refer to. This is
++ used for GROUP BY. fix_fields() will not be called in this case,
++ so we call set_properties to make this item "fixed". set_properties
++ performs a subset of action Item_ref::fix_fields does, and this subset
++ is enough for Item_ref's used in GROUP BY.
++
++ TODO we probably fix a superset of problems like in BUG#6658. Check this
++ with Bar, and if we have a more broader set of problems like this.
++ */
++ Item_ref(Item **item, const char *table_name_par, const char *field_name_par);
++
++ /* Constructor need to process subselect with temporary tables (see Item) */
++ Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {}
++ enum Type type() const { return REF_ITEM; }
++ bool eq(const Item *item, bool binary_cmp) const
++ { return ref && (*ref)->eq(item, binary_cmp); }
++ double val_real();
++ longlong val_int();
++ my_decimal *val_decimal(my_decimal *);
++ bool val_bool();
++ String *val_str(String* tmp);
++ bool is_null();
++ bool get_date(TIME *ltime,uint fuzzydate);
++ double val_result();
++ longlong val_int_result();
++ String *str_result(String* tmp);
++ my_decimal *val_decimal_result(my_decimal *);
++ bool val_bool_result();
++ bool send(Protocol *prot, String *tmp);
++ void make_field(Send_field *field) { (*ref)->make_field(field); }
++ bool fix_fields(THD *, struct st_table_list *, Item **);
++ int save_in_field(Field *field, bool no_conversions)
++ { return (*ref)->save_in_field(field, no_conversions); }
++ void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); }
++ enum Item_result result_type () const { return (*ref)->result_type(); }
++ enum_field_types field_type() const { return (*ref)->field_type(); }
++ Field *get_tmp_table_field() { return result_field; }
++ table_map used_tables() const
++ {
++ return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables();
++ }
++ void set_result_field(Field *field) { result_field= field; }
++ bool is_result_field() { return 1; }
++ void save_in_result_field(bool no_conversions)
++ {
++ (*ref)->save_in_field(result_field, no_conversions);
++ }
++ Item *real_item() { return *ref; }
++ bool walk(Item_processor processor, byte *arg)
++ { return (*ref)->walk(processor, arg); }
++ void print(String *str);
++ void cleanup();
++};
++
++
++/*
++ The same as Item_ref, but get value from val_* family of method to get
++ value of item on which it referred instead of result* family.
++*/
++class Item_direct_ref :public Item_ref
++{
++public:
++ Item_direct_ref(Item **item, const char *table_name_par,
++ const char *field_name_par)
++ :Item_ref(item, table_name_par, field_name_par) {}
++ /* Constructor need to process subselect with temporary tables (see Item) */
++ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
++
++ double val_real();
++ longlong val_int();
++ String *val_str(String* tmp);
++ my_decimal *val_decimal(my_decimal *);
++ bool val_bool();
++ bool is_null();
++ bool get_date(TIME *ltime,uint fuzzydate);
++};
++
++
++class Item_in_subselect;
++
++class Item_ref_null_helper: public Item_ref
++{
++protected:
++ Item_in_subselect* owner;
++public:
++ Item_ref_null_helper(Item_in_subselect* master, Item **item,
++ const char *table_name_par, const char *field_name_par):
++ Item_ref(item, table_name_par, field_name_par), owner(master) {}
++ double val_real();
++ longlong val_int();
++ String* val_str(String* s);
++ my_decimal *val_decimal(my_decimal *);
++ bool val_bool();
++ bool get_date(TIME *ltime, uint fuzzydate);
++ void print(String *str);
++};
++
++class Item_null_helper :public Item_ref_null_helper
++{
++ Item *store;
++public:
++ Item_null_helper(Item_in_subselect* master, Item *item,
++ const char *table_name_par, const char *field_name_par)
++ :Item_ref_null_helper(master, (store= 0, &store), table_name_par,
++ field_name_par),
++ store(item)
++ { ref= &store; }
++ void print(String *str);
++};
++
++/*
++ The following class is used to optimize comparing of date and bigint columns
++ We need to save the original item, to be able to set the field to the
++ original value in 'opt_range'.
++ An instance of Item_int_with_ref may refer to a signed or an unsigned
++ integer.
++*/
++
++class Item_int_with_ref :public Item_int
++{
++ Item *ref;
++public:
++ Item_int_with_ref(longlong i, Item *ref_arg) :Item_int(i), ref(ref_arg)
++ {
++ unsigned_flag= ref_arg->unsigned_flag;
++ }
++ int save_in_field(Field *field, bool no_conversions)
++ {
++ return ref->save_in_field(field, no_conversions);
++ }
++ Item *new_item();
++};
++
++
++#include "gstream.h"
++#include "spatial.h"
++#include "item_sum.h"
++#include "item_func.h"
++#include "item_row.h"
++#include "item_cmpfunc.h"
++#include "item_strfunc.h"
++#include "item_geofunc.h"
++#include "item_timefunc.h"
++#include "item_uniq.h"
++#include "item_subselect.h"
++
++class Item_copy_string :public Item
++{
++ enum enum_field_types cached_field_type;
++public:
++ Item *item;
++ Item_copy_string(Item *i) :item(i)
++ {
++ null_value=maybe_null=item->maybe_null;
++ decimals=item->decimals;
++ max_length=item->max_length;
++ name=item->name;
++ cached_field_type= item->field_type();
++ }
++ enum Type type() const { return COPY_STR_ITEM; }
++ enum Item_result result_type () const { return STRING_RESULT; }
++ enum_field_types field_type() const { return cached_field_type; }
++ double val_real()
++ {
++ int err_not_used;
++ char *end_not_used;
++ return (null_value ? 0.0 :
++ my_strntod(str_value.charset(), (char*) str_value.ptr(),
++ str_value.length(), &end_not_used, &err_not_used));
++ }
++ longlong val_int()
++ {
++ int err;
++ return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err);
++ }
++ String *val_str(String*);
++ my_decimal *val_decimal(my_decimal *);
++ void make_field(Send_field *field) { item->make_field(field); }
++ void copy();
++ int save_in_field(Field *field, bool no_conversions);
++ table_map used_tables() const { return (table_map) 1L; }
++ bool const_item() const { return 0; }
++ bool is_null() { return null_value; }
++};
++
++
++class Item_buff :public Sql_alloc
++{
++public:
++ my_bool null_value;
++ Item_buff() :null_value(0) {}
++ virtual bool cmp(void)=0;
++ virtual ~Item_buff(); /*line -e1509 */
++};
++
++class Item_str_buff :public Item_buff
++{
++ Item *item;
++ String value,tmp_value;
++public:
++ Item_str_buff(Item *arg) :item(arg),value(arg->max_length) {}
++ bool cmp(void);
++ ~Item_str_buff(); // Deallocate String:s
++};
++
++
++class Item_real_buff :public Item_buff
++{
++ Item *item;
++ double value;
++public:
++ Item_real_buff(Item *item_par) :item(item_par),value(0.0) {}
++ bool cmp(void);
++};
++
++class Item_int_buff :public Item_buff
++{
++ Item *item;
++ longlong value;
++public:
++ Item_int_buff(Item *item_par) :item(item_par),value(0) {}
++ bool cmp(void);
++};
++
++
++class Item_decimal_buff :public Item_buff
++{
++ Item *item;
++ my_decimal value;
++public:
++ Item_decimal_buff(Item *item_par);
++ bool cmp(void);
++};
++
++class Item_field_buff :public Item_buff
++{
++ char *buff;
++ Field *field;
++ uint length;
++
++public:
++ Item_field_buff(Item_field *item)
++ {
++ field=item->field;
++ buff= (char*) sql_calloc(length=field->pack_length());
++ }
++ bool cmp(void);
++};
++
++class Item_default_value : public Item_field
++{
++public:
++ Item *arg;
++ Item_default_value() :
++ Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(NULL) {}
++ Item_default_value(Item *a) :
++ Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {}
++ enum Type type() const { return DEFAULT_VALUE_ITEM; }
++ bool eq(const Item *item, bool binary_cmp) const;
++ bool fix_fields(THD *, struct st_table_list *, Item **);
++ void print(String *str);
++ int save_in_field(Field *field_arg, bool no_conversions);
++ table_map used_tables() const { return (table_map)0L; }
++
++ bool walk(Item_processor processor, byte *args)
++ {
++ return arg->walk(processor, args) ||
++ (this->*processor)(args);
++ }
++
++ /*
++ This method like the walk method traverses the item tree, but
++ at the same time it can replace some nodes in the tree
++ */
++ Item *transform(Item_transformer transformer, byte *args)
++ {
++ Item *new_item= arg->transform(transformer, args);
++ if (!new_item)
++ return 0;
++ arg= new_item;
++ return (this->*transformer)(args);
++ }
++};
++
++class Item_insert_value : public Item_field
++{
++public:
++ Item *arg;
++ Item_insert_value(Item *a) :
++ Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {}
++ bool eq(const Item *item, bool binary_cmp) const;
++ bool fix_fields(THD *, struct st_table_list *, Item **);
++ void print(String *str);
++ int save_in_field(Field *field_arg, bool no_conversions)
++ {
++ return Item_field::save_in_field(field_arg, no_conversions);
++ }
++ table_map used_tables() const { return (table_map)0L; }
++
++ bool walk(Item_processor processor, byte *args)
++ {
++ return arg->walk(processor, args) ||
++ (this->*processor)(args);
++ }
++};
++
++
++/*
++ We need this two enums here instead of sql_lex.h because
++ at least one of them is used by Item_trigger_field interface.
++
++ Time when trigger is invoked (i.e. before or after row actually
++ inserted/updated/deleted).
++*/
++enum trg_action_time_type
++{
++ TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1
++};
++
++/*
++ Event on which trigger is invoked.
++*/
++enum trg_event_type
++{
++ TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2
++};
++
++/*
++ Represents NEW/OLD version of field of row which is
++ changed/read in trigger.
++
++ Note: For this item actual binding to Field object happens not during
++ fix_fields() (like for Item_field) but during parsing of trigger
++ definition, when table is opened, with special setup_field() call.
++*/
++class Item_trigger_field : public Item_field
++{
++public:
++ /* Is this item represents row from NEW or OLD row ? */
++ enum row_version_type {OLD_ROW, NEW_ROW};
++ row_version_type row_version;
++ /* Next in list of all Item_trigger_field's in trigger */
++ Item_trigger_field *next_trg_field;
++
++ Item_trigger_field(row_version_type row_ver_par,
++ const char *field_name_par):
++ Item_field((const char *)NULL, (const char *)NULL, field_name_par),
++ row_version(row_ver_par)
++ {}
++ void setup_field(THD *thd, TABLE *table, enum trg_event_type event);
++ enum Type type() const { return TRIGGER_FIELD_ITEM; }
++ bool eq(const Item *item, bool binary_cmp) const;
++ bool fix_fields(THD *, struct st_table_list *, Item **);
++ void print(String *str);
++ table_map used_tables() const { return (table_map)0L; }
++ void cleanup();
++};
++
++
++class Item_cache: public Item
++{
++protected:
++ Item *example;
++ table_map used_table_map;
++public:
++ Item_cache(): example(0), used_table_map(0) {fixed= 1; null_value= 1;}
++
++ void set_used_tables(table_map map) { used_table_map= map; }
++
++ virtual bool allocate(uint i) { return 0; }
++ virtual bool setup(Item *item)
++ {
++ example= item;
++ max_length= item->max_length;
++ decimals= item->decimals;
++ collation.set(item->collation);
++ return 0;
++ };
++ virtual void store(Item *)= 0;
++ enum Type type() const { return CACHE_ITEM; }
++ static Item_cache* get_cache(Item_result type);
++ table_map used_tables() const { return used_table_map; }
++ virtual void keep_array() {}
++ // to prevent drop fixed flag (no need parent cleanup call)
++ void cleanup() {}
++ void print(String *str);
++};
++
++
++class Item_cache_int: public Item_cache
++{
++protected:
++ longlong value;
++public:
++ Item_cache_int(): Item_cache(), value(0) {}
++
++ void store(Item *item);
++ double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
++ longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
++ String* val_str(String *str);
++ my_decimal *val_decimal(my_decimal *);
++ enum Item_result result_type() const { return INT_RESULT; }
++};
++
++
++class Item_cache_real: public Item_cache
++{
++ double value;
++public:
++ Item_cache_real(): Item_cache(), value(0) {}
++
++ void store(Item *item);
++ double val_real() { DBUG_ASSERT(fixed == 1); return value; }
++ longlong val_int();
++ String* val_str(String *str);
++ my_decimal *val_decimal(my_decimal *);
++ enum Item_result result_type() const { return REAL_RESULT; }
++};
++
++
++class Item_cache_decimal: public Item_cache
++{
++protected:
++ my_decimal decimal_value;
++public:
++ Item_cache_decimal(): Item_cache() {}
++
++ void store(Item *item);
++ double val_real();
++ longlong val_int();
++ String* val_str(String *str);
++ my_decimal *val_decimal(my_decimal *);
++ enum Item_result result_type() const { return DECIMAL_RESULT; }
++};
++
++
++class Item_cache_str: public Item_cache
++{
++ char buffer[STRING_BUFFER_USUAL_SIZE];
++ String *value, value_buff;
++public:
++ Item_cache_str(): Item_cache(), value(0) { }
++
++ void store(Item *item);
++ double val_real();
++ longlong val_int();
++ String* val_str(String *) { DBUG_ASSERT(fixed == 1); return value; }
++ my_decimal *val_decimal(my_decimal *);
++ enum Item_result result_type() const { return STRING_RESULT; }
++ CHARSET_INFO *charset() const { return value->charset(); };
++};
++
++class Item_cache_row: public Item_cache
++{
++ Item_cache **values;
++ uint item_count;
++ bool save_array;
++public:
++ Item_cache_row()
++ :Item_cache(), values(0), item_count(2), save_array(0) {}
++
++ /*
++ 'allocate' used only in row transformer, to preallocate space for row
++ cache.
++ */
++ bool allocate(uint num);
++ /*
++ 'setup' is needed only by row => it not called by simple row subselect
++ (only by IN subselect (in subselect optimizer))
++ */
++ bool setup(Item *item);
++ void store(Item *item);
++ void illegal_method_call(const char *);
++ void make_field(Send_field *)
++ {
++ illegal_method_call((const char*)"make_field");
++ };
++ double val_real()
++ {
++ illegal_method_call((const char*)"val");
++ return 0;
++ };
++ longlong val_int()
++ {
++ illegal_method_call((const char*)"val_int");
++ return 0;
++ };
++ String *val_str(String *)
++ {
++ illegal_method_call((const char*)"val_str");
++ return 0;
++ };
++ my_decimal *val_decimal(my_decimal *val)
++ {
++ illegal_method_call((const char*)"val_decimal");
++ return 0;
++ };
++
++ enum Item_result result_type() const { return ROW_RESULT; }
++
++ uint cols() { return item_count; }
++ Item* el(uint i) { return values[i]; }
++ Item** addr(uint i) { return (Item **) (values + i); }
++ bool check_cols(uint c);
++ bool null_inside();
++ void bring_value();
++ void keep_array() { save_array= 1; }
++ void cleanup()
++ {
++ DBUG_ENTER("Item_cache_row::cleanup");
++ Item_cache::cleanup();
++ if (save_array)
++ bzero(values, item_count*sizeof(Item**));
++ else
++ values= 0;
++ DBUG_VOID_RETURN;
++ }
++};
++
++
++/*
++ Item_type_holder used to store type. name, length of Item for UNIONS &
++ derived tables.
++
++ Item_type_holder do not need cleanup() because its time of live limited by
++ single SP/PS execution.
++*/
++class Item_type_holder: public Item
++{
++protected:
++ TYPELIB *enum_set_typelib;
++ enum_field_types fld_type;
++
++ void get_full_info(Item *item);
++
++ /* It is used to count decimal precision in join_types */
++ int prev_decimal_int_part;
++public:
++ Item_type_holder(THD*, Item*);
++
++ Item_result result_type() const;
++ virtual enum_field_types field_type() const { return fld_type; };
++ enum Type type() const { return TYPE_HOLDER; }
++ double val_real();
++ longlong val_int();
++ my_decimal *val_decimal(my_decimal *);
++ String *val_str(String*);
++ bool join_types(THD *thd, Item *);
++ Field *make_field_by_type(TABLE *table);
++ static uint32 display_length(Item *item);
++ static enum_field_types get_real_type(Item *);
++};
++
++class st_select_lex;
++void mark_select_range_as_dependent(THD *thd,
++ st_select_lex *last_select,
++ st_select_lex *current_sel,
++ Field *found_field, Item *found_item,
++ Item_ident *resolved_item);
++
++extern Item_buff *new_Item_buff(Item *item);
++extern Item_result item_cmp_type(Item_result a,Item_result b);
++extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item);
++extern bool field_is_equal_to_item(Field *field,Item *item);
+diff -Naur mysql.orig/sql/item_create.cc mysql.xml/sql/item_create.cc
+--- mysql.orig/sql/item_create.cc 2005-05-15 06:16:52.000000000 +0200
++++ mysql.xml/sql/item_create.cc 2005-05-20 15:19:29.000000000 +0200
+@@ -496,6 +496,16 @@
+ return new Item_func_quote(a);
+ }
+
++Item *create_func_xml_extractvalue(Item *a, Item *b)
++{
++ return new Item_func_xml_extractvalue(a, b);
++}
++
++Item *create_func_xml_update(Item *a, Item *b, Item *c)
++{
++ return new Item_func_xml_update(a, b, c);
++}
++
+ #ifdef HAVE_SPATIAL
+ Item *create_func_as_wkt(Item *a)
+ {
+diff -Naur mysql.orig/sql/item_create.cc.orig mysql.xml/sql/item_create.cc.orig
+--- mysql.orig/sql/item_create.cc.orig 1970-01-01 01:00:00.000000000 +0100
++++ mysql.xml/sql/item_create.cc.orig 2005-05-15 06:16:52.000000000 +0200
+@@ -0,0 +1,725 @@
++/* Copyright (C) 2000-2003 MySQL AB
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program 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 should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++/* Functions to create an item. Used by lex.h */
++
++#include "mysql_priv.h"
++
++Item *create_func_abs(Item* a)
++{
++ return new Item_func_abs(a);
++}
++
++Item *create_func_acos(Item* a)
++{
++ return new Item_func_acos(a);
++}
++
++Item *create_func_aes_encrypt(Item* a, Item* b)
++{
++ return new Item_func_aes_encrypt(a, b);
++}
++
++Item *create_func_aes_decrypt(Item* a, Item* b)
++{
++ return new Item_func_aes_decrypt(a, b);
++}
++
++Item *create_func_ascii(Item* a)
++{
++ return new Item_func_ascii(a);
++}
++
++Item *create_func_ord(Item* a)
++{
++ return new Item_func_ord(a);
++}
++
++Item *create_func_asin(Item* a)
++{
++ return new Item_func_asin(a);
++}
++
++Item *create_func_bin(Item* a)
++{
++ return new Item_func_conv(a,new Item_int((int32) 10,2),
++ new Item_int((int32) 2,1));
++}
++
++Item *create_func_bit_count(Item* a)
++{
++ return new Item_func_bit_count(a);
++}
++
++Item *create_func_ceiling(Item* a)
++{
++ return new Item_func_ceiling(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);
++}
++
++Item *create_func_conv(Item* a, Item *b, Item *c)
++{
++ return new Item_func_conv(a,b,c);
++}
++
++Item *create_func_cos(Item* a)
++{
++ return new Item_func_cos(a);
++}
++
++Item *create_func_cot(Item* a)
++{
++ return new Item_func_div(new Item_int((char*) "1",1,1),
++ new Item_func_tan(a));
++}
++
++Item *create_func_date_format(Item* a,Item *b)
++{
++ return new Item_func_date_format(a,b,0);
++}
++
++Item *create_func_dayofmonth(Item* a)
++{
++ return new Item_func_dayofmonth(a);
++}
++
++Item *create_func_dayofweek(Item* a)
++{
++ return new Item_func_weekday(new Item_func_to_days(a),1);
++}
++
++Item *create_func_dayofyear(Item* a)
++{
++ return new Item_func_dayofyear(a);
++}
++
++Item *create_func_dayname(Item* a)
++{
++ return new Item_func_dayname(new Item_func_to_days(a));
++}
++
++Item *create_func_degrees(Item *a)
++{
++ return new Item_func_units((char*) "degrees",a,180/M_PI,0.0);
++}
++
++Item *create_func_exp(Item* a)
++{
++ return new Item_func_exp(a);
++}
++
++Item *create_func_find_in_set(Item* a, Item *b)
++{
++ return new Item_func_find_in_set(a, b);
++}
++
++Item *create_func_floor(Item* a)
++{
++ return new Item_func_floor(a);
++}
++
++Item *create_func_found_rows(void)
++{
++ THD *thd=current_thd;
++ thd->lex->safe_to_cache_query= 0;
++ return new Item_func_found_rows();
++}
++
++Item *create_func_from_days(Item* a)
++{
++ return new Item_func_from_days(a);
++}
++
++Item *create_func_get_lock(Item* a, Item *b)
++{
++ current_thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
++ return new Item_func_get_lock(a, b);
++}
++
++Item *create_func_hex(Item *a)
++{
++ return new Item_func_hex(a);
++}
++
++Item *create_func_inet_ntoa(Item* a)
++{
++ return new Item_func_inet_ntoa(a);
++}
++
++Item *create_func_inet_aton(Item* a)
++{
++ return new Item_func_inet_aton(a);
++}
++
++
++Item *create_func_ifnull(Item* a, Item *b)
++{
++ return new Item_func_ifnull(a,b);
++}
++
++Item *create_func_nullif(Item* a, Item *b)
++{
++ return new Item_func_nullif(a,b);
++}
++
++Item *create_func_locate(Item* a, Item *b)
++{
++ return new Item_func_locate(b,a);
++}
++
++Item *create_func_instr(Item* a, Item *b)
++{
++ return new Item_func_locate(a,b);
++}
++
++Item *create_func_isnull(Item* a)
++{
++ return new Item_func_isnull(a);
++}
++
++Item *create_func_lcase(Item* a)
++{
++ return new Item_func_lcase(a);
++}
++
++Item *create_func_length(Item* a)
++{
++ return new Item_func_length(a);
++}
++
++Item *create_func_bit_length(Item* a)
++{
++ return new Item_func_bit_length(a);
++}
++
++Item *create_func_coercibility(Item* a)
++{
++ return new Item_func_coercibility(a);
++}
++
++Item *create_func_char_length(Item* a)
++{
++ return new Item_func_char_length(a);
++}
++
++Item *create_func_ln(Item* a)
++{
++ return new Item_func_ln(a);
++}
++
++Item *create_func_log2(Item* a)
++{
++ return new Item_func_log2(a);
++}
++
++Item *create_func_log10(Item* a)
++{
++ return new Item_func_log10(a);
++}
++
++Item *create_func_lpad(Item* a, Item *b, Item *c)
++{
++ return new Item_func_lpad(a,b,c);
++}
++
++Item *create_func_ltrim(Item* a)
++{
++ return new Item_func_ltrim(a);
++}
++
++Item *create_func_md5(Item* a)
++{
++ return new Item_func_md5(a);
++}
++
++Item *create_func_mod(Item* a, Item *b)
++{
++ return new Item_func_mod(a,b);
++}
++
++Item *create_func_monthname(Item* a)
++{
++ return new Item_func_monthname(a);
++}
++
++Item *create_func_month(Item* a)
++{
++ return new Item_func_month(a);
++}
++
++Item *create_func_oct(Item *a)
++{
++ return new Item_func_conv(a,new Item_int((int32) 10,2),
++ new Item_int((int32) 8,1));
++}
++
++Item *create_func_period_add(Item* a, Item *b)
++{
++ return new Item_func_period_add(a,b);
++}
++
++Item *create_func_period_diff(Item* a, Item *b)
++{
++ return new Item_func_period_diff(a,b);
++}
++
++Item *create_func_pi(void)
++{
++ return new Item_static_float_func("pi()", M_PI, 6, 8);
++}
++
++Item *create_func_pow(Item* a, Item *b)
++{
++ return new Item_func_pow(a,b);
++}
++
++Item *create_func_current_user()
++{
++ THD *thd=current_thd;
++ char buff[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
++ uint length;
++
++ thd->lex->safe_to_cache_query= 0;
++ length= (uint) (strxmov(buff, thd->priv_user, "@", thd->priv_host, NullS) -
++ buff);
++ return new Item_static_string_func("current_user()",
++ thd->memdup(buff, length), length,
++ system_charset_info);
++}
++
++Item *create_func_radians(Item *a)
++{
++ return new Item_func_units((char*) "radians",a,M_PI/180,0.0);
++}
++
++Item *create_func_release_lock(Item* a)
++{
++ current_thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
++ return new Item_func_release_lock(a);
++}
++
++Item *create_func_repeat(Item* a, Item *b)
++{
++ return new Item_func_repeat(a,b);
++}
++
++Item *create_func_reverse(Item* a)
++{
++ return new Item_func_reverse(a);
++}
++
++Item *create_func_rpad(Item* a, Item *b, Item *c)
++{
++ return new Item_func_rpad(a,b,c);
++}
++
++Item *create_func_rtrim(Item* a)
++{
++ return new Item_func_rtrim(a);
++}
++
++Item *create_func_sec_to_time(Item* a)
++{
++ return new Item_func_sec_to_time(a);
++}
++
++Item *create_func_sign(Item* a)
++{
++ return new Item_func_sign(a);
++}
++
++Item *create_func_sin(Item* a)
++{
++ return new Item_func_sin(a);
++}
++
++Item *create_func_sha(Item* a)
++{
++ return new Item_func_sha(a);
++}
++
++Item *create_func_space(Item *a)
++{
++ CHARSET_INFO *cs= current_thd->variables.collation_connection;
++ Item *sp;
++
++ if (cs->mbminlen > 1)
++ {
++ uint dummy_errors;
++ sp= new Item_string("",0,cs);
++ if (sp)
++ sp->str_value.copy(" ", 1, &my_charset_latin1, cs, &dummy_errors);
++ }
++ else
++ {
++ sp= new Item_string(" ",1,cs);
++ }
++ return sp ? new Item_func_repeat(sp, a) : 0;
++}
++
++Item *create_func_soundex(Item* a)
++{
++ return new Item_func_soundex(a);
++}
++
++Item *create_func_sqrt(Item* a)
++{
++ return new Item_func_sqrt(a);
++}
++
++Item *create_func_strcmp(Item* a, Item *b)
++{
++ return new Item_func_strcmp(a,b);
++}
++
++Item *create_func_tan(Item* a)
++{
++ return new Item_func_tan(a);
++}
++
++Item *create_func_time_format(Item *a, Item *b)
++{
++ return new Item_func_date_format(a,b,1);
++}
++
++Item *create_func_time_to_sec(Item* a)
++{
++ return new Item_func_time_to_sec(a);
++}
++
++Item *create_func_to_days(Item* a)
++{
++ return new Item_func_to_days(a);
++}
++
++Item *create_func_ucase(Item* a)
++{
++ return new Item_func_ucase(a);
++}
++
++Item *create_func_unhex(Item* a)
++{
++ return new Item_func_unhex(a);
++}
++
++Item *create_func_uuid(void)
++{
++ return new Item_func_uuid();
++}
++
++Item *create_func_version(void)
++{
++ return new Item_static_string_func("version()", server_version,
++ (uint) strlen(server_version),
++ system_charset_info, DERIVATION_SYSCONST);
++}
++
++Item *create_func_weekday(Item* a)
++{
++ return new Item_func_weekday(new Item_func_to_days(a),0);
++}
++
++Item *create_func_year(Item* a)
++{
++ return new Item_func_year(a);
++}
++
++Item *create_load_file(Item* a)
++{
++ current_thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
++ return new Item_load_file(a);
++}
++
++
++Item *create_func_cast(Item *a, Cast_target cast_type, int len, int dec,
++ CHARSET_INFO *cs)
++{
++ Item *res;
++ LINT_INIT(res);
++
++ switch (cast_type) {
++ case ITEM_CAST_BINARY: res= new Item_func_binary(a); break;
++ case ITEM_CAST_SIGNED_INT: res= new Item_func_signed(a); break;
++ case ITEM_CAST_UNSIGNED_INT: res= new Item_func_unsigned(a); break;
++ case ITEM_CAST_DATE: res= new Item_date_typecast(a); break;
++ case ITEM_CAST_TIME: res= new Item_time_typecast(a); break;
++ case ITEM_CAST_DATETIME: res= new Item_datetime_typecast(a); break;
++ case ITEM_CAST_DECIMAL:
++ res= new Item_decimal_typecast(a, (len>0) ? len : 10, dec ? dec : 2);
++ break;
++ case ITEM_CAST_CHAR:
++ res= new Item_char_typecast(a, len, cs ? cs :
++ current_thd->variables.collation_connection);
++ break;
++ }
++ return res;
++}
++
++Item *create_func_is_free_lock(Item* a)
++{
++ current_thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
++ return new Item_func_is_free_lock(a);
++}
++
++Item *create_func_is_used_lock(Item* a)
++{
++ current_thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
++ return new Item_func_is_used_lock(a);
++}
++
++Item *create_func_quote(Item* a)
++{
++ return new Item_func_quote(a);
++}
++
++#ifdef HAVE_SPATIAL
++Item *create_func_as_wkt(Item *a)
++{
++ return new Item_func_as_wkt(a);
++}
++
++Item *create_func_as_wkb(Item *a)
++{
++ return new Item_func_as_wkb(a);
++}
++
++Item *create_func_srid(Item *a)
++{
++ return new Item_func_srid(a);
++}
++
++Item *create_func_startpoint(Item *a)
++{
++ return new Item_func_spatial_decomp(a, Item_func::SP_STARTPOINT);
++}
++
++Item *create_func_endpoint(Item *a)
++{
++ return new Item_func_spatial_decomp(a, Item_func::SP_ENDPOINT);
++}
++
++Item *create_func_exteriorring(Item *a)
++{
++ return new Item_func_spatial_decomp(a, Item_func::SP_EXTERIORRING);
++}
++
++Item *create_func_pointn(Item *a, Item *b)
++{
++ return new Item_func_spatial_decomp_n(a, b, Item_func::SP_POINTN);
++}
++
++Item *create_func_interiorringn(Item *a, Item *b)
++{
++ return new Item_func_spatial_decomp_n(a, b, Item_func::SP_INTERIORRINGN);
++}
++
++Item *create_func_geometryn(Item *a, Item *b)
++{
++ return new Item_func_spatial_decomp_n(a, b, Item_func::SP_GEOMETRYN);
++}
++
++Item *create_func_centroid(Item *a)
++{
++ return new Item_func_centroid(a);
++}
++
++Item *create_func_envelope(Item *a)
++{
++ return new Item_func_envelope(a);
++}
++
++Item *create_func_equals(Item *a, Item *b)
++{
++ return new Item_func_spatial_rel(a, b, Item_func::SP_EQUALS_FUNC);
++}
++
++Item *create_func_disjoint(Item *a, Item *b)
++{
++ return new Item_func_spatial_rel(a, b, Item_func::SP_DISJOINT_FUNC);
++}
++
++Item *create_func_intersects(Item *a, Item *b)
++{
++ return new Item_func_spatial_rel(a, b, Item_func::SP_INTERSECTS_FUNC);
++}
++
++Item *create_func_touches(Item *a, Item *b)
++{
++ return new Item_func_spatial_rel(a, b, Item_func::SP_TOUCHES_FUNC);
++}
++
++Item *create_func_crosses(Item *a, Item *b)
++{
++ return new Item_func_spatial_rel(a, b, Item_func::SP_CROSSES_FUNC);
++}
++
++Item *create_func_within(Item *a, Item *b)
++{
++ return new Item_func_spatial_rel(a, b, Item_func::SP_WITHIN_FUNC);
++}
++
++Item *create_func_contains(Item *a, Item *b)
++{
++ return new Item_func_spatial_rel(a, b, Item_func::SP_CONTAINS_FUNC);
++}
++
++Item *create_func_overlaps(Item *a, Item *b)
++{
++ return new Item_func_spatial_rel(a, b, Item_func::SP_OVERLAPS_FUNC);
++}
++
++Item *create_func_isempty(Item *a)
++{
++ return new Item_func_isempty(a);
++}
++
++Item *create_func_issimple(Item *a)
++{
++ return new Item_func_issimple(a);
++}
++
++Item *create_func_isclosed(Item *a)
++{
++ return new Item_func_isclosed(a);
++}
++
++Item *create_func_geometry_type(Item *a)
++{
++ return new Item_func_geometry_type(a);
++}
++
++Item *create_func_dimension(Item *a)
++{
++ return new Item_func_dimension(a);
++}
++
++Item *create_func_x(Item *a)
++{
++ return new Item_func_x(a);
++}
++
++Item *create_func_y(Item *a)
++{
++ return new Item_func_y(a);
++}
++
++Item *create_func_numpoints(Item *a)
++{
++ return new Item_func_numpoints(a);
++}
++
++Item *create_func_numinteriorring(Item *a)
++{
++ return new Item_func_numinteriorring(a);
++}
++
++Item *create_func_numgeometries(Item *a)
++{
++ return new Item_func_numgeometries(a);
++}
++
++Item *create_func_area(Item *a)
++{
++ return new Item_func_area(a);
++}
++
++Item *create_func_glength(Item *a)
++{
++ return new Item_func_glength(a);
++}
++
++Item *create_func_point(Item *a, Item *b)
++{
++ return new Item_func_point(a, b);
++}
++#endif /*HAVE_SPATIAL*/
++
++Item *create_func_crc32(Item* a)
++{
++ return new Item_func_crc32(a);
++}
++
++Item *create_func_compress(Item* a)
++{
++ return new Item_func_compress(a);
++}
++
++Item *create_func_uncompress(Item* a)
++{
++ return new Item_func_uncompress(a);
++}
++
++Item *create_func_uncompressed_length(Item* a)
++{
++ return new Item_func_uncompressed_length(a);
++}
++
++Item *create_func_datediff(Item *a, Item *b)
++{
++ return new Item_func_minus(new Item_func_to_days(a),
++ new Item_func_to_days(b));
++}
++
++Item *create_func_weekofyear(Item *a)
++{
++ return new Item_func_week(a, new Item_int((char*) "0", 3, 1));
++}
++
++Item *create_func_makedate(Item* a,Item* b)
++{
++ return new Item_func_makedate(a, b);
++}
++
++Item *create_func_addtime(Item* a,Item* b)
++{
++ return new Item_func_add_time(a, b, 0, 0);
++}
++
++Item *create_func_subtime(Item* a,Item* b)
++{
++ return new Item_func_add_time(a, b, 0, 1);
++}
++
++Item *create_func_timediff(Item* a,Item* b)
++{
++ return new Item_func_timediff(a, b);
++}
++
++Item *create_func_maketime(Item* a,Item* b,Item* c)
++{
++ return new Item_func_maketime(a, b, c);
++}
++
++Item *create_func_str_to_date(Item* a,Item* b)
++{
++ return new Item_func_str_to_date(a, b);
++}
++
++Item *create_func_last_day(Item *a)
++{
++ return new Item_func_last_day(a);
++}
+diff -Naur mysql.orig/sql/item_create.h mysql.xml/sql/item_create.h
+--- mysql.orig/sql/item_create.h 2005-05-15 06:16:52.000000000 +0200
++++ mysql.xml/sql/item_create.h 2005-05-20 15:19:29.000000000 +0200
+@@ -100,7 +100,8 @@
+ Item *create_func_is_free_lock(Item* a);
+ Item *create_func_is_used_lock(Item* a);
+ Item *create_func_quote(Item* a);
+-
++Item *create_func_xml_extractvalue(Item *a, Item *b);
++Item *create_func_xml_update(Item *a, Item *b, Item *c);
+ #ifdef HAVE_SPATIAL
+
+ Item *create_func_geometry_from_text(Item *a);
+diff -Naur mysql.orig/sql/item_xmlfunc.cc mysql.xml/sql/item_xmlfunc.cc
+--- mysql.orig/sql/item_xmlfunc.cc 1970-01-01 01:00:00.000000000 +0100
++++ mysql.xml/sql/item_xmlfunc.cc 2005-04-16 13:49:09.000000000 +0200
+@@ -0,0 +1,2555 @@
++/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program 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 should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++
++#ifdef __GNUC__
++#pragma implementation
++#endif
++
++#include "mysql_priv.h"
++#include "my_xml.h"
++
++
++/*
++ TODO: future development directions:
++ 1. add real constants for XPATH_NODESET_CMP and XPATH_NODESET
++ into enum Type in item.h.
++ 2. add nodeset_to_nodeset_comparator
++ 3. add lacking functions:
++ - name()
++ - last()
++ - lang()
++ - string()
++ - id()
++ - translate()
++ - local-name()
++ - starts-with()
++ - namespace-uri()
++ - substring-after()
++ - normalize-space()
++ - substring-before()
++ 4. add lacking axis:
++ - following-sibling
++ - following,
++ - preceding-sibling
++ - preceding
++*/
++
++
++/* Structure to store a parsed XML tree */
++typedef struct my_xml_node_st
++{
++ uint level; /* level in XML tree, 0 means root node */
++ enum my_xml_node_type type; /* node type: node, or attribute, or text */
++ uint parent; /* link to the parent */
++ const char *beg; /* beginning of the name or text */
++ const char *end; /* end of the name or text */
++ const char *tagend; /* where this tag ends */
++} MY_XML_NODE;
++
++
++/* Lexical analizer token */
++typedef struct my_xpath_lex_st
++{
++ int term; /* token type, see MY_XPATH_LEX_XXXXX below */
++ const char *beg; /* beginnign of the token */
++ const char *end; /* end of the token */
++} MY_XPATH_LEX;
++
++
++/* Structure to store nodesets */
++typedef struct my_xpath_flt_st
++{
++ uint num; /* absolute position in MY_XML_NODE array */
++ uint pos; /* relative position in context */
++} MY_XPATH_FLT;
++
++
++/* XPath function creator */
++typedef struct my_xpath_function_names_st
++{
++ const char *name; /* function name */
++ size_t length; /* function name length */
++ size_t minargs; /* min number of arguments */
++ size_t maxargs; /* max number of arguments */
++ Item *(*create)(struct my_xpath_st *xpath, Item **args, uint nargs);
++} MY_XPATH_FUNC;
++
++
++/* XPath query parser */
++typedef struct my_xpath_st
++{
++ int debug;
++ MY_XPATH_LEX query; /* Whole query */
++ MY_XPATH_LEX lasttok; /* last scanned token */
++ MY_XPATH_LEX prevtok; /* previous scanned token */
++ int axis; /* last scanned axis */
++ int extra; /* last scanned "extra", context dependent */
++ MY_XPATH_FUNC *func; /* last scanned function creator */
++ Item *item; /* current expression */
++ Item *context; /* last scanned context */
++ String *context_cache; /* last context provider */
++ String *pxml; /* Parsed XML, an array of MY_XML_NODE */
++ CHARSET_INFO *cs; /* character set/collation string comparison */
++} MY_XPATH;
++
++
++/* Dynamic array of MY_XPATH_FLT */
++class XPathFilter :public String
++{
++public:
++ XPathFilter() :String() {}
++ inline bool append_element(MY_XPATH_FLT *flt)
++ {
++ String *str= this;
++ return str->append((const char*)flt, (uint32) sizeof(MY_XPATH_FLT));
++ }
++ inline bool append_element(uint32 num, uint32 pos)
++ {
++ MY_XPATH_FLT add;
++ add.num= num;
++ add.pos= pos;
++ return append_element(&add);
++ }
++ inline MY_XPATH_FLT *element(uint i)
++ {
++ return (MY_XPATH_FLT*) (ptr() + i * sizeof(MY_XPATH_FLT));
++ }
++ inline uint32 numelements()
++ {
++ return length() / sizeof(MY_XPATH_FLT);
++ }
++};
++
++
++/*
++ Common features of the functions returning a node set.
++*/
++class Item_nodeset_func :public Item_str_func
++{
++protected:
++ String tmp_value, tmp2_value;
++ MY_XPATH_FLT *fltbeg, *fltend;
++ MY_XML_NODE *nodebeg, *nodeend;
++ uint numnodes;
++public:
++ String *pxml;
++ String context_cache;
++ Item_nodeset_func(String *pxml_arg) :Item_str_func(), pxml(pxml_arg) {}
++ Item_nodeset_func(Item *a, String *pxml_arg)
++ :Item_str_func(a), pxml(pxml_arg) {}
++ Item_nodeset_func(Item *a, Item *b, String *pxml_arg)
++ :Item_str_func(a, b), pxml(pxml_arg) {}
++ Item_nodeset_func(Item *a, Item *b, Item *c, String *pxml_arg)
++ :Item_str_func(a,b,c), pxml(pxml_arg) {}
++ void prepare_nodes()
++ {
++ nodebeg= (MY_XML_NODE*) pxml->ptr();
++ nodeend= (MY_XML_NODE*) (pxml->ptr() + pxml->length());
++ numnodes= nodeend - nodebeg;
++ }
++ void prepare(String *nodeset)
++ {
++ prepare_nodes();
++ String *res= args[0]->val_nodeset(&tmp_value);
++ fltbeg= (MY_XPATH_FLT*) res->ptr();
++ fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
++ nodeset->length(0);
++ }
++ enum Type type() const { return XPATH_NODESET; }
++ String *val_str(String *str)
++ {
++ prepare_nodes();
++ String *res= val_nodeset(&tmp2_value);
++ fltbeg= (MY_XPATH_FLT*) res->ptr();
++ fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
++ String active;
++ active.alloc(numnodes);
++ bzero((char*) active.ptr(), numnodes);
++ for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
++ {
++ MY_XML_NODE *node;
++ uint j;
++ for (j=0, node= nodebeg ; j < numnodes; j++, node++)
++ {
++ if (node->type == MY_XML_NODE_TEXT &&
++ node->parent == flt->num)
++ active[j]= 1;
++ }
++ }
++
++ str->length(0);
++ str->set_charset(collation.collation);
++ for (uint i=0 ; i < numnodes; i++)
++ {
++ if(active[i])
++ {
++ if (str->length())
++ str->append(" ", 1, &my_charset_latin1);
++ str->append(nodebeg[i].beg, nodebeg[i].end - nodebeg[i].beg);
++ }
++ }
++ return str;
++ }
++ enum Item_result result_type () const { return STRING_RESULT; }
++ void fix_length_and_dec() { max_length= MAX_BLOB_WIDTH; }
++ const char *func_name() const { return "nodeset"; }
++};
++
++
++/* Returns an XML root */
++class Item_nodeset_func_rootelement :public Item_nodeset_func
++{
++public:
++ Item_nodeset_func_rootelement(String *pxml): Item_nodeset_func(pxml) {}
++ String *val_nodeset(String *nodeset);
++};
++
++
++/* Returns a Union of two node sets */
++class Item_nodeset_func_union :public Item_nodeset_func
++{
++public:
++ Item_nodeset_func_union(Item *a, Item *b, String *pxml)
++ :Item_nodeset_func(a, b, pxml) {}
++ String *val_nodeset(String *nodeset);
++};
++
++
++/* Makes one step towards the given axis */
++class Item_nodeset_func_axisbyname :public Item_nodeset_func
++{
++ const char *node_name;
++ uint node_namelen;
++public:
++ Item_nodeset_func_axisbyname(Item *a, const char *n_arg, uint l_arg,
++ String *pxml):
++ Item_nodeset_func(a, pxml), node_name(n_arg), node_namelen(l_arg) { }
++ bool validname(MY_XML_NODE *n)
++ {
++ if (node_name[0] == '*')
++ return 1;
++ return (node_namelen == (uint) (n->end - n->beg)) &&
++ !memcmp(node_name, n->beg, node_namelen);
++ }
++};
++
++
++/* Returns children */
++class Item_nodeset_func_childbyname: public Item_nodeset_func_axisbyname
++{
++public:
++ Item_nodeset_func_childbyname(Item *a, const char *n_arg, uint l_arg,
++ String *pxml):
++ Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml) {}
++ String *val_nodeset(String *nodeset);
++};
++
++
++/* Returns descendants */
++class Item_nodeset_func_descendantbyname: public Item_nodeset_func_axisbyname
++{
++ bool need_self;
++public:
++ Item_nodeset_func_descendantbyname(Item *a, const char *n_arg, uint l_arg,
++ String *pxml, bool need_self_arg):
++ Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml),
++ need_self(need_self_arg) {}
++ String *val_nodeset(String *nodeset);
++};
++
++
++/* Returns ancestors */
++class Item_nodeset_func_ancestorbyname: public Item_nodeset_func_axisbyname
++{
++ bool need_self;
++public:
++ Item_nodeset_func_ancestorbyname(Item *a, const char *n_arg, uint l_arg,
++ String *pxml, bool need_self_arg):
++ Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml),
++ need_self(need_self_arg) {}
++ String *val_nodeset(String *nodeset);
++};
++
++
++/* Returns parents */
++class Item_nodeset_func_parentbyname: public Item_nodeset_func_axisbyname
++{
++public:
++ Item_nodeset_func_parentbyname(Item *a, const char *n_arg, uint l_arg,
++ String *pxml):
++ Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml) {}
++ String *val_nodeset(String *nodeset);
++};
++
++
++/* Returns attributes */
++class Item_nodeset_func_attributebyname: public Item_nodeset_func_axisbyname
++{
++public:
++ Item_nodeset_func_attributebyname(Item *a, const char *n_arg, uint l_arg,
++ String *pxml):
++ Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml) {}
++ String *val_nodeset(String *nodeset);
++};
++
++
++/*
++ Condition iterator: goes through all nodes in the current
++ context and checks a condition, returning those nodes
++ giving TRUE condition result.
++*/
++class Item_nodeset_func_predicate :public Item_nodeset_func
++{
++public:
++ Item_nodeset_func_predicate(Item *a, Item *b, String *pxml):
++ Item_nodeset_func(a, b, pxml) {}
++ String *val_nodeset(String *nodeset);
++};
++
++
++/* Selects nodes with a given position in context */
++class Item_nodeset_func_elementbyindex :public Item_nodeset_func
++{
++public:
++ Item_nodeset_func_elementbyindex(Item *a, Item *b, String *pxml):
++ Item_nodeset_func(a, b, pxml) { }
++ String *val_nodeset(String *nodeset);
++};
++
++
++/*
++ We need to distinguish a number from a boolean:
++ a[1] and a[true] are different things in XPath.
++*/
++class Item_bool :public Item_int
++{
++public:
++ Item_bool(int32 i): Item_int(i) {}
++ bool is_bool_func() { return 1; }
++};
++
++
++/*
++ Converts its argument into a boolean value.
++ * a number is true if it is non-zero
++ * a node-set is true if and only if it is non-empty
++ * a string is true if and only if its length is non-zero
++*/
++class Item_xpath_cast_bool :public Item_int_func
++{
++ String *pxml;
++ String tmp_value;
++public:
++ Item_xpath_cast_bool(Item *a, String *pxml_arg)
++ :Item_int_func(a), pxml(pxml_arg) {}
++ bool is_bool_func() { return 1; }
++ longlong val_int()
++ {
++ if (args[0]->type() == XPATH_NODESET)
++ {
++ String *flt= args[0]->val_nodeset(&tmp_value);
++ return flt->length() == sizeof(MY_XPATH_FLT) ? 1 : 0;
++ }
++ return args[0]->val_real() ? 1 : 0;
++ }
++};
++
++
++/*
++ Converts its argument into a number
++*/
++class Item_xpath_cast_number :public Item_real_func
++{
++public:
++ Item_xpath_cast_number(Item *a): Item_real_func(a) {}
++ virtual double val_real() { return args[0]->val_real(); }
++};
++
++
++/*
++ Context cache, for predicate
++*/
++class Item_nodeset_context_cache :public Item_nodeset_func
++{
++public:
++ String *string_cache;
++ Item_nodeset_context_cache(String *str_arg, String *pxml):
++ Item_nodeset_func(pxml), string_cache(str_arg) { }
++ String *val_nodeset(String *res)
++ { return string_cache; }
++ void fix_length_and_dec() { max_length= MAX_BLOB_WIDTH; }
++};
++
++
++class Item_func_xpath_position :public Item_int_func
++{
++ String *pxml;
++ String tmp_value;
++public:
++ Item_func_xpath_position(Item *a, String *p)
++ :Item_int_func(a), pxml(p) {}
++ void fix_length_and_dec() { max_length=10; }
++ longlong val_int()
++ {
++ String *flt= args[0]->val_nodeset(&tmp_value);
++ if (flt->length() == sizeof(MY_XPATH_FLT))
++ return ((MY_XPATH_FLT*)flt->ptr())->pos + 1;
++ return 0;
++ }
++};
++
++
++class Item_func_xpath_count :public Item_int_func
++{
++ String *pxml;
++ String tmp_value;
++public:
++ Item_func_xpath_count(Item *a, String *p)
++ :Item_int_func(a), pxml(p) {}
++ void fix_length_and_dec() { max_length=10; }
++ longlong val_int()
++ {
++ String *res= args[0]->val_nodeset(&tmp_value);
++ return res->length() / sizeof(MY_XPATH_FLT);
++ }
++};
++
++
++class Item_func_xpath_sum :public Item_real_func
++{
++ String *pxml;
++ String tmp_value;
++public:
++ Item_func_xpath_sum(Item *a, String *p)
++ :Item_real_func(a), pxml(p) {}
++
++ double val_real()
++ {
++ double sum= 0;
++ String *res= args[0]->val_nodeset(&tmp_value);
++ MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr();
++ MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
++ uint numnodes= pxml->length() / sizeof(MY_XML_NODE);
++ MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml->ptr();
++
++ for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
++ {
++ MY_XML_NODE *self= &nodebeg[flt->num];
++ for (uint j= flt->num + 1; j < numnodes; j++)
++ {
++ MY_XML_NODE *node= &nodebeg[j];
++ if (node->level <= self->level)
++ break;
++ if ((node->parent == flt->num) &&
++ (node->type == MY_XML_NODE_TEXT))
++ {
++ char *end;
++ int err;
++ double add= my_strntod(collation.collation, (char*) node->beg,
++ node->end - node->beg, &end, &err);
++ if (!err)
++ sum+= add;
++ }
++ }
++ }
++ return sum;
++ }
++};
++
++
++class Item_nodeset_to_const_comparator :public Item_bool_func
++{
++ String *pxml;
++ String tmp_nodeset;
++public:
++ Item_nodeset_to_const_comparator(Item *nodeset, Item *cmpfunc, String *p)
++ :Item_bool_func(nodeset,cmpfunc), pxml(p) {}
++ enum Type type() const { return XPATH_NODESET_CMP; };
++ bool is_bool_func() { return 1; }
++
++ longlong val_int()
++ {
++ Item_func *comp= (Item_func*)args[1];
++ Item_string *fake= (Item_string*)(comp->arguments()[1]);
++ String *res= args[0]->val_nodeset(&tmp_nodeset);
++ MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr();
++ MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
++ MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml->ptr();
++ uint numnodes= pxml->length() / sizeof(MY_XML_NODE);
++
++ for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
++ {
++ MY_XML_NODE *self= &nodebeg[flt->num];
++ for (uint j= flt->num + 1; j < numnodes; j++)
++ {
++ MY_XML_NODE *node= &nodebeg[j];
++ if (node->level <= self->level)
++ break;
++ if ((node->parent == flt->num) &&
++ (node->type == MY_XML_NODE_TEXT))
++ {
++ fake->str_value.set(node->beg, node->end - node->beg,
++ collation.collation);
++ if (args[1]->val_int())
++ return 1;
++ }
++ }
++ }
++ return 0;
++ }
++};
++
++
++String *Item_nodeset_func_rootelement::val_nodeset(String *nodeset)
++{
++ nodeset->length(0);
++ ((XPathFilter*)nodeset)->append_element(0, 0);
++ return nodeset;
++}
++
++
++String * Item_nodeset_func_union::val_nodeset(String *nodeset)
++{
++ uint numnodes= pxml->length() / sizeof(MY_XML_NODE);
++ String set0, *s0= args[0]->val_nodeset(&set0);
++ String set1, *s1= args[1]->val_nodeset(&set1);
++ String both_str;
++ both_str.alloc(numnodes);
++ char *both= (char*) both_str.ptr();
++ bzero((void*)both, numnodes);
++ uint pos= 0;
++ MY_XPATH_FLT *flt;
++
++ fltbeg= (MY_XPATH_FLT*) s0->ptr();
++ fltend= (MY_XPATH_FLT*) (s0->ptr() + s0->length());
++ for (flt= fltbeg; flt < fltend; flt++)
++ both[flt->num]= 1;
++
++ fltbeg= (MY_XPATH_FLT*) s1->ptr();
++ fltend= (MY_XPATH_FLT*) (s1->ptr() + s1->length());
++ for (flt= fltbeg; flt < fltend; flt++)
++ both[flt->num]= 1;
++
++ nodeset->length(0);
++ for (uint i= 0, pos= 0; i < numnodes; i++)
++ {
++ if (both[i])
++ ((XPathFilter*)nodeset)->append_element(i, pos++);
++ }
++ return nodeset;
++}
++
++
++String *Item_nodeset_func_childbyname::val_nodeset(String *nodeset)
++{
++ prepare(nodeset);
++ for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
++ {
++ MY_XML_NODE *self= &nodebeg[flt->num];
++ for (uint pos= 0, j= flt->num + 1 ; j < numnodes; j++)
++ {
++ MY_XML_NODE *node= &nodebeg[j];
++ if (node->level <= self->level)
++ break;
++ if ((node->parent == flt->num) &&
++ (node->type == MY_XML_NODE_TAG) &&
++ validname(node))
++ ((XPathFilter*)nodeset)->append_element(j, pos++);
++ }
++ }
++ return nodeset;
++}
++
++
++String *Item_nodeset_func_descendantbyname::val_nodeset(String *nodeset)
++{
++ prepare(nodeset);
++ for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
++ {
++ uint pos= 0;
++ MY_XML_NODE *self= &nodebeg[flt->num];
++ if (need_self && validname(self))
++ ((XPathFilter*)nodeset)->append_element(flt->num,pos++);
++ for (uint j= flt->num + 1 ; j < numnodes ; j++)
++ {
++ MY_XML_NODE *node= &nodebeg[j];
++ if (node->level <= self->level)
++ break;
++ if ((node->type == MY_XML_NODE_TAG) && validname(node))
++ ((XPathFilter*)nodeset)->append_element(j,pos++);
++ }
++ }
++ return nodeset;
++}
++
++
++String *Item_nodeset_func_ancestorbyname::val_nodeset(String *nodeset)
++{
++ char *active;
++ String active_str;
++ prepare(nodeset);
++ active_str.alloc(numnodes);
++ active= (char*) active_str.ptr();
++ bzero((void*)active, numnodes);
++ uint pos= 0;
++
++ for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
++ {
++ /*
++ Go to the root and add all nodes on the way.
++ Don't add the root if context is the root itelf
++ */
++ MY_XML_NODE *self= &nodebeg[flt->num];
++ if (need_self && validname(self))
++ {
++ active[flt->num]= 1;
++ pos++;
++ }
++
++ for (uint j= self->parent; nodebeg[j].parent != j; j= nodebeg[j].parent)
++ {
++ if (flt->num && validname(&nodebeg[j]))
++ {
++ active[j]= 1;
++ pos++;
++ }
++ }
++ }
++
++ for (uint j= 0; j < numnodes ; j++)
++ {
++ if (active[j])
++ ((XPathFilter*)nodeset)->append_element(j, --pos);
++ }
++ return nodeset;
++}
++
++
++String *Item_nodeset_func_parentbyname::val_nodeset(String *nodeset)
++{
++ char *active;
++ String active_str;
++ prepare(nodeset);
++ active_str.alloc(numnodes);
++ active= (char*) active_str.ptr();
++ bzero((void*)active, numnodes);
++ for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
++ {
++ uint j= nodebeg[flt->num].parent;
++ if (flt->num && validname(&nodebeg[j]))
++ active[j]= 1;
++ }
++ for (uint j= 0, pos= 0; j < numnodes ; j++)
++ {
++ if (active[j])
++ ((XPathFilter*)nodeset)->append_element(j, pos++);
++ }
++ return nodeset;
++}
++
++
++String *Item_nodeset_func_attributebyname::val_nodeset(String *nodeset)
++{
++ prepare(nodeset);
++ for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
++ {
++ MY_XML_NODE *self= &nodebeg[flt->num];
++ for (uint pos=0, j= flt->num + 1 ; j < numnodes; j++)
++ {
++ MY_XML_NODE *node= &nodebeg[j];
++ if (node->level <= self->level)
++ break;
++ if ((node->parent == flt->num) &&
++ (node->type == MY_XML_NODE_ATTR) &&
++ validname(node))
++ ((XPathFilter*)nodeset)->append_element(j, pos++);
++ }
++ }
++ return nodeset;
++}
++
++
++String *Item_nodeset_func_predicate::val_nodeset(String *str)
++{
++ Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
++ Item_func *comp_func= (Item_func*)args[1];
++ uint pos= 0;
++ prepare(str);
++ for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
++ {
++ nodeset_func->context_cache.length(0);
++ ((XPathFilter*)(&nodeset_func->context_cache))->append_element(flt->num,
++ flt->pos);
++ if (comp_func->val_int())
++ ((XPathFilter*)str)->append_element(flt->num, pos++);
++ }
++ return str;
++};
++
++
++String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset)
++{
++ prepare(nodeset);
++ int index= args[1]->val_int() - 1;
++ if (index >= 0)
++ {
++ MY_XPATH_FLT *flt;
++ uint pos;
++ for (pos= 0, flt= fltbeg; flt < fltend; flt++)
++ {
++ if (flt->pos == (uint) index || args[1]->is_bool_func())
++ ((XPathFilter*)nodeset)->append_element(flt->num, pos++);
++ }
++ }
++ return nodeset;
++}
++
++
++/*
++ If item is a node set, then casts it to boolean,
++ otherwise returns the item itself.
++*/
++static Item* nodeset2bool(MY_XPATH *xpath, Item *item)
++{
++ if (item->type() == Item::XPATH_NODESET)
++ return new Item_xpath_cast_bool(item, xpath->pxml);
++ return item;
++}
++
++
++/*
++ XPath lexical tokens
++*/
++#define MY_XPATH_LEX_DIGITS 'd'
++#define MY_XPATH_LEX_IDENT 'i'
++#define MY_XPATH_LEX_STRING 's'
++#define MY_XPATH_LEX_SLASH '/'
++#define MY_XPATH_LEX_LB '['
++#define MY_XPATH_LEX_RB ']'
++#define MY_XPATH_LEX_LP '('
++#define MY_XPATH_LEX_RP ')'
++#define MY_XPATH_LEX_EQ '='
++#define MY_XPATH_LEX_LESS '<'
++#define MY_XPATH_LEX_GREATER '>'
++#define MY_XPATH_LEX_AT '@'
++#define MY_XPATH_LEX_COLON ':'
++#define MY_XPATH_LEX_ASTERISK '*'
++#define MY_XPATH_LEX_DOT '.'
++#define MY_XPATH_LEX_VLINE '|'
++#define MY_XPATH_LEX_MINUS '-'
++#define MY_XPATH_LEX_PLUS '+'
++#define MY_XPATH_LEX_EXCL '!'
++#define MY_XPATH_LEX_COMMA ','
++#define MY_XPATH_LEX_DOLLAR '$'
++#define MY_XPATH_LEX_ERROR 'A'
++#define MY_XPATH_LEX_EOF 'B'
++#define MY_XPATH_LEX_AND 'C'
++#define MY_XPATH_LEX_OR 'D'
++#define MY_XPATH_LEX_DIV 'E'
++#define MY_XPATH_LEX_MOD 'F'
++#define MY_XPATH_LEX_FUNC 'G'
++#define MY_XPATH_LEX_NODETYPE 'H'
++#define MY_XPATH_LEX_AXIS 'I'
++#define MY_XPATH_LEX_LE 'J'
++#define MY_XPATH_LEX_GE 'K'
++
++
++/*
++ XPath axis type
++*/
++#define MY_XPATH_AXIS_ANCESTOR 0
++#define MY_XPATH_AXIS_ANCESTOR_OR_SELF 1
++#define MY_XPATH_AXIS_ATTRIBUTE 2
++#define MY_XPATH_AXIS_CHILD 3
++#define MY_XPATH_AXIS_DESCENDANT 4
++#define MY_XPATH_AXIS_DESCENDANT_OR_SELF 5
++#define MY_XPATH_AXIS_FOLLOWING 6
++#define MY_XPATH_AXIS_FOLLOWING_SIBLING 7
++#define MY_XPATH_AXIS_NAMESPACE 8
++#define MY_XPATH_AXIS_PARENT 9
++#define MY_XPATH_AXIS_PRECEDING 10
++#define MY_XPATH_AXIS_PRECEDING_SIBLING 11
++#define MY_XPATH_AXIS_SELF 12
++
++
++/*
++ Create scalar comparator
++
++ SYNOPSYS
++ Create a comparator function for scalar arguments,
++ for the given arguments and operation.
++
++ RETURN
++ The newly created item.
++*/
++static Item *eq_func(int oper, Item *a, Item *b)
++{
++ switch (oper)
++ {
++ case '=': return new Item_func_eq(a, b);
++ case '!': return new Item_func_ne(a, b);
++ case MY_XPATH_LEX_GE: return new Item_func_ge(a, b);
++ case MY_XPATH_LEX_LE: return new Item_func_le(a, b);
++ case MY_XPATH_LEX_GREATER: return new Item_func_gt(a, b);
++ case MY_XPATH_LEX_LESS: return new Item_func_lt(a, b);
++ }
++ return 0;
++}
++
++
++/*
++ Create scalar comparator
++
++ SYNOPSYS
++ Create a comparator function for scalar arguments,
++ for the given arguments and reverse operation, e.g.
++
++ A >= B is converted into A < B
++
++ RETURN
++ The newly created item.
++*/
++static Item *eq_func_reverse(int oper, Item *a, Item *b)
++{
++ switch (oper)
++ {
++ case '=': return new Item_func_eq(a, b);
++ case '!': return new Item_func_ne(a, b);
++ case MY_XPATH_LEX_GE: return new Item_func_lt(a, b);
++ case MY_XPATH_LEX_LE: return new Item_func_gt(a, b);
++ case MY_XPATH_LEX_GREATER: return new Item_func_le(a, b);
++ case MY_XPATH_LEX_LESS: return new Item_func_ge(a, b);
++ }
++ return 0;
++}
++
++
++/*
++ Create a comparator
++
++ SYNOPSYS
++ Create a comparator for scalar or non-scalar arguments,
++ for the given arguments and operation.
++
++ RETURN
++ The newly created item.
++*/
++static Item *create_comparator(MY_XPATH *xpath, int oper, Item *a, Item *b)
++{
++ if (a->type() != Item::XPATH_NODESET &&
++ b->type() != Item::XPATH_NODESET)
++ {
++ return eq_func(oper, a, b); // two scalar arguments
++ }
++ else if (a->type() == Item::XPATH_NODESET &&
++ b->type() == Item::XPATH_NODESET)
++ {
++ return 0; // TODO: Comparison of two nodesets
++ }
++ else
++ {
++ /*
++ Compare a node set to a scalar value.
++ We just create a fake Item_string() argument,
++ which will be filled to the partular value
++ in a loop through all of the nodes in the node set.
++ */
++
++ Item *fake= new Item_string("", 0, xpath->cs);
++ Item_nodeset_func *nodeset;
++ Item *scalar, *comp;
++ if (a->type() == Item::XPATH_NODESET)
++ {
++ nodeset= (Item_nodeset_func*) a;
++ scalar= b;
++ comp= eq_func(oper, scalar, fake);
++ }
++ else
++ {
++ nodeset= (Item_nodeset_func*) b;
++ scalar= a;
++ comp= eq_func_reverse(oper, scalar, fake);
++ }
++ return new Item_nodeset_to_const_comparator(nodeset, comp, xpath->pxml);
++ }
++}
++
++
++/*
++ Create a step
++
++ SYNOPSYS
++ Create a step function for the given argument and axis.
++
++ RETURN
++ The newly created item.
++*/
++static Item* nametestfunc(MY_XPATH *xpath,
++ int type, Item *arg, const char *beg, uint len)
++{
++ DBUG_ASSERT(arg != 0);
++ DBUG_ASSERT(arg->type() == Item::XPATH_NODESET);
++ DBUG_ASSERT(beg != 0);
++ DBUG_ASSERT(len > 0);
++
++ Item *res;
++ switch (type)
++ {
++ case MY_XPATH_AXIS_ANCESTOR:
++ res= new Item_nodeset_func_ancestorbyname(arg, beg, len, xpath->pxml, 0);
++ break;
++ case MY_XPATH_AXIS_ANCESTOR_OR_SELF:
++ res= new Item_nodeset_func_ancestorbyname(arg, beg, len, xpath->pxml, 1);
++ break;
++ case MY_XPATH_AXIS_PARENT:
++ res= new Item_nodeset_func_parentbyname(arg, beg, len, xpath->pxml);
++ break;
++ case MY_XPATH_AXIS_DESCENDANT:
++ res= new Item_nodeset_func_descendantbyname(arg, beg, len, xpath->pxml, 0);
++ break;
++ case MY_XPATH_AXIS_DESCENDANT_OR_SELF:
++ res= new Item_nodeset_func_descendantbyname(arg, beg, len, xpath->pxml, 1);
++ break;
++ case MY_XPATH_AXIS_ATTRIBUTE:
++ res= new Item_nodeset_func_attributebyname(arg, beg, len, xpath->pxml);
++ break;
++ default:
++ res= new Item_nodeset_func_childbyname(arg, beg, len, xpath->pxml);
++ }
++ return res;
++}
++
++
++/*
++ Tokens consisting of one character, for faster lexical analizer.
++*/
++static char simpletok[128]=
++{
++ 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,0,0,0,0,0,0,0,
++/*
++ ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
++ @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
++ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ €
++*/
++ 0,1,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,
++ 1,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,0,1,0,1,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,0,0,0,0,0,1,0,0,0
++};
++
++
++/*
++ XPath keywords
++*/
++struct my_xpath_keyword_names_st
++{
++ int tok;
++ const char *name;
++ size_t length;
++ int extra;
++};
++
++
++static struct my_xpath_keyword_names_st my_keyword_names[] =
++{
++ {MY_XPATH_LEX_AND , "and" , 3, 0 },
++ {MY_XPATH_LEX_OR , "or" , 2, 0 },
++ {MY_XPATH_LEX_DIV , "div" , 3, 0 },
++ {MY_XPATH_LEX_MOD , "mod" , 3, 0 },
++
++ {MY_XPATH_LEX_NODETYPE, "comment" , 7, 0 },
++ {MY_XPATH_LEX_NODETYPE, "text" , 4, 0 },
++ {MY_XPATH_LEX_NODETYPE, "processing-instruction" , 22,0 },
++ {MY_XPATH_LEX_NODETYPE, "node" , 4, 0 },
++
++ {MY_XPATH_LEX_AXIS,"ancestor" , 8,MY_XPATH_AXIS_ANCESTOR },
++ {MY_XPATH_LEX_AXIS,"ancestor-or-self" ,16,MY_XPATH_AXIS_ANCESTOR_OR_SELF },
++ {MY_XPATH_LEX_AXIS,"attribute" , 9,MY_XPATH_AXIS_ATTRIBUTE },
++ {MY_XPATH_LEX_AXIS,"child" , 5,MY_XPATH_AXIS_CHILD },
++ {MY_XPATH_LEX_AXIS,"descendant" ,10,MY_XPATH_AXIS_DESCENDANT },
++ {MY_XPATH_LEX_AXIS,"descendant-or-self",18,MY_XPATH_AXIS_DESCENDANT_OR_SELF},
++ {MY_XPATH_LEX_AXIS,"following" , 9,MY_XPATH_AXIS_FOLLOWING },
++ {MY_XPATH_LEX_AXIS,"following-sibling" ,17,MY_XPATH_AXIS_FOLLOWING_SIBLING },
++ {MY_XPATH_LEX_AXIS,"namespace" , 9,MY_XPATH_AXIS_NAMESPACE },
++ {MY_XPATH_LEX_AXIS,"parent" , 6,MY_XPATH_AXIS_PARENT },
++ {MY_XPATH_LEX_AXIS,"preceding" , 9,MY_XPATH_AXIS_PRECEDING },
++ {MY_XPATH_LEX_AXIS,"preceding-sibling" ,17,MY_XPATH_AXIS_PRECEDING_SIBLING },
++ {MY_XPATH_LEX_AXIS,"self" , 4,MY_XPATH_AXIS_SELF },
++
++ {0,NULL,0,0}
++};
++
++
++/*
++ Lookup a keyword
++
++ SYNOPSYS
++ Check that the last scanned identifier is a keyword.
++
++ RETURN
++ - Token type, on lookup success.
++ - MY_XPATH_LEX_IDENT, on lookup failure.
++*/
++static int my_xpath_keyword(MY_XPATH *x, const char *beg, const char *end)
++{
++ struct my_xpath_keyword_names_st *k;
++ size_t length= end-beg;
++ for (k= my_keyword_names; k->name; k++)
++ {
++ if (length == k->length && !strncasecmp(beg, k->name, length))
++ {
++ x->extra= k->extra;
++ return k->tok;
++ }
++ }
++ return MY_XPATH_LEX_IDENT;
++}
++
++
++/*
++ Functions to create an item, a-la those in item_create.cc
++*/
++
++static Item *create_func_true(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_bool(1);
++}
++
++
++static Item *create_func_false(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_bool(0);
++}
++
++
++static Item *create_func_not(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_func_not(nodeset2bool(xpath, args[0]));
++}
++
++
++static Item *create_func_ceiling(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_func_ceiling(args[0]);
++}
++
++
++static Item *create_func_floor(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_func_floor(args[0]);
++}
++
++
++static Item *create_func_bool(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_xpath_cast_bool(args[0], xpath->pxml);
++}
++
++
++static Item *create_func_number(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_xpath_cast_number(args[0]);
++}
++
++
++static Item *create_func_round(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_func_round(args[0], new Item_int((char*)"0",0,1),0);
++}
++
++
++static Item *create_func_last(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_func_xpath_count(xpath->context, xpath->pxml);
++}
++
++
++static Item *create_func_position(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_func_xpath_position(xpath->context, xpath->pxml);
++}
++
++
++static Item *create_func_contains(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_xpath_cast_bool(new Item_func_locate(args[0], args[1]),
++ xpath->pxml);
++}
++
++
++static Item *create_func_concat(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ return new Item_func_concat(args[0], args[1]);
++}
++
++
++static Item *create_func_substr(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ if (nargs == 2)
++ return new Item_func_substr(args[0], args[1]);
++ else
++ return new Item_func_substr(args[0], args[1], args[2]);
++}
++
++
++static Item *create_func_count(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ if (args[0]->type() != Item::XPATH_NODESET)
++ return 0;
++ return new Item_func_xpath_count(args[0], xpath->pxml);
++}
++
++
++static Item *create_func_sum(MY_XPATH *xpath, Item **args, uint nargs)
++{
++ if (args[0]->type() != Item::XPATH_NODESET)
++ return 0;
++ return new Item_func_xpath_sum(args[0], xpath->pxml);
++}
++
++
++/*
++ Functions names. Separate lists for names with
++ lengths 3,4,5 and 6 for faster lookups.
++*/
++static MY_XPATH_FUNC my_func_names3[]=
++{
++ {"sum", 3, 1 , 1 , create_func_sum},
++ {"not", 3, 1 , 1 , create_func_not},
++ {0 , 0, 0 , 0, 0}
++};
++
++
++static MY_XPATH_FUNC my_func_names4[]=
++{
++ {"last", 4, 0, 0, create_func_last},
++ {"true", 4, 0, 0, create_func_true},
++ {"name", 4, 0, 1, 0},
++ {"lang", 4, 1, 1, 0},
++ {0 , 0, 0, 0, 0}
++};
++
++
++static MY_XPATH_FUNC my_func_names5[]=
++{
++ {"count", 5, 1, 1, create_func_count},
++ {"false", 5, 0, 0, create_func_false},
++ {"floor", 5, 1, 1, create_func_floor},
++ {"round", 5, 1, 1, create_func_round},
++ {0 , 0, 0, 0, 0}
++};
++
++
++static MY_XPATH_FUNC my_func_names6[]=
++{
++ {"concat", 6, 2, 255, create_func_concat},
++ {"number", 6, 0, 1 , create_func_number},
++ {"string", 6, 0, 1 , 0},
++ {0 , 0, 0, 0 , 0}
++};
++
++
++/* Other functions, with name longer than 6, all together */
++static MY_XPATH_FUNC my_func_names[] =
++{
++ {"id" , 2 , 1 , 1 , 0},
++ {"boolean" , 7 , 1 , 1 , create_func_bool},
++ {"ceiling" , 7 , 1 , 1 , create_func_ceiling},
++ {"position" , 8 , 0 , 0 , create_func_position},
++ {"contains" , 8 , 2 , 2 , create_func_contains},
++ {"substring" , 9 , 2 , 3 , create_func_substr},
++ {"translate" , 9 , 3 , 3 , 0},
++
++ {"local-name" , 10 , 0 , 1 , 0},
++ {"starts-with" , 11 , 2 , 2 , 0},
++ {"namespace-uri" , 13 , 0 , 1 , 0},
++ {"substring-after" , 15 , 2 , 2 , 0},
++ {"normalize-space" , 15 , 0 , 1 , 0},
++ {"substring-before" , 16 , 2 , 2 , 0},
++
++ {NULL,0,0,0,0}
++};
++
++
++/*
++ Lookup a function by name
++
++ SYNOPSYS
++ Lookup a function by its name.
++
++ RETURN
++ Pointer to a MY_XPATH_FUNC variable on success.
++ 0 - on failure.
++
++*/
++MY_XPATH_FUNC *
++my_xpath_function(const char *beg, const char *end)
++{
++ MY_XPATH_FUNC *k, *function_names;
++ uint length= end-beg;
++ switch (length)
++ {
++ case 1: return 0;
++ case 3: function_names= my_func_names3; break;
++ case 4: function_names= my_func_names4; break;
++ case 5: function_names= my_func_names5; break;
++ case 6: function_names= my_func_names6; break;
++ default: function_names= my_func_names;
++ }
++ for (k= function_names; k->name; k++)
++ if (k->create && length == k->length && !strncasecmp(beg, k->name, length))
++ return k;
++ return NULL;
++}
++
++
++/* Initialize a lex analizer token */
++static void
++my_xpath_lex_init(MY_XPATH_LEX *lex,
++ const char *str, const char *strend)
++{
++ lex->beg= str;
++ lex->end= strend;
++}
++
++
++/* Initialize an XPath query parser */
++static void
++my_xpath_init(MY_XPATH *xpath)
++{
++ bzero((void*)xpath, sizeof(xpath[0]));
++}
++
++
++/*
++ Some ctype-alike helper functions. Note, we cannot
++ reuse cs->ident_map[], because in Xpath, unlike in SQL,
++ dash character is a valid identifier part.
++*/
++static int
++my_xident_beg(int c)
++{
++ return (((c) >= 'a' && (c) <= 'z') ||
++ ((c) >= 'A' && (c) <= 'Z') ||
++ ((c) == '_'));
++}
++
++
++static int
++my_xident_body(int c)
++{
++ return (((c) >= 'a' && (c) <= 'z') ||
++ ((c) >= 'A' && (c) <= 'Z') ||
++ ((c) >= '0' && (c) <= '9') ||
++ ((c)=='-'));
++}
++
++
++static int
++my_xdigit(int c)
++{
++ return ((c) >= '0' && (c) <= '9');
++}
++
++
++/*
++ Scan the next token
++
++ SYNOPSYS
++ Scan the next token from the input.
++ lex->term is set to the scanned token type.
++ lex->beg and lex->end are set to the beginnig
++ and to the end of the token.
++ RETURN
++ N/A
++*/
++static void
++my_xpath_lex_scan(MY_XPATH *xpath,
++ MY_XPATH_LEX *lex, const char *beg, const char *end)
++{
++ int ch;
++ for ( ; beg < end && *beg == ' ' ; beg++); // skip leading spaces
++ lex->beg= beg;
++
++ if (beg >= end)
++ {
++ lex->end= beg;
++ lex->term= MY_XPATH_LEX_EOF; // end of line reached
++ return;
++ }
++ ch= *beg++;
++
++ if (ch > 0 && ch < 128 && simpletok[ch])
++ {
++ // a token consisting of one character found
++ lex->end= beg;
++ lex->term= ch;
++ return;
++ }
++
++ if (my_xident_beg(ch)) // ident, or a function call, or a keyword
++ {
++ // scan until the end of the identifier
++ for ( ; beg < end && my_xident_body(*beg); beg++);
++ lex->end= beg;
++
++ // check if a function call
++ if (*beg == '(' && (xpath->func= my_xpath_function(lex->beg, beg)))
++ {
++ lex->term= MY_XPATH_LEX_FUNC;
++ return;
++ }
++
++ // check if a keyword
++ lex->term= my_xpath_keyword(xpath, lex->beg, beg);
++ return;
++ }
++
++ if (my_xdigit(ch)) // a sequence of digits
++ {
++ for ( ; beg < end && my_xdigit(*beg) ; beg++);
++ lex->end= beg;
++ lex->term= MY_XPATH_LEX_DIGITS;
++ return;
++ }
++
++ if (ch == '"' || ch == '\'') // a string: either '...' or "..."
++ {
++ for ( ; beg < end && *beg != ch ; beg++);
++ if (beg < end)
++ {
++ lex->end= beg+1;
++ lex->term= MY_XPATH_LEX_STRING;
++ return;
++ }
++ else
++ {
++ // unexpected end-of-line, without closing quot sign
++ lex->end= end;
++ lex->term= MY_XPATH_LEX_ERROR;
++ return;
++ }
++ }
++
++ lex->end= beg;
++ lex->term= MY_XPATH_LEX_ERROR; // unknown character
++ return;
++}
++
++
++/*
++ Scan the given token
++
++ SYNOPSYS
++ Scan the given token and rotate lasttok to prevtok on success.
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int
++my_xpath_parse_term(MY_XPATH *xpath, int term)
++{
++ if (xpath->lasttok.term == term)
++ {
++ xpath->prevtok= xpath->lasttok;
++ my_xpath_lex_scan(xpath, &xpath->lasttok,
++ xpath->lasttok.end, xpath->query.end);
++ return 1;
++ }
++ return 0;
++}
++
++
++/*
++ Scan AxisName
++
++ SYNOPSYS
++ Scan an axis name and store the scanned axis type into xpath->axis.
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_AxisName(MY_XPATH *xpath)
++{
++ int rc= my_xpath_parse_term(xpath, MY_XPATH_LEX_AXIS);
++ xpath->axis= xpath->extra;
++ return rc;
++}
++
++
++/*********************************************
++** Grammar rules, according to http://www.w3.org/TR/xpath
++** Implemented using recursive descendant method.
++** All the following grammar processing functions accept
++** a signle "xpath" argument and return 1 on success and 0 on error.
++** They also modify "xpath" argument by creating new items.
++*/
++
++/* [9] PredicateExpr ::= Expr */
++#define my_xpath_parse_PredicateExpr(x) my_xpath_parse_Expr((x))
++
++/* [14] Expr ::= OrExpr */
++#define my_xpath_parse_Expr(x) my_xpath_parse_OrExpr((x))
++
++static int my_xpath_parse_LocationPath(MY_XPATH *xpath);
++static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH *xpath);
++static int my_xpath_parse_RelativeLocationPath(MY_XPATH *xpath);
++static int my_xpath_parse_AbbreviatedAbsoluteLocationPath(MY_XPATH *xpath);
++static int my_xpath_parse_AbbreviatedStep(MY_XPATH *xpath);
++static int my_xpath_parse_Step(MY_XPATH *xpath);
++static int my_xpath_parse_AxisSpecifier(MY_XPATH *xpath);
++static int my_xpath_parse_NodeTest(MY_XPATH *xpath);
++static int my_xpath_parse_AbbreviatedAxisSpecifier(MY_XPATH *xpath);
++static int my_xpath_parse_NameTest(MY_XPATH *xpath);
++static int my_xpath_parse_FunctionCall(MY_XPATH *xpath);
++static int my_xpath_parse_Number(MY_XPATH *xpath);
++static int my_xpath_parse_FilterExpr(MY_XPATH *xpath);
++static int my_xpath_parse_PathExpr(MY_XPATH *xpath);
++static int my_xpath_parse_OrExpr(MY_XPATH *xpath);
++static int my_xpath_parse_UnaryExpr(MY_XPATH *xpath);
++static int my_xpath_parse_MultiplicativeExpr(MY_XPATH *xpath);
++static int my_xpath_parse_AdditiveExpr(MY_XPATH *xpath);
++static int my_xpath_parse_RelationalExpr(MY_XPATH *xpath);
++static int my_xpath_parse_AndExpr(MY_XPATH *xpath);
++static int my_xpath_parse_EqualityExpr(MY_XPATH *xpath);
++static int my_xpath_parse_VariableReference(MY_XPATH *xpath);
++static int my_xpath_parse_slash_opt_slash(MY_XPATH *xpath);
++
++
++/*
++ Scan LocationPath
++
++ SYNOPSYS
++
++ [1] LocationPath ::= RelativeLocationPath
++ | AbsoluteLocationPath
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_LocationPath(MY_XPATH *xpath)
++{
++ Item *context= xpath->context;
++
++ int rc= my_xpath_parse_RelativeLocationPath(xpath) ||
++ my_xpath_parse_AbsoluteLocationPath(xpath);
++
++ xpath->item= xpath->context;
++ xpath->context= context;
++ return rc;
++}
++
++
++/*
++ Scan Absolute Location Path
++
++ SYNOPSYS
++
++ [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
++ | AbbreviatedAbsoluteLocationPath
++ [10] AbbreviatedAbsoluteLocationPath ::= '//' RelativeLocationPath
++
++ We combine these two rules into one rule for better performance:
++
++ [2,10] AbsoluteLocationPath ::= '/' RelativeLocationPath?
++ | '//' RelativeLocationPath
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
++ return 0;
++
++ xpath->context= new Item_nodeset_func_rootelement(xpath->pxml);
++
++ if (my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
++ {
++ xpath->context= new Item_nodeset_func_descendantbyname(xpath->context,
++ "*", 1,
++ xpath->pxml, 1);
++ return my_xpath_parse_RelativeLocationPath(xpath);
++ }
++
++ if (my_xpath_parse_RelativeLocationPath(xpath))
++ return 1;
++
++ return 1;
++}
++
++
++/*
++ Scan Relative Location Path
++
++ SYNOPSYS
++
++ For better performance we combine these two rules
++
++ [3] RelativeLocationPath ::= Step
++ | RelativeLocationPath '/' Step
++ | AbbreviatedRelativeLocationPath
++ [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
++
++
++ Into this one:
++
++ [3-11] RelativeLocationPath ::= Step
++ | RelativeLocationPath '/' Step
++ | RelativeLocationPath '//' Step
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_RelativeLocationPath(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_Step(xpath))
++ return 0;
++ while (my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
++ {
++ if (my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
++ xpath->context= new Item_nodeset_func_descendantbyname(xpath->context,
++ "*", 1,
++ xpath->pxml, 1);
++ if (!my_xpath_parse_Step(xpath))
++ return 0;
++ }
++ return 1;
++}
++
++
++/*
++ Scan non-abbreviated or abbreviated Step
++
++ SYNOPSYS
++
++ [4] Step ::= AxisSpecifier NodeTest Predicate*
++ | AbbreviatedStep
++ [8] Predicate ::= '[' PredicateExpr ']'
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int
++my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_AxisSpecifier(xpath))
++ return 0;
++
++ if (!my_xpath_parse_NodeTest(xpath))
++ return 0;
++
++ while (my_xpath_parse_term(xpath, MY_XPATH_LEX_LB))
++ {
++ Item *prev_context= xpath->context;
++ String *context_cache;
++ context_cache= &((Item_nodeset_func*)xpath->context)->context_cache;
++ xpath->context= new Item_nodeset_context_cache(context_cache, xpath->pxml);
++ xpath->context_cache= context_cache;
++
++ if(!my_xpath_parse_PredicateExpr(xpath))
++ return 0;
++
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_RB))
++ return 0;
++
++ xpath->item= nodeset2bool(xpath, xpath->item);
++
++ if (xpath->item->is_bool_func())
++ {
++ xpath->context= new Item_nodeset_func_predicate(prev_context,
++ xpath->item,
++ xpath->pxml);
++ }
++ else
++ {
++ xpath->context= new Item_nodeset_func_elementbyindex(prev_context,
++ xpath->item,
++ xpath->pxml);
++ }
++ }
++ return 1;
++}
++
++
++static int my_xpath_parse_Step(MY_XPATH *xpath)
++{
++ return
++ my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(xpath) ||
++ my_xpath_parse_AbbreviatedStep(xpath);
++}
++
++
++/*
++ Scan Abbreviated Axis Specifier
++
++ SYNOPSYS
++ [5] AxisSpecifier ::= AxisName '::'
++ | AbbreviatedAxisSpecifier
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_AbbreviatedAxisSpecifier(MY_XPATH *xpath)
++{
++ if (my_xpath_parse_term(xpath, MY_XPATH_LEX_AT))
++ xpath->axis= MY_XPATH_AXIS_ATTRIBUTE;
++ else
++ xpath->axis= MY_XPATH_AXIS_CHILD;
++ return 1;
++}
++
++
++/*
++ Scan non-abbreviated axis specifier
++
++ SYNOPSYS
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_AxisName_colon_colon(MY_XPATH *xpath)
++{
++ return my_xpath_parse_AxisName(xpath) &&
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_COLON) &&
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_COLON);
++}
++
++
++/*
++ Scan Abbreviated AxisSpecifier
++
++ SYNOPSYS
++ [13] AbbreviatedAxisSpecifier ::= '@'?
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_AxisSpecifier(MY_XPATH *xpath)
++{
++ return my_xpath_parse_AxisName_colon_colon(xpath) ||
++ my_xpath_parse_AbbreviatedAxisSpecifier(xpath);
++}
++
++
++/*
++ Scan NodeType followed by parens
++
++ SYNOPSYS
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_NodeTest_lp_rp(MY_XPATH *xpath)
++{
++ return my_xpath_parse_term(xpath, MY_XPATH_LEX_NODETYPE) &&
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_LP) &&
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_RP);
++}
++
++
++/*
++ Scan NodeTest
++
++ SYNOPSYS
++
++ [7] NodeTest ::= NameTest
++ | NodeType '(' ')'
++ | 'processing-instruction' '(' Literal ')'
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_NodeTest(MY_XPATH *xpath)
++{
++ return my_xpath_parse_NameTest(xpath) ||
++ my_xpath_parse_NodeTest_lp_rp(xpath);
++}
++
++
++/*
++ Scan Abbreviated Step
++
++ SYNOPSYS
++
++ [12] AbbreviatedStep ::= '.' | '..'
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_AbbreviatedStep(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DOT))
++ return 0;
++ if (my_xpath_parse_term(xpath, MY_XPATH_LEX_DOT))
++ xpath->context= new Item_nodeset_func_parentbyname(xpath->context, "*", 1,
++ xpath->pxml);
++ return 1;
++}
++
++
++/*
++ Scan Primary Expression
++
++ SYNOPSYS
++
++ [15] PrimaryExpr ::= VariableReference
++ | '(' Expr ')'
++ | Literal
++ | Number
++ | FunctionCall
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_lp_Expr_rp(MY_XPATH *xpath)
++{
++ return my_xpath_parse_term(xpath, MY_XPATH_LEX_LP) &&
++ my_xpath_parse_Expr(xpath) &&
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_RP);
++}
++static int my_xpath_parse_PrimaryExpr_literal(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_STRING))
++ return 0;
++ xpath->item= new Item_string(xpath->prevtok.beg + 1,
++ xpath->prevtok.end - xpath->prevtok.beg - 2,
++ xpath->cs);
++ return 1;
++}
++static int my_xpath_parse_PrimaryExpr(MY_XPATH *xpath)
++{
++ return
++ my_xpath_parse_lp_Expr_rp(xpath) ||
++ my_xpath_parse_VariableReference(xpath) ||
++ my_xpath_parse_PrimaryExpr_literal(xpath) ||
++ my_xpath_parse_Number(xpath) ||
++ my_xpath_parse_FunctionCall(xpath);
++}
++
++
++/*
++ Scan Function Call
++
++ SYNOPSYS
++ [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument )* )? ')'
++ [17] Argument ::= Expr
++
++ RETURN
++ 1 - success
++ 0 - failure
++
++*/
++static int my_xpath_parse_FunctionCall(MY_XPATH *xpath)
++{
++ Item *args[256];
++ uint nargs;
++
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_FUNC))
++ return 0;
++
++ MY_XPATH_FUNC *func= xpath->func;
++
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_LP))
++ return 0;
++
++ for (nargs= 0 ; nargs < func->maxargs; )
++ {
++ if (!my_xpath_parse_Expr(xpath))
++ return 0;
++ args[nargs++]= xpath->item;
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_COMMA))
++ {
++ if (nargs < func->minargs)
++ return 0;
++ else
++ break;
++ }
++ }
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_RP))
++ return 0;
++
++ return ((xpath->item= func->create(xpath, args, nargs))) ? 1 : 0;
++}
++
++
++/*
++ Scan Union Expression
++
++ SYNOPSYS
++ [18] UnionExpr ::= PathExpr
++ | UnionExpr '|' PathExpr
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_UnionExpr(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_PathExpr(xpath))
++ return 0;
++
++ while (my_xpath_parse_term(xpath, MY_XPATH_LEX_VLINE))
++ {
++ Item *prev= xpath->item;
++ if (prev->type() != Item::XPATH_NODESET)
++ return 0;
++
++ if (!my_xpath_parse_PathExpr(xpath)
++ || xpath->item->type() != Item::XPATH_NODESET)
++ return 0;
++ xpath->item= new Item_nodeset_func_union(prev, xpath->item, xpath->pxml);
++ }
++ return 1;
++}
++
++
++/*
++ Scan Path Expression
++
++ SYNOPSYS
++
++ [19] PathExpr ::= LocationPath
++ | FilterExpr
++ | FilterExpr '/' RelativeLocationPath
++ | FilterExpr '//' RelativeLocationPath
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int
++my_xpath_parse_FilterExpr_opt_slashes_RelativeLocationPath(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_FilterExpr(xpath))
++ return 0;
++
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
++ return 1;
++
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH);
++ return my_xpath_parse_RelativeLocationPath(xpath);
++}
++static int my_xpath_parse_PathExpr(MY_XPATH *xpath)
++{
++ return my_xpath_parse_LocationPath(xpath) ||
++ my_xpath_parse_FilterExpr_opt_slashes_RelativeLocationPath(xpath);
++}
++
++
++
++/*
++ Scan Filter Expression
++
++ SYNOPSYS
++ [20] FilterExpr ::= PrimaryExpr
++ | FilterExpr Predicate
++
++ or in other words:
++
++ [20] FilterExpr ::= PrimaryExpr Predicate*
++
++ RETURN
++ 1 - success
++ 0 - failure
++
++*/
++static int my_xpath_parse_FilterExpr(MY_XPATH *xpath)
++{
++ return my_xpath_parse_PrimaryExpr(xpath);
++}
++
++
++/*
++ Scan Or Expression
++
++ SYNOPSYS
++ [21] OrExpr ::= AndExpr
++ | OrExpr 'or' AndExpr
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_OrExpr(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_AndExpr(xpath))
++ return 0;
++
++ while (my_xpath_parse_term(xpath, MY_XPATH_LEX_OR))
++ {
++ Item *prev= xpath->item;
++ if (!my_xpath_parse_AndExpr(xpath))
++ return 0;
++ xpath->item= new Item_cond_or(nodeset2bool(xpath, prev),
++ nodeset2bool(xpath, xpath->item));
++ }
++ return 1;
++}
++
++
++/*
++ Scan And Expression
++
++ SYNOPSYS
++ [22] AndExpr ::= EqualityExpr
++ | AndExpr 'and' EqualityExpr
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_AndExpr(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_EqualityExpr(xpath))
++ return 0;
++
++ while (my_xpath_parse_term(xpath, MY_XPATH_LEX_AND))
++ {
++ Item *prev= xpath->item;
++ if (!my_xpath_parse_EqualityExpr(xpath))
++ return 0;
++
++ xpath->item= new Item_cond_and(nodeset2bool(xpath,prev),
++ nodeset2bool(xpath,xpath->item));
++ }
++ return 1;
++}
++
++
++/*
++ Scan Equality Expression
++
++ SYNOPSYS
++ [23] EqualityExpr ::= RelationalExpr
++ | EqualityExpr '=' RelationalExpr
++ | EqualityExpr '!=' RelationalExpr
++ or in other words:
++
++ [23] EqualityExpr ::= RelationalExpr ( EqualityOperator EqualityExpr )*
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_ne(MY_XPATH *xpath)
++{
++ return my_xpath_parse_term(xpath, MY_XPATH_LEX_EXCL) &&
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_EQ);
++}
++static int my_xpath_parse_EqualityOperator(MY_XPATH *xpath)
++{
++ if (my_xpath_parse_ne(xpath))
++ {
++ xpath->extra= '!';
++ return 1;
++ }
++ if (my_xpath_parse_term(xpath, MY_XPATH_LEX_EQ))
++ {
++ xpath->extra= '=';
++ return 1;
++ }
++ return 0;
++}
++static int my_xpath_parse_EqualityExpr(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_RelationalExpr(xpath))
++ return 0;
++ while (my_xpath_parse_EqualityOperator(xpath))
++ {
++ Item *prev= xpath->item;
++ int oper= xpath->extra;
++ if (!my_xpath_parse_RelationalExpr(xpath))
++ return 0;
++
++ if (!(xpath->item= create_comparator(xpath, oper, prev, xpath->item)))
++ return 0;
++ }
++ return 1;
++}
++
++
++/*
++ Scan Relational Expression
++
++ SYNOPSYS
++
++ [24] RelationalExpr ::= AdditiveExpr
++ | RelationalExpr '<' AdditiveExpr
++ | RelationalExpr '>' AdditiveExpr
++ | RelationalExpr '<=' AdditiveExpr
++ | RelationalExpr '>=' AdditiveExpr
++ or in other words:
++
++ [24] RelationalExpr ::= AdditiveExpr (RelationalOperator RelationalExpr)*
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_RelationalOperator(MY_XPATH *xpath)
++{
++ if (my_xpath_parse_term(xpath, MY_XPATH_LEX_LESS))
++ {
++ xpath->extra= my_xpath_parse_term(xpath, MY_XPATH_LEX_EQ) ?
++ MY_XPATH_LEX_LE : MY_XPATH_LEX_LESS;
++ return 1;
++ }
++ else if (my_xpath_parse_term(xpath, MY_XPATH_LEX_GREATER))
++ {
++ xpath->extra= my_xpath_parse_term(xpath, MY_XPATH_LEX_EQ) ?
++ MY_XPATH_LEX_GE : MY_XPATH_LEX_GREATER;
++ return 1;
++ }
++ return 0;
++}
++static int my_xpath_parse_RelationalExpr(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_AdditiveExpr(xpath))
++ return 0;
++ while (my_xpath_parse_RelationalOperator(xpath))
++ {
++ Item *prev= xpath->item;
++ int oper= xpath->extra;
++
++ if (!my_xpath_parse_AdditiveExpr(xpath))
++ return 0;
++
++ if (!(xpath->item= create_comparator(xpath, oper, prev, xpath->item)))
++ return 0;
++ }
++ return 1;
++}
++
++
++/*
++ Scan Additive Expression
++
++ SYNOPSYS
++
++ [25] AdditiveExpr ::= MultiplicativeExpr
++ | AdditiveExpr '+' MultiplicativeExpr
++ | AdditiveExpr '-' MultiplicativeExpr
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_AdditiveOperator(MY_XPATH *xpath)
++{
++ return my_xpath_parse_term(xpath, MY_XPATH_LEX_PLUS) ||
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_MINUS);
++}
++static int my_xpath_parse_AdditiveExpr(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_MultiplicativeExpr(xpath))
++ return 0;
++
++ while (my_xpath_parse_AdditiveOperator(xpath))
++ {
++ int oper= xpath->prevtok.term;
++ Item *prev= xpath->item;
++ if (!my_xpath_parse_MultiplicativeExpr(xpath))
++ return 0;
++
++ if (oper == MY_XPATH_LEX_PLUS)
++ xpath->item= new Item_func_plus(prev, xpath->item);
++ else
++ xpath->item= new Item_func_minus(prev, xpath->item);
++ };
++ return 1;
++}
++
++
++/*
++ Scan Multiplicative Expression
++
++ SYNOPSYS
++
++ [26] MultiplicativeExpr ::= UnaryExpr
++ | MultiplicativeExpr MultiplyOperator UnaryExpr
++ | MultiplicativeExpr 'div' UnaryExpr
++ | MultiplicativeExpr 'mod' UnaryExpr
++ or in other words:
++
++ [26] MultiplicativeExpr ::= UnaryExpr (MulOper MultiplicativeExpr)*
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_MultiplicativeOperator(MY_XPATH *xpath)
++{
++ return
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_ASTERISK) ||
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_DIV) ||
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_MOD);
++}
++static int my_xpath_parse_MultiplicativeExpr(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_UnaryExpr(xpath))
++ return 0;
++
++ while (my_xpath_parse_MultiplicativeOperator(xpath))
++ {
++ int oper= xpath->prevtok.term;
++ Item *prev= xpath->item;
++ if (!my_xpath_parse_UnaryExpr(xpath))
++ return 0;
++ switch (oper)
++ {
++ case MY_XPATH_LEX_ASTERISK:
++ xpath->item= new Item_func_mul(prev, xpath->item);
++ break;
++ case MY_XPATH_LEX_DIV:
++ xpath->item= new Item_func_int_div(prev, xpath->item);
++ break;
++ case MY_XPATH_LEX_MOD:
++ xpath->item= new Item_func_mod(prev, xpath->item);
++ break;
++ }
++ }
++ return 1;
++}
++
++
++/*
++ Scan Unary Expression
++
++ SYNOPSYS
++
++ [27] UnaryExpr ::= UnionExpr
++ | '-' UnaryExpr
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_UnaryExpr(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_MINUS))
++ return my_xpath_parse_UnionExpr(xpath);
++ if (!my_xpath_parse_UnaryExpr(xpath))
++ return 0;
++ xpath->item= new Item_func_neg(xpath->item);
++ return 1;
++}
++
++
++/*
++ Scan Number
++
++ SYNOPSYS
++
++ [30] Number ::= Digits ('.' Digits?)? | '.' Digits)
++
++ or in other words:
++
++ [30] Number ::= Digits
++ | Digits '.'
++ | Digits '.' Digits
++ | '.' Digits
++
++ Note: the last rule is not supported yet,
++ as it is in conflict with abbreviated step.
++ 1 + .123 does not work,
++ 1 + 0.123 does.
++ Perhaps it is better to move this code into lex analizer.
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int my_xpath_parse_Number(MY_XPATH *xpath)
++{
++ const char *beg;
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DIGITS))
++ return 0;
++ beg= xpath->prevtok.beg;
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DOT))
++ {
++ xpath->item= new Item_int(xpath->prevtok.beg,
++ xpath->prevtok.end - xpath->prevtok.beg);
++ return 1;
++ }
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_DIGITS);
++
++ xpath->item= new Item_float(beg, xpath->prevtok.end - beg);
++ return 1;
++}
++
++
++/*
++ Scan Variable reference
++
++ SYNOPSYS
++
++ [36] VariableReference ::= '$' QName
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int
++my_xpath_parse_VariableReference(MY_XPATH *xpath)
++{
++ return my_xpath_parse_term(xpath, MY_XPATH_LEX_DOLLAR) &&
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT);
++}
++
++
++/*
++ Scan Name Test
++
++ SYNOPSYS
++
++ [37] NameTest ::= '*'
++ | NCName ':' '*'
++ | QName
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int
++my_xpath_parse_NodeTest_QName(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))
++ return 0;
++ DBUG_ASSERT(xpath->context);
++ uint len= xpath->prevtok.end - xpath->prevtok.beg;
++ xpath->context= nametestfunc(xpath, xpath->axis, xpath->context,
++ xpath->prevtok.beg, len);
++ return 1;
++}
++static int
++my_xpath_parse_NodeTest_asterisk(MY_XPATH *xpath)
++{
++ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_ASTERISK))
++ return 0;
++ DBUG_ASSERT(xpath->context);
++ xpath->context= nametestfunc(xpath, xpath->axis, xpath->context, "*", 1);
++ return 1;
++}
++static int
++my_xpath_parse_NameTest(MY_XPATH *xpath)
++{
++ return my_xpath_parse_NodeTest_asterisk(xpath) ||
++ my_xpath_parse_NodeTest_QName(xpath);
++}
++
++
++/*
++ Scan an XPath expression
++
++ SYNOPSYS
++ Scan xpath expression.
++ The expression is returned in xpath->expr.
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static int
++my_xpath_parse(MY_XPATH *xpath, const char *str, const char *strend)
++{
++ my_xpath_lex_init(&xpath->query, str, strend);
++ my_xpath_lex_init(&xpath->prevtok, str, strend);
++ my_xpath_lex_scan(xpath, &xpath->lasttok, str, strend);
++
++ return
++ my_xpath_parse_Expr(xpath) &&
++ my_xpath_parse_term(xpath, MY_XPATH_LEX_EOF);
++}
++
++
++void Item_xml_str_func::fix_length_and_dec()
++{
++ String *xp, tmp;
++ MY_XPATH xpath;
++ int rc;
++
++ nodeset_func= 0;
++
++ if (agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV))
++ return;
++
++ if (collation.collation->mbminlen > 1)
++ {
++ /* UCS2 is not supported */
++ my_printf_error(ER_UNKNOWN_ERROR,
++ "Character set '%s' is not supported by XPATH",
++ MYF(0), collation.collation->csname);
++ return;
++ }
++
++ if (!args[1]->const_item())
++ {
++ my_printf_error(ER_UNKNOWN_ERROR,
++ "Only constant XPATH queries are supported", MYF(0));
++ return;
++ }
++
++ xp= args[1]->val_str(&tmp);
++ my_xpath_init(&xpath);
++ xpath.cs= collation.collation;
++ xpath.debug= 0;
++ xpath.pxml= &pxml;
++
++ rc= my_xpath_parse(&xpath, xp->ptr(), xp->ptr() + xp->length());
++
++ if (!rc)
++ {
++ char context[32];
++ uint clen= xpath.query.end - xpath.lasttok.beg;
++ set_if_bigger(clen, sizeof(context) - 1);
++ memcpy(context, xpath.lasttok.beg, clen);
++ context[clen]= '\0';
++ my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%s'",
++ MYF(0), context);
++ return;
++ }
++
++ nodeset_func= xpath.item;
++ if (nodeset_func)
++ nodeset_func->fix_fields(current_thd, 0, &nodeset_func);
++ max_length= MAX_BLOB_WIDTH;
++}
++
++
++#define MAX_LEVEL 256
++typedef struct
++{
++ uint level;
++ String *pxml; // parsed XML
++ uint pos[MAX_LEVEL]; // Tag position stack
++} MY_XML_USER_DATA;
++
++
++/*
++ Find the parent node
++
++ SYNOPSYS
++ Find the parent node, i.e. a tag or attrubute node on the given level.
++
++ RETURN
++ 1 - success
++ 0 - failure
++*/
++static uint xml_parent_tag(MY_XML_NODE *items, uint nitems, uint level)
++{
++ if (!nitems)
++ return 0;
++
++ MY_XML_NODE *p, *last= &items[nitems-1];
++ for (p= last; p >= items; p--)
++ {
++ if (p->level == level &&
++ (p->type == MY_XML_NODE_TAG ||
++ p->type == MY_XML_NODE_ATTR))
++ {
++ return p - items;
++ }
++ }
++ return 0;
++}
++
++
++/*
++ Process tag beginning
++
++ SYNOPSYS
++
++ A call-back function executed when XML parser
++ is entering a tag or an attribue.
++ Appends the new node into data->pxml.
++ Increments data->level.
++
++ RETURN
++ Currently only MY_XML_OK
++*/
++static int xml_enter(MY_XML_PARSER *st,const char *attr, uint len)
++{
++ MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
++ MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr();
++ uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE);
++ uint parent= xml_parent_tag(nodes, numnodes, data->level - 1);
++ MY_XML_NODE node;
++
++ data->pos[data->level]= numnodes;
++ node.level= data->level++;
++ node.type= st->current_node_type; // TAG or ATTR
++ node.beg= attr;
++ node.end= attr + len;
++ node.parent= parent;
++ data->pxml->append((const char*) &node, sizeof(MY_XML_NODE));
++ return MY_XML_OK;
++}
++
++
++/*
++ Process text node
++
++ SYNOPSYS
++
++ A call-back function executed when XML parser
++ is entering into a tag or an attribue textual value.
++ The value is appended into data->pxml.
++
++ RETURN
++ Currently only MY_XML_OK
++*/
++static int xml_value(MY_XML_PARSER *st,const char *attr, uint len)
++{
++ MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
++ MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr();
++ uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE);
++ uint parent= xml_parent_tag(nodes, numnodes, data->level - 1);
++ MY_XML_NODE node;
++
++ node.level= data->level;
++ node.type= MY_XML_NODE_TEXT;
++ node.beg= attr;
++ node.end= attr + len;
++ node.parent= parent;
++ data->pxml->append((const char*) &node, sizeof(MY_XML_NODE));
++ return MY_XML_OK;
++}
++
++
++/*
++ Leave a tag or an attribute
++
++ SYNOPSYS
++
++ A call-back function executed when XML parser
++ is leaving a tag or an attribue.
++ Decrements data->level.
++
++ RETURN
++ Currently only MY_XML_OK
++*/
++static int xml_leave(MY_XML_PARSER *st,const char *attr, uint len)
++{
++ MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
++ DBUG_ASSERT(data->level > 0);
++ data->level--;
++
++ MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr();
++ nodes+= data->pos[data->level];
++ nodes->tagend= st->cur;
++
++ return MY_XML_OK;
++}
++
++
++/*
++ Parse raw XML
++
++ SYNOPSYS
++
++
++ RETURN
++ Currently pointer to parsed XML on success
++ 0 on parse error
++*/
++String *Item_xml_str_func::parse_xml(String *raw_xml, String *parsed_xml_buf)
++{
++ MY_XML_PARSER p;
++ MY_XML_USER_DATA user_data;
++ int rc;
++
++ parsed_xml_buf->length(0);
++
++ /* Prepare XML parser */
++ my_xml_parser_create(&p);
++ p.flags= MY_XML_FLAG_RELATIVE_NAMES | MY_XML_FLAG_SKIP_TEXT_NORMALIZATION;
++ user_data.level= 0;
++ user_data.pxml= parsed_xml_buf;
++ my_xml_set_enter_handler(&p, xml_enter);
++ my_xml_set_value_handler(&p, xml_value);
++ my_xml_set_leave_handler(&p, xml_leave);
++ my_xml_set_user_data(&p, (void*) &user_data);
++
++ /* Add root node */
++ p.current_node_type= MY_XML_NODE_TAG;
++ xml_enter(&p, raw_xml->ptr(), 0);
++
++ /* Execute XML parser */
++ rc= my_xml_parse(&p, raw_xml->ptr(), raw_xml->length());
++ my_xml_parser_free(&p);
++
++ return rc == MY_XML_OK ? parsed_xml_buf : 0;
++}
++
++
++String *Item_func_xml_extractvalue::val_str(String *str)
++{
++ String *res;
++ if (!nodeset_func ||
++ !(res= args[0]->val_str(str)) ||
++ !parse_xml(res, &pxml))
++ {
++ null_value= 1;
++ return 0;
++ }
++ res= nodeset_func->val_str(&tmp_value);
++ return res;
++}
++
++
++String *Item_func_xml_update::val_str(String *str)
++{
++ String *res, *nodeset, *rep;
++
++ if (!nodeset_func ||
++ !(res= args[0]->val_str(str)) ||
++ !(rep= args[2]->val_str(&tmp_value3)) ||
++ !parse_xml(res, &pxml) ||
++ !(nodeset= nodeset_func->val_nodeset(&tmp_value2)))
++ {
++ null_value= 1;
++ return 0;
++ }
++
++ MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml.ptr();
++ MY_XML_NODE *nodeend= (MY_XML_NODE*) pxml.ptr() + pxml.length();
++ MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) nodeset->ptr();
++ MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (nodeset->ptr() + nodeset->length());
++
++ /* Allow replacing of one tag only */
++ if (fltend - fltbeg != 1)
++ {
++ /* TODO: perhaps add a warning that more than one tag selected */
++ return res;
++ }
++
++ nodebeg+= fltbeg->num;
++
++ tmp_value.length(0);
++ tmp_value.set_charset(collation.collation);
++ uint offs= nodebeg->type == MY_XML_NODE_TAG ? 1 : 0;
++ tmp_value.append(res->ptr(), nodebeg->beg - res->ptr() - offs);
++ tmp_value.append(rep->ptr(), rep->length());
++ const char *end= nodebeg->tagend + offs;
++ tmp_value.append(end, res->ptr() + res->length() - end);
++ return &tmp_value;
++}
+diff -Naur mysql.orig/sql/item_xmlfunc.h mysql.xml/sql/item_xmlfunc.h
+--- mysql.orig/sql/item_xmlfunc.h 1970-01-01 01:00:00.000000000 +0100
++++ mysql.xml/sql/item_xmlfunc.h 2005-04-13 07:03:10.000000000 +0200
+@@ -0,0 +1,54 @@
++/* Copyright (C) 2000-2005 MySQL AB
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program 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 should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++
++/* This file defines all XML functions */
++
++
++#ifdef __GNUC__
++#pragma interface /* gcc class implementation */
++#endif
++
++
++class Item_xml_str_func: public Item_str_func
++{
++protected:
++ String tmp_value, pxml;
++ Item *nodeset_func;
++public:
++ Item_xml_str_func(Item *a, Item *b): Item_str_func(a,b) {}
++ Item_xml_str_func(Item *a, Item *b, Item *c): Item_str_func(a,b,c) {}
++ void fix_length_and_dec();
++ String *parse_xml(String *raw_xml, String *parsed_xml_buf);
++};
++
++
++class Item_func_xml_extractvalue: public Item_xml_str_func
++{
++public:
++ Item_func_xml_extractvalue(Item *a,Item *b) :Item_xml_str_func(a,b) {}
++ String *val_str(String *);
++};
++
++
++class Item_func_xml_update: public Item_xml_str_func
++{
++ String tmp_value2, tmp_value3;
++public:
++ Item_func_xml_update(Item *a,Item *b,Item *c) :Item_xml_str_func(a,b,c) {}
++ String *val_str(String *);
++};
++
+diff -Naur mysql.orig/sql/lex.h mysql.xml/sql/lex.h
+--- mysql.orig/sql/lex.h 2005-05-15 06:16:51.000000000 +0200
++++ mysql.xml/sql/lex.h 2005-05-20 15:19:29.000000000 +0200
+@@ -607,6 +607,7 @@
+ { "EQUALS", F_SYM(FUNC_ARG2),0,CREATE_FUNC_GEOM(create_func_equals)},
+ { "EXTERIORRING", F_SYM(FUNC_ARG1),0,CREATE_FUNC_GEOM(create_func_exteriorring)},
+ { "EXTRACT", SYM(EXTRACT_SYM)},
++ { "EXTRACTVALUE", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_xml_extractvalue)},
+ { "EXP", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_exp)},
+ { "EXPORT_SET", SYM(EXPORT_SET)},
+ { "FIELD", SYM(FIELD_FUNC)}, /* For compability */
+@@ -759,6 +760,7 @@
+ { "UNHEX", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_unhex)},
+ { "UNIQUE_USERS", SYM(UNIQUE_USERS)},
+ { "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP)},
++ { "UPDATEXML", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_xml_update)},
+ { "UPPER", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
+ { "UUID", F_SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_uuid)},
+ { "VARIANCE", SYM(VARIANCE_SYM)},
+diff -Naur mysql.orig/strings/xml.c mysql.xml/strings/xml.c
+--- mysql.orig/strings/xml.c 2005-05-15 06:16:51.000000000 +0200
++++ mysql.xml/strings/xml.c 2005-05-20 15:19:29.000000000 +0200
+@@ -104,7 +104,8 @@
+ a->end=p->cur;
+ if (a->beg[0]==p->cur[0])p->cur++;
+ a->beg++;
+- my_xml_norm_text(a);
++ if (!(p->flags & MY_XML_FLAG_SKIP_TEXT_NORMALIZATION))
++ my_xml_norm_text(a);
+ lex=MY_XML_STRING;
+ }
+ else
+@@ -148,7 +149,11 @@
+ memcpy(st->attrend,str,len);
+ st->attrend+=len;
+ st->attrend[0]='\0';
+- return st->enter ? st->enter(st,st->attr,st->attrend-st->attr) : MY_XML_OK;
++
++ if (st->flags & MY_XML_FLAG_RELATIVE_NAMES)
++ return st->enter ? st->enter(st, str, len) : MY_XML_OK;
++ else
++ return st->enter ? st->enter(st,st->attr,st->attrend-st->attr) : MY_XML_OK;
+ }
+
+
+@@ -167,7 +172,7 @@
+ char s[32];
+ char g[32];
+ int rc;
+-
++
+ /* Find previous '.' or beginning */
+ for( e=p->attrend; (e>p->attr) && (e[0]!='.') ; e--);
+ glen = (e[0]=='.') ? (p->attrend-e-1) : p->attrend-e;
+@@ -179,9 +184,12 @@
+ sprintf(p->errstr,"'</%s>' unexpected ('</%s>' wanted)",s,g);
+ return MY_XML_ERROR;
+ }
+-
+- rc = p->leave_xml ? p->leave_xml(p,p->attr,p->attrend-p->attr) : MY_XML_OK;
+-
++
++ if (p->flags & MY_XML_FLAG_RELATIVE_NAMES)
++ rc= p->leave_xml ? p->leave_xml(p, str, slen) : MY_XML_OK;
++ else
++ rc= p->leave_xml ? p->leave_xml(p,p->attr,p->attrend-p->attr) : MY_XML_OK;
++
+ *e='\0';
+ p->attrend=e;
+
+@@ -240,6 +248,7 @@
+
+ if (MY_XML_IDENT==lex)
+ {
++ p->current_node_type= MY_XML_NODE_TAG;
+ if(MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg))
+ return MY_XML_ERROR;
+ }
+@@ -258,6 +267,7 @@
+ lex=my_xml_scan(p,&b);
+ if ( (lex==MY_XML_IDENT) || (lex==MY_XML_STRING) )
+ {
++ p->current_node_type= MY_XML_NODE_ATTR;
+ if((MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) ||
+ (MY_XML_OK!=my_xml_value(p,b.beg,b.end-b.beg)) ||
+ (MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg)))
+@@ -272,6 +282,7 @@
+ }
+ else if ( (MY_XML_STRING==lex) || (MY_XML_IDENT==lex) )
+ {
++ p->current_node_type= MY_XML_NODE_ATTR;
+ if((MY_XML_OK!=my_xml_enter(p,a.beg,a.end-a.beg)) ||
+ (MY_XML_OK!=my_xml_leave(p,a.beg,a.end-a.beg)))
+ return MY_XML_ERROR;
+@@ -318,7 +329,8 @@
+ for ( ; (p->cur < p->end) && (p->cur[0]!='<') ; p->cur++);
+ a.end=p->cur;
+
+- my_xml_norm_text(&a);
++ if (!(p->flags & MY_XML_FLAG_SKIP_TEXT_NORMALIZATION))
++ my_xml_norm_text(&a);
+ if (a.beg!=a.end)
+ {
+ my_xml_value(p,a.beg,a.end-a.beg);
diff --git a/070_all_make-test.patch b/070_all_make-test.patch
new file mode 100644
index 0000000..7bb65c9
--- /dev/null
+++ b/070_all_make-test.patch
@@ -0,0 +1,14 @@
+###MY_VER_RANGE [5.0.6_beta,5.0.6_beta] [5.1.0_alpha20050531,5.1.0_alpha20050531]
+--- mysql.Makefile.am/Makefile.am 2005-06-02 22:44:41.000000000 +0200
++++ mysql-5.0.6-beta/Makefile.am 2005-06-02 22:46:19.000000000 +0200
+@@ -104,8 +104,8 @@
+
+ test-force:
+ cd mysql-test; \
+- mysql-test-run --force ;\
+- mysql-test-run --ps-protocol --force
++ ./mysql-test-run --force ;\
++ ./mysql-test-run --ps-protocol --force
+
+ # Don't update the files from bitkeeper
+ %::SCCS/s.%
diff --git a/701_all_test-myisam-geometry.patch b/701_all_test-myisam-geometry.patch
new file mode 100644
index 0000000..536c92a
--- /dev/null
+++ b/701_all_test-myisam-geometry.patch
@@ -0,0 +1,26 @@
+###MY_VER_RANGE [4.1.3_alpha,4.1.14_alpha20050808)
+
+# MySQL Bugs: #11083: myisam.test fail w/ --without-geometry
+
+--- mysql.orig/mysql-test/t/myisam.test 2005-05-26 16:55:48.000000000 +0200
++++ mysql.fix/mysql-test/t/myisam.test 2005-06-03 21:26:28.000000000 +0200
+@@ -479,7 +479,7 @@
+ #
+ # Test RTREE index
+ #
+---error 1235
++--error 1235,1289
+ CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`)) ENGINE=MyISAM;
+ # INSERT INTO t1 VALUES (1,1),(1,1);
+ # DELETE FROM rt WHERE a<1;
+--- mysql.orig/mysql-test/r/myisam.result 2005-05-26 16:55:48.000000000 +0200
++++ mysql.fix/mysql-test/r/myisam.result 2005-06-03 21:27:20.000000000 +0200
+@@ -506,7 +506,7 @@
+ 1 SIMPLE t2 index NULL PRIMARY 4 NULL 2 Using index; Distinct
+ drop table t1,t2;
+ CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`)) ENGINE=MyISAM;
+-ERROR 42000: This version of MySQL doesn't yet support 'RTREE INDEX'
++Got one of the listed errors
+ create table t1 (a int, b varchar(200), c text not null) checksum=1;
+ create table t2 (a int, b varchar(200), c text not null) checksum=0;
+ insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, "");
diff --git a/703_all_test-rpl_rotate_logs.patch b/703_all_test-rpl_rotate_logs.patch
new file mode 100644
index 0000000..9fd3079
--- /dev/null
+++ b/703_all_test-rpl_rotate_logs.patch
@@ -0,0 +1,18 @@
+###MY_VER_RANGE [5.0.6_beta,5.1.0_alpha) [5.1.0_alpha,)
+
+# MySQL Bugs: #9763: Test rpl_rotate_logs fails in default mode and with --force
+# Error: 1201 SQLSTATE: HY000 (ER_MASTER_INFO)
+# Message: Could not initialize master info structure; more error messages can be found in the MySQL
+# error log
+
+--- mysql.orig/mysql-test/t/rpl_rotate_logs.test 2005-05-26 16:55:48.000000000 +0200
++++ mysql.fix/mysql-test/t/rpl_rotate_logs.test 2005-06-03 20:21:51.000000000 +0200
+@@ -24,7 +24,7 @@
+ # START SLAVE will fail because it can't read the file (mode 000)
+ # (system error 13)
+ --replace_result $MYSQL_TEST_DIR TESTDIR
+---error 1105,1105,29
++--error 1201,1105,29
+ start slave;
+ system chmod 600 var/slave-data/master.info;
+ # It will fail again because the file is empty so the slave cannot get valuable
diff --git a/705_all_view_geometry.patch b/705_all_view_geometry.patch
new file mode 100644
index 0000000..53c2367
--- /dev/null
+++ b/705_all_view_geometry.patch
@@ -0,0 +1,71 @@
+###MY_VER_RANGE [5.0.11_beta,5.0.12_beta] [5.1,)
+diff -Naur mysql.orig/mysql-test/r/view.result mysql.new/mysql-test/r/view.result
+--- mysql.orig/mysql-test/r/view.result 2005-08-13 04:20:59.000000000 +0200
++++ mysql.new/mysql-test/r/view.result 2005-08-13 04:29:43.000000000 +0200
+@@ -2021,17 +2021,6 @@
+ DROP PROCEDURE p1;
+ DROP VIEW v1;
+ DROP TABLE t1;
+-create table t1 (f1 tinyint(1), f2 char(1), f3 varchar(1), f4 geometry, f5 datetime);
+-create view v1 as select * from t1;
+-desc v1;
+-Field Type Null Key Default Extra
+-f1 tinyint(1) YES NULL
+-f2 char(1) YES NULL
+-f3 varchar(1) YES NULL
+-f4 geometry YES NULL
+-f5 datetime YES NULL
+-drop view v1;
+-drop table t1;
+ create table t1(f1 datetime);
+ insert into t1 values('2005.01.01 12:0:0');
+ create view v1 as select f1, subtime(f1, '1:1:1') as sb from t1;
+diff -Naur mysql.orig/mysql-test/t/gis-view.test mysql.new/mysql-test/t/gis-view.test
+--- mysql.orig/mysql-test/t/gis-view.test 1970-01-01 01:00:00.000000000 +0100
++++ mysql.new/mysql-test/t/gis-view.test 2005-08-13 04:27:30.000000000 +0200
+@@ -0,0 +1,11 @@
++-- source include/have_geometry.inc
++
++#
++# Bug #11335 View redefines column types
++#
++create table t1 (f1 tinyint(1), f2 char(1), f3 varchar(1), f4 geometry, f5 datetime);
++create view v1 as select * from t1;
++desc v1;
++drop view v1;
++drop table t1;
++
+diff -Naur mysql.orig/mysql-test/t/view.test mysql.new/mysql-test/t/view.test
+--- mysql.orig/mysql-test/t/view.test 2005-08-13 04:20:44.000000000 +0200
++++ mysql.new/mysql-test/t/view.test 2005-08-13 04:28:53.000000000 +0200
+@@ -1856,15 +1856,6 @@
+ DROP TABLE t1;
+
+ #
+-# Bug #11335 View redefines column types
+-#
+-create table t1 (f1 tinyint(1), f2 char(1), f3 varchar(1), f4 geometry, f5 datetime);
+-create view v1 as select * from t1;
+-desc v1;
+-drop view v1;
+-drop table t1;
+-
+-#
+ # Bug #11760 Typo in Item_func_add_time::print() results in NULLs returned
+ # subtime() in view
+ create table t1(f1 datetime);
+diff -Naur mysql.orig/mysql-test/r/gis-view.result mysql.new/mysql-test/r/gis-view.result
+--- mysql.orig/mysql-test/r/gis-view.result 1970-01-01 01:00:00.000000000 +0100
++++ mysql.new/mysql-test/r/gis-view.result 2005-08-15 19:11:19.000000000 +0200
+@@ -0,0 +1,11 @@
++create table t1 (f1 tinyint(1), f2 char(1), f3 varchar(1), f4 geometry, f5 datetime);
++create view v1 as select * from t1;
++desc v1;
++Field Type Null Key Default Extra
++f1 tinyint(1) YES NULL
++f2 char(1) YES NULL
++f3 varchar(1) YES NULL
++f4 geometry YES NULL
++f5 datetime YES NULL
++drop view v1;
++drop table t1;