1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

Merge branch '11.4' into 11.8

This commit is contained in:
Oleksandr Byelkin
2026-10-22 14:46:40 +02:00
38 changed files with 1270 additions and 339 deletions

View File

@@ -10908,7 +10908,7 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
my_bind= (MYSQL_BIND*) my_malloc(PSI_NOT_INSTRUMENTED, num_fields * sizeof(MYSQL_BIND),
MYF(MY_WME|MY_FAE|MY_ZEROFILL));
length= (ulong*) my_malloc(PSI_NOT_INSTRUMENTED, num_fields * sizeof(ulong),
MYF(MY_WME|MY_FAE));
MYF(MY_WME|MY_FAE|MY_ZEROFILL));
is_null= (my_bool*) my_malloc(PSI_NOT_INSTRUMENTED, num_fields * sizeof(my_bool),
MYF(MY_WME|MY_FAE));

View File

@@ -65,8 +65,8 @@ MACRO(BUNDLE_PCRE2)
ExternalProject_Add(
pcre2
PREFIX "${dir}"
URL "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.47/pcre2-10.47.zip"
URL_MD5 7906aec38f872b74f1b925122dde9069
URL "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.49/pcre2-10.49.zip"
URL_MD5 11e0345ad037d7b3f9342aa3251ac4a7
INSTALL_COMMAND ""
CMAKE_ARGS
"-DCMAKE_WARN_DEPRECATED=FALSE"

View File

@@ -102,6 +102,7 @@ if(WOLFSSL_INTELASM)
if(MSVC_INTEL)
target_sources(wolfssl PRIVATE
${WOLFCRYPT_SRCDIR}/aes_asm.asm
${WOLFCRYPT_SRCDIR}/aes_x86_64_asm.asm
${WOLFCRYPT_SRCDIR}/aes_gcm_asm.asm
${WOLFCRYPT_SRCDIR}/sp_x86_64_asm.asm
)
@@ -113,6 +114,7 @@ if(WOLFSSL_INTELASM)
set(USE_INTEL_SPEEDUP 1)
target_sources(wolfssl PRIVATE
${WOLFCRYPT_SRCDIR}/aes_asm.S
${WOLFCRYPT_SRCDIR}/aes_x86_64_asm.S
${WOLFCRYPT_SRCDIR}/aes_gcm_asm.S
${WOLFCRYPT_SRCDIR}/chacha_asm.S
${WOLFCRYPT_SRCDIR}/fe_x25519_asm.S
@@ -123,7 +125,8 @@ if(WOLFSSL_INTELASM)
)
target_compile_options(wolfssl PRIVATE -maes -msse4.2 -mpclmul)
# Workaround 5.5.4 bug (user_settings.h not included into aes_asm.S)
set_property(SOURCE ${WOLFCRYPT_SRCDIR}/aes_asm.S APPEND PROPERTY COMPILE_OPTIONS "-DWOLFSSL_X86_64_BUILD")
set_property(SOURCE ${WOLFCRYPT_SRCDIR}/aes_asm.S
${WOLFCRYPT_SRCDIR}/aes_x86_64_asm.S APPEND PROPERTY COMPILE_OPTIONS "-DWOLFSSL_X86_64_BUILD")
endif()
endif()

View File

@@ -28,8 +28,6 @@ SET(HEADERS
mariadb_capi_rename.h
pack.h
my_byteorder.h
little_endian.h
big_endian.h
mysql_time.h
ma_dyncol.h
my_list.h

View File

@@ -1,82 +0,0 @@
/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
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; version 2 of the License.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
/*
Data in big-endian format.
*/
#define float4store(T,A) do { *((T)+0)=(char) ((uchar *) &A)[3];\
*((T)+1)=(char) ((uchar *) &A)[2];\
*((T)+2)=(char) ((uchar *) &A)[1];\
*((T)+3)=(char) ((uchar *) &A)[0]; } while(0)
#define float4get(V,M) do { float def_temp;\
((uchar*) &def_temp)[0]=(M)[3];\
((uchar*) &def_temp)[1]=(M)[2];\
((uchar*) &def_temp)[2]=(M)[1];\
((uchar*) &def_temp)[3]=(M)[0];\
(V)=def_temp; } while(0)
#define float8store(T,V) do { *((T)+0)=(char) ((uchar *) &V)[7];\
*((T)+1)=(char) ((uchar *) &V)[6];\
*((T)+2)=(char) ((uchar *) &V)[5];\
*((T)+3)=(char) ((uchar *) &V)[4];\
*((T)+4)=(char) ((uchar *) &V)[3];\
*((T)+5)=(char) ((uchar *) &V)[2];\
*((T)+6)=(char) ((uchar *) &V)[1];\
*((T)+7)=(char) ((uchar *) &V)[0]; } while(0)
#define float8get(V,M) do { double def_temp;\
((uchar*) &def_temp)[0]=(M)[7];\
((uchar*) &def_temp)[1]=(M)[6];\
((uchar*) &def_temp)[2]=(M)[5];\
((uchar*) &def_temp)[3]=(M)[4];\
((uchar*) &def_temp)[4]=(M)[3];\
((uchar*) &def_temp)[5]=(M)[2];\
((uchar*) &def_temp)[6]=(M)[1];\
((uchar*) &def_temp)[7]=(M)[0];\
(V) = def_temp; } while(0)
#define ushortget(V,M) do { V = (uint16) (((uint16) ((uchar) (M)[1]))+\
((uint16) ((uint16) (M)[0]) << 8)); } while(0)
#define shortget(V,M) do { V = (short) (((short) ((uchar) (M)[1]))+\
((short) ((short) (M)[0]) << 8)); } while(0)
#define longget(V,M) do { int32 def_temp;\
((uchar*) &def_temp)[0]=(M)[0];\
((uchar*) &def_temp)[1]=(M)[1];\
((uchar*) &def_temp)[2]=(M)[2];\
((uchar*) &def_temp)[3]=(M)[3];\
(V)=def_temp; } while(0)
#define ulongget(V,M) do { uint32 def_temp;\
((uchar*) &def_temp)[0]=(M)[0];\
((uchar*) &def_temp)[1]=(M)[1];\
((uchar*) &def_temp)[2]=(M)[2];\
((uchar*) &def_temp)[3]=(M)[3];\
(V)=def_temp; } while(0)
#define shortstore(T,A) do { uint def_temp=(uint) (A) ;\
*(((char*)T)+1)=(char)(def_temp); \
*(((char*)T)+0)=(char)(def_temp >> 8); } while(0)
#define longstore(T,A) do { *(((char*)T)+3)=((A));\
*(((char*)T)+2)=(((A) >> 8));\
*(((char*)T)+1)=(((A) >> 16));\
*(((char*)T)+0)=(((A) >> 24)); } while(0)
#define floatget(V,M) memcpy(&V, (M), sizeof(float))
/* Cast away type qualifiers (necessary as macro takes argument by value). */
#define floatstore(T,V) memcpy((T), (void*) (&V), sizeof(float))
#define doubleget(V,M) memcpy(&V, (M), sizeof(double))
/* Cast away type qualifiers (necessary as macro takes argument by value). */
#define doublestore(T,V) memcpy((T), (void*) &V, sizeof(double))
#define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong))
#define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong))

View File

@@ -1,75 +0,0 @@
/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
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; version 2 of the License.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
/*
Data in little-endian format.
*/
#ifndef MY_BYTE_ORDER_ARCH_OPTIMIZED
#define float4get(V,M) memcpy(&V, (M), sizeof(float))
#define float4store(V,M) memcpy(V, (&M), sizeof(float))
#define float8get(V,M) doubleget((V),(M))
#define float8store(V,M) doublestore((V),(M))
/* Bi-endian hardware.... */
#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
#define doublestore(T,V) do { *(((char*)T)+0)=(char) ((uchar *) &V)[4];\
*(((char*)T)+1)=(char) ((uchar *) &V)[5];\
*(((char*)T)+2)=(char) ((uchar *) &V)[6];\
*(((char*)T)+3)=(char) ((uchar *) &V)[7];\
*(((char*)T)+4)=(char) ((uchar *) &V)[0];\
*(((char*)T)+5)=(char) ((uchar *) &V)[1];\
*(((char*)T)+6)=(char) ((uchar *) &V)[2];\
*(((char*)T)+7)=(char) ((uchar *) &V)[3]; }\
while(0)
#define doubleget(V,M) do { double def_temp;\
((uchar*) &def_temp)[0]=(M)[4];\
((uchar*) &def_temp)[1]=(M)[5];\
((uchar*) &def_temp)[2]=(M)[6];\
((uchar*) &def_temp)[3]=(M)[7];\
((uchar*) &def_temp)[4]=(M)[0];\
((uchar*) &def_temp)[5]=(M)[1];\
((uchar*) &def_temp)[6]=(M)[2];\
((uchar*) &def_temp)[7]=(M)[3];\
(V) = def_temp; } while(0)
#else /* Bi-endian hardware.... */
/* Cast away type qualifiers (necessary as macro takes argument by value). */
#define doublestore(T,V) memcpy((T), (void*) &V, sizeof(double))
#define doubleget(V,M) memcpy(&V, (M), sizeof(double))
#endif /* Bi-endian hardware.... */
#endif /* !MY_BYTE_ORDER_ARCH_OPTIMIZED */
#define ushortget(V,M) do { uchar *pM= (uchar*)(M);V = uint2korr(pM);} while(0)
#define shortget(V,M) do { uchar *pM= (uchar*)(M);V = sint2korr(pM);} while(0)
#define longget(V,M) do { uchar *pM= (uchar*)(M);V = sint4korr(pM);} while(0)
#define ulongget(V,M) do { uchar *pM= (uchar*)(M);V = uint4korr(pM);} while(0)
#define shortstore(T,V) int2store(T,V)
#define longstore(T,V) int4store(T,V)
#ifndef floatstore
/* Cast away type qualifiers (necessary as macro takes argument by value). */
#define floatstore(T,V) memcpy((T), (void*) (&V), sizeof(float))
#define floatget(V,M) memcpy(&V, (M), sizeof(float))
#endif
#ifndef doubleget
#define doubleget(V,M) memcpy(&V, (M), sizeof(double))
#define doublestore(T,V) memcpy((T), (void *) &V, sizeof(double))
#endif /* doubleget */
#define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong))
#define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong))

View File

@@ -280,15 +280,100 @@ static inline int32 int4net(const void *p)
}
/*
Some macros for reading doubles and floats (clean, do not assume alignment)
These are defined in big_endian.h and little_endian.h
Macros for reading and storing floating point numbers, and 16-bit and 32-bit
integers in the native byte order. They have no alignment requirement.
The float4*() and float8*() macros use the little-endian byte order on any
host. The mi_float*() macros in myisampack.h use the big-endian byte order.
*/
/* Copy 4 or 8 bytes in the reverse order */
#define MY_SWAPCPY4(DST,SRC) \
do { \
uint32 tmp_; \
memcpy(&tmp_, (SRC), sizeof(tmp_)); \
tmp_= MY_BSWAP32(tmp_); \
memcpy((DST), &tmp_, sizeof(tmp_)); \
} while(0)
#define MY_SWAPCPY8(DST,SRC) \
do { \
uint64 tmp_; \
memcpy(&tmp_, (SRC), sizeof(tmp_)); \
tmp_= MY_BSWAP64(tmp_); \
memcpy((DST), &tmp_, sizeof(tmp_)); \
} while(0)
/* Copy 4 or 8 bytes between the host order and the little/big-endian order */
#ifdef WORDS_BIGENDIAN
#include "big_endian.h"
#define MY_COPY_LE4(DST,SRC) MY_SWAPCPY4(DST, SRC)
#define MY_COPY_LE8(DST,SRC) MY_SWAPCPY8(DST, SRC)
#define MY_COPY_BE4(DST,SRC) memcpy((DST), (SRC), 4)
#define MY_COPY_BE8(DST,SRC) memcpy((DST), (SRC), 8)
#else
#include "little_endian.h"
#define MY_COPY_LE4(DST,SRC) memcpy((DST), (SRC), 4)
#define MY_COPY_LE8(DST,SRC) memcpy((DST), (SRC), 8)
#define MY_COPY_BE4(DST,SRC) MY_SWAPCPY4(DST, SRC)
#define MY_COPY_BE8(DST,SRC) MY_SWAPCPY8(DST, SRC)
#endif
/* The "const void*" casts allow storing from volatile objects */
#define float4store(T,A) MY_COPY_LE4((T), (const void*) &(A))
#define float8store(T,V) MY_COPY_LE8((T), (const void*) &(V))
#define float4get(V,M) \
do { \
compile_time_assert(sizeof(V) == sizeof(float)); \
MY_COPY_LE4(&(V), (M)); \
} while(0)
#define float8get(V,M) \
do { \
compile_time_assert(sizeof(V) == sizeof(double)); \
MY_COPY_LE8(&(V), (M)); \
} while(0)
/* The following use the native byte order. */
#define ushortget(V,M) \
do { \
uint16 tmp_; \
memcpy(&tmp_, (M), sizeof(tmp_)); \
(V)= tmp_; \
} while(0)
#define shortget(V,M) \
do { \
int16 tmp_; \
memcpy(&tmp_, (M), sizeof(tmp_)); \
(V)= tmp_; \
} while(0)
#define longget(V,M) \
do { \
int32 tmp_; \
memcpy(&tmp_, (M), sizeof(tmp_)); \
(V)= tmp_; \
} while(0)
#define shortstore(T,A) \
do { \
uint16 tmp_= (uint16) (A); \
memcpy((T), &tmp_, sizeof(tmp_)); \
} while(0)
#define longstore(T,A) \
do { \
uint32 tmp_= (uint32) (A); \
memcpy((T), &tmp_, sizeof(tmp_)); \
} while(0)
#define floatget(V,M) memcpy(&(V), (M), sizeof(float))
#define doubleget(V,M) memcpy(&(V), (M), sizeof(double))
#define longlongget(V,M) memcpy(&(V), (M), sizeof(ulonglong))
#define longlongstore(T,V) memcpy((T), (const void*) &(V), sizeof(ulonglong))
#define floatstore(T,V) memcpy((T), (const void*) &(V), sizeof(float))
#define doublestore(T,V) memcpy((T), (const void*) &(V), sizeof(double))
/* convenienve helpers */
static inline float get_float(const void *from)
{

View File

@@ -141,96 +141,22 @@
mi_int4store((uchar*) (T) + 0, def_temp4);\
mi_int4store((uchar*) (T) + 4, def_temp3); }
#ifdef WORDS_BIGENDIAN
/* Floating point numbers in MyISAM/Aria keys and in filesort keys are stored
in big-endian byte order. */
#define mi_float4store(T,A) MY_COPY_BE4((T), (const void*) &(A))
#define mi_float8store(T,V) MY_COPY_BE8((T), (const void*) &(V))
#define mi_float4store(T,A) { ((uchar*) (T))[0]= ((uchar*) &A)[0];\
((uchar*) (T))[1]= ((uchar*) &A)[1];\
((uchar*) (T))[2]= ((uchar*) &A)[2];\
((uchar*) (T))[3]= ((uchar*) &A)[3]; }
#define mi_float4get(V,M) \
do { \
compile_time_assert(sizeof(V) == sizeof(float)); \
MY_COPY_BE4(&(V), (M)); \
} while(0)
#define mi_float4get(V,M) { float def_temp;\
((uchar*) &def_temp)[0]= ((const uchar*) (M))[0];\
((uchar*) &def_temp)[1]= ((const uchar*) (M))[1]; \
((uchar*) &def_temp)[2]= ((const uchar*) (M))[2];\
((uchar*) &def_temp)[3]= ((const uchar*) (M))[3];\
(V)= def_temp; }
#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[0];\
((uchar*) (T))[1]= ((const uchar*) &V)[1];\
((uchar*) (T))[2]= ((const uchar*) &V)[2];\
((uchar*) (T))[3]= ((const uchar*) &V)[3];\
((uchar*) (T))[4]= ((const uchar*) &V)[4];\
((uchar*) (T))[5]= ((const uchar*) &V)[5];\
((uchar*) (T))[6]= ((const uchar*) &V)[6];\
((uchar*) (T))[7]= ((const uchar*) &V)[7]; }
#define mi_float8get(V,M) { double def_temp;\
((uchar*) &def_temp)[0]= ((const uchar*) (M))[0];\
((uchar*) &def_temp)[1]= ((const uchar*) (M))[1];\
((uchar*) &def_temp)[2]= ((const uchar*) (M))[2];\
((uchar*) &def_temp)[3]= ((const uchar*) (M))[3];\
((uchar*) &def_temp)[4]= ((const uchar*) (M))[4];\
((uchar*) &def_temp)[5]= ((const uchar*) (M))[5];\
((uchar*) &def_temp)[6]= ((const uchar*) (M))[6];\
((uchar*) &def_temp)[7]= ((const uchar*) (M))[7]; \
(V)= def_temp; }
#else
#define mi_float4store(T,A) { ((uchar*) (T))[0]= ((const uchar*) &A)[3];\
((uchar*) (T))[1]= ((const uchar*) &A)[2];\
((uchar*) (T))[2]= ((const uchar*) &A)[1];\
((uchar*) (T))[3]= ((const uchar*) &A)[0]; }
#define mi_float4get(V,M) { float def_temp;\
((uchar*) &def_temp)[0]= ((const uchar*) (M))[3];\
((uchar*) &def_temp)[1]= ((const uchar*) (M))[2];\
((uchar*) &def_temp)[2]= ((const uchar*) (M))[1];\
((uchar*) &def_temp)[3]= ((const uchar*) (M))[0];\
(V)= def_temp; }
#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[3];\
((uchar*) (T))[1]= ((const uchar*) &V)[2];\
((uchar*) (T))[2]= ((const uchar*) &V)[1];\
((uchar*) (T))[3]= ((const uchar*) &V)[0];\
((uchar*) (T))[4]= ((const uchar*) &V)[7];\
((uchar*) (T))[5]= ((const uchar*) &V)[6];\
((uchar*) (T))[6]= ((const uchar*) &V)[5];\
((uchar*) (T))[7]= ((const uchar*) &V)[4];}
#define mi_float8get(V,M) { double def_temp;\
((uchar*) &def_temp)[0]= ((const uchar*) (M))[3];\
((uchar*) &def_temp)[1]= ((const uchar*) (M))[2];\
((uchar*) &def_temp)[2]= ((const uchar*) (M))[1];\
((uchar*) &def_temp)[3]= ((const uchar*) (M))[0];\
((uchar*) &def_temp)[4]= ((const uchar*) (M))[7];\
((uchar*) &def_temp)[5]= ((const uchar*) (M))[6];\
((uchar*) &def_temp)[6]= ((const uchar*) (M))[5];\
((uchar*) &def_temp)[7]= ((const uchar*) (M))[4];\
(V)= def_temp; }
#else
#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[7];\
((uchar*) (T))[1]= ((const uchar*) &V)[6];\
((uchar*) (T))[2]= ((const uchar*) &V)[5];\
((uchar*) (T))[3]= ((const uchar*) &V)[4];\
((uchar*) (T))[4]= ((const uchar*) &V)[3];\
((uchar*) (T))[5]= ((const uchar*) &V)[2];\
((uchar*) (T))[6]= ((const uchar*) &V)[1];\
((uchar*) (T))[7]= ((const uchar*) &V)[0];}
#define mi_float8get(V,M) { double def_temp;\
((uchar*) &def_temp)[0]= ((const uchar*) (M))[7];\
((uchar*) &def_temp)[1]= ((const uchar*) (M))[6];\
((uchar*) &def_temp)[2]= ((const uchar*) (M))[5];\
((uchar*) &def_temp)[3]= ((const uchar*) (M))[4];\
((uchar*) &def_temp)[4]= ((const uchar*) (M))[3];\
((uchar*) &def_temp)[5]= ((const uchar*) (M))[2];\
((uchar*) &def_temp)[6]= ((const uchar*) (M))[1];\
((uchar*) &def_temp)[7]= ((const uchar*) (M))[0];\
(V)= def_temp; }
#endif /* __FLOAT_WORD_ORDER */
#endif /* WORDS_BIGENDIAN */
#define mi_float8get(V,M) \
do { \
compile_time_assert(sizeof(V) == sizeof(double)); \
MY_COPY_BE8(&(V), (M)); \
} while(0)
/* Fix to avoid warnings when sizeof(ha_rows) == sizeof(long) */

View File

@@ -13,9 +13,18 @@ if(!`select $MTR_PARALLEL = 1`)
# This is important for backward compatibility
# Emulate creating password in an interactive client session, with older clients
# which communicates with the server using with something like cp850
# which communicates with the server using with something like cp850.
# Do not use chcp: the console codepage is shared by all parallel mtr workers.
# 0x81 is 'ü' in cp850.
exec chcp 850 > NUL && echo CREATE USER 'u' IDENTIFIED by 'ü' | $MYSQL --default-character-set=cp850;
--perl
open(F, '>', "$ENV{MYSQL_TMP_DIR}/create_user_cp850.sql") or die;
binmode F;
print F "CREATE USER 'u' IDENTIFIED BY '\x81';\n";
close F;
EOF
--exec $MYSQL --default-character-set=cp850 < $MYSQL_TMP_DIR/create_user_cp850.sql
--remove_file $MYSQL_TMP_DIR/create_user_cp850.sql
# Can't connect with UTF8

View File

@@ -6427,6 +6427,12 @@ Warning 1292 Incorrect time value: '9430886' for column `test`.`t1`.`c2` at row
Warning 1292 Incorrect time value: '9430816' for column `test`.`t1`.`c1` at row 2
Warning 1292 Incorrect time value: '9430816' for column `test`.`t1`.`c2` at row 2
drop table t1;
#
# MDEV-40616: MSAN - use-of-uninitialized-value in extract_date_time()
#
DO STR_TO_DATE(1, '%#');
DO STR_TO_DATE(LOWER('q'), '%@');
DO STR_TO_DATE(LOWER('.'), '%.');
# End of 10.11 tests
#
# MDEV-34829 LOCALTIME returns a wrong data type

View File

@@ -3281,6 +3281,14 @@ insert into t1 values (9430886, 9430886), (9430816, 9430816);
select cast(c1 as time), cast(c2 as time) from t1;
drop table t1;
--echo #
--echo # MDEV-40616: MSAN - use-of-uninitialized-value in extract_date_time()
--echo #
DO STR_TO_DATE(1, '%#');
DO STR_TO_DATE(LOWER('q'), '%@');
DO STR_TO_DATE(LOWER('.'), '%.');
--echo # End of 10.11 tests
--echo #

View File

@@ -265,3 +265,102 @@ ERROR 70100: Query execution was interrupted
DROP TABLE t1;
disconnect con1;
SET debug_sync='RESET';
#
# MDEV-31567 SIGSEGV in reinit_stmt_before_use | Prepared_statement::execute
#
# The first EXECUTE is killed after the one-time semi-join rewrite, but
# before the nested selects save their WHERE. The statement must be
# re-prepared, not run half-rewritten. The bug was reported with
# max_statement_time, KILL QUERY at a sync point makes it deterministic.
CREATE TABLE t (a INT);
connect con1,localhost,root,,;
PREPARE s FROM <62 nested IN subqueries>
SET debug_sync='before_join_optimize SIGNAL parked WAIT_FOR go EXECUTE 1';
EXECUTE s;
connection default;
SET debug_sync='now WAIT_FOR parked';
KILL QUERY id;
SET debug_sync='now SIGNAL go';
connection con1;
ERROR 70100: Query execution was interrupted
SET debug_sync='RESET';
EXECUTE s;
a
EXECUTE s;
a
DEALLOCATE PREPARE s;
# The same with rows, the results must be correct
INSERT INTO t VALUES (1),(2),(3);
PREPARE s FROM <62 nested IN subqueries>
SET debug_sync='before_join_optimize SIGNAL parked WAIT_FOR go EXECUTE 1';
EXECUTE s;
connection default;
SET debug_sync='now WAIT_FOR parked';
KILL QUERY id;
SET debug_sync='now SIGNAL go';
connection con1;
ERROR 70100: Query execution was interrupted
SET debug_sync='RESET';
EXECUTE s;
a
1
EXECUTE s;
a
1
DEALLOCATE PREPARE s;
# The same in a stored procedure
CREATE PROCEDURE p() <62 nested IN subqueries>
SET debug_sync='before_join_optimize SIGNAL parked WAIT_FOR go EXECUTE 1';
CALL p();
connection default;
SET debug_sync='now WAIT_FOR parked';
KILL QUERY id;
SET debug_sync='now SIGNAL go';
connection con1;
ERROR 70100: Query execution was interrupted
SET debug_sync='RESET';
CALL p();
a
1
CALL p();
a
1
DROP PROCEDURE p;
connection default;
disconnect con1;
# If the re-prepare fails, it must be tried again on the next EXECUTE
CREATE USER u@localhost;
GRANT SUPER ON *.* TO u@localhost;
GRANT SELECT ON test.t TO u@localhost;
connect con2,localhost,u,,test;
PREPARE s FROM <62 nested IN subqueries>
SET debug_sync='before_join_optimize SIGNAL parked WAIT_FOR go EXECUTE 1';
EXECUTE s;
connection default;
SET debug_sync='now WAIT_FOR parked';
KILL QUERY id;
SET debug_sync='now SIGNAL go';
REVOKE SELECT ON test.t FROM u@localhost;
connection con2;
ERROR 70100: Query execution was interrupted
SET debug_sync='RESET';
EXECUTE s;
ERROR 42000: SELECT command denied to user 'u'@'localhost' for table `test`.`t`
SHOW STATUS LIKE 'Com_stmt_reprepare';
Variable_name Value
Com_stmt_reprepare 1
connection default;
GRANT SELECT ON test.t TO u@localhost;
connection con2;
EXECUTE s;
a
1
SHOW STATUS LIKE 'Com_stmt_reprepare';
Variable_name Value
Com_stmt_reprepare 2
connection default;
disconnect con2;
DROP USER u@localhost;
DROP TABLE t;
SET debug_sync='RESET';
# End of 11.4 tests

View File

@@ -361,3 +361,120 @@ reap;
DROP TABLE t1;
disconnect con1;
SET debug_sync='RESET';
--echo #
--echo # MDEV-31567 SIGSEGV in reinit_stmt_before_use | Prepared_statement::execute
--echo #
--echo # The first EXECUTE is killed after the one-time semi-join rewrite, but
--echo # before the nested selects save their WHERE. The statement must be
--echo # re-prepared, not run half-rewritten. The bug was reported with
--echo # max_statement_time, KILL QUERY at a sync point makes it deterministic.
CREATE TABLE t (a INT);
let $q= 1;
let $d= 62;
while ($d)
{
let $q= SELECT a FROM t WHERE a IN ($q);
dec $d;
}
connect (con1,localhost,root,,);
let $id= `SELECT CONNECTION_ID()`;
--echo PREPARE s FROM <62 nested IN subqueries>
--disable_query_log
eval PREPARE s FROM '$q';
--enable_query_log
SET debug_sync='before_join_optimize SIGNAL parked WAIT_FOR go EXECUTE 1';
send EXECUTE s;
connection default;
SET debug_sync='now WAIT_FOR parked';
replace_result $id id;
eval KILL QUERY $id;
SET debug_sync='now SIGNAL go';
connection con1;
--error ER_QUERY_INTERRUPTED
reap;
SET debug_sync='RESET';
EXECUTE s;
EXECUTE s;
DEALLOCATE PREPARE s;
--echo # The same with rows, the results must be correct
INSERT INTO t VALUES (1),(2),(3);
--echo PREPARE s FROM <62 nested IN subqueries>
--disable_query_log
eval PREPARE s FROM '$q';
--enable_query_log
SET debug_sync='before_join_optimize SIGNAL parked WAIT_FOR go EXECUTE 1';
send EXECUTE s;
connection default;
SET debug_sync='now WAIT_FOR parked';
replace_result $id id;
eval KILL QUERY $id;
SET debug_sync='now SIGNAL go';
connection con1;
--error ER_QUERY_INTERRUPTED
reap;
SET debug_sync='RESET';
EXECUTE s;
EXECUTE s;
DEALLOCATE PREPARE s;
--echo # The same in a stored procedure
--echo CREATE PROCEDURE p() <62 nested IN subqueries>
--disable_query_log
eval CREATE PROCEDURE p() $q;
--enable_query_log
SET debug_sync='before_join_optimize SIGNAL parked WAIT_FOR go EXECUTE 1';
send CALL p();
connection default;
SET debug_sync='now WAIT_FOR parked';
replace_result $id id;
eval KILL QUERY $id;
SET debug_sync='now SIGNAL go';
connection con1;
--error ER_QUERY_INTERRUPTED
reap;
SET debug_sync='RESET';
CALL p();
CALL p();
DROP PROCEDURE p;
connection default;
disconnect con1;
--echo # If the re-prepare fails, it must be tried again on the next EXECUTE
CREATE USER u@localhost;
GRANT SUPER ON *.* TO u@localhost;
GRANT SELECT ON test.t TO u@localhost;
connect (con2,localhost,u,,test);
let $id= `SELECT CONNECTION_ID()`;
--echo PREPARE s FROM <62 nested IN subqueries>
--disable_query_log
eval PREPARE s FROM '$q';
--enable_query_log
SET debug_sync='before_join_optimize SIGNAL parked WAIT_FOR go EXECUTE 1';
send EXECUTE s;
connection default;
SET debug_sync='now WAIT_FOR parked';
replace_result $id id;
eval KILL QUERY $id;
SET debug_sync='now SIGNAL go';
REVOKE SELECT ON test.t FROM u@localhost;
connection con2;
--error ER_QUERY_INTERRUPTED
reap;
SET debug_sync='RESET';
--error ER_TABLEACCESS_DENIED_ERROR
EXECUTE s;
SHOW STATUS LIKE 'Com_stmt_reprepare';
connection default;
GRANT SELECT ON test.t TO u@localhost;
connection con2;
EXECUTE s;
SHOW STATUS LIKE 'Com_stmt_reprepare';
connection default;
disconnect con2;
DROP USER u@localhost;
DROP TABLE t;
SET debug_sync='RESET';
--echo # End of 11.4 tests

View File

@@ -236,3 +236,152 @@ DROP PROCEDURE forIterateBug;
#
# End of 10.4 tests
#
#
# MDEV-37563 Crash on a FOR loop with a row comparison in the upper bound
#
CREATE OR REPLACE PROCEDURE p1()
BEGIN
DECLARE i INT;
FOR i IN 0..((1,'b1')=(1,'b1')) DO
SELECT i;
END FOR;
END;
$$
CALL p1;
i
0
i
1
CALL p1;
i
0
i
1
DROP PROCEDURE p1;
# The same for a cursor FOR loop parameter
CREATE OR REPLACE PROCEDURE p2()
BEGIN
DECLARE c CURSOR (p INT) FOR SELECT p;
FOR r IN c((1,'b1')=(1,'b1')) DO
SELECT r.p;
END FOR;
END;
$$
CALL p2;
r.p
1
CALL p2;
r.p
1
DROP PROCEDURE p2;
# The same for a cursor FOR loop with more than one parameter
CREATE OR REPLACE PROCEDURE p3()
BEGIN
DECLARE c CURSOR (a INT, b INT) FOR SELECT a, b;
FOR r IN c(1, (1,'b1')=(1,'b1')) DO
SELECT r.a, r.b;
END FOR;
END;
$$
CALL p3;
r.a r.b
1 1
CALL p3;
r.a r.b
1 1
DROP PROCEDURE p3;
# The same with a row comparison in more than one parameter
CREATE OR REPLACE PROCEDURE p4()
BEGIN
DECLARE c CURSOR (p1 INT, p2 INT, p3 INT) FOR SELECT p1, p2, p3;
FOR r IN c((1,'a')=(1,'a'), 7, (2,'b')=(2,'c')) DO
SELECT r.p1, r.p2, r.p3;
END FOR;
END;
$$
CALL p4;
r.p1 r.p2 r.p3
1 7 0
CALL p4;
r.p1 r.p2 r.p3
1 7 0
DROP PROCEDURE p4;
# The same with a row comparison in a derived table of the lower bound
CREATE OR REPLACE PROCEDURE p5()
BEGIN
FOR i IN 0+(SELECT z FROM (SELECT (1,'b1')=(1,'b1') AS z) dt)..2 DO
SELECT i;
END FOR;
END;
$$
CALL p5;
i
1
i
2
CALL p5;
i
1
i
2
DROP PROCEDURE p5;
# The same for a REVERSE loop, whose target bound is the left one
CREATE OR REPLACE PROCEDURE p6()
BEGIN
FOR i IN REVERSE 0+((1,'b1')=(1,'b1'))..2 DO
SELECT i;
END FOR;
END;
$$
CALL p6;
i
2
i
1
CALL p6;
i
2
i
1
DROP PROCEDURE p6;
# A trigger re-parses the upper bound after ALTER TABLE
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (b INT);
INSERT INTO t2 VALUES (1);
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW
BEGIN
FOR i IN 0..(SELECT NEW.a + COUNT(*) FROM t2) DO
SET @x= i;
END FOR;
END;
$$
INSERT INTO t1 VALUES (1);
ALTER TABLE t2 ADD COLUMN c INT;
INSERT INTO t1 VALUES (2);
INSERT INTO t1 VALUES (3);
SELECT @x;
@x
4
DROP TABLE t1, t2;
# A trigger with NEW fields in more than one cursor parameter
CREATE TABLE t1 (a INT, b INT);
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW
BEGIN
DECLARE c CURSOR (p1 INT, p2 INT) FOR SELECT p1, p2;
FOR r IN c(NEW.a, NEW.b + ((NEW.a,'x')=(NEW.a,'x'))) DO
SET @x= CONCAT(r.p1, ',', r.p2);
END FOR;
END;
$$
INSERT INTO t1 VALUES (1, 10);
SELECT @x;
@x
1,11
INSERT INTO t1 VALUES (2, 20);
SELECT @x;
@x
2,21
DROP TABLE t1;
#
# End of 11.4 tests
#

View File

@@ -248,3 +248,145 @@ DROP PROCEDURE forIterateBug;
--echo #
--echo # End of 10.4 tests
--echo #
--echo #
--echo # MDEV-37563 Crash on a FOR loop with a row comparison in the upper bound
--echo #
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p1()
BEGIN
DECLARE i INT;
FOR i IN 0..((1,'b1')=(1,'b1')) DO
SELECT i;
END FOR;
END;
$$
DELIMITER ;$$
CALL p1;
CALL p1;
DROP PROCEDURE p1;
--echo # The same for a cursor FOR loop parameter
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p2()
BEGIN
DECLARE c CURSOR (p INT) FOR SELECT p;
FOR r IN c((1,'b1')=(1,'b1')) DO
SELECT r.p;
END FOR;
END;
$$
DELIMITER ;$$
CALL p2;
CALL p2;
DROP PROCEDURE p2;
--echo # The same for a cursor FOR loop with more than one parameter
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p3()
BEGIN
DECLARE c CURSOR (a INT, b INT) FOR SELECT a, b;
FOR r IN c(1, (1,'b1')=(1,'b1')) DO
SELECT r.a, r.b;
END FOR;
END;
$$
DELIMITER ;$$
CALL p3;
CALL p3;
DROP PROCEDURE p3;
--echo # The same with a row comparison in more than one parameter
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p4()
BEGIN
DECLARE c CURSOR (p1 INT, p2 INT, p3 INT) FOR SELECT p1, p2, p3;
FOR r IN c((1,'a')=(1,'a'), 7, (2,'b')=(2,'c')) DO
SELECT r.p1, r.p2, r.p3;
END FOR;
END;
$$
DELIMITER ;$$
CALL p4;
CALL p4;
DROP PROCEDURE p4;
--echo # The same with a row comparison in a derived table of the lower bound
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p5()
BEGIN
FOR i IN 0+(SELECT z FROM (SELECT (1,'b1')=(1,'b1') AS z) dt)..2 DO
SELECT i;
END FOR;
END;
$$
DELIMITER ;$$
CALL p5;
CALL p5;
DROP PROCEDURE p5;
--echo # The same for a REVERSE loop, whose target bound is the left one
DELIMITER $$;
CREATE OR REPLACE PROCEDURE p6()
BEGIN
FOR i IN REVERSE 0+((1,'b1')=(1,'b1'))..2 DO
SELECT i;
END FOR;
END;
$$
DELIMITER ;$$
CALL p6;
CALL p6;
DROP PROCEDURE p6;
--echo # A trigger re-parses the upper bound after ALTER TABLE
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (b INT);
INSERT INTO t2 VALUES (1);
DELIMITER $$;
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW
BEGIN
FOR i IN 0..(SELECT NEW.a + COUNT(*) FROM t2) DO
SET @x= i;
END FOR;
END;
$$
DELIMITER ;$$
INSERT INTO t1 VALUES (1);
ALTER TABLE t2 ADD COLUMN c INT;
INSERT INTO t1 VALUES (2);
INSERT INTO t1 VALUES (3);
SELECT @x;
DROP TABLE t1, t2;
--echo # A trigger with NEW fields in more than one cursor parameter
CREATE TABLE t1 (a INT, b INT);
DELIMITER $$;
CREATE TRIGGER tr BEFORE INSERT ON t1 FOR EACH ROW
BEGIN
DECLARE c CURSOR (p1 INT, p2 INT) FOR SELECT p1, p2;
FOR r IN c(NEW.a, NEW.b + ((NEW.a,'x')=(NEW.a,'x'))) DO
SET @x= CONCAT(r.p1, ',', r.p2);
END FOR;
END;
$$
DELIMITER ;$$
INSERT INTO t1 VALUES (1, 10);
SELECT @x;
INSERT INTO t1 VALUES (2, 20);
SELECT @x;
DROP TABLE t1;
--echo #
--echo # End of 11.4 tests
--echo #

View File

@@ -2093,3 +2093,43 @@ drop user 'root
definer_host=localhost
suid=1'@localhost;
# End of 10.6 tests
#
# MDEV-22374: VIEW with security definer require FILE privilege from
# definer not invoker in case of INTO OUTFILE
#
create user test@localhost;
grant select on test.* to test@localhost;
create table t1 (a int);
insert into t1 values (1),(2);
create definer=test@localhost sql security definer view v1 as select * from t1;
# FILE privilege should be checked for the invoker, not the view definer
select * into outfile 'MYSQLTEST_VARDIR/tmp/mdev22374.txt' from t1;
select * from v1;
a
1
2
select * into outfile 'MYSQLTEST_VARDIR/tmp/mdev22374.txt' from (select count(*) from v1) as dv1;
select * into outfile 'MYSQLTEST_VARDIR/tmp/mdev22374.txt' from (select * from v1) as dv1;
select * into outfile 'MYSQLTEST_VARDIR/tmp/mdev22374.txt' from v1;
drop view v1;
# Invoker without FILE privilege can not use the definer's one
create definer=root@localhost sql security definer view v1 as select * from t1;
connect con1, localhost, test;
select * into outfile 'MYSQLTEST_VARDIR/tmp/mdev22374.txt' from t1;
ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
select * from v1;
a
1
2
select * into outfile 'MYSQLTEST_VARDIR/tmp/mdev22374.txt' from (select count(*) from v1) as dv1;
ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
select * into outfile 'MYSQLTEST_VARDIR/tmp/mdev22374.txt' from (select * from v1) as dv1;
ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
select * into outfile 'MYSQLTEST_VARDIR/tmp/mdev22374.txt' from v1;
ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
disconnect con1;
connection default;
drop view v1;
drop table t1;
drop user test@localhost;
# End of 10.11 tests

View File

@@ -2347,5 +2347,57 @@ suid=1'@localhost;
--echo # End of 10.6 tests
--echo #
--echo # MDEV-22374: VIEW with security definer require FILE privilege from
--echo # definer not invoker in case of INTO OUTFILE
--echo #
create user test@localhost;
grant select on test.* to test@localhost;
create table t1 (a int);
insert into t1 values (1),(2);
create definer=test@localhost sql security definer view v1 as select * from t1;
--echo # FILE privilege should be checked for the invoker, not the view definer
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--eval select * into outfile '$MYSQLTEST_VARDIR/tmp/mdev22374.txt' from t1
--remove_file $MYSQLTEST_VARDIR/tmp/mdev22374.txt
select * from v1;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--eval select * into outfile '$MYSQLTEST_VARDIR/tmp/mdev22374.txt' from (select count(*) from v1) as dv1
--remove_file $MYSQLTEST_VARDIR/tmp/mdev22374.txt
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--eval select * into outfile '$MYSQLTEST_VARDIR/tmp/mdev22374.txt' from (select * from v1) as dv1
--remove_file $MYSQLTEST_VARDIR/tmp/mdev22374.txt
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--eval select * into outfile '$MYSQLTEST_VARDIR/tmp/mdev22374.txt' from v1
--remove_file $MYSQLTEST_VARDIR/tmp/mdev22374.txt
drop view v1;
--echo # Invoker without FILE privilege can not use the definer's one
create definer=root@localhost sql security definer view v1 as select * from t1;
connect con1, localhost, test;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
--eval select * into outfile '$MYSQLTEST_VARDIR/tmp/mdev22374.txt' from t1
select * from v1;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
--eval select * into outfile '$MYSQLTEST_VARDIR/tmp/mdev22374.txt' from (select count(*) from v1) as dv1
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
--eval select * into outfile '$MYSQLTEST_VARDIR/tmp/mdev22374.txt' from (select * from v1) as dv1
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
--eval select * into outfile '$MYSQLTEST_VARDIR/tmp/mdev22374.txt' from v1
disconnect con1;
connection default;
drop view v1;
drop table t1;
drop user test@localhost;
--echo # End of 10.11 tests
# Wait till we reached the initial number of concurrent sessions
--source include/wait_until_count_sessions.inc

View File

@@ -0,0 +1,42 @@
connection node_2;
connection node_1;
connection node_1;
connection node_2;
# Take node_2 down first: a per-table DATA/INDEX DIRECTORY names an
# absolute host path, and mtr runs both nodes on the same host, so
# creating the tables while node_2 is a live cluster member would
# replicate the same CREATE TABLE to node_2 and make it race node_1
# for the same external path. Node_2 must only ever receive these
# tables as SST-transferred files, not as replicated DDL.
connection node_2;
connection node_1;
CALL mtr.add_suppression("InnoDB: File .* was not found");
CREATE TABLE t_aria (f1 INT PRIMARY KEY, f2 VARCHAR(100))
ENGINE=Aria
DATA DIRECTORY='MYSQLTEST_VARDIR/tmp/MDEV-40727_aria_data'
INDEX DIRECTORY='MYSQLTEST_VARDIR/tmp/MDEV-40727_aria_index';
CREATE TABLE t_innodb (f1 INT PRIMARY KEY, f2 VARCHAR(100))
ENGINE=InnoDB
DATA DIRECTORY='MYSQLTEST_VARDIR/tmp/MDEV-40727_innodb_data';
INSERT INTO t_aria VALUES (1, 'aria_row_1'), (2, 'aria_row_2');
INSERT INTO t_innodb VALUES (1, 'innodb_row_1'), (2, 'innodb_row_2');
# Clean node_2's data directory so that a restart forces a full SST.
connection node_2;
SET SESSION wsrep_sync_wait = 15;
# Check that every table in database test, not only t_aria and
# t_innodb, has identical content on node_2 after the SST.
connection node_1;
connection node_2;
connection node_1;
connection node_2;
connection node_1;
connection node_2;
connection node_2;
# Confirm the donor's rsync SST script flushed the filesystems
# holding the Aria and InnoDB per-table directories, not only the
# data directory itself.
FOUND 1 /Synced filesystem: MYSQLTEST_VARDIR/tmp/MDEV-40727_aria_data/ in mysqld.1.err
FOUND 1 /Synced filesystem: MYSQLTEST_VARDIR/tmp/MDEV-40727_aria_index/ in mysqld.1.err
FOUND 1 /Synced filesystem: MYSQLTEST_VARDIR/tmp/MDEV-40727_innodb_data/test/ in mysqld.1.err
connection node_1;
DROP TABLE t_aria, t_innodb;

View File

@@ -0,0 +1,10 @@
!include ../galera_2nodes.cnf
[mysqld]
wsrep_sst_method=rsync
[mysqld.1]
wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.1.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;pc.wait_prim_timeout=PT60S;gcache.size=10M'
[mysqld.2]
wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.2.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;pc.wait_prim_timeout=PT60S;gcache.size=10M'

View File

@@ -0,0 +1,142 @@
--source include/big_test.inc
--source include/galera_cluster.inc
--source include/have_innodb.inc
--source include/have_aria.inc
#
# MDEV-40727 rsync SST donor stalls in a whole-host sync()
#
# The rsync SST donor flushes, to disk, every filesystem that the
# transfer reads from, before the transfer starts. That flush must
# also reach a filesystem holding a table placed outside the data
# directory by a per-table DATA DIRECTORY or INDEX DIRECTORY option.
# MyISAM and Aria place an OS symlink to the table file one level
# below the database directory; InnoDB instead leaves a small '.isl'
# file next to the tablespace, holding the real path as plain text -
# no OS symlink at all. This test forces a full SST and checks the
# donor's log for both cases.
#
# The per-database-directory transfer also needs to dereference these
# symlinks (--copy-links, not --links): the rsync daemon on the joiner
# cannot recreate an absolute symlink target as-is, so a MyISAM or
# Aria table placed by DATA DIRECTORY or INDEX DIRECTORY would
# otherwise come out unreadable after every rsync SST. This test
# checksums every table in database test on both nodes after the SST
# to check that all of them, not only t_aria and t_innodb, transferred
# with identical content.
#
--let $aria_data_dir = $MYSQLTEST_VARDIR/tmp/MDEV-40727_aria_data
--let $aria_index_dir = $MYSQLTEST_VARDIR/tmp/MDEV-40727_aria_index
--let $innodb_data_dir = $MYSQLTEST_VARDIR/tmp/MDEV-40727_innodb_data
--let $node_1=node_1
--let $node_2=node_2
--source include/auto_increment_offset_save.inc
--echo # Take node_2 down first: a per-table DATA/INDEX DIRECTORY names an
--echo # absolute host path, and mtr runs both nodes on the same host, so
--echo # creating the tables while node_2 is a live cluster member would
--echo # replicate the same CREATE TABLE to node_2 and make it race node_1
--echo # for the same external path. Node_2 must only ever receive these
--echo # tables as SST-transferred files, not as replicated DDL.
--connection node_2
--source include/shutdown_mysqld.inc
--connection node_1
--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
--source include/wait_condition.inc
# Dropping a table whose tablespace lives under a per-table DATA
# DIRECTORY logs this message; it is not a query failure.
CALL mtr.add_suppression("InnoDB: File .* was not found");
--exec rm -rf $aria_data_dir $aria_index_dir $innodb_data_dir
--exec mkdir -p $aria_data_dir $aria_index_dir $innodb_data_dir
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval CREATE TABLE t_aria (f1 INT PRIMARY KEY, f2 VARCHAR(100))
ENGINE=Aria
DATA DIRECTORY='$aria_data_dir'
INDEX DIRECTORY='$aria_index_dir';
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval CREATE TABLE t_innodb (f1 INT PRIMARY KEY, f2 VARCHAR(100))
ENGINE=InnoDB
DATA DIRECTORY='$innodb_data_dir';
INSERT INTO t_aria VALUES (1, 'aria_row_1'), (2, 'aria_row_2');
INSERT INTO t_innodb VALUES (1, 'innodb_row_1'), (2, 'innodb_row_2');
--echo # Clean node_2's data directory so that a restart forces a full SST.
--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/mtr
--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/performance_schema
--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/test
--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/mysql
--remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data
--connection node_2
--source include/start_mysqld.inc
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
--source include/wait_condition.inc
SET SESSION wsrep_sync_wait = 15;
--echo # Check that every table in database test, not only t_aria and
--echo # t_innodb, has identical content on node_2 after the SST.
--connection node_1
--let $n_tables_node1 = `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test'`
--connection node_2
--let $n_tables_node2 = `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'test'`
if ($n_tables_node1 != $n_tables_node2)
{
--die Database test has a different number of tables on node_1 and node_2 after SST
}
--let $ctr = 1
while ($ctr <= $n_tables_node1)
{
--connection node_1
--let $tbl = query_get_value(SELECT table_name FROM information_schema.tables WHERE table_schema = 'test' ORDER BY table_name, table_name, $ctr)
--let $checksum_node1 = query_get_value(CHECKSUM TABLE test.$tbl, Checksum, 1)
--connection node_2
--let $checksum_node2 = query_get_value(CHECKSUM TABLE test.$tbl, Checksum, 1)
if ($checksum_node1 != $checksum_node2)
{
--die Table test.$tbl differs between node_1 and node_2 after SST
}
--inc $ctr
}
--connection node_2
--echo # Confirm the donor's rsync SST script flushed the filesystems
--echo # holding the Aria and InnoDB per-table directories, not only the
--echo # data directory itself.
--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err
--let SEARCH_PATTERN = Synced filesystem: $aria_data_dir
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN = Synced filesystem: $aria_index_dir
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN = Synced filesystem: $innodb_data_dir/test
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--source include/search_pattern_in_file.inc
--connection node_1
DROP TABLE t_aria, t_innodb;
--exec rm -rf $aria_data_dir $aria_index_dir $innodb_data_dir
--source include/auto_increment_offset_restore.inc

View File

@@ -171,11 +171,121 @@ check_pid_and_port()
check_pid "$pid_file" && [ "$CHECK_PID" -eq "$pid" ]
}
# Resolves a directory to its physical path, with symlinks expanded.
# A relative path is interpreted against the data directory, which is
# how the server itself resolves these options. Prints nothing when the
# directory cannot be reached.
resolve_dir()
{
case "$1" in
/*) (cd -P "$1" 2>/dev/null && pwd -P) || : ;;
*) (cd -P "$DATA_DIR" 2>/dev/null && \
cd -P "$1" 2>/dev/null && pwd -P) || : ;;
esac
}
# Flushes the filesystems that hold the files to be transferred.
# A bare 'sync' flushes every mounted filesystem on the host and can
# block for minutes on I/O unrelated to the SST, while the donor holds
# the global read lock. 'sync -f' is limited to a single filesystem,
# but it is not available on every platform.
sync_filesystems()
{
local NL=$'\n'
local data_fs candidates synced dir path target isl
# 'sync -f' (syncfs) is a GNU coreutils extension. The Darwin and
# FreeBSD 'sync' ignores its operands, flushes everything and still
# exits with zero status, so a functional probe alone cannot detect
# it and every call below would become a whole-host sync - worse
# than the single sync being replaced. Gate on the platform first.
if [ "$OS" != 'Linux' ]; then
sync
return
fi
# The data directory itself may be a symlink. Resolve it to the
# physical path.
data_fs=$(resolve_dir "$DATA_DIR")
[ -n "$data_fs" ] || data_fs="$DATA_DIR"
if ! sync -f "$data_fs" 2>/dev/null; then
sync
return
fi
# The InnoDB and Aria directories are resolved by create_dirs() and
# default to the data directory, but each of them may be placed on
# a filesystem of its own, and the transfer reads from all of them.
# Binlogs may likewise reside elsewhere: a relative binlog path is
# taken relative to the data directory, but it can still escape it
# or be a mount point of its own.
candidates="$ib_home_dir$NL$ib_log_dir$NL$ib_undo_dir$NL$ar_log_dir"
candidates="$candidates$NL$binlog_dir$NL"
# Database directories may be symlinks to other filesystems, and so
# may an individual table file placed one level deeper by a
# per-table DATA DIRECTORY or INDEX DIRECTORY (MyISAM, Aria). The
# transfer follows both, so flush them as well.
candidates="$candidates$(find "$data_fs" -mindepth 1 -maxdepth 2 \
-type l 2>/dev/null || :)$NL"
# InnoDB's per-table DATA DIRECTORY does not create an OS symlink:
# it leaves a small '.isl' file next to the tablespace, holding the
# real file's path as plain text. Flush the filesystem it names too.
while IFS= read -r isl; do
[ -n "$isl" ] || continue
target=$(sed -e '1q' -e 's/[[:space:]]*$//' "$isl" 2>/dev/null) || continue
[ -n "$target" ] || continue
candidates="$candidates$(dirname "$target")$NL"
done <<< "$(find "$data_fs" -mindepth 2 -maxdepth 2 -type f \
-name '*.isl' 2>/dev/null || :)"
# Paths already flushed, newline delimited on both sides so that a
# membership test cannot match a partial path component.
synced="$NL$data_fs$NL"
while IFS= read -r dir; do
[ -n "$dir" ] || continue
if [ -L "$dir" ]; then
# readlink -f gives the physical path whether the link
# points to a directory (a symlinked database directory)
# or to a file (a symlinked per-table data/index file);
# 'cd -P', which resolve_dir() relies on, only works for
# the former.
target=$(readlink -f "$dir" 2>/dev/null) || continue
[ -e "$target" ] || continue
if [ -d "$target" ]; then
path=$target
else
path=$(dirname "$target")
fi
else
# resolve_dir() prints nothing unless the path is a
# reachable directory, so it doubles as the existence
# check. Testing $dir directly would resolve a relative
# path against the current directory rather than against
# the data directory.
path=$(resolve_dir "$dir")
fi
[ -n "$path" ] || continue
case "$synced" in
*"$NL$path$NL"*) continue ;;
esac
sync -f "$path" || :
wsrep_log_info "Synced filesystem: $path"
synced="$synced$path$NL"
done <<< "$candidates"
}
get_binlog
if [ -n "$WSREP_SST_OPT_BINLOG" ]; then
binlog_dir=$(dirname "$WSREP_SST_OPT_BINLOG")
binlog_base=$(basename "$WSREP_SST_OPT_BINLOG")
else
binlog_dir=""
binlog_base=""
fi
BINLOG_TAR_FILE="$DATA_DIR/wsrep_sst_binlog.tar"
@@ -383,7 +493,7 @@ EOF
STATE=$(cat "$FLUSHED")
rm "$FLUSHED"
sync
sync_filesystems
wsrep_log_info "Tables flushed"
@@ -621,11 +731,19 @@ FILTER="-f '- /lost+found'
findopt='-L'
[ "$OS" = 'FreeBSD' ] && findopt="$findopt -E"
# --copy-links, not --links: a per-table DATA DIRECTORY or INDEX
# DIRECTORY (MyISAM, Aria) places a real OS symlink here, and
# the rsync daemon on the joiner cannot recreate an absolute
# symlink target as-is (with 'use chroot = no', it either
# rewrites the target into a dangling '/rsyncd-munged/...'
# path, or, with symlink munging turned off, still drops the
# target's leading '/'). Dereferencing the symlink and copying
# the file it points to avoids depending on either behavior.
find $findopt . -maxdepth 1 -mindepth 1 -type d -not -name 'lost+found' \
-not -name '.zfs' -not -name .snapshot -print0 \
| xargs -I{} -0 -P $backup_threads \
rsync ${STUNNEL:+--rsh="$STUNNEL"} \
--owner --group --perms --links --specials --ignore-times \
--owner --group --perms --copy-links --specials --ignore-times \
--inplace --recursive --delete --quiet $WHOLE_FILE_OPT \
-f '- $ib_home_dir/ib_lru_dump' \
-f '- $ib_home_dir/ibdata*' \

View File

@@ -2454,20 +2454,7 @@ void change_double_for_sort(double nr,uchar *to)
}
else
{
#ifdef WORDS_BIGENDIAN
memcpy(tmp, &nr, sizeof(nr));
#else
{
uchar *ptr= (uchar*) &nr;
#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
tmp[0]= ptr[3]; tmp[1]=ptr[2]; tmp[2]= ptr[1]; tmp[3]=ptr[0];
tmp[4]= ptr[7]; tmp[5]=ptr[6]; tmp[6]= ptr[5]; tmp[7]=ptr[4];
#else
tmp[0]= ptr[7]; tmp[1]=ptr[6]; tmp[2]= ptr[5]; tmp[3]=ptr[4];
tmp[4]= ptr[3]; tmp[5]=ptr[2]; tmp[6]= ptr[1]; tmp[7]=ptr[0];
#endif
}
#endif
mi_float8store(tmp, nr);
if (tmp[0] & 128) /* Negative */
{ /* make complement */
uint i;

View File

@@ -333,15 +333,15 @@ static bool extract_date_time(THD *thd, DATE_TIME_FORMAT *format,
/* Conversion specifiers that match classes of characters */
case '.':
while (my_ispunct(cs, *val) && val != val_end)
while (val < val_end && my_ispunct(cs, *val))
val++;
break;
case '@':
while (my_isalpha(cs, *val) && val != val_end)
while (val < val_end && my_isalpha(cs, *val))
val++;
break;
case '#':
while (my_isdigit(cs, *val) && val != val_end)
while (val < val_end && my_isdigit(cs, *val))
val++;
break;
default:

View File

@@ -6141,6 +6141,7 @@ int mysqld_main(int argc, char **argv)
my_report_svc_status(SERVICE_START_PENDING, NO_ERROR, slow_start_timeout);
#endif
vio_check_ssl_init();
if (init_server_components())
unireg_abort(1);

View File

@@ -3220,6 +3220,73 @@ int sp_head::add_instr(sp_instr_cursor_copy_struct *instr)
}
/**
In a trigger, add_instr() also takes the NEW and OLD fields in
m_cur_instr_trig_field_items. Rebuild this list from THD::free_list
after a split, so the fields go with their items.
*/
static void set_trig_field_items(THD *thd, sp_head *sp)
{
if (sp->m_handler->type() != SP_TYPE_TRIGGER)
return;
sp->m_cur_instr_trig_field_items.empty();
for (Item *item= thd->free_list; item; item= item->next)
{
if (item->type() == Item::TRIGGER_FIELD_ITEM)
{
Item_trigger_field *field= static_cast<Item_trigger_field*>(item);
sp->m_cur_instr_trig_field_items.insert(field, &field->next_trg_field);
}
}
}
/**
Move the items of an expression from an item list to THD::free_list.
The list starts with the newest item, and the parser creates the parts
of an item before the item itself. So the first item in the list that
walk() finds in expr, and all items after it, belong to expr, even
those walk() does not visit, like the LIMIT of a subquery.
@param thd Thread handle
@param list Item list to take the items from
@param expr Root of the oldest expression that has items in list
*/
void sp_head::move_expr_items_to_free_list(THD *thd, Item **list, Item *expr)
{
DBUG_ASSERT(!thd->free_list || thd->free_list == *list);
Item **pos= list;
while (*pos && !expr->walk(&Item::find_item_processor, true, *pos))
pos= &(*pos)->next;
DBUG_ASSERT(*pos); // expr itself is always found
thd->free_list= *pos;
*pos= NULL;
set_trig_field_items(thd, this);
}
/**
Put an item list back on THD::free_list, so that the next added
instruction owns the items, or on an error the routine frees them.
*/
void sp_head::add_to_free_list(THD *thd, Item *items)
{
if (items)
{
Item *last= items;
while (last->next)
last= last->next;
last->next= thd->free_list;
thd->free_list= items;
}
set_trig_field_items(thd, this);
}
/**
Add instruction to SP.
@@ -3981,6 +4048,15 @@ sp_head::add_set_for_loop_cursor_param_variables(THD *thd,
Item_args *parameters)
{
DBUG_ASSERT(param_spcont->context_var_count() == parameters->argument_count());
/*
All parameters were parsed as one expression, so THD::free_list holds:
[items of no parameter] [items of arg N-1] ... [items of arg 0]
Give each sp_instr_set the items of the argument it evaluates.
*/
Item *rest= thd->free_list;
thd->free_list= NULL;
for (uint idx= 0; idx < parameters->argument_count(); idx ++)
{
/*
@@ -3990,13 +4066,29 @@ sp_head::add_set_for_loop_cursor_param_variables(THD *thd,
*/
bool last= idx + 1 == parameters->argument_count();
sp_variable *spvar= param_spcont->get_context_variable(idx);
/*
The last instruction also takes the Item_func_sp of the cursor call
and anything that belongs to no argument.
*/
if (last)
{
add_to_free_list(thd, rest);
rest= NULL;
}
else
move_expr_items_to_free_list(thd, &rest, parameters->arguments()[idx]);
if (set_local_variable(thd, param_spcont,
&sp_rcontext_handler_local,
spvar, parameters->arguments()[idx],
param_lex, last,
param_lex->get_expr_str()))
{
add_to_free_list(thd, rest);
return true;
}
}
/* With no parameters, nothing took the items */
add_to_free_list(thd, rest);
return false;
}

View File

@@ -403,6 +403,9 @@ public:
int
add_instr(sp_instr_cursor_copy_struct *instr);
void move_expr_items_to_free_list(THD *thd, Item **list, Item *expr);
void add_to_free_list(THD *thd, Item *items);
bool
add_instr_jump(THD *thd, sp_pcontext *spcont);

View File

@@ -495,7 +495,10 @@ int sp_lex_keeper::validate_lex_and_exec_core(THD *thd, uint *nextp,
while (true)
{
if (instr->is_invalid() || m_lex->needs_reprepare)
if (!instr->is_invalid() && m_lex->needs_reprepare)
instr->invalidate();
if (instr->is_invalid())
{
thd->clear_error();
free_lex(thd);

View File

@@ -7419,12 +7419,34 @@ bool LEX::sp_for_loop_intrange_declarations(THD *thd, Lex_for_loop_st *loop,
my_error(ER_SP_UNDECLARED_VAR, MYF(0), item->full_name());
return true;
}
/*
Both bounds were parsed before any instruction was added, so give each
bound instruction only the items of its own bound. The left bound was
parsed first, so split there; with REVERSE the index is the right bound.
Splitting here, not in the grammar, keeps the items on THD::free_list,
so a parse error cannot leak them.
*/
Item *rest= thd->free_list;
sphead->move_expr_items_to_free_list(thd, &rest, bounds.m_direction > 0 ?
bounds.m_index->get_item() :
bounds.m_target_bound->get_item());
if (bounds.m_direction < 0)
{
Item *left= thd->free_list;
thd->free_list= NULL;
sphead->add_to_free_list(thd, rest);
rest= left;
}
if (!(loop->m_index=
bounds.m_index->sp_add_for_loop_variable(thd, index,
bounds.m_index->get_item(),
bounds.m_index->get_expr_str())
))
{
sphead->add_to_free_list(thd, rest);
return true;
}
sphead->add_to_free_list(thd, rest);
if (unlikely(!(loop->m_target_bound=
bounds.m_target_bound->
sp_add_for_loop_target_bound(thd,

View File

@@ -3177,9 +3177,9 @@ public:
Explain_query *explain;
/*
If true, query optimizer has encountered an unrecoverable error when doing
If true, query optimizer has encountered an error when doing
once-per-statement optimization and it is not safe to re-execute this
statement.
statement without re-preparing it.
*/
bool needs_reprepare{false};

View File

@@ -4434,13 +4434,12 @@ Prepared_statement::execute_loop(String *expanded_query,
*/
DBUG_ASSERT(thd->free_list == NULL);
if (lex->needs_reprepare)
if (lex->needs_reprepare && state != Query_arena::STMT_ERROR)
{
/*
Something has happened on previous execution that requires us to
re-prepare before we try to execute.
*/
lex->needs_reprepare= false;
goto start_with_reprepare;
}
@@ -4615,7 +4614,6 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
Something has happened on previous execution that requires us to
re-prepare before we try to execute.
*/
lex->needs_reprepare= false;
error= reprepare();
if (error)
goto err;

View File

@@ -2020,7 +2020,13 @@ int JOIN::optimize()
if (optimization_state != JOIN::NOT_OPTIMIZED)
return FALSE;
optimization_state= JOIN::OPTIMIZATION_IN_PROGRESS;
bool first_optimization= select_lex->first_cond_optimization;
res= optimize_inner();
if (unlikely(res) && first_optimization)
{
/* A failed first optimization may leave the statement half-done */
thd->lex->needs_reprepare= true;
}
}
if (!with_two_phase_optimization)
{

View File

@@ -108,6 +108,8 @@ ExternalProject_Add(duckdb_build
"-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}"
"-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}"
"-DCMAKE_MODULE_LINKER_FLAGS=${CMAKE_MODULE_LINKER_FLAGS}"
"-DCMAKE_C_LINKER_LAUNCHER=${CMAKE_C_LINKER_LAUNCHER}"
"-DCMAKE_CXX_LINKER_LAUNCHER=${CMAKE_CXX_LINKER_LAUNCHER}"
-DENABLE_SANITIZER=${ADDRESS_SANITIZER}
-DENABLE_UBSAN=${UB_SANITIZER}
-DOVERRIDE_GIT_DESCRIBE=${_DUCKDB_GIT_DESCRIBE}

View File

@@ -554,19 +554,7 @@ mach_double_read(
const byte* b) /*!< in: pointer to memory from where to read */
{
double d;
ulint i;
byte* ptr;
ptr = (byte*) &d;
for (i = 0; i < sizeof(double); i++) {
#ifdef WORDS_BIGENDIAN
ptr[sizeof(double) - i - 1] = b[i];
#else
ptr[i] = b[i];
#endif
}
float8get(d, b);
return(d);
}
@@ -579,18 +567,7 @@ mach_double_write(
byte* b, /*!< in: pointer to memory where to write */
double d) /*!< in: double */
{
ulint i;
byte* ptr;
ptr = (byte*) &d;
for (i = 0; i < sizeof(double); i++) {
#ifdef WORDS_BIGENDIAN
b[i] = ptr[sizeof(double) - i - 1];
#else
b[i] = ptr[i];
#endif
}
float8store(b, d);
}
/*********************************************************//**
@@ -603,19 +580,7 @@ mach_float_read(
const byte* b) /*!< in: pointer to memory from where to read */
{
float d;
ulint i;
byte* ptr;
ptr = (byte*) &d;
for (i = 0; i < sizeof(float); i++) {
#ifdef WORDS_BIGENDIAN
ptr[sizeof(float) - i - 1] = b[i];
#else
ptr[i] = b[i];
#endif
}
float4get(d, b);
return(d);
}
@@ -628,18 +593,7 @@ mach_float_write(
byte* b, /*!< in: pointer to memory where to write */
float d) /*!< in: float */
{
ulint i;
byte* ptr;
ptr = (byte*) &d;
for (i = 0; i < sizeof(float); i++) {
#ifdef WORDS_BIGENDIAN
b[i] = ptr[sizeof(float) - i - 1];
#else
b[i] = ptr[i];
#endif
}
float4store(b, d);
}
/*********************************************************//**

View File

@@ -549,8 +549,7 @@ typedef uint64 ULLong;
typedef union { double d; ULong L[2]; } U;
#if defined(WORDS_BIGENDIAN) || (defined(__FLOAT_WORD_ORDER) && \
(__FLOAT_WORD_ORDER == __BIG_ENDIAN))
#ifdef WORDS_BIGENDIAN
#define word0(x) (x)->L[0]
#define word1(x) (x)->L[1]
#else

View File

@@ -83,6 +83,81 @@ void test_byte_order()
TEST(mi_int8store, mi_uint8korr, ulonglong, 0x0807060504030201,
ARRAY_8(8, 7, 6, 5, 4, 3, 2, 1));
/*
Floating point macros. The stored bytes are IEEE 754, little-endian
(float4store etc.) or big-endian (the mi_ variants), on any host.
*/
#define TEST_FLOAT(STORE_NAME, LOAD_NAME, TYPE, VALUE, BYTES) \
{ \
TYPE value= VALUE, loaded; \
uchar bytes[]= BYTES; \
STORE_NAME(aligned, value); \
ok(!memcmp(aligned, bytes, sizeof(bytes)), "aligned\t\t" #STORE_NAME); \
LOAD_NAME(loaded, aligned); \
ok(!memcmp(&loaded, &value, sizeof(value)), "aligned\t\t" #LOAD_NAME); \
STORE_NAME(not_aligned, value); \
ok(!memcmp(not_aligned, bytes, sizeof(bytes)), \
"not aligned\t" #STORE_NAME); \
LOAD_NAME(loaded, not_aligned); \
ok(!memcmp(&loaded, &value, sizeof(value)), "not aligned\t" #LOAD_NAME); \
}
TEST_FLOAT(float4store, float4get, float, 1.0f, ARRAY_4(0, 0, 0x80, 0x3f));
TEST_FLOAT(float8store, float8get, double, 1.0,
ARRAY_8(0, 0, 0, 0, 0, 0, 0xf0, 0x3f));
TEST_FLOAT(float8store, float8get, double, -0.0,
ARRAY_8(0, 0, 0, 0, 0, 0, 0, 0x80));
TEST_FLOAT(mi_float4store, mi_float4get, float, 1.0f,
ARRAY_4(0x3f, 0x80, 0, 0));
TEST_FLOAT(mi_float4store, mi_float4get, float, -2.0f,
ARRAY_4(0xc0, 0, 0, 0));
TEST_FLOAT(mi_float8store, mi_float8get, double, 1.0,
ARRAY_8(0x3f, 0xf0, 0, 0, 0, 0, 0, 0));
TEST_FLOAT(mi_float8store, mi_float8get, double, -2.0,
ARRAY_8(0xc0, 0, 0, 0, 0, 0, 0, 0));
{
/* The bits of a NaN must be preserved, too */
ulonglong bits= 0x7ff8000000000001ULL;
uchar bytes[]= ARRAY_8(1, 0, 0, 0, 0, 0, 0xf8, 0x7f);
double nan, loaded;
memcpy(&nan, &bits, sizeof(nan));
float8store(aligned, nan);
ok(!memcmp(aligned, bytes, sizeof(bytes)), "NaN\t\tfloat8store");
float8get(loaded, aligned);
ok(!memcmp(&loaded, &nan, sizeof(nan)), "NaN\t\tfloat8get");
}
/* Native byte order integers, including sign and zero extension on read */
#define TEST_NATIVE(P, NAME) \
{ \
int16 s= -2; \
uint16 us= 0xfffe; \
int32 l= -70000; \
int16 s_loaded; \
int i_loaded; \
int32 l_loaded; \
longlong ll_loaded; \
shortstore(P, s); \
shortget(s_loaded, P); \
ok(s_loaded == s, NAME "\tshortstore/shortget"); \
shortget(i_loaded, P); \
ok(i_loaded == -2, NAME "\tshortget sign extension"); \
shortstore(P, us); \
ushortget(i_loaded, P); \
ok(i_loaded == 0xfffe, NAME "\tushortget zero extension"); \
longstore(P, l); \
longget(l_loaded, P); \
ok(l_loaded == l, NAME "\tlongstore/longget"); \
longget(ll_loaded, P); \
ok(ll_loaded == -70000, NAME "\tlongget sign extension"); \
}
TEST_NATIVE(aligned, "aligned");
TEST_NATIVE(not_aligned, "not aligned");
#undef TEST_NATIVE
#undef TEST_FLOAT
#undef ARRAY_8
#undef ARRAY_7
#undef ARRAY_6
@@ -96,7 +171,7 @@ void test_byte_order()
int main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
{
plan(68);
plan(108);
test_byte_order();
return exit_status();
}

View File

@@ -1,4 +1,4 @@
SET(HEIDISQL_VERSION "12.20")
SET(HEIDISQL_VERSION "12.21")
SET(HEIDISQL_BASE_NAME "HeidiSQL_${HEIDISQL_VERSION}_64_Portable")
SET(HEIDISQL_ZIP "${HEIDISQL_BASE_NAME}.zip")
SET(HEIDISQL_URL "https://github.com/HeidiSQL/HeidiSQL/releases/download/v${HEIDISQL_VERSION}/${HEIDISQL_ZIP}")
@@ -7,7 +7,7 @@ SET(HEIDISQL_DOWNLOAD_DIR ${THIRD_PARTY_DOWNLOAD_LOCATION}/${HEIDISQL_BASE_NAME}
MAKE_DIRECTORY(${HEIDISQL_DOWNLOAD_DIR})
MESSAGE(STATUS "Downloading ${HEIDISQL_URL} to ${HEIDISQL_DOWNLOAD_DIR}/${HEIDISQL_ZIP}")
FILE(DOWNLOAD ${HEIDISQL_URL} ${HEIDISQL_DOWNLOAD_DIR}/${HEIDISQL_ZIP} TIMEOUT 300
SHOW_PROGRESS EXPECTED_HASH SHA256=d84742736e4508c206c28c58018bbd934319c941dc9d68ff4673737a3f4df731)
SHOW_PROGRESS EXPECTED_HASH SHA256=fecb76a69e29a53ea05b1d57fc2f7b7aaed5b8f889556c6eca545e2a800df1ab)
EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E chdir ${HEIDISQL_DOWNLOAD_DIR}
${CMAKE_COMMAND} -E tar xfz ${HEIDISQL_DOWNLOAD_DIR}/${HEIDISQL_ZIP})