From dd30ba4c1bfbf7bd6c55a170ac6d718bdb10dab1 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sat, 24 Aug 2019 16:14:24 +0200 Subject: [PATCH 01/68] In CONNECT version 1.6.10 NOSQL facility is enhanced by a new way to retrieve NOSQL data. In addition to files and Mongo collections, JSON as well as XML and CSV data can be retrieved from the net as answers from REST queries. Because it uses and external package (cpprestsdk) this is currently available only to MariaDB servers compiled from source. -- Add the REST support when Microsoft Casablanca package (cpprestsdk) is installed. -- Add compile flags needed on Windows /MD or /MDd (debug) -- Also include some changes specific to MariaDB 10.3. modified: storage/connect/CMakeLists.txt -- Add conditional REST support -- Added string options HTTP and URI. -- Added added internal table type TAB_REST. modified: storage/connect/ha_connect.cc modified: storage/connect/mycat.cc modified: storage/connect/mycat.h modified: storage/connect/plgdbsem.h -- Add conditional code based on the preprocessor definition MARIADB -- This to be able to use the same code in CONNECT and EOM modules modified: storage/connect/osutil.h modified: storage/connect/tabrest.cpp -- Add files for the REST OEM module added: storage/connect/mini-global.h added: storage/connect/rest.def -- Fix MDEV-19648 Variable connect_conv_size doesn't change -- Change Variable wrong block parameter from 8169 to 1. -- Also change connect_conv_size default value to 1024. modified: storage/connect/ha_connect.cc -- Fix compilation error when ZIP is not supported modified: storage/connect/ha_connect.cc modified: storage/connect/tabfmt.cpp -- Replace PlugSetPath by some concat (crashed on Fedora) + typo modified: storage/connect/reldef.cpp -- Avoid possible buffer overflow -- In particular by the function ShowValue. modified: storage/connect/tabdos.cpp modified: storage/connect/tabfmt.cpp modified: storage/connect/value.cpp modified: storage/connect/value.h -- Add some cast to avoid some compiler warnings modified: storage/connect/filamdbf.cpp -- Fix some C++ error modified: storage/connect/javaconn.cpp modified: storage/connect/jmgoconn.cpp modified: storage/connect/plugutil.cpp -- Add some tracing + typo modified: storage/connect/mycat.cc modified: storage/connect/tabjson.cpp -- Add the xtrc tracing function modified: storage/connect/global.h modified: storage/connect/plugutil.cpp -- Modify tracing to use xtrc and some typo modified: storage/connect/array.cpp modified: storage/connect/block.h -- Miscellaneous Typo and warning suppressing changes modified: storage/connect/connect.cpp modified: storage/connect/connect.h modified: storage/connect/filamvct.cpp modified: storage/connect/inihandl.cpp modified: storage/connect/jsonudf.cpp modified: storage/connect/libdoc.cpp modified: storage/connect/tabjson.cpp modified: storage/connect/tabtbl.cpp modified: storage/connect/tabxml.cpp modified: storage/connect/user_connect.cc modified: storage/connect/user_connect.h -- Update failing test results and disbling modified: storage/connect/mysql-test/connect/disabled.def modified: storage/connect/mysql-test/connect/r/dir.result modified: storage/connect/mysql-test/connect/r/grant.result modified: storage/connect/mysql-test/connect/r/jdbc.result modified: storage/connect/mysql-test/connect/r/jdbc_postgresql.result modified: storage/connect/mysql-test/connect/r/xml.result modified: storage/connect/mysql-test/connect/r/xml2.result modified: storage/connect/mysql-test/connect/r/xml2_mult.result modified: storage/connect/mysql-test/connect/r/xml_mult.result -- Add an option modified: storage/connect/mysql-test/connect/t/grant.test --- storage/connect/CMakeLists.txt | 50 +- storage/connect/array.cpp | 127 +-- storage/connect/block.h | 4 +- storage/connect/connect.cc | 3 +- storage/connect/connect.h | 2 +- storage/connect/global.h | 1 + storage/connect/ha_connect.cc | 637 ++++++------ storage/connect/ha_connect.h | 6 +- storage/connect/inihandl.cpp | 4 +- storage/connect/jmgoconn.cpp | 5 +- storage/connect/jsonudf.cpp | 8 +- storage/connect/libdoc.cpp | 2 +- storage/connect/mini-global.h | 33 + storage/connect/mycat.cc | 166 +-- storage/connect/mycat.h | 6 +- storage/connect/osutil.h | 4 + storage/connect/plgdbsem.h | 6 +- storage/connect/plugutil.cpp | 38 +- storage/connect/reldef.cpp | 297 +++--- storage/connect/rest.def | 4 + storage/connect/restget.cpp | 94 ++ storage/connect/tabfmt.cpp | 2 + storage/connect/tabjdbc.cpp | 26 +- storage/connect/tabjson.cpp | 1709 ++++++++++++++++--------------- storage/connect/tabrest.cpp | 201 ++++ storage/connect/tabrest.h | 29 + storage/connect/tabtbl.cpp | 4 +- storage/connect/tabxml.cpp | 2 +- storage/connect/user_connect.cc | 2 +- storage/connect/user_connect.h | 2 +- 30 files changed, 1975 insertions(+), 1499 deletions(-) create mode 100644 storage/connect/mini-global.h create mode 100644 storage/connect/rest.def create mode 100644 storage/connect/restget.cpp create mode 100644 storage/connect/tabrest.cpp create mode 100644 storage/connect/tabrest.h diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index c8747f889c6..fd006e104c1 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -11,7 +11,7 @@ # # 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-1301 USA +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA SET(CONNECT_PLUGIN_STATIC "connect") SET(CONNECT_PLUGIN_DYNAMIC "connect") @@ -68,7 +68,15 @@ ELSE(NOT UNIX) tabwmi.cpp tabwmi.h tabmac.cpp tabmac.h macutil.cpp macutil.h) # Add exception handling to the CONNECT project) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") + SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") + SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD") + SET(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD") SET(IPHLPAPI_LIBRARY iphlpapi.lib) + IF(MSVC AND (CMAKE_CXX_COMPILER_ID MATCHES Clang)) + # Connect does not work with clang-cl + RETURN() + ENDIF() ENDIF(UNIX) @@ -109,7 +117,6 @@ IF(CONNECT_WITH_LIBXML2) FIND_PACKAGE(LibXml2) IF (LIBXML2_FOUND) INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR}) - SET(ZLIB_LIBRARY "z") # see ZLIB_INCLUDE_DIR below SET(XML_LIBRARY ${LIBXML2_LIBRARIES}) SET(CONNECT_SOURCES ${CONNECT_SOURCES} libdoc.cpp libdoc.h) add_definitions(-DLIBXML2_SUPPORT) @@ -301,6 +308,30 @@ IF(CONNECT_WITH_MONGO) ENDIF(CONNECT_WITH_MONGO) +# +# REST +# + +OPTION(CONNECT_WITH_REST "Compile CONNECT storage engine with REST support" ON) + +IF(CONNECT_WITH_REST) + MESSAGE(STATUS "=====> REST support is ON") + FIND_PACKAGE(cpprestsdk) + IF (cpprestsdk_FOUND) + MESSAGE(STATUS "=====> cpprestsdk found") + IF(UNIX) +# INCLUDE_DIRECTORIES(${CPPRESTSDK_INCLUDE_DIR}) +# If needed edit next line to set the path to libcpprest.so + SET(REST_LIBRARY -lcpprest) + MESSAGE (STATUS ${REST_LIBRARY}) + ENDIF(UNIX) + SET(CONNECT_SOURCES ${CONNECT_SOURCES} tabrest.cpp restget.cpp tabrest.h) + add_definitions(-DREST_SUPPORT) + ELSE(NOT cpprestsdk_FOUND) + MESSAGE(STATUS "=====> cpprestsdk package not found") + ENDIF (cpprestsdk_FOUND) +ENDIF(CONNECT_WITH_REST) + # # XMAP # @@ -320,24 +351,16 @@ MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES} COMPONENT connect-engine RECOMPILE_FOR_EMBEDDED LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY} - ${ODBC_LIBRARY} ${JDBC_LIBRARY} ${MONGOC_LIBRARY} ${IPHLPAPI_LIBRARY}) + ${ODBC_LIBRARY} ${JDBC_LIBRARY} ${MONGOC_LIBRARY} ${IPHLPAPI_LIBRARY} ${REST_LIBRARY}) IF(NOT TARGET connect) RETURN() ENDIF() -# Don't link with bundled zlib and systel libxml2 at the same time. -# System libxml2 uses system zlib, might conflict with the bundled one. -IF (XML_LIBRARY AND BUILD_BUNDLED_ZLIB) - GET_PROPERTY(INCS TARGET connect PROPERTY INCLUDE_DIRECTORIES) - LIST(REMOVE_ITEM INCS ${ZLIB_INCLUDE_DIR}) - SET_PROPERTY(TARGET connect PROPERTY INCLUDE_DIRECTORIES ${INCS}) -ENDIF() - IF(WIN32) IF (libmongoc-1.0_FOUND) - SET_TARGET_PROPERTIES(connect PROPERTIES LINK_FLAGS - "/DELAYLOAD:libbson-1.0.dll /DELAYLOAD:libmongoc-1.0.dll") + SET_TARGET_PROPERTIES(connect PROPERTIES LINK_FLAGS + "/DELAYLOAD:libbson-1.0.dll /DELAYLOAD:libmongoc-1.0.dll") ENDIF(libmongoc-1.0_FOUND) ENDIF(WIN32) @@ -364,3 +387,4 @@ IF(CONNECT_WITH_JDBC AND JAVA_FOUND AND JNI_FOUND) ${CMAKE_CURRENT_BINARY_DIR}/JdbcInterface.jar DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine) ENDIF() + diff --git a/storage/connect/array.cpp b/storage/connect/array.cpp index cd1785b48ac..3478342a788 100644 --- a/storage/connect/array.cpp +++ b/storage/connect/array.cpp @@ -1,7 +1,7 @@ /************* Array C++ Functions Source Code File (.CPP) *************/ /* Name: ARRAY.CPP Version 2.3 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2005-2017 */ +/* (C) Copyright to the author Olivier BERTRAND 2005-2019 */ /* */ /* This file contains the XOBJECT derived class ARRAY functions. */ /* ARRAY is used for elaborate type of processing, such as sorting */ @@ -67,7 +67,7 @@ PARRAY MakeValueArray(PGLOBAL g, PPARM pp); // avoid gcc warning /* MakeValueArray: Makes a value array from a value list. */ /***********************************************************************/ PARRAY MakeValueArray(PGLOBAL g, PPARM pp) - { +{ int n, valtyp = 0; size_t len = 0; PARRAY par; @@ -82,8 +82,7 @@ PARRAY MakeValueArray(PGLOBAL g, PPARM pp) if ((valtyp = pp->Type) != TYPE_STRING) len = 1; - if (trace(1)) - htrc("valtyp=%d len=%d\n", valtyp, len); + xtrc(1, "valtyp=%d len=%d\n", valtyp, len); /*********************************************************************/ /* Firstly check the list and count the number of values in it. */ @@ -127,13 +126,13 @@ PARRAY MakeValueArray(PGLOBAL g, PPARM pp) // Integer stored inside pp->Value par->AddValue(g, parmp->Intval); break; - } // endswitch valtyp + } // endswitch valtyp /*********************************************************************/ /* Send back resulting array. */ /*********************************************************************/ return par; - } // end of MakeValueArray +} // end of MakeValueArray /* -------------------------- Class ARRAY ---------------------------- */ @@ -151,6 +150,9 @@ ARRAY::ARRAY(PGLOBAL g, int type, int size, int length, int prec) Type = type; Xsize = -1; Len = 1; + X = 0; + Inf = 0; + Sup = 0; switch (type) { case TYPE_STRING: @@ -281,130 +283,109 @@ void ARRAY::Empty(void) /* Add a string element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, PSZ strp) - { +{ if (Type != TYPE_STRING) { sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "CHAR"); return true; - } // endif Type + } // endif Type - if (trace(1)) - htrc(" adding string(%d): '%s'\n", Nval, strp); - -//Value->SetValue_psz(strp); -//Vblp->SetValue(valp, Nval++); + xtrc(1, " adding string(%d): '%s'\n", Nval, strp); Vblp->SetValue(strp, Nval++); return false; - } // end of AddValue +} // end of AddValue /***********************************************************************/ /* Add a char pointer element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, void *p) - { +{ if (Type != TYPE_PCHAR) { sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "PCHAR"); return true; - } // endif Type - - if (trace(1)) - htrc(" adding pointer(%d): %p\n", Nval, p); + } // endif Type + xtrc(1, " adding pointer(%d): %p\n", Nval, p); Vblp->SetValue((PSZ)p, Nval++); return false; - } // end of AddValue +} // end of AddValue /***********************************************************************/ /* Add a short integer element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, short n) - { +{ if (Type != TYPE_SHORT) { sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "SHORT"); return true; - } // endif Type + } // endif Type - if (trace(1)) - htrc(" adding SHORT(%d): %hd\n", Nval, n); - -//Value->SetValue(n); -//Vblp->SetValue(valp, Nval++); + xtrc(1, " adding SHORT(%d): %hd\n", Nval, n); Vblp->SetValue(n, Nval++); return false; - } // end of AddValue +} // end of AddValue /***********************************************************************/ /* Add an integer element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, int n) - { +{ if (Type != TYPE_INT) { sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "INTEGER"); return true; - } // endif Type + } // endif Type - if (trace(1)) - htrc(" adding int(%d): %d\n", Nval, n); - -//Value->SetValue(n); -//Vblp->SetValue(valp, Nval++); + xtrc(1, " adding int(%d): %d\n", Nval, n); Vblp->SetValue(n, Nval++); return false; - } // end of AddValue +} // end of AddValue /***********************************************************************/ /* Add a double float element to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, double d) - { +{ if (Type != TYPE_DOUBLE) { sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "DOUBLE"); return true; - } // endif Type - - if (trace(1)) - htrc(" adding float(%d): %lf\n", Nval, d); + } // endif Type + xtrc(1, " adding float(%d): %lf\n", Nval, d); Value->SetValue(d); Vblp->SetValue(Value, Nval++); return false; - } // end of AddValue +} // end of AddValue /***********************************************************************/ /* Add the value of a XOBJECT block to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, PXOB xp) - { - if (Type != xp->GetResultType()) { - sprintf(g->Message, MSG(ADD_BAD_TYPE), - GetTypeName(xp->GetResultType()), GetTypeName(Type)); - return true; - } // endif Type +{ + if (Type != xp->GetResultType()) { + sprintf(g->Message, MSG(ADD_BAD_TYPE), + GetTypeName(xp->GetResultType()), GetTypeName(Type)); + return true; + } // endif Type - if (trace(1)) - htrc(" adding (%d) from xp=%p\n", Nval, xp); - -//AddValue(xp->GetValue()); - Vblp->SetValue(xp->GetValue(), Nval++); - return false; - } // end of AddValue + xtrc(1, " adding (%d) from xp=%p\n", Nval, xp); + Vblp->SetValue(xp->GetValue(), Nval++); + return false; +} // end of AddValue /***********************************************************************/ /* Add a value to an array. */ /***********************************************************************/ bool ARRAY::AddValue(PGLOBAL g, PVAL vp) - { +{ if (Type != vp->GetType()) { sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(vp->GetType()), GetTypeName(Type)); return true; - } // endif Type - - if (trace(1)) - htrc(" adding (%d) from vp=%p\n", Nval, vp); + } // endif Type + xtrc(1, " adding (%d) from vp=%p\n", Nval, vp); Vblp->SetValue(vp, Nval++); return false; - } // end of AddValue +} // end of AddValue /***********************************************************************/ /* Retrieve the nth value of the array. */ @@ -973,7 +954,7 @@ int ARRAY::BlockTest(PGLOBAL, int opc, int opm, /* MakeArrayList: Makes a value list from an SQL IN array (in work). */ /***********************************************************************/ PSZ ARRAY::MakeArrayList(PGLOBAL g) - { +{ char *p, *tp; int i; size_t z, len = 2; @@ -988,11 +969,9 @@ PSZ ARRAY::MakeArrayList(PGLOBAL g) Value->SetValue_pvblk(Vblp, i); Value->Prints(g, tp, z); len += strlen(tp); - } // enfor i - - if (trace(1)) - htrc("Arraylist: len=%d\n", len); + } // enfor i + xtrc(1, "Arraylist: len=%d\n", len); p = (char *)PlugSubAlloc(g, NULL, len); strcpy(p, "("); @@ -1001,19 +980,17 @@ PSZ ARRAY::MakeArrayList(PGLOBAL g) Value->Prints(g, tp, z); strcat(p, tp); strcat(p, (++i == Nval) ? ")" : ","); - } // enfor i - - if (trace(1)) - htrc("Arraylist: newlen=%d\n", strlen(p)); + } // enfor i + xtrc(1, "Arraylist: newlen=%d\n", strlen(p)); return p; - } // end of MakeArrayList +} // end of MakeArrayList /***********************************************************************/ /* Make file output of ARRAY contents. */ /***********************************************************************/ void ARRAY::Printf(PGLOBAL g, FILE *f, uint n) - { +{ char m[64]; int lim = MY_MIN(Nval,10); @@ -1035,19 +1012,19 @@ void ARRAY::Printf(PGLOBAL g, FILE *f, uint n) } else fprintf(f, "%sVALLST: numval=%d\n", m, Nval); - } // end of Printf +} // end of Printf /***********************************************************************/ /* Make string output of ARRAY contents. */ /***********************************************************************/ void ARRAY::Prints(PGLOBAL, char *ps, uint z) - { +{ if (z < 16) return; sprintf(ps, "ARRAY: type=%d\n", Type); // More to be implemented later - } // end of Prints +} // end of Prints /* -------------------------- Class MULAR ---------------------------- */ diff --git a/storage/connect/block.h b/storage/connect/block.h index 737c74c1293..2ca9586ee3f 100644 --- a/storage/connect/block.h +++ b/storage/connect/block.h @@ -38,9 +38,7 @@ typedef class BLOCK *PBLOCK; class DllExport BLOCK { public: void * operator new(size_t size, PGLOBAL g, void *p = NULL) { - if (trace(256)) - htrc("New BLOCK: size=%d g=%p p=%p\n", size, g, p); - + xtrc(256, "New BLOCK: size=%d g=%p p=%p\n", size, g, p); return (PlugSubAlloc(g, p, size)); } // end of new diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index 21bca637eab..b1078de8eaa 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -13,7 +13,7 @@ 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /***********************************************************************/ /* Author Olivier BERTRAND bertrandop@gmail.com 2004-2017 */ @@ -33,6 +33,7 @@ /* plgdbsem.h is header containing the DB applic. declarations. */ /***********************************************************************/ #define DONT_DEFINE_VOID +#include #include "handler.h" #undef OFFSET diff --git a/storage/connect/connect.h b/storage/connect/connect.h index 2bca8bf54cb..3a60cd40160 100644 --- a/storage/connect/connect.h +++ b/storage/connect/connect.h @@ -11,7 +11,7 @@ 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /**************** Cnt H Declares Source Code File (.H) *****************/ /* Name: CONNECT.H Version 2.4 */ diff --git a/storage/connect/global.h b/storage/connect/global.h index dc1e149745f..fd26c87b800 100644 --- a/storage/connect/global.h +++ b/storage/connect/global.h @@ -224,6 +224,7 @@ DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t); DllExport char *PlugDup(PGLOBAL g, const char *str); DllExport void *MakePtr(void *, OFFSET); DllExport void htrc(char const *fmt, ...); +DllExport void xtrc(uint, char const* fmt, ...); DllExport uint GetTraceValue(void); #if defined(__cplusplus) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 191230cb03c..be7c6548181 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -11,7 +11,7 @@ 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file ha_connect.cc @@ -164,15 +164,15 @@ /***********************************************************************/ /* Initialize the ha_connect static members. */ /***********************************************************************/ -#define SZCONV 8192 +#define SZCONV 1024 // Default converted text size #define SZWORK 67108864 // Default work area size 64M #define SZWMIN 4194304 // Minimum work area size 4M #define JSONMAX 10 // JSON Default max grp size extern "C" { - char version[]= "Version 1.06.0009 January 27, 2019"; + char version[]= "Version 1.06.0010 June 01, 2019"; #if defined(__WIN__) - char compver[]= "Version 1.06.0009 " __DATE__ " " __TIME__; + char compver[]= "Version 1.06.0010 " __DATE__ " " __TIME__; char slash= '\\'; #else // !__WIN__ char slash= '/'; @@ -211,14 +211,14 @@ char *GetUserVariable(PGLOBAL g, const uchar *varname) { char buf[1024]; bool b; - THD *thd = current_thd; - CHARSET_INFO *cs = system_charset_info; - String *str = NULL, tmp(buf, sizeof(buf), cs); - HASH uvars = thd->user_vars; - user_var_entry *uvar = (user_var_entry*)my_hash_search(&uvars, varname, 0); + THD *thd= current_thd; + CHARSET_INFO *cs= system_charset_info; + String *str= NULL, tmp(buf, sizeof(buf), cs); + HASH uvars= thd->user_vars; + user_var_entry *uvar= (user_var_entry*)my_hash_search(&uvars, varname, 0); if (uvar) - str = uvar->val_str(&b, &tmp, NOT_FIXED_DEC); + str= uvar->val_str(&b, &tmp, NOT_FIXED_DEC); return str ? PlugDup(g, str->ptr()) : NULL; }; // end of GetUserVariable @@ -231,6 +231,9 @@ PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); PQRYRES VirColumns(PGLOBAL g, bool info); PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info); PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info); +#if defined(REST_SUPPORT) +PQRYRES RESTColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info); +#endif // REST_SUPPORT #if defined(JAVA_SUPPORT) PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ url, PTOS topt, bool info); #endif // JAVA_SUPPORT @@ -238,7 +241,9 @@ int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v); void PushWarning(PGLOBAL g, THD *thd, int level); bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, PCSZ host, PCSZ db, PCSZ tab, PCSZ src, int port); +#if defined(ZIP_SUPPORT) bool ZipLoadFile(PGLOBAL, PCSZ, PCSZ, PCSZ, bool, bool); +#endif // ZIP_SUPPORT bool ExactInfo(void); #if defined(CMGO_SUPPORT) //void mongo_init(bool); @@ -352,7 +357,7 @@ static MYSQL_THDVAR_UINT(work_size, static MYSQL_THDVAR_INT(conv_size, PLUGIN_VAR_RQCMDARG, // opt "Size used when converting TEXT columns.", - NULL, NULL, SZCONV, 0, 65500, 8192); + NULL, NULL, SZCONV, 0, 65500, 1); /** Type conversion: @@ -583,7 +588,9 @@ ha_create_table_option connect_table_option_list[]= HA_TOPTION_STRING("FILTER", filter), HA_TOPTION_STRING("OPTION_LIST", oplist), HA_TOPTION_STRING("DATA_CHARSET", data_charset), - HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1), + HA_TOPTION_STRING("HTTP", http), + HA_TOPTION_STRING("URI", uri), + HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1), HA_TOPTION_NUMBER("BLOCK_SIZE", elements, 0, 0, INT_MAX32, 1), //HA_TOPTION_NUMBER("ESTIMATE", estimate, 0, 0, INT_MAX32, 1), HA_TOPTION_NUMBER("MULTIPLE", multiple, 0, 0, 3, 1), @@ -991,11 +998,11 @@ static PCONNECT GetUser(THD *thd, PCONNECT xp) pthread_mutex_unlock(&usrmut); if (!xp) { - xp = new user_connect(thd); + xp= new user_connect(thd); if (xp->user_init()) { delete xp; - xp = NULL; + xp= NULL; } // endif user_init } // endif xp @@ -1027,6 +1034,19 @@ TABTYPE ha_connect::GetRealType(PTOS pos) if (type == TAB_UNDEF) type= pos->srcdef ? TAB_MYSQL : pos->tabname ? TAB_PRX : TAB_DOS; +#if defined(REST_SUPPORT) + else if (pos->http) + switch (type) { + case TAB_JSON: + case TAB_XML: + case TAB_CSV: + type = TAB_REST; + break; + case TAB_REST: + type = TAB_NIY; + break; + } // endswitch type +#endif // REST_SUPPORT } else type= TAB_UNDEF; @@ -1130,48 +1150,48 @@ PCSZ GetListOption(PGLOBAL g, PCSZ opname, PCSZ oplist, PCSZ def) return (char*)def; char key[16], val[256]; - char *pv, *pn, *pk = (char*)oplist; - PCSZ opval = def; + char *pv, *pn, *pk= (char*)oplist; + PCSZ opval= def; int n; while (*pk == ' ') pk++; - for (; pk; pk = pn) { - pn = strchr(pk, ','); - pv = strchr(pk, '='); + for (; pk; pk= pn) { + pn= strchr(pk, ','); + pv= strchr(pk, '='); if (pv && (!pn || pv < pn)) { - n = MY_MIN(static_cast(pv - pk), sizeof(key) - 1); + n= MY_MIN(static_cast(pv - pk), sizeof(key) - 1); memcpy(key, pk, n); while (n && key[n - 1] == ' ') n--; - key[n] = 0; + key[n]= 0; while (*(++pv) == ' '); - n = MY_MIN((pn ? pn - pv : strlen(pv)), sizeof(val) - 1); + n= MY_MIN((pn ? pn - pv : strlen(pv)), sizeof(val) - 1); memcpy(val, pv, n); while (n && val[n - 1] == ' ') n--; - val[n] = 0; + val[n]= 0; } else { - n = MY_MIN((pn ? pn - pk : strlen(pk)), sizeof(key) - 1); + n= MY_MIN((pn ? pn - pk : strlen(pk)), sizeof(key) - 1); memcpy(key, pk, n); while (n && key[n - 1] == ' ') n--; - key[n] = 0; - val[0] = 0; + key[n]= 0; + val[0]= 0; } // endif pv if (!stricmp(opname, key)) { - opval = PlugDup(g, val); + opval= PlugDup(g, val); break; } else if (!pn) break; @@ -1219,9 +1239,13 @@ PCSZ GetStringTableOption(PGLOBAL g, PTOS options, PCSZ opname, PCSZ sdef) else if (!stricmp(opname, "Colist")) opval= options->colist; else if (!stricmp(opname, "Filter")) - opval = options->filter; + opval= options->filter; else if (!stricmp(opname, "Data_charset")) opval= options->data_charset; + else if (!stricmp(opname, "Http") || !stricmp(opname, "URL")) + opval = options->http; + else if (!stricmp(opname, "Uri")) + opval = options->uri; if (!opval && options->oplist) opval= GetListOption(g, opname, options->oplist); @@ -1252,7 +1276,7 @@ bool GetBooleanTableOption(PGLOBAL g, PTOS options, PCSZ opname, bool bdef) else if (!stricmp(opname, "Header")) opval= (options->header != 0); // Is Boolean for some table types else if (!stricmp(opname, "Zipped")) - opval = options->zipped; + opval= options->zipped; else if (options->oplist) if ((pv= GetListOption(g, opname, options->oplist))) opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0); @@ -1346,8 +1370,8 @@ PCSZ ha_connect::GetStringOption(PCSZ opname, PCSZ sdef) } else if (!stricmp(opname, "Query_String")) { // This escapes everything and returns a wrong query -// opval = thd_query_string(table->in_use)->str; - opval = (PCSZ)PlugSubAlloc(xp->g, NULL, +// opval= thd_query_string(table->in_use)->str; + opval= (PCSZ)PlugSubAlloc(xp->g, NULL, thd_query_string(table->in_use)->length + 1); strcpy((char*)opval, thd_query_string(table->in_use)->str); // sprintf((char*)opval, "%s", thd_query_string(table->in_use)->str); @@ -1368,7 +1392,7 @@ PCSZ ha_connect::GetStringOption(PCSZ opname, PCSZ sdef) || !stricmp(opname, "filename") || !stricmp(opname, "optname") || !stricmp(opname, "entry"))) - opval = GetRealString(opval); + opval= GetRealString(opval); if (!opval) { if (sdef && !strcmp(sdef, "*")) { @@ -1497,7 +1521,7 @@ PFOS ha_connect::GetFieldOptionStruct(Field *fdp) void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) { const char *cp; - char *chset, v = 0; + char *chset, v= 0; ha_field_option_struct *fop; Field* fp; Field* *fldp; @@ -1549,7 +1573,7 @@ void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf) pcf->Fieldfmt= NULL; } // endif fop - chset = (char *)fp->charset()->name; + chset= (char *)fp->charset()->name; switch (fp->type()) { case MYSQL_TYPE_BLOB: @@ -1817,7 +1841,7 @@ const char *ha_connect::GetTableName(void) { const char *path= tshp ? tshp->path.str : table_share->path.str; const char *name= strrchr(path, slash); - return name ? name+1 : path; + return name ? name + 1 : path; } // end of GetTableName char *ha_connect::GetPartName(void) @@ -2055,10 +2079,10 @@ bool ha_connect::CheckColumnList(PGLOBAL g) } catch (int n) { if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); - brc = true; + brc= true; } catch (const char *msg) { strcpy(g->Message, msg); - brc = true; + brc= true; } // end catch return brc; @@ -2185,9 +2209,9 @@ int ha_connect::MakeRecord(char *buf) rc= fp->store(p, strlen(p), charset, CHECK_FIELD_WARN); break; case TYPE_BIN: - p = value->GetCharValue(); - charset = &my_charset_bin; - rc = fp->store(p, strlen(p), charset, CHECK_FIELD_WARN); + p= value->GetCharValue(); + charset= &my_charset_bin; + rc= fp->store(p, strlen(p), charset, CHECK_FIELD_WARN); break; case TYPE_DOUBLE: rc= fp->store(value->GetFloatValue()); @@ -2436,7 +2460,7 @@ bool ha_connect::MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL vop, char q, kfp= &table->key_info[active_index]; old_map= dbug_tmp_use_all_columns(table, table->write_set); - for (i = 0; i <= 1; i++) { + for (i= 0; i <= 1; i++) { if (ranges[i] == NULL) continue; @@ -2547,7 +2571,7 @@ const char *ha_connect::GetValStr(OPVAL vop, bool neg) switch (vop) { case OP_EQ: - val= " = "; + val= "= "; break; case OP_NE: val= " <> "; @@ -2817,7 +2841,7 @@ PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond) /***********************************************************************/ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) { - AMT tty = filp->Type; + AMT tty= filp->Type; char *body= filp->Body; char *havg= filp->Having; unsigned int i; @@ -2834,7 +2858,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) if (cond->type() == COND::COND_ITEM) { char *pb0, *pb1, *pb2, *ph0= 0, *ph1= 0, *ph2= 0; - bool bb = false, bh = false; + bool bb= false, bh= false; Item_cond *cond_item= (Item_cond *)cond; if (x) @@ -2893,13 +2917,13 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) bb |= filp->Bd; bh |= filp->Hv; - filp->Bd = filp->Hv = false; + filp->Bd= filp->Hv= false; } else return NULL; if (bb) { strcpy(pb1, ")"); - filp->Bd = bb; + filp->Bd= bb; } else *pb0= 0; @@ -2907,13 +2931,13 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) if (bb && bh && vop == OP_OR) { // Cannot or'ed a where clause with a having clause bb= bh= 0; - *pb0 = 0; - *ph0 = 0; + *pb0= 0; + *ph0= 0; } else if (bh) { strcpy(ph1, ")"); filp->Hv= bh; } else - *ph0 = 0; + *ph0= 0; } // endif havg @@ -2926,7 +2950,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) Item_func *condf= (Item_func *)cond; Item* *args= condf->arguments(); - filp->Bd = filp->Hv = false; + filp->Bd= filp->Hv= false; if (trace(1)) htrc("Func type=%d argnum=%d\n", condf->functype(), @@ -2942,10 +2966,10 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) case Item_func::GT_FUNC: vop= OP_GT; break; case Item_func::LIKE_FUNC: vop= OP_LIKE; - neg = ((Item_func_opt_neg *)condf)->negated; + neg= ((Item_func_opt_neg *)condf)->negated; break; case Item_func::ISNOTNULL_FUNC: - neg = true; + neg= true; // fall through case Item_func::ISNULL_FUNC: vop= OP_NULL; break; case Item_func::IN_FUNC: vop= OP_IN; /* fall through */ @@ -3003,12 +3027,12 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) } else { bool h; - fnm = filp->Chk(pField->field->field_name, &h); + fnm= filp->Chk(pField->field->field_name, &h); if (h && i && !ishav) return NULL; // Having should be col VOP arg else - ishav = h; + ishav= h; } // endif's @@ -3059,7 +3083,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) if (!x) { const char *p; - char *s = (ishav) ? havg : body; + char *s= (ishav) ? havg : body; uint j, k, n; // Append the value to the filter @@ -3116,37 +3140,37 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) strcat(s, "'}"); break; default: - j = strlen(s); - s[j++] = '\''; - p = res->ptr(); - n = res->length(); + j= strlen(s); + s[j++]= '\''; + p= res->ptr(); + n= res->length(); - for (k = 0; k < n; k++) { + for (k= 0; k < n; k++) { if (p[k] == '\'') - s[j++] = '\''; + s[j++]= '\''; - s[j++] = p[k]; + s[j++]= p[k]; } // endfor k - s[j++] = '\''; - s[j] = 0; + s[j++]= '\''; + s[j]= 0; } // endswitch field type } else { - j = strlen(s); - s[j++] = '\''; - p = res->ptr(); - n = res->length(); + j= strlen(s); + s[j++]= '\''; + p= res->ptr(); + n= res->length(); - for (k = 0; k < n; k++) { + for (k= 0; k < n; k++) { if (p[k] == '\'') - s[j++] = '\''; + s[j++]= '\''; - s[j++] = p[k]; + s[j++]= p[k]; } // endfor k - s[j++] = '\''; - s[j] = 0; + s[j++]= '\''; + s[j]= 0; } // endif tty break; @@ -3170,7 +3194,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) } // endif's Type if (!x) { - char *s = (ishav) ? havg : body; + char *s= (ishav) ? havg : body; if (!i) strcat(s, GetValStr(vop, neg)); @@ -3184,11 +3208,11 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond) } // endfor i if (x) - filp->Op = vop; + filp->Op= vop; else if (ishav) - filp->Hv = true; + filp->Hv= true; else - filp->Bd = true; + filp->Bd= true; } else { if (trace(1)) @@ -3238,21 +3262,21 @@ const COND *ha_connect::cond_push(const COND *cond) PCFIL filp; int rc; - if ((filp = tdbp->GetCondFil()) && tdbp->GetCond() == cond && + if ((filp= tdbp->GetCondFil()) && tdbp->GetCond() == cond && filp->Idx == active_index && filp->Type == tty) goto fin; - filp = new(g) CONDFIL(active_index, tty); - rc = filp->Init(g, this); + filp= new(g) CONDFIL(active_index, tty); + rc= filp->Init(g, this); if (rc == RC_INFO) { - filp->Having = (char*)PlugSubAlloc(g, NULL, 256); - *filp->Having = 0; + filp->Having= (char*)PlugSubAlloc(g, NULL, 256); + *filp->Having= 0; } else if (rc == RC_FX) goto fin; - filp->Body = (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0); - *filp->Body = 0; + filp->Body= (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0); + *filp->Body= 0; if (CheckCond(g, filp, cond)) { if (filp->Having && strlen(filp->Having) > 255) @@ -3266,7 +3290,7 @@ const COND *ha_connect::cond_push(const COND *cond) if (!x) PlugSubAlloc(g, NULL, strlen(filp->Body) + 1); else - cond = NULL; // Does this work? + cond= NULL; // Does this work? tdbp->SetCondFil(filp); } else if (x && cond) @@ -3316,8 +3340,8 @@ ha_rows ha_connect::records() int ha_connect::check(THD* thd, HA_CHECK_OPT* check_opt) { - int rc = HA_ADMIN_OK; - PGLOBAL g = ((table && table->in_use) ? GetPlug(table->in_use, xp) : + int rc= HA_ADMIN_OK; + PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use, xp) : (xp) ? xp->g : NULL); DBUG_ENTER("ha_connect::check"); @@ -3327,32 +3351,32 @@ int ha_connect::check(THD* thd, HA_CHECK_OPT* check_opt) // Do not close the table if it was opened yet (possible?) if (IsOpened()) { if (IsPartitioned() && CheckColumnList(g)) // map can have been changed - rc = HA_ADMIN_CORRUPT; + rc= HA_ADMIN_CORRUPT; else if (tdbp->OpenDB(g)) // Rewind table - rc = HA_ADMIN_CORRUPT; + rc= HA_ADMIN_CORRUPT; } else if (xp->CheckQuery(valid_query_id)) { - tdbp = NULL; // Not valid anymore + tdbp= NULL; // Not valid anymore if (OpenTable(g, false)) - rc = HA_ADMIN_CORRUPT; + rc= HA_ADMIN_CORRUPT; } else // possible? DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR); if (rc == HA_ADMIN_OK) { - TABTYPE type = GetTypeID(GetStringOption("Type", "*")); + TABTYPE type= GetTypeID(GetStringOption("Type", "*")); if (IsFileType(type)) { if (check_opt->flags & T_MEDIUM) { // TO DO do { - if ((rc = CntReadNext(g, tdbp)) == RC_FX) + if ((rc= CntReadNext(g, tdbp)) == RC_FX) break; } while (rc != RC_EF); - rc = (rc == RC_EF) ? HA_ADMIN_OK : HA_ADMIN_CORRUPT; + rc= (rc == RC_EF) ? HA_ADMIN_OK : HA_ADMIN_CORRUPT; } else if (check_opt->flags & T_EXTEND) { // TO DO } // endif's flags @@ -3380,7 +3404,7 @@ bool ha_connect::get_error_message(int error, String* buf) DBUG_ENTER("ha_connect::get_error_message"); if (xp && xp->g) { - PGLOBAL g = xp->g; + PGLOBAL g= xp->g; if (trace(1)) htrc("GEM(%d): %s\n", error, g->Message); @@ -3489,32 +3513,32 @@ int ha_connect::optimize(THD* thd, HA_CHECK_OPT*) try { // Ignore error on the opt file dup->Check &= ~CHK_OPT; - tdbp = GetTDB(g); + tdbp= GetTDB(g); dup->Check |= CHK_OPT; if (tdbp && !tdbp->IsRemote()) { - bool dop = IsTypeIndexable(GetRealType(NULL)); - bool dox = (tdbp->GetDef()->Indexable() == 1); + bool dop= IsTypeIndexable(GetRealType(NULL)); + bool dox= (tdbp->GetDef()->Indexable() == 1); - if ((rc = ((PTDBASE)tdbp)->ResetTableOpt(g, dop, dox))) { + if ((rc= ((PTDBASE)tdbp)->ResetTableOpt(g, dop, dox))) { if (rc == RC_INFO) { push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); - rc = 0; + rc= 0; } else - rc = HA_ERR_CRASHED_ON_USAGE; // Table must be repaired + rc= HA_ERR_CRASHED_ON_USAGE; // Table must be repaired } // endif rc } else if (!tdbp) - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; } catch (int n) { if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; } catch (const char *msg) { strcpy(g->Message, msg); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; } // end catch if (rc) @@ -4214,7 +4238,7 @@ int ha_connect::rnd_pos(uchar *buf, uchar *pos) tdbp->SetFilter(NULL); rc= rnd_next(buf); } else { - PGLOBAL g = GetPlug((table) ? table->in_use : NULL, xp); + PGLOBAL g= GetPlug((table) ? table->in_use : NULL, xp); // strcpy(g->Message, "Not supported by this table type"); my_message(ER_ILLEGAL_HA, g->Message, MYF(0)); rc= HA_ERR_INTERNAL_ERROR; @@ -4298,12 +4322,12 @@ int ha_connect::info(uint flag) } else DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen - if (!(tdbp = GetTDB(g))) { + if (!(tdbp= GetTDB(g))) { my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } // endif tdbp - valid_info = false; + valid_info= false; } // endif tdbp if (!valid_info) { @@ -4446,6 +4470,7 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick) case TAB_XML: case TAB_INI: case TAB_VEC: + case TAB_REST: case TAB_JSON: if (options->filename && *options->filename) { if (!quick) { @@ -4582,13 +4607,13 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, // newmode= MODE_UPDATE; // To be checked // break; case SQLCOM_DELETE_MULTI: - *cras = true; + *cras= true; case SQLCOM_DELETE: case SQLCOM_TRUNCATE: newmode= MODE_DELETE; break; case SQLCOM_UPDATE_MULTI: - *cras = true; + *cras= true; case SQLCOM_UPDATE: newmode= MODE_UPDATE; break; @@ -4616,7 +4641,7 @@ MODE ha_connect::CheckMode(PGLOBAL g, THD *thd, break; // } // endif partitioned case SQLCOM_REPAIR: // TODO implement it - newmode = MODE_UPDATE; + newmode= MODE_UPDATE; break; default: htrc("Unsupported sql_command=%d\n", thd_sql_command(thd)); @@ -4731,15 +4756,15 @@ int ha_connect::start_stmt(THD *thd, thr_lock_type lock_type) if (CloseTable(g)) { // Make error a warning to avoid crash push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); - rc = 0; + rc= 0; } // endif Close - locked = 0; - xmod = MODE_ANY; // For info commands + locked= 0; + xmod= MODE_ANY; // For info commands DBUG_RETURN(rc); } // endif MODE_ANY - newmode = CheckMode(g, thd, newmode, &chk, &cras); + newmode= CheckMode(g, thd, newmode, &chk, &cras); if (newmode == MODE_ERROR) DBUG_RETURN(HA_ERR_INTERNAL_ERROR); @@ -4815,7 +4840,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) DBUG_RETURN(0); } else if (g->Xchk) { if (!tdbp) { - if (!(tdbp = GetTDB(g))) { + if (!(tdbp= GetTDB(g))) { // DBUG_RETURN(HA_ERR_INTERNAL_ERROR); causes assert error push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); DBUG_RETURN(0); @@ -4952,7 +4977,7 @@ int ha_connect::external_lock(THD *thd, int lock_type) int ha_connect::check_stmt(PGLOBAL g, MODE newmode, bool cras) { - int rc = 0; + int rc= 0; DBUG_ENTER("ha_connect::check_stmt"); // If this is the start of a new query, cleanup the previous one @@ -5039,7 +5064,7 @@ THR_LOCK_DATA **ha_connect::store_lock(THD *, { if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) lock.type=lock_type; - *to++ = &lock; + *to++= &lock; return to; } @@ -5316,7 +5341,7 @@ static bool add_field(String *sql, const char *field_name, int typ, int len, int dec, char *key, uint tm, const char *rem, char *dft, char *xtra, char *fmt, int flag, bool dbf, char v) { - char var = (len > 255) ? 'V' : v; + char var= (len > 255) ? 'V' : v; bool q, error= false; const char *type= PLGtoMYSQLtype(typ, dbf, var); @@ -5360,9 +5385,9 @@ static bool add_field(String *sql, const char *field_name, int typ, int len, error|= sql->append(" DEFAULT "); if (typ == TYPE_DATE) - q = (strspn(dft, "0123456789 -:/") == strlen(dft)); + q= (strspn(dft, "0123456789 -:/") == strlen(dft)); else - q = !IsTypeNum(typ); + q= !IsTypeNum(typ); if (q) { error|= sql->append("'"); @@ -5514,13 +5539,13 @@ static int connect_assisted_discovery(handlerton *, THD* thd, PCSZ fncn= "?"; PCSZ user, fn, db, host, pwd, sep, tbl, src; PCSZ col, ocl, rnk, pic, fcl, skc, zfn; - char *tab, *dsn, *shm, *dpath; + char *tab, *dsn, *shm, *dpath, *url; #if defined(__WIN__) PCSZ nsp= NULL, cls= NULL; #endif // __WIN__ //int hdr, mxe; - int port = 0, mxr = 0, rc = 0, mul = 0, lrecl = 0; -//PCSZ tabtyp = NULL; + int port= 0, mxr= 0, rc= 0, mul= 0, lrecl= 0; +//PCSZ tabtyp= NULL; #if defined(ODBC_SUPPORT) POPARM sop= NULL; PCSZ ucnc= NULL; @@ -5530,7 +5555,6 @@ static int connect_assisted_discovery(handlerton *, THD* thd, #if defined(JAVA_SUPPORT) PJPARM sjp= NULL; PCSZ driver= NULL; - char *url= NULL; #endif // JAVA_SUPPORT uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); bool bif, ok= false, dbf= false; @@ -5550,7 +5574,8 @@ static int connect_assisted_discovery(handlerton *, THD* thd, String sql(buf, sizeof(buf), system_charset_info); sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info); - user= host= pwd= tbl= src= col= ocl= pic= fcl= skc= rnk= zfn= dsn= NULL; + user = host = pwd = tbl = src = col = ocl = pic = fcl = skc = rnk = zfn = NULL; + dsn = url = NULL; // Get the useful create options ttp= GetTypeID(topt->type); @@ -5561,7 +5586,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, fncn= topt->catfunc; fnc= GetFuncID(fncn); sep= topt->separator; - mul = (int)topt->multiple; + mul= (int)topt->multiple; tbl= topt->tablist; col= topt->colist; @@ -5584,7 +5609,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, #endif // __WIN__ port= atoi(GetListOption(g, "port", topt->oplist, "0")); #if defined(ODBC_SUPPORT) -// tabtyp = GetListOption(g, "Tabtype", topt->oplist, NULL); +// tabtyp= GetListOption(g, "Tabtype", topt->oplist, NULL); mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0")); cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1")); qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1")); @@ -5599,7 +5624,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0")); #endif // PROMPT_OK #if defined(ZIP_SUPPORT) - zfn = GetListOption(g, "Zipfile", topt->oplist, NULL); + zfn= GetListOption(g, "Zipfile", topt->oplist, NULL); #endif // ZIP_SUPPORT } else { host= "localhost"; @@ -5612,14 +5637,24 @@ static int connect_assisted_discovery(handlerton *, THD* thd, try { // Check table type if (ttp == TAB_UNDEF) { - topt->type = (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS"; - ttp = GetTypeID(topt->type); + topt->type= (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS"; + ttp= GetTypeID(topt->type); sprintf(g->Message, "No table_type. Was set to %s", topt->type); push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message); } else if (ttp == TAB_NIY) { sprintf(g->Message, "Unsupported table type %s", topt->type); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; goto err; +#if defined(REST_SUPPORT) + } else if (topt->http) { + switch (ttp) { + case TAB_JSON: + case TAB_XML: + case TAB_CSV: + ttp = TAB_REST; + break; + } // endswitch type +#endif // REST_SUPPORT } // endif ttp if (!tab) { @@ -5629,39 +5664,39 @@ static int connect_assisted_discovery(handlerton *, THD* thd, if (!tbl) { strcpy(g->Message, "Missing table list"); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; goto err; } // endif tbl - tab = PlugDup(g, tbl); + tab= PlugDup(g, tbl); - if ((p = strchr(tab, ','))) - *p = 0; + if ((p= strchr(tab, ','))) + *p= 0; - if ((p = strchr(tab, '.'))) { - *p = 0; - db = tab; - tab = p + 1; + if ((p= strchr(tab, '.'))) { + *p= 0; + db= tab; + tab= p + 1; } // endif p } else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL))) - tab = (char*)table_s->table_name.str; // Default value + tab= (char*)table_s->table_name.str; // Default value } // endif tab switch (ttp) { #if defined(ODBC_SUPPORT) case TAB_ODBC: - dsn = strz(g, create_info->connect_string); + dsn= strz(g, create_info->connect_string); if (fnc & (FNC_DSN | FNC_DRIVER)) { - ok = true; + ok= true; #if defined(PROMPT_OK) } else if (!stricmp(thd->main_security_ctx.host, "localhost") && cop == 1) { - if ((dsn = ODBCCheckConnection(g, dsn, cop)) != NULL) { + if ((dsn= ODBCCheckConnection(g, dsn, cop)) != NULL) { thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn)); - ok = true; + ok= true; } // endif dsn #endif // PROMPT_OK @@ -5669,13 +5704,13 @@ static int connect_assisted_discovery(handlerton *, THD* thd, sprintf(g->Message, "Missing %s connection string", topt->type); } else { // Store ODBC additional parameters - sop = (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM)); - sop->User = (char*)user; - sop->Pwd = (char*)pwd; - sop->Cto = cto; - sop->Qto = qto; - sop->UseCnc = cnc; - ok = true; + sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM)); + sop->User= (char*)user; + sop->Pwd= (char*)pwd; + sop->Cto= cto; + sop->Qto= qto; + sop->UseCnc= cnc; + ok= true; } // endif's supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER); @@ -5684,31 +5719,31 @@ static int connect_assisted_discovery(handlerton *, THD* thd, #if defined(JAVA_SUPPORT) case TAB_JDBC: if (fnc & FNC_DRIVER) { - ok = true; - } else if (!(url = strz(g, create_info->connect_string))) { + ok= true; + } else if (!(url= strz(g, create_info->connect_string))) { strcpy(g->Message, "Missing URL"); } else { // Store JDBC additional parameters int rc; - PJDBCDEF jdef = new(g) JDBCDEF(); + PJDBCDEF jdef= new(g) JDBCDEF(); jdef->SetName(create_info->alias); - sjp = (PJPARM)PlugSubAlloc(g, NULL, sizeof(JDBCPARM)); - sjp->Driver = driver; - // sjp->Properties = prop; - sjp->Fsize = 0; - sjp->Scrollable = false; + sjp= (PJPARM)PlugSubAlloc(g, NULL, sizeof(JDBCPARM)); + sjp->Driver= driver; + // sjp->Properties= prop; + sjp->Fsize= 0; + sjp->Scrollable= false; - if ((rc = jdef->ParseURL(g, url, false)) == RC_OK) { - sjp->Url = url; - sjp->User = (char*)user; - sjp->Pwd = (char*)pwd; - ok = true; + if ((rc= jdef->ParseURL(g, url, false)) == RC_OK) { + sjp->Url= url; + sjp->User= (char*)user; + sjp->Pwd= (char*)pwd; + ok= true; } else if (rc == RC_NF) { if (jdef->GetTabname()) - tab = (char*)jdef->GetTabname(); + tab= (char*)jdef->GetTabname(); - ok = jdef->SetParms(sjp); + ok= jdef->SetParms(sjp); } // endif rc } // endif's @@ -5717,7 +5752,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, break; #endif // JAVA_SUPPORT case TAB_DBF: - dbf = true; + dbf= true; // fall through case TAB_CSV: if (!fn && fnc != FNC_NO) @@ -5725,55 +5760,55 @@ static int connect_assisted_discovery(handlerton *, THD* thd, else if (sep && strlen(sep) > 1) sprintf(g->Message, "Invalid separator %s", sep); else - ok = true; + ok= true; break; case TAB_MYSQL: - ok = true; + ok= true; if (create_info->connect_string.str && create_info->connect_string.length) { - PMYDEF mydef = new(g) MYSQLDEF(); + PMYDEF mydef= new(g) MYSQLDEF(); - dsn = strz(g, create_info->connect_string); + dsn= strz(g, create_info->connect_string); mydef->SetName(create_info->alias); if (!mydef->ParseURL(g, dsn, false)) { if (mydef->GetHostname()) - host = mydef->GetHostname(); + host= mydef->GetHostname(); if (mydef->GetUsername()) - user = mydef->GetUsername(); + user= mydef->GetUsername(); if (mydef->GetPassword()) - pwd = mydef->GetPassword(); + pwd= mydef->GetPassword(); if (mydef->GetTabschema()) - db = mydef->GetTabschema(); + db= mydef->GetTabschema(); if (mydef->GetTabname()) - tab = (char*)mydef->GetTabname(); + tab= (char*)mydef->GetTabname(); if (mydef->GetPortnumber()) - port = mydef->GetPortnumber(); + port= mydef->GetPortnumber(); } else - ok = false; + ok= false; } else if (!user) - user = "root"; + user= "root"; if (ok && CheckSelf(g, table_s, host, db, tab, src, port)) - ok = false; + ok= false; break; #if defined(__WIN__) case TAB_WMI: - ok = true; + ok= true; break; #endif // __WIN__ case TAB_PIVOT: - supfnc = FNC_NO; + supfnc= FNC_NO; case TAB_PRX: case TAB_TBL: case TAB_XCL: @@ -5782,12 +5817,12 @@ static int connect_assisted_discovery(handlerton *, THD* thd, (!db || !stricmp(db, table_s->db.str))) sprintf(g->Message, "A %s table cannot refer to itself", topt->type); else - ok = true; + ok= true; break; case TAB_OEM: if (topt->module && topt->subtype) - ok = true; + ok= true; else strcpy(g->Message, "Missing OEM module or subtype"); @@ -5796,24 +5831,33 @@ static int connect_assisted_discovery(handlerton *, THD* thd, case TAB_XML: #endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT case TAB_JSON: - dsn = strz(g, create_info->connect_string); + dsn= strz(g, create_info->connect_string); if (!fn && !zfn && !mul && !dsn) sprintf(g->Message, "Missing %s file name", topt->type); else - ok = true; + ok= true; break; #if defined(JAVA_SUPPORT) case TAB_MONGO: if (!topt->tabname) - topt->tabname = tab; + topt->tabname= tab; - ok = true; + ok= true; break; #endif // JAVA_SUPPORT +#if defined(REST_SUPPORT) + case TAB_REST: + if (!topt->http) + sprintf(g->Message, "Missing %s HTTP address", topt->type); + else + ok = true; + + break; +#endif // REST_SUPPORT case TAB_VIR: - ok = true; + ok= true; break; default: sprintf(g->Message, "Cannot get column info for table type %s", topt->type); @@ -5824,12 +5868,12 @@ static int connect_assisted_discovery(handlerton *, THD* thd, if (ok && !(supfnc & fnc)) { sprintf(g->Message, "Unsupported catalog function %s for table type %s", fncn, topt->type); - ok = false; + ok= false; } // endif supfnc if (src && fnc != FNC_NO) { strcpy(g->Message, "Cannot make catalog table from srcdef"); - ok = false; + ok= false; } // endif src if (ok) { @@ -5837,23 +5881,23 @@ static int connect_assisted_discovery(handlerton *, THD* thd, char *dft, *xtra, *key, *fmt; int i, len, prec, dec, typ, flg; - if (!(dpath = SetPath(g, table_s->db.str))) { - rc = HA_ERR_INTERNAL_ERROR; + if (!(dpath= SetPath(g, table_s->db.str))) { + rc= HA_ERR_INTERNAL_ERROR; goto err; } // endif dpath if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC && ttp != TAB_JDBC) { - qrp = SrcColumns(g, host, db, user, pwd, src, port); + qrp= SrcColumns(g, host, db, user, pwd, src, port); if (qrp && ttp == TAB_OCCUR) if (OcrSrcCols(g, qrp, col, ocl, rnk)) { - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; goto err; } // endif OcrSrcCols } else switch (ttp) { case TAB_DBF: - qrp = DBFColumns(g, dpath, fn, fnc == FNC_COL); + qrp= DBFColumns(g, dpath, fn, fnc == FNC_COL); break; #if defined(ODBC_SUPPORT) case TAB_ODBC: @@ -5861,21 +5905,21 @@ static int connect_assisted_discovery(handlerton *, THD* thd, case FNC_NO: case FNC_COL: if (src) { - qrp = ODBCSrcCols(g, dsn, (char*)src, sop); - src = NULL; // for next tests + qrp= ODBCSrcCols(g, dsn, (char*)src, sop); + src= NULL; // for next tests } else - qrp = ODBCColumns(g, dsn, shm, tab, NULL, + qrp= ODBCColumns(g, dsn, shm, tab, NULL, mxr, fnc == FNC_COL, sop); break; case FNC_TABLE: - qrp = ODBCTables(g, dsn, shm, tab, NULL, mxr, true, sop); + qrp= ODBCTables(g, dsn, shm, tab, NULL, mxr, true, sop); break; case FNC_DSN: - qrp = ODBCDataSources(g, mxr, true); + qrp= ODBCDataSources(g, mxr, true); break; case FNC_DRIVER: - qrp = ODBCDrivers(g, mxr, true); + qrp= ODBCDrivers(g, mxr, true); break; default: sprintf(g->Message, "invalid catfunc %s", fncn); @@ -5890,23 +5934,23 @@ static int connect_assisted_discovery(handlerton *, THD* thd, case FNC_NO: case FNC_COL: if (src) { - qrp = JDBCSrcCols(g, (char*)src, sjp); - src = NULL; // for next tests + qrp= JDBCSrcCols(g, (char*)src, sjp); + src= NULL; // for next tests } else - qrp = JDBCColumns(g, shm, tab, NULL, mxr, fnc == FNC_COL, sjp); + qrp= JDBCColumns(g, shm, tab, NULL, mxr, fnc == FNC_COL, sjp); break; case FNC_TABLE: -// qrp = JDBCTables(g, shm, tab, tabtyp, mxr, true, sjp); - qrp = JDBCTables(g, shm, tab, NULL, mxr, true, sjp); +// qrp= JDBCTables(g, shm, tab, tabtyp, mxr, true, sjp); + qrp= JDBCTables(g, shm, tab, NULL, mxr, true, sjp); break; #if 0 case FNC_DSN: - qrp = JDBCDataSources(g, mxr, true); + qrp= JDBCDataSources(g, mxr, true); break; #endif // 0 case FNC_DRIVER: - qrp = JDBCDrivers(g, mxr, true); + qrp= JDBCDrivers(g, mxr, true); break; default: sprintf(g->Message, "invalid catfunc %s", fncn); @@ -5916,56 +5960,61 @@ static int connect_assisted_discovery(handlerton *, THD* thd, break; #endif // JAVA_SUPPORT case TAB_MYSQL: - qrp = MyColumns(g, thd, host, db, user, pwd, tab, + qrp= MyColumns(g, thd, host, db, user, pwd, tab, NULL, port, fnc == FNC_COL); break; case TAB_CSV: - qrp = CSVColumns(g, dpath, topt, fnc == FNC_COL); + qrp= CSVColumns(g, dpath, topt, fnc == FNC_COL); break; #if defined(__WIN__) case TAB_WMI: - qrp = WMIColumns(g, nsp, cls, fnc == FNC_COL); + qrp= WMIColumns(g, nsp, cls, fnc == FNC_COL); break; #endif // __WIN__ case TAB_PRX: case TAB_TBL: case TAB_XCL: case TAB_OCCUR: - bif = fnc == FNC_COL; - qrp = TabColumns(g, thd, db, tab, bif); + bif= fnc == FNC_COL; + qrp= TabColumns(g, thd, db, tab, bif); if (!qrp && bif && fnc != FNC_COL) // tab is a view - qrp = MyColumns(g, thd, host, db, user, pwd, tab, NULL, port, false); + qrp= MyColumns(g, thd, host, db, user, pwd, tab, NULL, port, false); if (qrp && ttp == TAB_OCCUR && fnc != FNC_COL) if (OcrColumns(g, qrp, col, ocl, rnk)) { - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; goto err; } // endif OcrColumns break; case TAB_PIVOT: - qrp = PivotColumns(g, tab, src, pic, fcl, skc, host, db, user, pwd, port); + qrp= PivotColumns(g, tab, src, pic, fcl, skc, host, db, user, pwd, port); break; case TAB_VIR: - qrp = VirColumns(g, fnc == FNC_COL); + qrp= VirColumns(g, fnc == FNC_COL); break; case TAB_JSON: - qrp = JSONColumns(g, db, dsn, topt, fnc == FNC_COL); + qrp= JSONColumns(g, db, dsn, topt, fnc == FNC_COL); break; #if defined(JAVA_SUPPORT) case TAB_MONGO: - url = strz(g, create_info->connect_string); - qrp = MGOColumns(g, db, url, topt, fnc == FNC_COL); + url= strz(g, create_info->connect_string); + qrp= MGOColumns(g, db, url, topt, fnc == FNC_COL); break; #endif // JAVA_SUPPORT #if defined(LIBXML2_SUPPORT) || defined(DOMDOC_SUPPORT) case TAB_XML: - qrp = XMLColumns(g, (char*)db, tab, topt, fnc == FNC_COL); + qrp= XMLColumns(g, (char*)db, tab, topt, fnc == FNC_COL); break; #endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT +#if defined(REST_SUPPORT) + case TAB_REST: + qrp = RESTColumns(g, topt, tab, (char *)db, fnc == FNC_COL); + break; +#endif // REST_SUPPORT case TAB_OEM: - qrp = OEMColumns(g, topt, tab, (char*)db, fnc == FNC_COL); + qrp= OEMColumns(g, topt, tab, (char*)db, fnc == FNC_COL); break; default: strcpy(g->Message, "System error during assisted discovery"); @@ -5973,33 +6022,33 @@ static int connect_assisted_discovery(handlerton *, THD* thd, } // endswitch ttp if (!qrp) { - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; goto err; } // endif !qrp if (fnc != FNC_NO || src || ttp == TAB_PIVOT) { // Catalog like table - for (crp = qrp->Colresp; !rc && crp; crp = crp->Next) { - cnm = (ttp == TAB_PIVOT) ? crp->Name : encode(g, crp->Name); - typ = crp->Type; - len = crp->Length; - dec = crp->Prec; - flg = crp->Flag; - v = (crp->Kdata->IsUnsigned()) ? 'U' : crp->Var; - tm = (crp->Kdata->IsNullable()) ? 0 : NOT_NULL_FLAG; + for (crp= qrp->Colresp; !rc && crp; crp= crp->Next) { + cnm= (ttp == TAB_PIVOT) ? crp->Name : encode(g, crp->Name); + typ= crp->Type; + len= crp->Length; + dec= crp->Prec; + flg= crp->Flag; + v= (crp->Kdata->IsUnsigned()) ? 'U' : crp->Var; + tm= (crp->Kdata->IsNullable()) ? 0 : NOT_NULL_FLAG; if (!len && typ == TYPE_STRING) - len = 256; // STRBLK's have 0 length + len= 256; // STRBLK's have 0 length // Now add the field if (add_field(&sql, cnm, typ, len, dec, NULL, tm, NULL, NULL, NULL, NULL, flg, dbf, v)) - rc = HA_ERR_OUT_OF_MEM; + rc= HA_ERR_OUT_OF_MEM; } // endfor crp } else { - char *schem = NULL; - char *tn = NULL; + char *schem= NULL; + char *tn= NULL; // Not a catalog table if (!qrp->Nblin) { @@ -6008,57 +6057,57 @@ static int connect_assisted_discovery(handlerton *, THD* thd, else strcpy(g->Message, "Fail to retrieve columns"); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; goto err; } // endif !nblin - for (i = 0; !rc && i < qrp->Nblin; i++) { - typ = len = prec = dec = 0; - tm = NOT_NULL_FLAG; - cnm = (char*)"noname"; - dft = xtra = key = fmt = tn = NULL; - v = ' '; - rem = NULL; + for (i= 0; !rc && i < qrp->Nblin; i++) { + typ= len= prec= dec= 0; + tm= NOT_NULL_FLAG; + cnm= (char*)"noname"; + dft= xtra= key= fmt= tn= NULL; + v= ' '; + rem= NULL; - for (crp = qrp->Colresp; crp; crp = crp->Next) + for (crp= qrp->Colresp; crp; crp= crp->Next) switch (crp->Fld) { case FLD_NAME: if (ttp == TAB_PRX || (ttp == TAB_CSV && topt->data_charset && (!stricmp(topt->data_charset, "UTF8") || !stricmp(topt->data_charset, "UTF-8")))) - cnm = crp->Kdata->GetCharValue(i); + cnm= crp->Kdata->GetCharValue(i); else - cnm = encode(g, crp->Kdata->GetCharValue(i)); + cnm= encode(g, crp->Kdata->GetCharValue(i)); break; case FLD_TYPE: - typ = crp->Kdata->GetIntValue(i); - v = (crp->Nulls) ? crp->Nulls[i] : 0; + typ= crp->Kdata->GetIntValue(i); + v= (crp->Nulls) ? crp->Nulls[i] : 0; break; case FLD_TYPENAME: - tn = crp->Kdata->GetCharValue(i); + tn= crp->Kdata->GetCharValue(i); break; case FLD_PREC: // PREC must be always before LENGTH - len = prec = crp->Kdata->GetIntValue(i); + len= prec= crp->Kdata->GetIntValue(i); break; case FLD_LENGTH: - len = crp->Kdata->GetIntValue(i); + len= crp->Kdata->GetIntValue(i); break; case FLD_SCALE: - dec = (!crp->Kdata->IsNull(i)) ? crp->Kdata->GetIntValue(i) : -1; + dec= (!crp->Kdata->IsNull(i)) ? crp->Kdata->GetIntValue(i) : -1; break; case FLD_NULL: if (crp->Kdata->GetIntValue(i)) - tm = 0; // Nullable + tm= 0; // Nullable break; case FLD_FORMAT: - fmt = (crp->Kdata) ? crp->Kdata->GetCharValue(i) : NULL; + fmt= (crp->Kdata) ? crp->Kdata->GetCharValue(i) : NULL; break; case FLD_REM: - rem = crp->Kdata->GetCharValue(i); + rem= crp->Kdata->GetCharValue(i); break; // case FLD_CHARSET: // No good because remote table is already translated @@ -6067,19 +6116,19 @@ static int connect_assisted_discovery(handlerton *, THD* thd, // break; case FLD_DEFAULT: - dft = crp->Kdata->GetCharValue(i); + dft= crp->Kdata->GetCharValue(i); break; case FLD_EXTRA: - xtra = crp->Kdata->GetCharValue(i); + xtra= crp->Kdata->GetCharValue(i); // Auto_increment is not supported yet if (!stricmp(xtra, "AUTO_INCREMENT")) - xtra = NULL; + xtra= NULL; break; case FLD_KEY: if (ttp == TAB_VIR) - key = crp->Kdata->GetCharValue(i); + key= crp->Kdata->GetCharValue(i); break; case FLD_SCHEM: @@ -6088,10 +6137,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd, if (schem && stricmp(schem, crp->Kdata->GetCharValue(i))) { sprintf(g->Message, "Several %s tables found, specify DBNAME", tab); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; goto err; } else if (!schem) - schem = crp->Kdata->GetCharValue(i); + schem= crp->Kdata->GetCharValue(i); } // endif ttp #endif // ODBC_SUPPORT || JAVA_SUPPORT @@ -6102,10 +6151,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd, #if defined(ODBC_SUPPORT) if (ttp == TAB_ODBC) { int plgtyp; - bool w = false; // Wide character type + bool w= false; // Wide character type // typ must be PLG type, not SQL type - if (!(plgtyp = TranslateSQLType(typ, dec, prec, v, w))) { + if (!(plgtyp= TranslateSQLType(typ, dec, prec, v, w))) { if (GetTypeConv() == TPC_SKIP) { // Skip this column sprintf(g->Message, "Column %s skipped (unsupported type %d)", @@ -6114,12 +6163,12 @@ static int connect_assisted_discovery(handlerton *, THD* thd, continue; } else { sprintf(g->Message, "Unsupported SQL type %d", typ); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; goto err; } // endif type_conv } else - typ = plgtyp; + typ= plgtyp; switch (typ) { case TYPE_STRING: @@ -6134,10 +6183,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd, prec += (dec + 2); // To be safe break; case TYPE_DECIM: - prec = len; + prec= len; break; default: - dec = 0; + dec= 0; } // endswitch typ } else @@ -6147,7 +6196,7 @@ static int connect_assisted_discovery(handlerton *, THD* thd, int plgtyp; // typ must be PLG type, not SQL type - if (!(plgtyp = TranslateJDBCType(typ, tn, dec, prec, v))) { + if (!(plgtyp= TranslateJDBCType(typ, tn, dec, prec, v))) { if (GetTypeConv() == TPC_SKIP) { // Skip this column sprintf(g->Message, "Column %s skipped (unsupported type %d)", @@ -6156,12 +6205,12 @@ static int connect_assisted_discovery(handlerton *, THD* thd, continue; } else { sprintf(g->Message, "Unsupported SQL type %d", typ); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; goto err; } // endif type_conv } else - typ = plgtyp; + typ= plgtyp; switch (typ) { case TYPE_DOUBLE: @@ -6170,43 +6219,43 @@ static int connect_assisted_discovery(handlerton *, THD* thd, prec += (dec + 2); // To be safe break; default: - dec = 0; + dec= 0; } // endswitch typ } else #endif // ODBC_SUPPORT // Make the arguments as required by add_fields if (typ == TYPE_DOUBLE) - prec = len; + prec= len; if (typ == TYPE_DATE) - prec = 0; + prec= 0; // Now add the field if (add_field(&sql, cnm, typ, prec, dec, key, tm, rem, dft, xtra, fmt, 0, dbf, v)) - rc = HA_ERR_OUT_OF_MEM; + rc= HA_ERR_OUT_OF_MEM; } // endfor i } // endif fnc if (!rc) - rc = init_table_share(thd, table_s, create_info, &sql); + rc= init_table_share(thd, table_s, create_info, &sql); //g->jump_level--; //PopUser(xp); //return rc; } else { - rc = HA_ERR_UNSUPPORTED; + rc= HA_ERR_UNSUPPORTED; } // endif ok } catch (int n) { if (trace(1)) htrc("Exception %d: %s\n", n, g->Message); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; } catch (const char *msg) { strcpy(g->Message, msg); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; } // end catch err: @@ -6274,9 +6323,9 @@ int ha_connect::create(const char *name, TABLE *table_arg, TABTYPE type; TABLE *st= table; // Probably unuseful THD *thd= ha_thd(); - LEX_STRING cnc = table_arg->s->connect_string; -#ifdef WITH_PARTITION_STORAGE_ENGINE - partition_info *part_info= table_arg->part_info; + LEX_STRING cnc= table_arg->s->connect_string; +#if defined(WITH_PARTITION_STORAGE_ENGINE) + partition_info *part_info= table_arg->part_info; #else // !WITH_PARTITION_STORAGE_ENGINE #define part_info 0 #endif // !WITH_PARTITION_STORAGE_ENGINE @@ -6401,7 +6450,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, host= mydef->GetHostname(); if (mydef->GetTabschema()) - db = mydef->GetTabschema(); + db= mydef->GetTabschema(); if (mydef->GetTabname()) tab= mydef->GetTabname(); @@ -6484,7 +6533,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, } // endif type JSON if (type == TAB_CSV) { - const char *sep = options->separator; + const char *sep= options->separator; if (sep && strlen(sep) > 1) { sprintf(g->Message, "Invalid separator %s", sep); @@ -6683,17 +6732,18 @@ int ha_connect::create(const char *name, TABLE *table_arg, if (trace(1)) htrc("xchk=%p createas=%d\n", g->Xchk, g->Createas); +#if defined(ZIP_SUPPORT) if (options->zipped) { // Check whether the zip entry must be made from a file - PCSZ fn = GetListOption(g, "Load", options->oplist, NULL); + PCSZ fn= GetListOption(g, "Load", options->oplist, NULL); if (fn) { char zbuf[_MAX_PATH], buf[_MAX_PATH], dbpath[_MAX_PATH]; - PCSZ entry = GetListOption(g, "Entry", options->oplist, NULL); - PCSZ a = GetListOption(g, "Append", options->oplist, "NO"); - bool append = *a == '1' || *a == 'Y' || *a == 'y' || !stricmp(a, "ON"); - PCSZ m = GetListOption(g, "Mulentries", options->oplist, "NO"); - bool mul = *m == '1' || *m == 'Y' || *m == 'y' || !stricmp(m, "ON"); + PCSZ entry= GetListOption(g, "Entry", options->oplist, NULL); + PCSZ a= GetListOption(g, "Append", options->oplist, "NO"); + bool append= *a == '1' || *a == 'Y' || *a == 'y' || !stricmp(a, "ON"); + PCSZ m= GetListOption(g, "Mulentries", options->oplist, "NO"); + bool mul= *m == '1' || *m == 'Y' || *m == 'y' || !stricmp(m, "ON"); if (!entry && !mul) { my_message(ER_UNKNOWN_ERROR, "Missing entry name", MYF(0)); @@ -6712,6 +6762,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, } // endif fn } // endif zipped +#endif // ZIP_SUPPORT // To check whether indexes have to be made or remade if (!g->Xchk) { @@ -6761,7 +6812,7 @@ int ha_connect::create(const char *name, TABLE *table_arg, if (SetDataPath(g, table_arg->s->db.str)) { my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); - rc = HA_ERR_INTERNAL_ERROR; + rc= HA_ERR_INTERNAL_ERROR; } else if (cat) { if (part_info) strncpy(partname, @@ -7103,7 +7154,7 @@ ha_connect::check_if_supported_inplace_alter(TABLE *altered_table, /* ALTER TABLE tbl_name CONVERT TO CHARACTER SET .. and - ALTER TABLE table_name DEFAULT CHARSET = .. most likely + ALTER TABLE table_name DEFAULT CHARSET= .. most likely change column charsets and so not supported in-place through old API. @@ -7335,7 +7386,7 @@ maria_declare_plugin(connect) 0x0106, /* version number (1.06) */ NULL, /* status variables */ connect_system_variables, /* system variables */ - "1.06.0009", /* string version */ + "1.06.0010", /* string version */ MariaDB_PLUGIN_MATURITY_STABLE /* maturity */ } maria_declare_plugin_end; diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h index ea495557fcf..9a12ef94431 100644 --- a/storage/connect/ha_connect.h +++ b/storage/connect/ha_connect.h @@ -11,7 +11,7 @@ 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file ha_connect.h Author Olivier Bertrand @@ -32,6 +32,10 @@ /****************************************************************************/ #include "mycat.h" +#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) +bool MongoEnabled(void); +#endif // JAVA_SUPPORT || CMGO_SUPPORT + /****************************************************************************/ /* Structures used to pass info between CONNECT and ha_connect. */ /****************************************************************************/ diff --git a/storage/connect/inihandl.cpp b/storage/connect/inihandl.cpp index 8a911cb05c0..8e79aeac7ef 100644 --- a/storage/connect/inihandl.cpp +++ b/storage/connect/inihandl.cpp @@ -16,7 +16,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_global.h" @@ -194,7 +194,7 @@ static void PROFILE_Save( FILE *file, PROFILESECTION *section ) } for (key = section->key; key; key = key->next) - if (key->name[0]) { + if (key->name && key->name[0]) { fprintf(file, "%s", SVP(key->name)); if (key->value) diff --git a/storage/connect/jmgoconn.cpp b/storage/connect/jmgoconn.cpp index bd1ddadd80d..c80800bd897 100644 --- a/storage/connect/jmgoconn.cpp +++ b/storage/connect/jmgoconn.cpp @@ -272,7 +272,7 @@ bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, if (MakeSelector(g, filp, s)) { strcpy(g->Message, "Failed making selector"); - return NULL; + return true; } else s->Append('}'); @@ -340,7 +340,7 @@ bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, if (MakeSelector(g, filp, s)) { strcpy(g->Message, "Failed making selector"); - return NULL; + return true; } // endif Selector tdbp->SetFilter(NULL); // Not needed anymore @@ -813,4 +813,3 @@ PSZ JMgoConn::GetColumnValue(PSZ path) return fld; } // end of GetColumnValue - diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp index df9c7200416..dad86d51040 100644 --- a/storage/connect/jsonudf.cpp +++ b/storage/connect/jsonudf.cpp @@ -1,6 +1,6 @@ /****************** jsonudf C++ Program Source Code File (.CPP) ******************/ -/* PROGRAM NAME: jsonudf Version 1.7 */ -/* (C) Copyright to the author Olivier BERTRAND 2015-2018 */ +/* PROGRAM NAME: jsonudf Version 1.8 */ +/* (C) Copyright to the author Olivier BERTRAND 2015-2019 */ /* This program are the JSON User Defined Functions . */ /*********************************************************************************/ @@ -1686,7 +1686,7 @@ static PCSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i) } // endif *s if (n < 1) - return "Key"; + return (PCSZ) "Key"; if (!b) { if ((p = (PSZ)PlgDBSubAlloc(g, NULL, n + 1))) { @@ -1703,7 +1703,7 @@ static PCSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i) return s; } // endif count - return "Key"; + return (PCSZ) "Key"; } // end of MakeKey /*********************************************************************************/ diff --git a/storage/connect/libdoc.cpp b/storage/connect/libdoc.cpp index 9b30b315441..58b0267bd6d 100644 --- a/storage/connect/libdoc.cpp +++ b/storage/connect/libdoc.cpp @@ -1035,7 +1035,7 @@ PXNODE XML2NODE::AddChildNode(PGLOBAL g, PCSZ name, PXNODE np) // If name has the format m[n] only m is taken as node name if ((p = strchr(pn, '['))) - p = BufAlloc(g, pn, p - pn); + p = BufAlloc(g, pn, int(p - pn)); else p = pn; diff --git a/storage/connect/mini-global.h b/storage/connect/mini-global.h new file mode 100644 index 00000000000..f712795827c --- /dev/null +++ b/storage/connect/mini-global.h @@ -0,0 +1,33 @@ +/***********************************************************************/ +/* Definitions needed by the included files. */ +/***********************************************************************/ +#if !defined(MY_GLOBAL_H) +#define MY_GLOBAL_H +typedef unsigned int uint; +typedef unsigned int uint32; +typedef unsigned short ushort; +typedef unsigned long ulong; +typedef unsigned long DWORD; +typedef char *LPSTR; +typedef const char *LPCSTR; +typedef int BOOL; +#if defined(_WINDOWS) +typedef void *HANDLE; +#else +typedef int HANDLE; +#endif +typedef char *PSZ; +typedef const char *PCSZ; +typedef unsigned char BYTE; +typedef unsigned char uchar; +typedef long long longlong; +typedef unsigned long long ulonglong; +typedef char my_bool; +struct charset_info_st {}; +typedef const charset_info_st CHARSET_INFO; +#define FALSE 0 +#define TRUE 1 +#define Item char +#define MY_MAX(a,b) ((a>b)?(a):(b)) +#define MY_MIN(a,b) ((aGetName(), SVP(type)); +{ + PRELDEF tdp= NULL; - // If not specified get the type of this table - if (!type) - type= Hc->GetStringOption("Type","*"); + if (trace(1)) + htrc("GetTableDesc: name=%s am=%s\n", tablep->GetName(), SVP(type)); - return MakeTableDesc(g, tablep, type); - } // end of GetTableDesc + // If not specified get the type of this table + //if (!type) + // type= Hc->GetStringOption("Type","*"); + + tdp= MakeTableDesc(g, tablep, type); + + if (trace(1)) + htrc("GetTableDesc: tdp=%p\n", tdp); + + return tdp; +} // end of GetTableDesc /***********************************************************************/ /* MakeTableDesc: make a table/view description. */ @@ -501,18 +510,22 @@ PRELDEF MYCAT::GetTableDesc(PGLOBAL g, PTABLE tablep, PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) { TABTYPE tc; - LPCSTR name = (PSZ)PlugDup(g, tablep->GetName()); - LPCSTR schema = (PSZ)PlugDup(g, tablep->GetSchema()); + LPCSTR name= (PSZ)PlugDup(g, tablep->GetName()); + LPCSTR schema= (PSZ)PlugDup(g, tablep->GetSchema()); PRELDEF tdp= NULL; - if (trace(1)) - printf("MakeTableDesc: name=%s schema=%s am=%s\n", - name, SVP(schema), SVP(am)); + if (trace(1)) + htrc("MakeTableDesc: name=%s schema=%s am=%s\n", + name, SVP(schema), SVP(am)); /*********************************************************************/ /* Get a unique enum identifier for types. */ /*********************************************************************/ - tc= GetTypeID(am); + if (!am) { + tc= Hc->GetRealType(); + am= Hc->GetStringOption("Type","*"); + } else + tc= GetTypeID(am); switch (tc) { case TAB_FIX: @@ -527,46 +540,52 @@ PRELDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am) case TAB_XML: tdp= new(g) XMLDEF; break; #endif // XML_SUPPORT #if defined(VCT_SUPPORT) - case TAB_VEC: tdp = new(g) VCTDEF; break; + case TAB_VEC: tdp = new(g) VCTDEF; break; #endif // VCT_SUPPORT #if defined(ODBC_SUPPORT) case TAB_ODBC: tdp= new(g) ODBCDEF; break; #endif // ODBC_SUPPORT #if defined(JAVA_SUPPORT) - case TAB_JDBC: tdp= new(g) JDBCDEF; break; + case TAB_JDBC: tdp= new(g) JDBCDEF; break; #endif // JAVA_SUPPORT #if defined(__WIN__) case TAB_MAC: tdp= new(g) MACDEF; break; case TAB_WMI: tdp= new(g) WMIDEF; break; #endif // __WIN__ case TAB_OEM: tdp= new(g) OEMDEF; break; - case TAB_TBL: tdp= new(g) TBLDEF; break; - case TAB_XCL: tdp= new(g) XCLDEF; break; - case TAB_PRX: tdp= new(g) PRXDEF; break; - case TAB_OCCUR: tdp= new(g) OCCURDEF; break; - case TAB_MYSQL: tdp= new(g) MYSQLDEF; break; + case TAB_TBL: tdp= new(g) TBLDEF; break; + case TAB_XCL: tdp= new(g) XCLDEF; break; + case TAB_PRX: tdp= new(g) PRXDEF; break; + case TAB_OCCUR: tdp= new(g) OCCURDEF; break; + case TAB_MYSQL: tdp= new(g) MYSQLDEF; break; case TAB_PIVOT: tdp= new(g) PIVOTDEF; break; case TAB_VIR: tdp= new(g) VIRDEF; break; case TAB_JSON: tdp= new(g) JSONDEF; break; #if defined(ZIP_SUPPORT) - case TAB_ZIP: tdp = new(g) ZIPDEF; break; + case TAB_ZIP: tdp = new(g) ZIPDEF; break; #endif // ZIP_SUPPORT +#if defined(REST_SUPPORT) + case TAB_REST: tdp= new (g) RESTDEF; break; +#endif // REST_SUPPORT #if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) - case TAB_MONGO: - if (MongoEnabled()) { - tdp = new(g) MGODEF; - break; - } // endif enabled - // fall through + case TAB_MONGO: + if (MongoEnabled()) { + tdp = new(g) MGODEF; + break; + } // endif enabled + // fall through #endif // JAVA_SUPPORT || CMGO_SUPPORT - default: - sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name); + default: + sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name); } // endswitch // Do make the table/view definition if (tdp && tdp->Define(g, this, name, schema, am)) tdp= NULL; + if (trace(1)) + htrc("Table %s made\n", am); + return tdp; } // end of MakeTableDesc @@ -579,26 +598,29 @@ PTDB MYCAT::GetTable(PGLOBAL g, PTABLE tablep, MODE mode, LPCSTR type) PTDB tdbp= NULL; // LPCSTR name= tablep->GetName(); - if (trace(1)) - printf("GetTableDB: name=%s\n", tablep->GetName()); + if (trace(1)) + htrc("GetTableDB: name=%s\n", tablep->GetName()); // Look for the description of the requested table tdp= GetTableDesc(g, tablep, type); if (tdp) { - if (trace(1)) - printf("tdb=%p type=%s\n", tdp, tdp->GetType()); + if (trace(1)) + htrc("tdb=%p type=%s\n", tdp, tdp->GetType()); + + if (tablep->GetSchema()) + tdp->Database = SetPath(g, tablep->GetSchema()); + + if (trace(2)) + htrc("Going to get table...\n"); - if (tablep->GetSchema()) - tdp->Database = SetPath(g, tablep->GetSchema()); - tdbp= tdp->GetTable(g, mode); - } // endif tdp + } // endif tdp if (tdbp) { - if (trace(1)) - printf("tdbp=%p name=%s amtype=%d\n", tdbp, tdbp->GetName(), - tdbp->GetAmType()); + if (trace(1)) + htrc("tdbp=%p name=%s amtype=%d\n", tdbp, tdbp->GetName(), + tdbp->GetAmType()); tablep->SetTo_Tdb(tdbp); tdbp->SetTable(tablep); tdbp->SetMode(mode); diff --git a/storage/connect/mycat.h b/storage/connect/mycat.h index f0f889722dd..818e535b32d 100644 --- a/storage/connect/mycat.h +++ b/storage/connect/mycat.h @@ -11,10 +11,10 @@ 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /**************** MYCAT H Declares Source Code File (.H) ***************/ -/* Name: MYCAT.H Version 2.3 */ +/* Name: MYCAT.H Version 2.4 */ /* Author: Olivier Bertrand */ /* This file contains the CONNECT plugin MYCAT class definitions. */ /***********************************************************************/ @@ -50,6 +50,8 @@ struct ha_table_option_struct { const char *filter; const char *oplist; const char *data_charset; + const char *http; + const char *uri; ulonglong lrecl; ulonglong elements; //ulonglong estimate; diff --git a/storage/connect/osutil.h b/storage/connect/osutil.h index 7e6b8823b9b..380e7bebb22 100644 --- a/storage/connect/osutil.h +++ b/storage/connect/osutil.h @@ -3,7 +3,11 @@ #define __OSUTIL_H__ #if defined(UNIX) || defined(UNIV_LINUX) +#if defined(MARIADB) #include "my_global.h" +#else +#include "mini-global.h" +#endif #include #include #include "os.h" diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h index 5446e0d2a07..f10ae209e9d 100644 --- a/storage/connect/plgdbsem.h +++ b/storage/connect/plgdbsem.h @@ -1,7 +1,7 @@ /************** PlgDBSem H Declares Source Code File (.H) **************/ -/* Name: PLGDBSEM.H Version 3.7 */ +/* Name: PLGDBSEM.H Version 3.8 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 1998-2017 */ +/* (C) Copyright to the author Olivier BERTRAND 1998-2019 */ /* */ /* This file contains the CONNECT storage engine definitions. */ /***********************************************************************/ @@ -82,6 +82,7 @@ enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */ TAB_JDBC = 26, /* Table accessed via JDBC */ TAB_ZIP = 27, /* ZIP file info table */ TAB_MONGO = 28, /* Table retrieved from MongoDB */ + TAB_REST = 29, /* Table retrieved from Rest */ TAB_NIY = 30}; /* Table not implemented yet */ enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */ @@ -400,6 +401,7 @@ typedef class VCTDEF *PVCTDEF; typedef class PIVOTDEF *PPIVOTDEF; typedef class DOMDEF *PDOMDEF; typedef class DIRDEF *PDIRDEF; +typedef class RESTDEF *PRESTDEF; typedef class OEMDEF *POEMDEF; typedef class COLCRT *PCOLCRT; typedef class COLDEF *PCOLDEF; diff --git a/storage/connect/plugutil.cpp b/storage/connect/plugutil.cpp index 6790e7eb45c..e74937b942a 100644 --- a/storage/connect/plugutil.cpp +++ b/storage/connect/plugutil.cpp @@ -2,11 +2,11 @@ /* */ /* PROGRAM NAME: PLUGUTIL */ /* ------------- */ -/* Version 3.0 */ +/* Version 3.1 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 1993-2017 */ +/* (C) Copyright to the author Olivier BERTRAND 1993-2019 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -110,22 +110,32 @@ ACTIVITY defActivity = { /* Describes activity and language */ #include "rcmsg.h" #endif // UNIX +/**************************************************************************/ +/* Conditional tracing output function. */ +/**************************************************************************/ +void xtrc(uint x, char const *fmt, ...) +{ + if (GetTraceValue() & x) { + va_list ap; + va_start(ap, fmt); + + vfprintf(stderr, fmt, ap); + va_end(ap); + } // endif x + +} // end of xtrc + /**************************************************************************/ /* Tracing output function. */ /**************************************************************************/ -void htrc(char const *fmt, ...) - { - va_list ap; - va_start (ap, fmt); +void htrc(char const* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); - -//if (trace == 1) -// vfprintf(debug, fmt, ap); -//else - vfprintf(stderr, fmt, ap); - - va_end (ap); - } // end of htrc + vfprintf(stderr, fmt, ap); + va_end(ap); +} // end of htrc /***********************************************************************/ /* Plug initialization routine. */ diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp index 30d8063d1a6..8ba8aac3621 100644 --- a/storage/connect/reldef.cpp +++ b/storage/connect/reldef.cpp @@ -81,51 +81,51 @@ RELDEF::RELDEF(void) /* This function return a pointer to the Table Option Struct. */ /***********************************************************************/ PTOS RELDEF::GetTopt(void) - { - return Hc->GetTableOptionStruct(); - } // end of GetTopt + { + return Hc->GetTableOptionStruct(); + } // end of GetTopt /***********************************************************************/ /* This function sets an integer table information. */ /***********************************************************************/ bool RELDEF::SetIntCatInfo(PCSZ what, int n) - { - return Hc->SetIntegerOption(what, n); - } // end of SetIntCatInfo + { + return Hc->SetIntegerOption(what, n); + } // end of SetIntCatInfo /***********************************************************************/ /* This function returns integer table information. */ /***********************************************************************/ int RELDEF::GetIntCatInfo(PCSZ what, int idef) - { - int n= Hc->GetIntegerOption(what); + { + int n= Hc->GetIntegerOption(what); - return (n == NO_IVAL) ? idef : n; - } // end of GetIntCatInfo + return (n == NO_IVAL) ? idef : n; + } // end of GetIntCatInfo /***********************************************************************/ /* This function returns Boolean table information. */ /***********************************************************************/ bool RELDEF::GetBoolCatInfo(PCSZ what, bool bdef) - { - bool b= Hc->GetBooleanOption(what, bdef); + { + bool b= Hc->GetBooleanOption(what, bdef); - return b; - } // end of GetBoolCatInfo + return b; + } // end of GetBoolCatInfo /***********************************************************************/ /* This function returns size catalog information. */ /***********************************************************************/ int RELDEF::GetSizeCatInfo(PCSZ what, PCSZ sdef) - { - char c; - PCSZ s; + { + char c; + PCSZ s; int i, n= 0; - if (!(s= Hc->GetStringOption(what))) - s= sdef; + if (!(s= Hc->GetStringOption(what))) + s= sdef; - if ((i= sscanf(s, " %d %c ", &n, &c)) == 2) + if ((i= sscanf(s, " %d %c ", &n, &c)) == 2) switch (toupper(c)) { case 'M': n *= 1024; @@ -141,41 +141,41 @@ int RELDEF::GetSizeCatInfo(PCSZ what, PCSZ sdef) /* This function sets char table information in buf. */ /***********************************************************************/ int RELDEF::GetCharCatInfo(PCSZ what, PCSZ sdef, char *buf, int size) - { - PCSZ s= Hc->GetStringOption(what); + { + PCSZ s= Hc->GetStringOption(what); - strncpy(buf, ((s) ? s : sdef), size); - return size; - } // end of GetCharCatInfo + strncpy(buf, ((s) ? s : sdef), size); + return size; + } // end of GetCharCatInfo /***********************************************************************/ /* To be used by any TDB's. */ /***********************************************************************/ bool RELDEF::Partitioned(void) - { - return Hc->IsPartitioned(); - } // end of Partitioned + { + return Hc->IsPartitioned(); + } // end of Partitioned /***********************************************************************/ /* This function returns string table information. */ /* Default parameter is "*" to get the handler default. */ /***********************************************************************/ char *RELDEF::GetStringCatInfo(PGLOBAL g, PCSZ what, PCSZ sdef) - { - char *sval = NULL; - PCSZ name, s= Hc->GetStringOption(what, sdef); - - if (s) { + { + char *sval = NULL; + PCSZ name, s= Hc->GetStringOption(what, sdef); + + if (s) { if (!Hc->IsPartitioned() || (stricmp(what, "filename") && stricmp(what, "tabname") && stricmp(what, "connect"))) - sval= PlugDup(g, s); + sval= PlugDup(g, s); else sval= (char*)s; } else if (!stricmp(what, "filename")) { // Return default file name - PCSZ ftype= Hc->GetStringOption("Type", "*"); + PCSZ ftype= Hc->GetStringOption("Type", "*"); int i, n; if (IsFileType(GetTypeID(ftype))) { @@ -183,7 +183,7 @@ char *RELDEF::GetStringCatInfo(PGLOBAL g, PCSZ what, PCSZ sdef) sval= (char*)PlugSubAlloc(g, NULL, strlen(name) + 12); strcat(strcpy(sval, name), "."); n= strlen(sval); - + // Fold ftype to lower case for (i= 0; i < 12; i++) if (!ftype[i]) { @@ -196,8 +196,8 @@ char *RELDEF::GetStringCatInfo(PGLOBAL g, PCSZ what, PCSZ sdef) } // endif s - return sval; - } // end of GetStringCatInfo + return sval; + } // end of GetStringCatInfo /* --------------------------- Class TABDEF -------------------------- */ @@ -223,14 +223,14 @@ TABDEF::TABDEF(void) /***********************************************************************/ /* Define: initialize the table definition block from XDB file. */ /***********************************************************************/ -bool TABDEF::Define(PGLOBAL g, PCATLG cat, - LPCSTR name, LPCSTR schema, LPCSTR am) +bool TABDEF::Define(PGLOBAL g, PCATLG cat, + LPCSTR name, LPCSTR schema, LPCSTR am) { int poff = 0; - Hc = ((MYCAT*)cat)->GetHandler(); - Name = (PSZ)name; - Schema = (PSZ)Hc->GetDBName(schema); + Hc = ((MYCAT*)cat)->GetHandler(); + Name = (PSZ)name; + Schema = (PSZ)Hc->GetDBName(schema); Cat = cat; Catfunc = GetFuncID(GetStringCatInfo(g, "Catfunc", NULL)); Elemt = GetIntCatInfo("Elements", 0); @@ -263,14 +263,14 @@ PCSZ TABDEF::GetPath(void) /* This function returns column table information. */ /***********************************************************************/ int TABDEF::GetColCatInfo(PGLOBAL g) - { - char *type= GetStringCatInfo(g, "Type", "*"); + { + char *type= GetStringCatInfo(g, "Type", "*"); char c, fty, eds; - int i, n, loff, poff, nof, nlg; - void *field= NULL; + int i, n, loff, poff, nof, nlg; + void *field= NULL; TABTYPE tc; PCOLDEF cdp, lcdp= NULL, tocols= NULL; - PCOLINFO pcf= (PCOLINFO)PlugSubAlloc(g, NULL, sizeof(COLINFO)); + PCOLINFO pcf= (PCOLINFO)PlugSubAlloc(g, NULL, sizeof(COLINFO)); memset(pcf, 0, sizeof(COLINFO)); @@ -278,33 +278,33 @@ int TABDEF::GetColCatInfo(PGLOBAL g) tc= (Catfunc == FNC_NO) ? GetTypeID(type) : TAB_PRX; // Take care of the column definitions - i= poff= nof= nlg= 0; + i= poff= nof= nlg= 0; #if defined(__WIN__) - // Offsets of HTML and DIR tables start from 0, DBF at 1 - loff= (tc == TAB_DBF) ? 1 : (tc == TAB_XML || tc == TAB_DIR) ? -1 : 0; + // Offsets of HTML and DIR tables start from 0, DBF at 1 + loff= (tc == TAB_DBF) ? 1 : (tc == TAB_XML || tc == TAB_DIR) ? -1 : 0; #else // !__WIN__ - // Offsets of HTML tables start from 0, DIR and DBF at 1 - loff = (tc == TAB_DBF || tc == TAB_DIR) ? 1 : (tc == TAB_XML) ? -1 : 0; + // Offsets of HTML tables start from 0, DIR and DBF at 1 + loff = (tc == TAB_DBF || tc == TAB_DIR) ? 1 : (tc == TAB_XML) ? -1 : 0; #endif // !__WIN__ while (true) { - // Default Offset depends on table type - switch (tc) { + // Default Offset depends on table type + switch (tc) { case TAB_DOS: case TAB_FIX: case TAB_BIN: case TAB_VEC: case TAB_DBF: - poff= loff + nof; // Default next offset - nlg= MY_MAX(nlg, poff); // Default lrecl + poff= loff + nof; // Default next offset + nlg= MY_MAX(nlg, poff); // Default lrecl break; case TAB_CSV: case TAB_FMT: - nlg+= nof; + nlg+= nof; case TAB_DIR: case TAB_XML: - poff= loff + (pcf->Flags & U_VIRTUAL ? 0 : 1); + poff= loff + (pcf->Flags & U_VIRTUAL ? 0 : 1); break; case TAB_INI: case TAB_MAC: @@ -316,39 +316,39 @@ int TABDEF::GetColCatInfo(PGLOBAL g) poff = 0; // Offset represents an independant flag break; default: // VCT PLG ODBC JDBC MYSQL WMI... - poff = 0; // NA + poff = 0; // NA break; - } // endswitch tc + } // endswitch tc -// do { - field= Hc->GetColumnOption(g, field, pcf); +// do { + field= Hc->GetColumnOption(g, field, pcf); // } while (field && (*pcf->Name =='*' /*|| pcf->Flags & U_VIRTUAL*/)); - if (tc == TAB_DBF && pcf->Type == TYPE_DATE && !pcf->Datefmt) { - // DBF date format defaults to 'YYYMMDD' - pcf->Datefmt= "YYYYMMDD"; - pcf->Length= 8; - } // endif tc + if (tc == TAB_DBF && pcf->Type == TYPE_DATE && !pcf->Datefmt) { + // DBF date format defaults to 'YYYMMDD' + pcf->Datefmt= "YYYYMMDD"; + pcf->Length= 8; + } // endif tc - if (!field) - break; + if (!field) + break; // Allocate the column description block cdp= new(g) COLDEF; if ((nof= cdp->Define(g, NULL, pcf, poff)) < 0) - return -1; // Error, probably unhandled type - else - loff= cdp->GetOffset(); + return -1; // Error, probably unhandled type + else + loff= cdp->GetOffset(); - switch (tc) { - case TAB_VEC: - cdp->SetOffset(0); // Not to have shift - case TAB_BIN: - // BIN/VEC are packed by default + switch (tc) { + case TAB_VEC: + cdp->SetOffset(0); // Not to have shift + case TAB_BIN: + // BIN/VEC are packed by default if (nof) { - // Field width is the internal representation width - // that can also depend on the column format + // Field width is the internal representation width + // that can also depend on the column format fty = cdp->Decode ? 'C' : 'X'; eds = 0; n = 0; @@ -371,38 +371,38 @@ int TABDEF::GetColCatInfo(PGLOBAL g) if (n) nof = n; else switch (fty) { - case 'X': + case 'X': if (eds && IsTypeChar(cdp->Buf_Type)) nof = sizeof(longlong); else nof= cdp->Clen; break; - case 'C': break; - case 'R': - case 'F': nof = sizeof(float); break; - case 'I': nof = sizeof(int); break; - case 'D': nof = sizeof(double); break; - case 'S': nof = sizeof(short); break; - case 'T': nof = sizeof(char); break; - case 'G': nof = sizeof(longlong); break; - default: /* Wrong format */ + case 'C': break; + case 'R': + case 'F': nof = sizeof(float); break; + case 'I': nof = sizeof(int); break; + case 'D': nof = sizeof(double); break; + case 'S': nof = sizeof(short); break; + case 'T': nof = sizeof(char); break; + case 'G': nof = sizeof(longlong); break; + default: /* Wrong format */ sprintf(g->Message, "Invalid format %c", fty); return -1; - } // endswitch fty + } // endswitch fty } // endif nof default: - break; - } // endswitch tc + break; + } // endswitch tc - if (lcdp) - lcdp->SetNext(cdp); - else - tocols= cdp; + if (lcdp) + lcdp->SetNext(cdp); + else + tocols= cdp; - lcdp= cdp; + lcdp= cdp; i++; } // endwhile @@ -410,31 +410,31 @@ int TABDEF::GetColCatInfo(PGLOBAL g) if (i != GetDegree()) SetDegree(i); - if (GetDefType() == TYPE_AM_DOS) { - int ending, recln= 0; + if (GetDefType() == TYPE_AM_DOS) { + int ending, recln= 0; - // Was commented because sometimes ending is 0 even when - // not specified (for instance if quoted is specified) -// if ((ending= Hc->GetIntegerOption("Ending")) < 0) { - if ((ending= Hc->GetIntegerOption("Ending")) <= 0) { + // Was commented because sometimes ending is 0 even when + // not specified (for instance if quoted is specified) +// if ((ending= Hc->GetIntegerOption("Ending")) < 0) { + if ((ending= Hc->GetIntegerOption("Ending")) <= 0) { ending= (tc == TAB_BIN || tc == TAB_VEC) ? 0 : CRLF; - Hc->SetIntegerOption("Ending", ending); - } // endif ending + Hc->SetIntegerOption("Ending", ending); + } // endif ending - // Calculate the default record size - switch (tc) { + // Calculate the default record size + switch (tc) { case TAB_FIX: case TAB_BIN: recln= nlg + ending; // + length of line ending break; case TAB_VEC: recln= nlg; - + // if ((k= (pak < 0) ? 8 : pak) > 1) // See above for detailed comment // Round up lrecl to multiple of 8 or pak // recln= ((recln + k - 1) / k) * k; - + break; case TAB_DOS: case TAB_DBF: @@ -443,26 +443,30 @@ int TABDEF::GetColCatInfo(PGLOBAL g) case TAB_CSV: case TAB_FMT: // The number of separators (assuming an extra one can exist) -// recln= poff * ((qotd) ? 3 : 1); to be investigated - recln= nlg + poff * 3; // To be safe +// recln= poff * ((qotd) ? 3 : 1); to be investigated + recln= nlg + poff * 3; // To be safe default: break; } // endswitch tc - // lrecl must be at least recln to avoid buffer overflow - if (trace(1)) - htrc("Lrecl: Calculated=%d defined=%d\n", - recln, Hc->GetIntegerOption("Lrecl")); + // lrecl must be at least recln to avoid buffer overflow + if (trace(1)) + htrc("Lrecl: Calculated=%d defined=%d\n", + recln, Hc->GetIntegerOption("Lrecl")); - recln = MY_MAX(recln, Hc->GetIntegerOption("Lrecl")); - Hc->SetIntegerOption("Lrecl", recln); - ((PDOSDEF)this)->SetLrecl(recln); - } // endif Lrecl + recln = MY_MAX(recln, Hc->GetIntegerOption("Lrecl")); + Hc->SetIntegerOption("Lrecl", recln); + ((PDOSDEF)this)->SetLrecl(recln); - // Attach the column definition to the tabdef - SetCols(tocols); - return poff; - } // end of GetColCatInfo + if (trace(1)) + htrc("Lrecl set to %d\n", recln); + + } // endif Lrecl + + // Attach the column definition to the tabdef + SetCols(tocols); + return poff; + } // end of GetColCatInfo /***********************************************************************/ /* SetIndexInfo: retrieve index description from the table structure. */ @@ -487,16 +491,17 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g) PCATLG cat = Cat; /*********************************************************************/ - /* Ensure that the .dll doesn't have a path. */ - /* This is done to ensure that only approved dll from the system */ + /* Ensure that the module name doesn't have a path. */ + /* This is done to ensure that only approved libs from the system */ /* directories are used (to make this even remotely secure). */ /*********************************************************************/ if (check_valid_path(Module, strlen(Module))) { strcpy(g->Message, "Module cannot contain a path"); return NULL; } else - PlugSetPath(soname, Module, GetPluginDir()); - +// PlugSetPath(soname, Module, GetPluginDir()); // Crashes on Fedora + strncat(strcpy(soname, GetPluginDir()), Module, _MAX_PATH); + #if defined(__WIN__) // Is the DLL already loaded? if (!Hdll && !(Hdll = GetModuleHandle(soname))) @@ -522,31 +527,31 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g) // Get the function returning an instance of the external DEF class if (!(getdef = (XGETDEF)GetProcAddress((HINSTANCE)Hdll, getname))) { - char buf[256]; - DWORD rc = GetLastError(); + char buf[256]; + DWORD rc = GetLastError(); - sprintf(g->Message, MSG(PROCADD_ERROR), rc, getname); - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0, - (LPTSTR)buf, sizeof(buf), NULL); - strcat(strcat(g->Message, ": "), buf); - FreeLibrary((HMODULE)Hdll); + sprintf(g->Message, MSG(PROCADD_ERROR), rc, getname); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0, + (LPTSTR)buf, sizeof(buf), NULL); + strcat(strcat(g->Message, ": "), buf); + FreeLibrary((HMODULE)Hdll); return NULL; } // endif getdef #else // !__WIN__ const char *error = NULL; - -#if 0 // Don't know what all this stuff does - Dl_info dl_info; - // The OEM lib must retrieve exported CONNECT variables +#if 0 // Don't know what all this stuff does + Dl_info dl_info; + + // The OEM lib must retrieve exported CONNECT variables if (dladdr(&connect_hton, &dl_info)) { if (dlopen(dl_info.dli_fname, RTLD_NOLOAD | RTLD_NOW | RTLD_GLOBAL) == 0) { error = dlerror(); sprintf(g->Message, "dlopen failed: %s, OEM not supported", SVP(error)); return NULL; } // endif dlopen - + } else { error = dlerror(); sprintf(g->Message, "dladdr failed: %s, OEM not supported", SVP(error)); @@ -626,7 +631,7 @@ bool OEMDEF::DefineAM(PGLOBAL g, LPCSTR, int) char *desc = (char*)PlugSubAlloc(g, NULL, strlen(Module) + strlen(Subtype) + 3); sprintf(desc, "%s(%s)", Module, Subtype); - Desc = desc; + Desc = desc; return false; } // end of DefineAM @@ -701,17 +706,17 @@ PTDB OEMDEF::GetTable(PGLOBAL g, MODE mode) txfp = new(g) FIXFAM(defp); } else if (rfm == RECFM_VCT) { #if defined(VCT_SUPPORT) - assert(Pxdef->GetDefType() == TYPE_AM_VCT); + assert(Pxdef->GetDefType() == TYPE_AM_VCT); if (map) txfp = new(g) VCMFAM((PVCTDEF)defp); else txfp = new(g) VCTFAM((PVCTDEF)defp); #else // !VCT_SUPPORT - strcpy(g->Message, "VCT no more supported"); - return NULL; + strcpy(g->Message, "VCT no more supported"); + return NULL; #endif // !VCT_SUPPORT - } // endif's + } // endif's ((PTDBDOS)tdbp)->SetTxfp(txfp); } // endif Txfp diff --git a/storage/connect/rest.def b/storage/connect/rest.def new file mode 100644 index 00000000000..71c76740af9 --- /dev/null +++ b/storage/connect/rest.def @@ -0,0 +1,4 @@ +LIBRARY REST2 +EXPORTS + GetREST @1 + ColREST @2 diff --git a/storage/connect/restget.cpp b/storage/connect/restget.cpp new file mode 100644 index 00000000000..6b184ae6926 --- /dev/null +++ b/storage/connect/restget.cpp @@ -0,0 +1,94 @@ +/************* Restget C++ Program Source Code File (.CPP) *************/ +/* Adapted from the sample program of the Casablanca tutorial. */ +/* Copyright Olivier Bertrand 2019. */ +/***********************************************************************/ +#include +#include +#if defined(MARIADB) +#include +#else +#include "mini-global.h" +#define _OS_H_INCLUDED // Prevent os.h to be called +#endif + +using namespace utility::conversions; // String conversions utilities +using namespace web; // Common features like URIs. +using namespace web::http; // Common HTTP functionality +using namespace web::http::client; // HTTP client features +using namespace concurrency::streams; // Asynchronous streams + +#include "global.h" + +/***********************************************************************/ +/* Make a local copy of the requested file. */ +/***********************************************************************/ +int restGetFile(PGLOBAL g, PCSZ http, PCSZ uri, PCSZ fn) +{ + int rc = 0; + bool xt = trace(515); + auto fileStream = std::make_shared(); + + if (!http || !fn) { + strcpy(g->Message, "Missing http or filename"); + return 2; + } // endif + + if (xt) + htrc("restGetFile: fn=%s\n", fn); + + // Open stream to output file. + pplx::task requestTask = fstream::open_ostream(to_string_t(fn)) + .then([=](ostream outFile) { + *fileStream= outFile; + + if (xt) + htrc("Outfile isopen=%d\n", outFile.is_open()); + + // Create http_client to send the request. + http_client client(to_string_t(http)); + + if (uri) { + // Build request URI and start the request. + uri_builder builder(to_string_t(uri)); + return client.request(methods::GET, builder.to_string()); + } else + return client.request(methods::GET); + }) + + // Handle response headers arriving. + .then([=](http_response response) { + if (xt) + htrc("Received response status code:%u\n", + response.status_code()); + + // Write response body into the file. + return response.body().read_to_end(fileStream->streambuf()); + }) + + // Close the file stream. + .then([=](size_t n) { + if (xt) + htrc("Return size=%u\n", n); + + return fileStream->close(); + }); + + // Wait for all the outstanding I/O to complete and handle any exceptions + try { + requestTask.wait(); + + if (xt) + htrc("In Wait\n"); + + } catch (const std::exception &e) { + if (xt) + htrc("Error exception: %s\n", e.what()); + sprintf(g->Message, "Error exception: %s", e.what()); + rc= 1; + } // end try/catch + + if (xt) + htrc("restget done: rc=%d\n", rc); + + return rc; +} // end of restGetFile diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp index 02720a3089a..746382178fb 100644 --- a/storage/connect/tabfmt.cpp +++ b/storage/connect/tabfmt.cpp @@ -189,9 +189,11 @@ PQRYRES CSVColumns(PGLOBAL g, PCSZ dp, PTOS topt, bool info) htrc("File %s Sep=%c Qot=%c Header=%d maxerr=%d\n", SVP(tdp->Fn), tdp->Sep, tdp->Qot, tdp->Header, tdp->Maxerr); +#if defined(ZIP_SUPPORT) if (tdp->Zipped) tcvp = new(g)TDBCSV(tdp, new(g)UNZFAM(tdp)); else +#endif // ZIP_SUPPORT tcvp = new(g) TDBCSV(tdp, new(g) DOSFAM(tdp)); tcvp->SetMode(MODE_READ); diff --git a/storage/connect/tabjdbc.cpp b/storage/connect/tabjdbc.cpp index c6b2802c1f6..06b6b3a9730 100644 --- a/storage/connect/tabjdbc.cpp +++ b/storage/connect/tabjdbc.cpp @@ -72,7 +72,6 @@ #include "tabext.h" #include "tabjdbc.h" #include "tabmul.h" -//#include "reldef.h" #include "tabcol.h" #include "valblk.h" #include "ha_connect.h" @@ -89,6 +88,9 @@ extern int num_read, num_there, num_eq[2]; // Statistics /* External function. */ /***********************************************************************/ bool ExactInfo(void); +#if defined(DEVELOPMENT) +extern char *GetUserVariable(PGLOBAL g, const uchar *varname); +#endif // DEVELOPMENT /* -------------------------- Class JDBCDEF -------------------------- */ @@ -147,10 +149,6 @@ int JDBCDEF::ParseURL(PGLOBAL g, char *url, bool b) return RC_FX; Tabname = p; -// } else if (b) { -// // Otherwise, straight server name, -// Tabname = GetStringCatInfo(g, "Name", NULL); -// Tabname = GetStringCatInfo(g, "Tabname", Tabname); } // endif if (trace(1)) @@ -165,6 +163,11 @@ int JDBCDEF::ParseURL(PGLOBAL g, char *url, bool b) return RC_FX; } // endif server +#if defined(DEVELOPMENT) + if (*server->host == '@') { + Url = GetUserVariable(g, (const uchar*)&server->host[1]); + } else +#endif // 0 if (strncmp(server->host, "jdbc:", 5)) { // Now make the required URL Url = (PSZ)PlugSubAlloc(g, NULL, 0); @@ -191,6 +194,9 @@ int JDBCDEF::ParseURL(PGLOBAL g, char *url, bool b) if (!Password && server->password) Password = PlugDup(g, server->password); + Driver = PlugDup(g, GetListOption(g, "Driver", server->owner, NULL)); + Wrapname = PlugDup(g, GetListOption(g, "Wrapper", server->owner, NULL)); + Memory = atoi(GetListOption(g, "Memory", server->owner, "0")); return RC_NF; } // endif @@ -208,7 +214,6 @@ bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) if (EXTDEF::DefineAM(g, am, poff)) return true; - Driver = GetStringCatInfo(g, "Driver", NULL); Desc = Url = GetStringCatInfo(g, "Connect", NULL); if (!Url && !Catfunc) { @@ -228,7 +233,10 @@ bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) return true; } // endif rc - Wrapname = GetStringCatInfo(g, "Wrapper", NULL); + // Default values may have been set in ParseURL + Memory = GetIntCatInfo("Memory", Memory); + Driver = GetStringCatInfo(g, "Driver", Driver); + Wrapname = GetStringCatInfo(g, "Wrapper", Wrapname); return false; } // end of DefineAM @@ -633,7 +641,9 @@ bool TDBJDBC::OpenDB(PGLOBAL g) Cnp->InitValue(g); if ((n = Jcp->GetResultSize(Query->GetStr(), Cnp)) < 0) { - sprintf(g->Message, "Cannot get result size rc=%d", n); + char* msg = PlugDup(g, g->Message); + + sprintf(g->Message, "Get result size: %s (rc=%d)", msg, n); return true; } else if (n) { Jcp->m_Rows = n; diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index afab52aa282..0b282345c8a 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -71,15 +71,15 @@ char *GetJsonNull(void); /***********************************************************************/ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) { - static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, + static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING}; - static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, + static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT}; static unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0}; - int i, n = 0; + int i, n = 0; int ncol = sizeof(buftyp) / sizeof(int); - PJCL jcp; - JSONDISC *pjdc = NULL; + PJCL jcp; + JSONDISC *pjdc = NULL; PQRYRES qrp; PCOLRES crp; @@ -89,15 +89,15 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) goto skipit; } // endif info - if (GetIntegerTableOption(g, topt, "Multiple", 0)) { - strcpy(g->Message, "Cannot find column definition for multiple table"); - return NULL; - } // endif Multiple + if (GetIntegerTableOption(g, topt, "Multiple", 0)) { + strcpy(g->Message, "Cannot find column definition for multiple table"); + return NULL; + } // endif Multiple - pjdc = new(g) JSONDISC(g, length); + pjdc = new(g) JSONDISC(g, length); - if (!(n = pjdc->GetColumns(g, db, dsn, topt))) - return NULL; + if (!(n = pjdc->GetColumns(g, db, dsn, topt))) + return NULL; skipit: if (trace(1)) @@ -110,8 +110,8 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) buftyp, fldtyp, length, false, false); crp = qrp->Colresp->Next->Next->Next->Next->Next->Next; - crp->Name = PlugDup(g, "Nullable"); - crp->Next->Name = PlugDup(g, "Jpath"); + crp->Name = PlugDup(g, "Nullable"); + crp->Next->Name = PlugDup(g, "Jpath"); if (info || !qrp) return qrp; @@ -122,8 +122,8 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) /* Now get the results into blocks. */ /*********************************************************************/ for (i = 0, jcp = pjdc->fjcp; jcp; i++, jcp = jcp->Next) { - if (jcp->Type == TYPE_UNKNOWN) - jcp->Type = TYPE_STRING; // Void column + if (jcp->Type == TYPE_UNKNOWN) + jcp->Type = TYPE_STRING; // Void column crp = qrp->Colresp; // Column Name crp->Kdata->SetValue(jcp->Name, i); @@ -159,380 +159,380 @@ PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info) /***********************************************************************/ JSONDISC::JSONDISC(PGLOBAL g, uint *lg) { - length = lg; - jcp = fjcp = pjcp = NULL; - tjnp = NULL; - jpp = NULL; - tjsp = NULL; - jsp = NULL; - row = NULL; - sep = NULL; - i = n = bf = ncol = lvl = 0; - all = false; -} // end of JSONDISC constructor + length = lg; + jcp = fjcp = pjcp = NULL; + tjnp = NULL; + jpp = NULL; + tjsp = NULL; + jsp = NULL; + row = NULL; + sep = NULL; + i = n = bf = ncol = lvl = 0; + all = false; +} // end of JSONDISC constructor int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) { - char filename[_MAX_PATH]; - bool mgo = (GetTypeID(topt->type) == TAB_MONGO); - PCSZ level = GetStringTableOption(g, topt, "Level", NULL); + char filename[_MAX_PATH]; + bool mgo = (GetTypeID(topt->type) == TAB_MONGO); + PCSZ level = GetStringTableOption(g, topt, "Level", NULL); - if (level) { - lvl = atoi(level); - lvl = (lvl > 16) ? 16 : lvl; - } else - lvl = 0; + if (level) { + lvl = atoi(level); + lvl = (lvl > 16) ? 16 : lvl; + } else + lvl = 0; - sep = GetStringTableOption(g, topt, "Separator", "."); + sep = GetStringTableOption(g, topt, "Separator", "."); - /*********************************************************************/ - /* Open the input file. */ - /*********************************************************************/ - tdp = new(g) JSONDEF; + /*********************************************************************/ + /* Open the input file. */ + /*********************************************************************/ + tdp = new(g) JSONDEF; #if defined(ZIP_SUPPORT) - tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL); - tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false); + tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL); + tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false); #endif // ZIP_SUPPORT - tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); + tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL); - if (!(tdp->Database = SetPath(g, db))) - return 0; + if (!(tdp->Database = SetPath(g, db))) + return 0; - tdp->Objname = GetStringTableOption(g, topt, "Object", NULL); - tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0; - tdp->Pretty = GetIntegerTableOption(g, topt, "Pretty", 2); - tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL); - tdp->Accept = GetBooleanTableOption(g, topt, "Accept", false); - tdp->Uri = (dsn && *dsn ? dsn : NULL); + tdp->Objname = GetStringTableOption(g, topt, "Object", NULL); + tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0; + tdp->Pretty = GetIntegerTableOption(g, topt, "Pretty", 2); + tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL); + tdp->Accept = GetBooleanTableOption(g, topt, "Accept", false); + tdp->Uri = (dsn && *dsn ? dsn : NULL); - if (!tdp->Fn && !tdp->Uri) { - strcpy(g->Message, MSG(MISSING_FNAME)); - return 0; - } // endif Fn + if (!tdp->Fn && !tdp->Uri) { + strcpy(g->Message, MSG(MISSING_FNAME)); + return 0; + } // endif Fn - if (tdp->Fn) { - // We used the file name relative to recorded datapath - PlugSetPath(filename, tdp->Fn, tdp->GetPath()); - tdp->Fn = PlugDup(g, filename); - } // endif Fn + if (tdp->Fn) { + // We used the file name relative to recorded datapath + PlugSetPath(filename, tdp->Fn, tdp->GetPath()); + tdp->Fn = PlugDup(g, filename); + } // endif Fn - if (trace(1)) - htrc("File %s objname=%s pretty=%d lvl=%d\n", - tdp->Fn, tdp->Objname, tdp->Pretty, lvl); + if (trace(1)) + htrc("File %s objname=%s pretty=%d lvl=%d\n", + tdp->Fn, tdp->Objname, tdp->Pretty, lvl); - if (tdp->Uri) { + if (tdp->Uri) { #if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) - tdp->Collname = GetStringTableOption(g, topt, "Name", NULL); - tdp->Collname = GetStringTableOption(g, topt, "Tabname", tdp->Collname); - tdp->Schema = GetStringTableOption(g, topt, "Dbname", "test"); - tdp->Options = (PSZ)GetStringTableOption(g, topt, "Colist", "all"); - tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false); - tdp->Driver = (PSZ)GetStringTableOption(g, topt, "Driver", NULL); - tdp->Version = GetIntegerTableOption(g, topt, "Version", 3); - tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper", - (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface"); - tdp->Pretty = 0; + tdp->Collname = GetStringTableOption(g, topt, "Name", NULL); + tdp->Collname = GetStringTableOption(g, topt, "Tabname", tdp->Collname); + tdp->Schema = GetStringTableOption(g, topt, "Dbname", "test"); + tdp->Options = (PSZ)GetStringTableOption(g, topt, "Colist", "all"); + tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false); + tdp->Driver = (PSZ)GetStringTableOption(g, topt, "Driver", NULL); + tdp->Version = GetIntegerTableOption(g, topt, "Version", 3); + tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper", + (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface"); + tdp->Pretty = 0; #else // !MONGO_SUPPORT - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); - return 0; + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); + return 0; #endif // !MONGO_SUPPORT - } // endif Uri + } // endif Uri - if (tdp->Pretty == 2) { - if (tdp->Zipped) { + if (tdp->Pretty == 2) { + if (tdp->Zipped) { #if defined(ZIP_SUPPORT) - tjsp = new(g) TDBJSON(tdp, new(g) UNZFAM(tdp)); + tjsp = new(g) TDBJSON(tdp, new(g) UNZFAM(tdp)); #else // !ZIP_SUPPORT - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); - return 0; + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return 0; #endif // !ZIP_SUPPORT - } else - tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp)); + } else + tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp)); - if (tjsp->MakeDocument(g)) - return 0; + if (tjsp->MakeDocument(g)) + return 0; - jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL; - } else { - if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0))) - if (!mgo) { - sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty); - return 0; - } else - tdp->Lrecl = 8192; // Should be enough + jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetValue(0) : NULL; + } else { + if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0))) + if (!mgo) { + sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty); + return 0; + } else + tdp->Lrecl = 8192; // Should be enough - tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); + tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF); - if (tdp->Zipped) { + if (tdp->Zipped) { #if defined(ZIP_SUPPORT) - tjnp = new(g)TDBJSN(tdp, new(g) UNZFAM(tdp)); + tjnp = new(g)TDBJSN(tdp, new(g) UNZFAM(tdp)); #else // !ZIP_SUPPORT - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); - return NULL; + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; #endif // !ZIP_SUPPORT - } else if (tdp->Uri) { - if (tdp->Driver && toupper(*tdp->Driver) == 'C') { + } else if (tdp->Uri) { + if (tdp->Driver && toupper(*tdp->Driver) == 'C') { #if defined(CMGO_SUPPORT) - tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp)); + tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp)); #else - sprintf(g->Message, "Mongo %s Driver not available", "C"); - return 0; + sprintf(g->Message, "Mongo %s Driver not available", "C"); + return 0; #endif - } else if (tdp->Driver && toupper(*tdp->Driver) == 'J') { + } else if (tdp->Driver && toupper(*tdp->Driver) == 'J') { #if defined(JAVA_SUPPORT) - tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp)); + tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp)); #else - sprintf(g->Message, "Mongo %s Driver not available", "Java"); - return 0; + sprintf(g->Message, "Mongo %s Driver not available", "Java"); + return 0; #endif - } else { // Driver not specified + } else { // Driver not specified #if defined(CMGO_SUPPORT) - tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp)); + tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp)); #elif defined(JAVA_SUPPORT) - tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp)); + tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp)); #else - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); - return 0; + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); + return 0; #endif - } // endif Driver + } // endif Driver - } else - tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp)); + } else + tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp)); - tjnp->SetMode(MODE_READ); + tjnp->SetMode(MODE_READ); - // Allocate the parse work memory - PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); - memset(G, 0, sizeof(GLOBAL)); - G->Sarea_Size = tdp->Lrecl * 10; - G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); - PlugSubSet(G->Sarea, G->Sarea_Size); - G->jump_level = 0; - tjnp->SetG(G); + // Allocate the parse work memory + PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); + memset(G, 0, sizeof(GLOBAL)); + G->Sarea_Size = tdp->Lrecl * 10; + G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); + PlugSubSet(G->Sarea, G->Sarea_Size); + G->jump_level = 0; + tjnp->SetG(G); - if (tjnp->OpenDB(g)) - return 0; + if (tjnp->OpenDB(g)) + return 0; - switch (tjnp->ReadDB(g)) { - case RC_EF: - strcpy(g->Message, "Void json table"); - case RC_FX: - goto err; - default: - jsp = tjnp->GetRow(); - } // endswitch ReadDB + switch (tjnp->ReadDB(g)) { + case RC_EF: + strcpy(g->Message, "Void json table"); + case RC_FX: + goto err; + default: + jsp = tjnp->GetRow(); + } // endswitch ReadDB - } // endif pretty + } // endif pretty - if (!(row = (jsp) ? jsp->GetObject() : NULL)) { - strcpy(g->Message, "Can only retrieve columns from object rows"); - goto err; - } // endif row + if (!(row = (jsp) ? jsp->GetObject() : NULL)) { + strcpy(g->Message, "Can only retrieve columns from object rows"); + goto err; + } // endif row - all = GetBooleanTableOption(g, topt, "Fullarray", false); - jcol.Name = jcol.Fmt = NULL; - jcol.Next = NULL; - jcol.Found = true; - colname[0] = 0; + all = GetBooleanTableOption(g, topt, "Fullarray", false); + jcol.Name = jcol.Fmt = NULL; + jcol.Next = NULL; + jcol.Found = true; + colname[0] = 0; - if (!tdp->Uri) { - fmt[0] = '$'; - fmt[1] = '.'; - bf = 2; - } // endif Uri + if (!tdp->Uri) { + fmt[0] = '$'; + fmt[1] = '.'; + bf = 2; + } // endif Uri - /*********************************************************************/ - /* Analyse the JSON tree and define columns. */ - /*********************************************************************/ - for (i = 1; ; i++) { - for (jpp = row->GetFirst(); jpp; jpp = jpp->GetNext()) { - strncpy(colname, jpp->GetKey(), 64); - fmt[bf] = 0; + /*********************************************************************/ + /* Analyse the JSON tree and define columns. */ + /*********************************************************************/ + for (i = 1; ; i++) { + for (jpp = row->GetFirst(); jpp; jpp = jpp->GetNext()) { + strncpy(colname, jpp->GetKey(), 64); + fmt[bf] = 0; - if (Find(g, jpp->GetVal(), colname, MY_MIN(lvl, 0))) - goto err; + if (Find(g, jpp->GetVal(), colname, MY_MIN(lvl, 0))) + goto err; - } // endfor jpp + } // endfor jpp - // Missing column can be null - for (jcp = fjcp; jcp; jcp = jcp->Next) { - jcp->Cbn |= !jcp->Found; - jcp->Found = false; - } // endfor jcp + // Missing column can be null + for (jcp = fjcp; jcp; jcp = jcp->Next) { + jcp->Cbn |= !jcp->Found; + jcp->Found = false; + } // endfor jcp - if (tdp->Pretty != 2) { - // Read next record - switch (tjnp->ReadDB(g)) { - case RC_EF: - jsp = NULL; - break; - case RC_FX: - goto err; - default: - jsp = tjnp->GetRow(); - } // endswitch ReadDB + if (tdp->Pretty != 2) { + // Read next record + switch (tjnp->ReadDB(g)) { + case RC_EF: + jsp = NULL; + break; + case RC_FX: + goto err; + default: + jsp = tjnp->GetRow(); + } // endswitch ReadDB - } else - jsp = tjsp->GetDoc()->GetValue(i); + } else + jsp = tjsp->GetDoc()->GetValue(i); - if (!(row = (jsp) ? jsp->GetObject() : NULL)) - break; + if (!(row = (jsp) ? jsp->GetObject() : NULL)) + break; - } // endfor i + } // endfor i - if (tdp->Pretty != 2) - tjnp->CloseDB(g); + if (tdp->Pretty != 2) + tjnp->CloseDB(g); - return n; + return n; err: - if (tdp->Pretty != 2) - tjnp->CloseDB(g); + if (tdp->Pretty != 2) + tjnp->CloseDB(g); - return 0; -} // end of GetColumns + return 0; +} // end of GetColumns bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j) { - char *p, *pc = colname + strlen(colname); - int ars; - PJOB job; - PJAR jar; + char *p, *pc = colname + strlen(colname); + int ars; + PJOB job; + PJAR jar; - if ((valp = jvp ? jvp->GetValue() : NULL)) { - jcol.Type = valp->GetType(); - jcol.Len = valp->GetValLen(); - jcol.Scale = valp->GetValPrec(); - jcol.Cbn = valp->IsNull(); - } else if (!jvp || jvp->IsNull()) { - jcol.Type = TYPE_UNKNOWN; - jcol.Len = jcol.Scale = 0; - jcol.Cbn = true; - } else if (j < lvl) { - if (!fmt[bf]) - strcat(fmt, colname); + if ((valp = jvp ? jvp->GetValue() : NULL)) { + jcol.Type = valp->GetType(); + jcol.Len = valp->GetValLen(); + jcol.Scale = valp->GetValPrec(); + jcol.Cbn = valp->IsNull(); + } else if (!jvp || jvp->IsNull()) { + jcol.Type = TYPE_UNKNOWN; + jcol.Len = jcol.Scale = 0; + jcol.Cbn = true; + } else if (j < lvl) { + if (!fmt[bf]) + strcat(fmt, colname); - p = fmt + strlen(fmt); - jsp = jvp->GetJson(); + p = fmt + strlen(fmt); + jsp = jvp->GetJson(); - switch (jsp->GetType()) { - case TYPE_JOB: - job = (PJOB)jsp; + switch (jsp->GetType()) { + case TYPE_JOB: + job = (PJOB)jsp; - for (PJPR jrp = job->GetFirst(); jrp; jrp = jrp->GetNext()) { - PCSZ k = jrp->GetKey(); + for (PJPR jrp = job->GetFirst(); jrp; jrp = jrp->GetNext()) { + PCSZ k = jrp->GetKey(); - if (*k != '$') { - strncat(strncat(fmt, sep, 128), k, 128); - strncat(strncat(colname, "_", 64), k, 64); - } // endif Key + if (*k != '$') { + strncat(strncat(fmt, sep, 128), k, 128); + strncat(strncat(colname, "_", 64), k, 64); + } // endif Key - if (Find(g, jrp->GetVal(), k, j + 1)) - return true; + if (Find(g, jrp->GetVal(), k, j + 1)) + return true; - *p = *pc = 0; - } // endfor jrp + *p = *pc = 0; + } // endfor jrp - return false; - case TYPE_JAR: - jar = (PJAR)jsp; + return false; + case TYPE_JAR: + jar = (PJAR)jsp; - if (all || (tdp->Xcol && !stricmp(tdp->Xcol, key))) - ars = jar->GetSize(false); - else - ars = MY_MIN(jar->GetSize(false), 1); + if (all || (tdp->Xcol && !stricmp(tdp->Xcol, key))) + ars = jar->GetSize(false); + else + ars = MY_MIN(jar->GetSize(false), 1); - for (int k = 0; k < ars; k++) { - if (!tdp->Xcol || stricmp(tdp->Xcol, key)) { - sprintf(buf, "%d", k); + for (int k = 0; k < ars; k++) { + if (!tdp->Xcol || stricmp(tdp->Xcol, key)) { + sprintf(buf, "%d", k); - if (tdp->Uri) - strncat(strncat(fmt, sep, 128), buf, 128); - else - strncat(strncat(strncat(fmt, "[", 128), buf, 128), "]", 128); + if (tdp->Uri) + strncat(strncat(fmt, sep, 128), buf, 128); + else + strncat(strncat(strncat(fmt, "[", 128), buf, 128), "]", 128); - if (all) - strncat(strncat(colname, "_", 64), buf, 64); + if (all) + strncat(strncat(colname, "_", 64), buf, 64); - } else - strncat(fmt, (tdp->Uri ? sep : "[*]"), 128); + } else + strncat(fmt, (tdp->Uri ? sep : "[*]"), 128); - if (Find(g, jar->GetValue(k), "", j)) - return true; + if (Find(g, jar->GetValue(k), "", j)) + return true; - *p = *pc = 0; - } // endfor k + *p = *pc = 0; + } // endfor k - return false; - default: - sprintf(g->Message, "Logical error after %s", fmt); - return true; - } // endswitch Type + return false; + default: + sprintf(g->Message, "Logical error after %s", fmt); + return true; + } // endswitch Type - } else if (lvl >= 0) { - jcol.Type = TYPE_STRING; - jcol.Len = 256; - jcol.Scale = 0; - jcol.Cbn = true; - } else - return false; + } else if (lvl >= 0) { + jcol.Type = TYPE_STRING; + jcol.Len = 256; + jcol.Scale = 0; + jcol.Cbn = true; + } else + return false; - AddColumn(g); - return false; -} // end of Find + AddColumn(g); + return false; +} // end of Find void JSONDISC::AddColumn(PGLOBAL g) { - bool b = fmt[bf] != 0; // True if formatted + bool b = fmt[bf] != 0; // True if formatted - // Check whether this column was already found - for (jcp = fjcp; jcp; jcp = jcp->Next) - if (!strcmp(colname, jcp->Name)) - break; + // Check whether this column was already found + for (jcp = fjcp; jcp; jcp = jcp->Next) + if (!strcmp(colname, jcp->Name)) + break; - if (jcp) { - if (jcp->Type != jcol.Type) { - if (jcp->Type == TYPE_UNKNOWN) - jcp->Type = jcol.Type; - else if (jcol.Type != TYPE_UNKNOWN) - jcp->Type = TYPE_STRING; + if (jcp) { + if (jcp->Type != jcol.Type) { + if (jcp->Type == TYPE_UNKNOWN) + jcp->Type = jcol.Type; + else if (jcol.Type != TYPE_UNKNOWN) + jcp->Type = TYPE_STRING; - } // endif Type + } // endif Type - if (b && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) { - jcp->Fmt = PlugDup(g, fmt); - length[7] = MY_MAX(length[7], strlen(fmt)); - } // endif fmt + if (b && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) { + jcp->Fmt = PlugDup(g, fmt); + length[7] = MY_MAX(length[7], strlen(fmt)); + } // endif fmt - jcp->Len = MY_MAX(jcp->Len, jcol.Len); - jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale); - jcp->Cbn |= jcol.Cbn; - jcp->Found = true; - } else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) { - // New column - jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL)); - *jcp = jcol; - jcp->Cbn |= (i > 1); - jcp->Name = PlugDup(g, colname); - length[0] = MY_MAX(length[0], strlen(colname)); + jcp->Len = MY_MAX(jcp->Len, jcol.Len); + jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale); + jcp->Cbn |= jcol.Cbn; + jcp->Found = true; + } else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) { + // New column + jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL)); + *jcp = jcol; + jcp->Cbn |= (i > 1); + jcp->Name = PlugDup(g, colname); + length[0] = MY_MAX(length[0], strlen(colname)); - if (b) { - jcp->Fmt = PlugDup(g, fmt); - length[7] = MY_MAX(length[7], strlen(fmt)); - } else - jcp->Fmt = NULL; + if (b) { + jcp->Fmt = PlugDup(g, fmt); + length[7] = MY_MAX(length[7], strlen(fmt)); + } else + jcp->Fmt = NULL; - if (pjcp) { - jcp->Next = pjcp->Next; - pjcp->Next = jcp; - } else - fjcp = jcp; + if (pjcp) { + jcp->Next = pjcp->Next; + pjcp->Next = jcp; + } else + fjcp = jcp; - n++; - } // endif jcp + n++; + } // endif jcp - if (jcp) - pjcp = jcp; + if (jcp) + pjcp = jcp; } // end of AddColumn @@ -548,13 +548,13 @@ JSONDEF::JSONDEF(void) Limit = 1; Base = 0; Strict = false; - Sep = '.'; - Uri = NULL; - Collname = Options = Filter = NULL; - Pipe = false; - Driver = NULL; - Version = 0; - Wrapname = NULL; + Sep = '.'; + Uri = NULL; + Collname = Options = Filter = NULL; + Pipe = false; + Driver = NULL; + Version = 0; + Wrapname = NULL; } // end of JSONDEF constructor /***********************************************************************/ @@ -562,41 +562,41 @@ JSONDEF::JSONDEF(void) /***********************************************************************/ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) { - Schema = GetStringCatInfo(g, "DBname", Schema); - Jmode = (JMODE)GetIntCatInfo("Jmode", MODE_OBJECT); + Schema = GetStringCatInfo(g, "DBname", Schema); + Jmode = (JMODE)GetIntCatInfo("Jmode", MODE_OBJECT); Objname = GetStringCatInfo(g, "Object", NULL); Xcol = GetStringCatInfo(g, "Expand", NULL); Pretty = GetIntCatInfo("Pretty", 2); Limit = GetIntCatInfo("Limit", 10); Base = GetIntCatInfo("Base", 0) ? 1 : 0; - Sep = *GetStringCatInfo(g, "Separator", "."); - Accept = GetBoolCatInfo("Accept", false); + Sep = *GetStringCatInfo(g, "Separator", "."); + Accept = GetBoolCatInfo("Accept", false); - // Don't use url as uri when called from REST OEM module - if (stricmp(am, "REST") && (Uri = GetStringCatInfo(g, "Connect", NULL))) { + // Don't use url as MONGO uri when called from REST + if (stricmp(am, "REST") && (Uri = GetStringCatInfo(g, "Connect", NULL))) { #if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT) - Collname = GetStringCatInfo(g, "Name", - (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name); - Collname = GetStringCatInfo(g, "Tabname", Collname); - Options = GetStringCatInfo(g, "Colist", NULL); - Filter = GetStringCatInfo(g, "Filter", NULL); - Pipe = GetBoolCatInfo("Pipeline", false); - Driver = GetStringCatInfo(g, "Driver", NULL); - Version = GetIntCatInfo("Version", 3); - Pretty = 0; + Collname = GetStringCatInfo(g, "Name", + (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name); + Collname = GetStringCatInfo(g, "Tabname", Collname); + Options = GetStringCatInfo(g, "Colist", NULL); + Filter = GetStringCatInfo(g, "Filter", NULL); + Pipe = GetBoolCatInfo("Pipeline", false); + Driver = GetStringCatInfo(g, "Driver", NULL); + Version = GetIntCatInfo("Version", 3); + Pretty = 0; #if defined(JAVA_SUPPORT) - if (Version == 2) - Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface"); - else - Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface"); + if (Version == 2) + Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface"); + else + Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface"); #endif // JAVA_SUPPORT #else // !MONGO_SUPPORT - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); - return true; + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); + return true; #endif // !MONGO_SUPPORT - } // endif Uri + } // endif Uri - return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff); + return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff); } // end of DefineAM /***********************************************************************/ @@ -604,6 +604,9 @@ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) /***********************************************************************/ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) { + if (trace(1)) + htrc("JSON GetTable Pretty=%d Uri=%s\n", Pretty, SVP(Uri)); + if (Catfunc == FNC_COL) return new(g)TDBJCL(this); @@ -618,47 +621,47 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) !(tmp == TMP_FORCE && (m == MODE_UPDATE || m == MODE_DELETE)); - if (Uri) { - if (Driver && toupper(*Driver) == 'C') { + if (Uri) { + if (Driver && toupper(*Driver) == 'C') { #if defined(CMGO_SUPPORT) - txfp = new(g) CMGFAM(this); + txfp = new(g) CMGFAM(this); #else - sprintf(g->Message, "Mongo %s Driver not available", "C"); - return NULL; + sprintf(g->Message, "Mongo %s Driver not available", "C"); + return NULL; #endif - } else if (Driver && toupper(*Driver) == 'J') { + } else if (Driver && toupper(*Driver) == 'J') { #if defined(JAVA_SUPPORT) - txfp = new(g) JMGFAM(this); + txfp = new(g) JMGFAM(this); #else - sprintf(g->Message, "Mongo %s Driver not available", "Java"); - return NULL; + sprintf(g->Message, "Mongo %s Driver not available", "Java"); + return NULL; #endif - } else { // Driver not specified + } else { // Driver not specified #if defined(CMGO_SUPPORT) - txfp = new(g) CMGFAM(this); + txfp = new(g) CMGFAM(this); #elif defined(JAVA_SUPPORT) - txfp = new(g) JMGFAM(this); -#else // !MONGO_SUPPORT - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); - return NULL; + txfp = new(g) JMGFAM(this); +#else // !MONGO_SUPPORT + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO"); + return NULL; #endif // !MONGO_SUPPORT - } // endif Driver + } // endif Driver - } else if (Zipped) { + } else if (Zipped) { #if defined(ZIP_SUPPORT) - if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) { - txfp = new(g) UNZFAM(this); - } else if (m == MODE_INSERT) { - txfp = new(g) ZIPFAM(this); - } else { - strcpy(g->Message, "UPDATE/DELETE not supported for ZIP"); - return NULL; - } // endif's m + if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) { + txfp = new(g) UNZFAM(this); + } else if (m == MODE_INSERT) { + txfp = new(g) ZIPFAM(this); + } else { + strcpy(g->Message, "UPDATE/DELETE not supported for ZIP"); + return NULL; + } // endif's m #else // !ZIP_SUPPORT - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); - return NULL; + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; #endif // !ZIP_SUPPORT - } else if (Compressed) { + } else if (Compressed) { #if defined(GZ_SUPPORT) if (Compressed == 1) txfp = new(g) GZFAM(this); @@ -668,7 +671,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ"); return NULL; #endif // !GZ_SUPPORT - } else if (map) + } else if (map) txfp = new(g) MAPFAM(this); else txfp = new(g) DOSFAM(this); @@ -676,41 +679,41 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) // Txfp must be set for TDBDOS tdbp = new(g) TDBJSN(this, txfp); - if (Lrecl) { - // Allocate the parse work memory - PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); - memset(G, 0, sizeof(GLOBAL)); - G->Sarea_Size = Lrecl * 10; - G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); - PlugSubSet(G->Sarea, G->Sarea_Size); - G->jump_level = 0; - ((TDBJSN*)tdbp)->G = G; - } else { - strcpy(g->Message, "LRECL is not defined"); - return NULL; - } // endif Lrecl + if (Lrecl) { + // Allocate the parse work memory + PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL)); + memset(G, 0, sizeof(GLOBAL)); + G->Sarea_Size = Lrecl * 10; + G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size); + PlugSubSet(G->Sarea, G->Sarea_Size); + G->jump_level = 0; + ((TDBJSN*)tdbp)->G = G; + } else { + strcpy(g->Message, "LRECL is not defined"); + return NULL; + } // endif Lrecl - } else { - if (Zipped) { + } else { + if (Zipped) { #if defined(ZIP_SUPPORT) - if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) { - txfp = new(g) UNZFAM(this); - } else if (m == MODE_INSERT) { - strcpy(g->Message, "INSERT supported only for zipped JSON when pretty=0"); - return NULL; - } else { - strcpy(g->Message, "UPDATE/DELETE not supported for ZIP"); - return NULL; - } // endif's m + if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) { + txfp = new(g) UNZFAM(this); + } else if (m == MODE_INSERT) { + strcpy(g->Message, "INSERT supported only for zipped JSON when pretty=0"); + return NULL; + } else { + strcpy(g->Message, "UPDATE/DELETE not supported for ZIP"); + return NULL; + } // endif's m #else // !ZIP_SUPPORT - sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); - return NULL; + sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP"); + return NULL; #endif // !ZIP_SUPPORT - } else - txfp = new(g) MAPFAM(this); + } else + txfp = new(g) MAPFAM(this); tdbp = new(g) TDBJSON(this, txfp); - ((TDBJSON*)tdbp)->G = g; + ((TDBJSON*)tdbp)->G = g; } // endif Pretty if (Multiple) @@ -738,16 +741,16 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp) Limit = tdp->Limit; Pretty = tdp->Pretty; B = tdp->Base ? 1 : 0; - Sep = tdp->Sep; + Sep = tdp->Sep; Strict = tdp->Strict; } else { Jmode = MODE_OBJECT; Objname = NULL; - Xcol = NULL; + Xcol = NULL; Limit = 1; Pretty = 0; B = 0; - Sep = '.'; + Sep = '.'; Strict = false; } // endif tdp @@ -761,7 +764,7 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp) TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp) { - G = NULL; + G = NULL; Top = tdbp->Top; Row = tdbp->Row; Val = tdbp->Val; @@ -777,7 +780,7 @@ TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp) SameRow = tdbp->SameRow; Xval = tdbp->Xval; B = tdbp->B; - Sep = tdbp->Sep; + Sep = tdbp->Sep; Pretty = tdbp->Pretty; Strict = tdbp->Strict; Comma = tdbp->Comma; @@ -786,7 +789,7 @@ TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp) // Used for update PTDB TDBJSN::Clone(PTABS t) { - G = NULL; + G = NULL; PTDB tp; PJCOL cp1, cp2; PGLOBAL g = t->G; @@ -860,33 +863,33 @@ PJSON TDBJSN::FindRow(PGLOBAL g) PJSON jsp = Row; PJVAL val = NULL; - for (objpath = PlugDup(g, Objname); jsp && objpath; objpath = p) { - if ((p = strchr(objpath, Sep))) - *p++ = 0; + for (objpath = PlugDup(g, Objname); jsp && objpath; objpath = p) { + if ((p = strchr(objpath, Sep))) + *p++ = 0; - if (*objpath != '[' && !IsNum(objpath)) { // objpass is a key - val = (jsp->GetType() == TYPE_JOB) ? - jsp->GetObject()->GetValue(objpath) : NULL; - } else { - if (*objpath == '[') { - if (objpath[strlen(objpath) - 1] == ']') - objpath++; - else - return NULL; - } // endif [ + if (*objpath != '[' && !IsNum(objpath)) { // objpass is a key + val = (jsp->GetType() == TYPE_JOB) ? + jsp->GetObject()->GetValue(objpath) : NULL; + } else { + if (*objpath == '[') { + if (objpath[strlen(objpath) - 1] == ']') + objpath++; + else + return NULL; + } // endif [ - val = (jsp->GetType() == TYPE_JAR) ? - jsp->GetArray()->GetValue(atoi(objpath) - B) : NULL; - } // endif objpath + val = (jsp->GetType() == TYPE_JAR) ? + jsp->GetArray()->GetValue(atoi(objpath) - B) : NULL; + } // endif objpath - jsp = (val) ? val->GetJson() : NULL; - } // endfor objpath + jsp = (val) ? val->GetJson() : NULL; + } // endfor objpath return jsp; } // end of FindRow /***********************************************************************/ -/* OpenDB: Data Base open routine for JSN access method. */ +/* OpenDB: Data Base open routine for JSN access method. */ /***********************************************************************/ bool TDBJSN::OpenDB(PGLOBAL g) { @@ -911,15 +914,15 @@ bool TDBJSN::OpenDB(PGLOBAL g) return true; } // endswitch Jmode - } // endif Use + } // endif Use - if (TDBDOS::OpenDB(g)) - return true; + if (TDBDOS::OpenDB(g)) + return true; - if (Xcol) - To_Filter = NULL; // Imcompatible + if (Xcol) + To_Filter = NULL; // Imcompatible - return false; + return false; } // end of OpenDB /***********************************************************************/ @@ -969,27 +972,27 @@ int TDBJSN::ReadDB(PGLOBAL g) NextSame = 0; M++; return RC_OK; - } else if ((rc = TDBDOS::ReadDB(g)) == RC_OK) { - if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK)) - // Deferred reading failed - return rc; + } else if ((rc = TDBDOS::ReadDB(g)) == RC_OK) { + if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK)) + // Deferred reading failed + return rc; - // Recover the memory used for parsing - PlugSubSet(G->Sarea, G->Sarea_Size); + // Recover the memory used for parsing + PlugSubSet(G->Sarea, G->Sarea_Size); - if ((Row = ParseJson(G, To_Line, strlen(To_Line), &Pretty, &Comma))) { - Row = FindRow(g); - SameRow = 0; - Fpos++; - M = 1; - rc = RC_OK; - } else if (Pretty != 1 || strcmp(To_Line, "]")) { - strcpy(g->Message, G->Message); - rc = RC_FX; - } else - rc = RC_EF; + if ((Row = ParseJson(G, To_Line, strlen(To_Line), &Pretty, &Comma))) { + Row = FindRow(g); + SameRow = 0; + Fpos++; + M = 1; + rc = RC_OK; + } else if (Pretty != 1 || strcmp(To_Line, "]")) { + strcpy(g->Message, G->Message); + rc = RC_FX; + } else + rc = RC_EF; - } // endif ReadDB + } // endif ReadDB return rc; } // end of ReadDB @@ -999,68 +1002,68 @@ int TDBJSN::ReadDB(PGLOBAL g) /***********************************************************************/ int TDBJSN::MakeTopTree(PGLOBAL g, PJSON jsp) { - if (Objname) { - if (!Val) { - // Parse and allocate Objname item(s) - char *p; - char *objpath = PlugDup(g, Objname); - int i; - PJOB objp; - PJAR arp; - PJVAL val = NULL; + if (Objname) { + if (!Val) { + // Parse and allocate Objname item(s) + char *p; + char *objpath = PlugDup(g, Objname); + int i; + PJOB objp; + PJAR arp; + PJVAL val = NULL; - Top = NULL; + Top = NULL; - for (; objpath; objpath = p) { - if ((p = strchr(objpath, Sep))) - *p++ = 0; + for (; objpath; objpath = p) { + if ((p = strchr(objpath, Sep))) + *p++ = 0; - if (*objpath != '[' && !IsNum(objpath)) { - objp = new(g) JOBJECT; + if (*objpath != '[' && !IsNum(objpath)) { + objp = new(g) JOBJECT; - if (!Top) - Top = objp; + if (!Top) + Top = objp; - if (val) - val->SetValue(objp); + if (val) + val->SetValue(objp); - val = new(g) JVALUE; - objp->SetValue(g, val, objpath); - } else { - if (*objpath == '[') { - // Old style - if (objpath[strlen(objpath) - 1] != ']') { - sprintf(g->Message, "Invalid Table path %s", Objname); - return RC_FX; - } else - objpath++; + val = new(g) JVALUE; + objp->SetValue(g, val, objpath); + } else { + if (*objpath == '[') { + // Old style + if (objpath[strlen(objpath) - 1] != ']') { + sprintf(g->Message, "Invalid Table path %s", Objname); + return RC_FX; + } else + objpath++; - } // endif objpath + } // endif objpath - arp = new(g) JARRAY; + arp = new(g) JARRAY; - if (!Top) - Top = arp; + if (!Top) + Top = arp; - if (val) - val->SetValue(arp); + if (val) + val->SetValue(arp); - val = new(g) JVALUE; - i = atoi(objpath) - B; - arp->SetValue(g, val, i); - arp->InitArray(g); - } // endif objpath + val = new(g) JVALUE; + i = atoi(objpath) - B; + arp->SetValue(g, val, i); + arp->InitArray(g); + } // endif objpath - } // endfor p + } // endfor p - Val = val; - } // endif Val + Val = val; + } // endif Val - Val->SetValue(jsp); - } else - Top = jsp; + Val->SetValue(jsp); + } else + Top = jsp; - return RC_OK; + return RC_OK; } // end of MakeTopTree /***********************************************************************/ @@ -1095,11 +1098,11 @@ int TDBJSN::MakeTopTree(PGLOBAL g, PJSON jsp) /***********************************************************************/ int TDBJSN::WriteDB(PGLOBAL g) { - int rc = TDBDOS::WriteDB(g); + int rc = TDBDOS::WriteDB(g); - PlugSubSet(G->Sarea, G->Sarea_Size); - Row->Clear(); - return rc; + PlugSubSet(G->Sarea, G->Sarea_Size); + Row->Clear(); + return rc; } // end of WriteDB /* ---------------------------- JSONCOL ------------------------------ */ @@ -1111,12 +1114,12 @@ JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) : DOSCOL(g, cdp, tdbp, cprec, i, "DOS") { Tjp = (TDBJSN *)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp); - G = Tjp->G; + G = Tjp->G; Jpath = cdp->GetFmt(); MulVal = NULL; Nodes = NULL; Nod = 0; - Sep = Tjp->Sep; + Sep = Tjp->Sep; Xnod = -1; Xpd = false; Parsed = false; @@ -1128,14 +1131,14 @@ JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) /***********************************************************************/ JSONCOL::JSONCOL(JSONCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp) { - G = col1->G; + G = col1->G; Tjp = col1->Tjp; Jpath = col1->Jpath; MulVal = col1->MulVal; Nodes = col1->Nodes; Nod = col1->Nod; - Sep = col1->Sep; - Xnod = col1->Xnod; + Sep = col1->Sep; + Xnod = col1->Xnod; Xpd = col1->Xpd; Parsed = col1->Parsed; } // end of JSONCOL copy constructor @@ -1153,7 +1156,7 @@ bool JSONCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check) return true; Tjp = (TDBJSN*)To_Tdb; - G = Tjp->G; + G = Tjp->G; return false; } // end of SetBuffer @@ -1179,130 +1182,130 @@ bool JSONCOL::CheckExpand(PGLOBAL g, int i, PSZ nm, bool b) /***********************************************************************/ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm) { - int n; - bool dg = true, b = false; - PJNODE jnp = &Nodes[i]; + int n; + bool dg = true, b = false; + PJNODE jnp = &Nodes[i]; - //if (*p == '[') p++; // Old syntax .[ or :[ - n = (int)strlen(p); + //if (*p == '[') p++; // Old syntax .[ or :[ + n = (int)strlen(p); - if (*p) { - if (p[n - 1] == ']') { - p[--n] = 0; - } else if (!IsNum(p)) { - // Wrong array specification - sprintf(g->Message, "Invalid array specification %s for %s", p, Name); - return true; - } // endif p + if (*p) { + if (p[n - 1] == ']') { + p[--n] = 0; + } else if (!IsNum(p)) { + // Wrong array specification + sprintf(g->Message, "Invalid array specification %s for %s", p, Name); + return true; + } // endif p - } else - b = true; + } else + b = true; - // To check whether a numeric Rank was specified - dg = IsNum(p); + // To check whether a numeric Rank was specified + dg = IsNum(p); - if (!n) { - // Default specifications - if (CheckExpand(g, i, nm, false)) - return true; - else if (jnp->Op != OP_EXP) { - if (b) { - // Return 1st value (B is the index base) - jnp->Rank = Tjp->B; - jnp->Op = OP_EQ; - } else if (!Value->IsTypeNum()) { - jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING); - jnp->Op = OP_CNC; - } else - jnp->Op = OP_ADD; + if (!n) { + // Default specifications + if (CheckExpand(g, i, nm, false)) + return true; + else if (jnp->Op != OP_EXP) { + if (b) { + // Return 1st value (B is the index base) + jnp->Rank = Tjp->B; + jnp->Op = OP_EQ; + } else if (!Value->IsTypeNum()) { + jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING); + jnp->Op = OP_CNC; + } else + jnp->Op = OP_ADD; - } // endif OP + } // endif OP - } else if (dg) { - // Return nth value - jnp->Rank = atoi(p) - Tjp->B; - jnp->Op = OP_EQ; - } else if (n == 1) { - // Set the Op value; - if (Sep == ':') - switch (*p) { - case '*': *p = 'x'; break; - case 'x': - case 'X': *p = '*'; break; // Expand this array - default: break; - } // endswitch p + } else if (dg) { + // Return nth value + jnp->Rank = atoi(p) - Tjp->B; + jnp->Op = OP_EQ; + } else if (n == 1) { + // Set the Op value; + if (Sep == ':') + switch (*p) { + case '*': *p = 'x'; break; + case 'x': + case 'X': *p = '*'; break; // Expand this array + default: break; + } // endswitch p - switch (*p) { - case '+': jnp->Op = OP_ADD; break; - case 'x': jnp->Op = OP_MULT; break; - case '>': jnp->Op = OP_MAX; break; - case '<': jnp->Op = OP_MIN; break; - case '!': jnp->Op = OP_SEP; break; // Average - case '#': jnp->Op = OP_NUM; break; - case '*': // Expand this array - if (!Tjp->Xcol && nm) { - Xpd = true; - jnp->Op = OP_EXP; - Tjp->Xval = i; - Tjp->Xcol = nm; - } else if (CheckExpand(g, i, nm, true)) - return true; + switch (*p) { + case '+': jnp->Op = OP_ADD; break; + case 'x': jnp->Op = OP_MULT; break; + case '>': jnp->Op = OP_MAX; break; + case '<': jnp->Op = OP_MIN; break; + case '!': jnp->Op = OP_SEP; break; // Average + case '#': jnp->Op = OP_NUM; break; + case '*': // Expand this array + if (!Tjp->Xcol && nm) { + Xpd = true; + jnp->Op = OP_EXP; + Tjp->Xval = i; + Tjp->Xcol = nm; + } else if (CheckExpand(g, i, nm, true)) + return true; - break; - default: - sprintf(g->Message, - "Invalid function specification %c for %s", *p, Name); - return true; - } // endswitch *p + break; + default: + sprintf(g->Message, + "Invalid function specification %c for %s", *p, Name); + return true; + } // endswitch *p - } else if (*p == '"' && p[n - 1] == '"') { - // This is a concat specification - jnp->Op = OP_CNC; + } else if (*p == '"' && p[n - 1] == '"') { + // This is a concat specification + jnp->Op = OP_CNC; - if (n > 2) { - // Set concat intermediate string - p[n - 1] = 0; - jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING); - } // endif n + if (n > 2) { + // Set concat intermediate string + p[n - 1] = 0; + jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING); + } // endif n - } else { - sprintf(g->Message, "Wrong array specification for %s", Name); - return true; - } // endif's + } else { + sprintf(g->Message, "Wrong array specification for %s", Name); + return true; + } // endif's - // For calculated arrays, a local Value must be used - switch (jnp->Op) { - case OP_NUM: - jnp->Valp = AllocateValue(g, TYPE_INT); - break; - case OP_ADD: - case OP_MULT: - case OP_SEP: - if (!IsTypeChar(Buf_Type)) - jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision()); - else - jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2); + // For calculated arrays, a local Value must be used + switch (jnp->Op) { + case OP_NUM: + jnp->Valp = AllocateValue(g, TYPE_INT); + break; + case OP_ADD: + case OP_MULT: + case OP_SEP: + if (!IsTypeChar(Buf_Type)) + jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision()); + else + jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2); - break; - case OP_MIN: - case OP_MAX: - jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision()); - break; - case OP_CNC: - if (IsTypeChar(Buf_Type)) - jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision()); - else - jnp->Valp = AllocateValue(g, TYPE_STRING, 512); + break; + case OP_MIN: + case OP_MAX: + jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision()); + break; + case OP_CNC: + if (IsTypeChar(Buf_Type)) + jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision()); + else + jnp->Valp = AllocateValue(g, TYPE_STRING, 512); - break; - default: - break; - } // endswitch Op + break; + default: + break; + } // endswitch Op - if (jnp->Valp) - MulVal = AllocateValue(g, jnp->Valp); + if (jnp->Valp) + MulVal = AllocateValue(g, jnp->Valp); - return false; + return false; } // end of SetArrayOptions /***********************************************************************/ @@ -1313,87 +1316,87 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm) /***********************************************************************/ bool JSONCOL::ParseJpath(PGLOBAL g) { - char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL; - int i; - bool a, mul = false; + char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL; + int i; + bool a, mul = false; - if (Parsed) - return false; // Already done - else if (InitValue(g)) - return true; - else if (!Jpath) - Jpath = Name; + if (Parsed) + return false; // Already done + else if (InitValue(g)) + return true; + else if (!Jpath) + Jpath = Name; - if (To_Tdb->GetOrig()) { - // This is an updated column, get nodes from origin - for (PJCOL colp = (PJCOL)Tjp->GetColumns(); colp; - colp = (PJCOL)colp->GetNext()) - if (!stricmp(Name, colp->GetName())) { - Nod = colp->Nod; - Nodes = colp->Nodes; - Xpd = colp->Xpd; - goto fin; - } // endif Name + if (To_Tdb->GetOrig()) { + // This is an updated column, get nodes from origin + for (PJCOL colp = (PJCOL)Tjp->GetColumns(); colp; + colp = (PJCOL)colp->GetNext()) + if (!stricmp(Name, colp->GetName())) { + Nod = colp->Nod; + Nodes = colp->Nodes; + Xpd = colp->Xpd; + goto fin; + } // endif Name - sprintf(g->Message, "Cannot parse updated column %s", Name); - return true; - } // endif To_Orig + sprintf(g->Message, "Cannot parse updated column %s", Name); + return true; + } // endif To_Orig - pbuf = PlugDup(g, Jpath); - if (*pbuf == '$') pbuf++; - if (*pbuf == Sep) pbuf++; - if (*pbuf == '[') p1 = pbuf++; + pbuf = PlugDup(g, Jpath); + if (*pbuf == '$') pbuf++; + if (*pbuf == Sep) pbuf++; + if (*pbuf == '[') p1 = pbuf++; - // Estimate the required number of nodes - for (i = 0, p = pbuf; (p = NextChr(p, Sep)); i++, p++) - Nod++; // One path node found + // Estimate the required number of nodes + for (i = 0, p = pbuf; (p = NextChr(p, Sep)); i++, p++) + Nod++; // One path node found - Nodes = (PJNODE)PlugSubAlloc(g, NULL, (++Nod) * sizeof(JNODE)); - memset(Nodes, 0, (Nod) * sizeof(JNODE)); + Nodes = (PJNODE)PlugSubAlloc(g, NULL, (++Nod) * sizeof(JNODE)); + memset(Nodes, 0, (Nod) * sizeof(JNODE)); - // Analyze the Jpath for this column - for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) { - a = (p1 != NULL); - p1 = strchr(p, '['); - p2 = strchr(p, Sep); + // Analyze the Jpath for this column + for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) { + a = (p1 != NULL); + p1 = strchr(p, '['); + p2 = strchr(p, Sep); - if (!p2) - p2 = p1; - else if (p1) { - if (p1 < p2) - p2 = p1; - else if (p1 == p2 + 1) - *p2++ = 0; // Old syntax .[ or :[ - else - p1 = NULL; + if (!p2) + p2 = p1; + else if (p1) { + if (p1 < p2) + p2 = p1; + else if (p1 == p2 + 1) + *p2++ = 0; // Old syntax .[ or :[ + else + p1 = NULL; - } // endif p1 + } // endif p1 - if (p2) - *p2++ = 0; + if (p2) + *p2++ = 0; - // Jpath must be explicit - if (a || *p == 0 || *p == '[' || IsNum(p)) { - // Analyse intermediate array processing - if (SetArrayOptions(g, p, i, Nodes[i - 1].Key)) - return true; + // Jpath must be explicit + if (a || *p == 0 || *p == '[' || IsNum(p)) { + // Analyse intermediate array processing + if (SetArrayOptions(g, p, i, Nodes[i - 1].Key)) + return true; - } else if (*p == '*') { - // Return JSON - Nodes[i].Op = OP_XX; - } else { - Nodes[i].Key = p; - Nodes[i].Op = OP_EXIST; - } // endif's + } else if (*p == '*') { + // Return JSON + Nodes[i].Op = OP_XX; + } else { + Nodes[i].Key = p; + Nodes[i].Op = OP_EXIST; + } // endif's - } // endfor i, p + } // endfor i, p - Nod = i; + Nod = i; fin: - MulVal = AllocateValue(g, Value); - Parsed = true; - return false; + MulVal = AllocateValue(g, Value); + Parsed = true; + return false; } // end of ParseJpath /***********************************************************************/ @@ -1401,66 +1404,66 @@ fin: /***********************************************************************/ PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj) { - if (Jpath) { - char *p1, *p2, *mgopath; - int i = 0; + if (Jpath) { + char *p1, *p2, *mgopath; + int i = 0; - if (strcmp(Jpath, "*")) { - p1 = Jpath; - if (*p1 == '$') p1++; - if (*p1 == '.') p1++; - mgopath = PlugDup(g, p1); - } else - return NULL; + if (strcmp(Jpath, "*")) { + p1 = Jpath; + if (*p1 == '$') p1++; + if (*p1 == '.') p1++; + mgopath = PlugDup(g, p1); + } else + return NULL; - for (p1 = p2 = mgopath; *p1; p1++) - if (i) { // Inside [] - if (isdigit(*p1)) { - if (!proj) - *p2++ = *p1; + for (p1 = p2 = mgopath; *p1; p1++) + if (i) { // Inside [] + if (isdigit(*p1)) { + if (!proj) + *p2++ = *p1; - } else if (*p1 == ']' && i == 1) { - if (proj && p1[1] == '.') - p1++; + } else if (*p1 == ']' && i == 1) { + if (proj && p1[1] == '.') + p1++; - i = 0; - } else if (*p1 == '.' && i == 2) { - if (!proj) - *p2++ = '.'; + i = 0; + } else if (*p1 == '.' && i == 2) { + if (!proj) + *p2++ = '.'; - i = 0; - } else if (!proj) - return NULL; - - } else switch (*p1) { - case ':': - case '.': - if (isdigit(p1[1])) - i = 2; + i = 0; + } else if (!proj) + return NULL; - *p2++ = '.'; - break; - case '[': - if (*(p2 - 1) != '.') - *p2++ = '.'; + } else switch (*p1) { + case ':': + case '.': + if (isdigit(p1[1])) + i = 2; - i = 1; - break; - case '*': - if (*(p2 - 1) == '.' && !*(p1 + 1)) { - p2--; // Suppress last :* - break; - } // endif p2 + *p2++ = '.'; + break; + case '[': + if (*(p2 - 1) != '.') + *p2++ = '.'; - default: - *p2++ = *p1; - break; - } // endswitch p1; + i = 1; + break; + case '*': + if (*(p2 - 1) == '.' && !*(p1 + 1)) { + p2--; // Suppress last :* + break; + } // endif p2 - *p2 = 0; - return mgopath; - } else - return NULL; + default: + *p2++ = *p1; + break; + } // endswitch p1; + + *p2 = 0; + return mgopath; + } else + return NULL; } // end of GetJpath @@ -1469,7 +1472,7 @@ PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj) /***********************************************************************/ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp) { - if (Value->IsTypeNum()) { + if (Value->IsTypeNum()) { strcpy(g->Message, "Cannot make Json for a numeric column"); Value->Reset(); } else @@ -1484,22 +1487,22 @@ PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp) void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n) { if (val) { - vp->SetNull(false); + vp->SetNull(false); switch (val->GetValType()) { case TYPE_STRG: case TYPE_INTG: - case TYPE_BINT: - case TYPE_DBL: - case TYPE_DTM: - vp->SetValue_pval(val->GetValue()); + case TYPE_BINT: + case TYPE_DBL: + case TYPE_DTM: + vp->SetValue_pval(val->GetValue()); break; case TYPE_BOOL: if (vp->IsTypeNum()) vp->SetValue(val->GetInteger() ? 1 : 0); else vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false")); - + break; case TYPE_JAR: SetJsonValue(g, vp, val->GetArray()->GetValue(0), n); @@ -1509,16 +1512,16 @@ void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n) vp->SetValue_psz(val->GetObject()->GetText(g, NULL)); break; // } // endif Type - - default: - vp->Reset(); - vp->SetNull(true); - } // endswitch Type - } else { - vp->Reset(); - vp->SetNull(true); - } // endif val + default: + vp->Reset(); + vp->SetNull(true); + } // endswitch Type + + } else { + vp->Reset(); + vp->SetNull(true); + } // endif val } // end of SetJsonValue @@ -1530,8 +1533,8 @@ void JSONCOL::ReadColumn(PGLOBAL g) if (!Tjp->SameRow || Xnod >= Tjp->SameRow) Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0)); - if (Xpd && Value->IsNull() && !((PJDEF)Tjp->To_Def)->Accept) - throw("Null expandable JSON value"); + if (Xpd && Value->IsNull() && !((PJDEF)Tjp->To_Def)->Accept) + throw("Null expandable JSON value"); // Set null when applicable if (!Nullable) @@ -1579,11 +1582,11 @@ PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i) else return CalculateArray(g, arp, i); - } else { - // Unexpected array, unwrap it as [0] - val = arp->GetValue(0); - i--; - } // endif's + } else { + // Unexpected array, unwrap it as [0] + val = arp->GetValue(0); + i--; + } // endif's break; case TYPE_JVAL: @@ -1612,17 +1615,17 @@ PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n) PJVAL jvp; JVALUE jval; - if (!ars) { - Value->Reset(); - Value->SetNull(true); - Tjp->NextSame = 0; - return Value; - } // endif ars + if (!ars) { + Value->Reset(); + Value->SetNull(true); + Tjp->NextSame = 0; + return Value; + } // endif ars if (!(jvp = arp->GetValue((Nodes[n].Rx = Nodes[n].Nx)))) { strcpy(g->Message, "Logical error expanding array"); - throw 666; - } // endif jvp + throw 666; + } // endif jvp if (n < Nod - 1 && jvp->GetJson()) { jval.SetValue(GetColumnValue(g, jvp->GetJson(), n + 1)); @@ -1637,7 +1640,7 @@ PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n) Xnod = n; Tjp->NextSame = Xnod; - } // endif NextSame + } // endif NextSame SetJsonValue(g, Value, jvp, n); return Value; @@ -1648,58 +1651,58 @@ PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n) /***********************************************************************/ PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n) { - int i, ars, nv = 0, nextsame = Tjp->NextSame; - bool err; + int i, ars, nv = 0, nextsame = Tjp->NextSame; + bool err; OPVAL op = Nodes[n].Op; PVAL val[2], vp = Nodes[n].Valp; PJVAL jvrp, jvp; JVALUE jval; vp->Reset(); - ars = MY_MIN(Tjp->Limit, arp->size()); + ars = MY_MIN(Tjp->Limit, arp->size()); - if (trace(1)) - htrc("CalculateArray: size=%d op=%d nextsame=%d\n", - ars, op, nextsame); + if (trace(1)) + htrc("CalculateArray: size=%d op=%d nextsame=%d\n", + ars, op, nextsame); - for (i = 0; i < ars; i++) { - jvrp = arp->GetValue(i); + for (i = 0; i < ars; i++) { + jvrp = arp->GetValue(i); - if (trace(1)) - htrc("i=%d nv=%d\n", i, nv); + if (trace(1)) + htrc("i=%d nv=%d\n", i, nv); - if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) do { - if (jvrp->IsNull()) { - jvrp->Value = AllocateValue(g, GetJsonNull(), TYPE_STRING); - jvp = jvrp; - } else if (n < Nod - 1 && jvrp->GetJson()) { + if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) do { + if (jvrp->IsNull()) { + jvrp->Value = AllocateValue(g, GetJsonNull(), TYPE_STRING); + jvp = jvrp; + } else if (n < Nod - 1 && jvrp->GetJson()) { Tjp->NextSame = nextsame; jval.SetValue(GetColumnValue(g, jvrp->GetJson(), n + 1)); jvp = &jval; } else jvp = jvrp; - - if (trace(1)) - htrc("jvp=%s null=%d\n", - jvp->GetString(g), jvp->IsNull() ? 1 : 0); - if (!nv++) { + if (trace(1)) + htrc("jvp=%s null=%d\n", + jvp->GetString(g), jvp->IsNull() ? 1 : 0); + + if (!nv++) { SetJsonValue(g, vp, jvp, n); continue; } else SetJsonValue(g, MulVal, jvp, n); - if (!MulVal->IsNull()) { - switch (op) { + if (!MulVal->IsNull()) { + switch (op) { case OP_CNC: if (Nodes[n].CncVal) { val[0] = Nodes[n].CncVal; err = vp->Compute(g, val, 1, op); } // endif CncVal - + val[0] = MulVal; err = vp->Compute(g, val, 1, op); - break; + break; // case OP_NUM: case OP_SEP: val[0] = Nodes[n].Valp; @@ -1714,16 +1717,16 @@ PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n) if (err) vp->Reset(); - - if (trace(1)) { - char buf(32); - htrc("vp='%s' err=%d\n", - vp->GetCharString(&buf), err ? 1 : 0); + if (trace(1)) { + char buf(32); - } // endif trace + htrc("vp='%s' err=%d\n", + vp->GetCharString(&buf), err ? 1 : 0); - } // endif Null + } // endif trace + + } // endif Null } while (Tjp->NextSame > nextsame); @@ -1753,8 +1756,8 @@ PJSON JSONCOL::GetRow(PGLOBAL g) PJAR arp; PJSON nwr, row = Tjp->Row; - for (int i = 0; i < Nod && row; i++) { - if (Nodes[i+1].Op == OP_XX) + for (int i = 0; i < Nod && row; i++) { + if (Nodes[i+1].Op == OP_XX) break; else switch (row->GetType()) { case TYPE_JOB: @@ -1765,19 +1768,19 @@ PJSON JSONCOL::GetRow(PGLOBAL g) val = ((PJOB)row)->GetValue(Nodes[i].Key); break; case TYPE_JAR: - arp = (PJAR)row; + arp = (PJAR)row; - if (!Nodes[i].Key) { + if (!Nodes[i].Key) { if (Nodes[i].Op == OP_EQ) val = arp->GetValue(Nodes[i].Rank); else val = arp->GetValue(Nodes[i].Rx); } else { - // Unexpected array, unwrap it as [0] - val = arp->GetValue(0); - i--; - } // endif Nodes + // Unexpected array, unwrap it as [0] + val = arp->GetValue(0); + i--; + } // endif Nodes break; case TYPE_JVAL: @@ -1827,10 +1830,10 @@ PJSON JSONCOL::GetRow(PGLOBAL g) /***********************************************************************/ void JSONCOL::WriteColumn(PGLOBAL g) { - if (Xpd && Tjp->Pretty < 2) { - strcpy(g->Message, "Cannot write expanded column when Pretty is not 2"); - throw 666; - } // endif Xpd + if (Xpd && Tjp->Pretty < 2) { + strcpy(g->Message, "Cannot write expanded column when Pretty is not 2"); + throw 666; + } // endif Xpd /*********************************************************************/ /* Check whether this node must be written. */ @@ -1864,8 +1867,8 @@ void JSONCOL::WriteColumn(PGLOBAL g) if (!(jsp = ParseJson(G, s, (int)strlen(s)))) { strcpy(g->Message, s); - throw 666; - } // endif jsp + throw 666; + } // endif jsp if (arp) { if (Nod > 1 && Nodes[Nod-2].Op == OP_EQ) @@ -1887,10 +1890,10 @@ void JSONCOL::WriteColumn(PGLOBAL g) // fall through case TYPE_DATE: case TYPE_INT: - case TYPE_TINY: - case TYPE_SHORT: - case TYPE_BIGINT: - case TYPE_DOUBLE: + case TYPE_TINY: + case TYPE_SHORT: + case TYPE_BIGINT: + case TYPE_DOUBLE: if (arp) { if (Nodes[Nod-1].Op == OP_EQ) arp->SetValue(G, new(G) JVALUE(G, Value), Nodes[Nod-1].Rank); @@ -1981,7 +1984,7 @@ int TDBJSON::MakeDocument(PGLOBAL g) return RC_OK; /*********************************************************************/ - /* Create the mapping file object in mode read. */ + /* Create the mapping file object in mode read. */ /*********************************************************************/ Mode = MODE_READ; @@ -2010,70 +2013,70 @@ int TDBJSON::MakeDocument(PGLOBAL g) if (!jsp && g->Message[0]) return RC_FX; - if ((objpath = PlugDup(g, Objname))) { - if (*objpath == '$') objpath++; - if (*objpath == '.') objpath++; + if ((objpath = PlugDup(g, Objname))) { + if (*objpath == '$') objpath++; + if (*objpath == '.') objpath++; - /*********************************************************************/ - /* Find the table in the tree structure. */ - /*********************************************************************/ - for (; jsp && objpath; objpath = p) { - if ((p = strchr(objpath, Sep))) - *p++ = 0; + /*********************************************************************/ + /* Find the table in the tree structure. */ + /*********************************************************************/ + for (; jsp && objpath; objpath = p) { + if ((p = strchr(objpath, Sep))) + *p++ = 0; - if (*objpath != '[' && !IsNum(objpath)) { - // objpass is a key - if (jsp->GetType() != TYPE_JOB) { - strcpy(g->Message, "Table path does not match the json file"); - return RC_FX; - } // endif Type + if (*objpath != '[' && !IsNum(objpath)) { + // objpass is a key + if (jsp->GetType() != TYPE_JOB) { + strcpy(g->Message, "Table path does not match the json file"); + return RC_FX; + } // endif Type - key = objpath; - objp = jsp->GetObject(); - arp = NULL; - val = objp->GetValue(key); + key = objpath; + objp = jsp->GetObject(); + arp = NULL; + val = objp->GetValue(key); - if (!val || !(jsp = val->GetJson())) { - sprintf(g->Message, "Cannot find object key %s", key); - return RC_FX; - } // endif val + if (!val || !(jsp = val->GetJson())) { + sprintf(g->Message, "Cannot find object key %s", key); + return RC_FX; + } // endif val - } else { - if (*objpath == '[') { - // Old style - if (objpath[strlen(objpath) - 1] != ']') { - sprintf(g->Message, "Invalid Table path %s", Objname); - return RC_FX; - } else - objpath++; + } else { + if (*objpath == '[') { + // Old style + if (objpath[strlen(objpath) - 1] != ']') { + sprintf(g->Message, "Invalid Table path %s", Objname); + return RC_FX; + } else + objpath++; - } // endif objpath + } // endif objpath - if (jsp->GetType() != TYPE_JAR) { - strcpy(g->Message, "Table path does not match the json file"); - return RC_FX; - } // endif Type + if (jsp->GetType() != TYPE_JAR) { + strcpy(g->Message, "Table path does not match the json file"); + return RC_FX; + } // endif Type - arp = jsp->GetArray(); - objp = NULL; - i = atoi(objpath) - B; - val = arp->GetValue(i); + arp = jsp->GetArray(); + objp = NULL; + i = atoi(objpath) - B; + val = arp->GetValue(i); - if (!val) { - sprintf(g->Message, "Cannot find array value %d", i); - return RC_FX; - } // endif val + if (!val) { + sprintf(g->Message, "Cannot find array value %d", i); + return RC_FX; + } // endif val - } // endif + } // endif - jsp = val->GetJson(); - } // endfor objpath + jsp = val->GetJson(); + } // endfor objpath - } // endif objpath + } // endif objpath if (jsp && jsp->GetType() == TYPE_JAR) Doc = jsp->GetArray(); - else { + else { // The table is void or is just one object or one value Doc = new(g) JARRAY; @@ -2149,7 +2152,7 @@ int TDBJSON::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool) } else return RC_OK; - } // end of MakeIndex + } // end of MakeIndex /***********************************************************************/ /* Return the position in the table. */ @@ -2227,11 +2230,11 @@ bool TDBJSON::OpenDB(PGLOBAL g) return true; } // endswitch Jmode - if (Xcol) - To_Filter = NULL; // Imcompatible + if (Xcol) + To_Filter = NULL; // Imcompatible - Use = USE_OPEN; - return false; + Use = USE_OPEN; + return false; } // end of OpenDB /***********************************************************************/ @@ -2241,7 +2244,7 @@ int TDBJSON::ReadDB(PGLOBAL) { int rc; - N++; + N++; if (NextSame) { SameRow = NextSame; @@ -2352,8 +2355,8 @@ void TDBJSON::CloseDB(PGLOBAL g) TDBJCL::TDBJCL(PJDEF tdp) : TDBCAT(tdp) { Topt = tdp->GetTopt(); - Db = tdp->Schema; - Dsn = tdp->Uri; + Db = tdp->Schema; + Dsn = tdp->Uri; } // end of TDBJCL constructor /***********************************************************************/ diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp new file mode 100644 index 00000000000..9e1a643c89f --- /dev/null +++ b/storage/connect/tabrest.cpp @@ -0,0 +1,201 @@ +/*************** Rest C++ Program Source Code File (.CPP) **************/ +/* PROGRAM NAME: Rest Version 1.5 */ +/* (C) Copyright to the author Olivier BERTRAND 2018 - 2019 */ +/* This program is the REST Web API support for MariaDB. */ +/* When compiled without MARIADB defined, it is the EOM module code. */ +/***********************************************************************/ + +/***********************************************************************/ +/* Definitions needed by the included files. */ +/***********************************************************************/ +#if defined(MARIADB) +#include // All MariaDB stuff +#else // !MARIADB OEM module +#include "mini-global.h" +#define _MAX_PATH 260 +#if !defined(__WIN__) +#define __stdcall +#endif // !__WIN__ +#define _OS_H_INCLUDED // Prevent os.h to be called +#endif // !MARIADB + +/***********************************************************************/ +/* Include application header files: */ +/* global.h is header containing all global declarations. */ +/* plgdbsem.h is header containing the DB application declarations. */ +/* (x)table.h is header containing the TDBASE declarations. */ +/***********************************************************************/ +#include "global.h" +#include "plgdbsem.h" +#include "xtable.h" +#include "filamtxt.h" +#include "tabdos.h" +#include "plgxml.h" +#include "tabxml.h" +#include "tabjson.h" +#include "tabfmt.h" +#include "tabrest.h" + +/***********************************************************************/ +/* Get the file from the Web. */ +/***********************************************************************/ +int restGetFile(PGLOBAL g, PCSZ http, PCSZ uri, PCSZ fn); + +#if defined(__WIN__) +static PCSZ slash = "\\"; +#else // !__WIN__ +static PCSZ slash = "/"; +#define stricmp strcasecmp +#endif // !__WIN__ + +#if !defined(MARIADB) +/***********************************************************************/ +/* DB static variables. */ +/***********************************************************************/ +int TDB::Tnum; +int DTVAL::Shift; +int CSORT::Limit = 0; +double CSORT::Lg2 = log(2.0); +size_t CSORT::Cpn[1000] = { 0 }; + +/***********************************************************************/ +/* These functions are exported from the REST library. */ +/***********************************************************************/ +extern "C" { + PTABDEF __stdcall GetREST(PGLOBAL, void*); + PQRYRES __stdcall ColREST(PGLOBAL, PTOS, char*, char*, bool); +} // extern "C" + +/***********************************************************************/ +/* This function returns a table definition class. */ +/***********************************************************************/ +PTABDEF __stdcall GetREST(PGLOBAL g, void *memp) +{ + return new(g, memp) RESTDEF; +} // end of GetREST +#endif // !MARIADB + +/***********************************************************************/ +/* Return the columns definition to MariaDB. */ +/***********************************************************************/ +#if defined(MARIADB) +PQRYRES RESTColumns(PGLOBAL g, PTOS tp, char *tab, char *db, bool info) +#else // !MARIADB +PQRYRES __stdcall ColREST(PGLOBAL g, PTOS tp, char *tab, char *db, bool info) +#endif // !MARIADB +{ + PQRYRES qrp= NULL; + char filename[_MAX_PATH + 1]; // MAX PATH ??? + PCSZ http, uri, fn, ftype; + + http = GetStringTableOption(g, tp, "Http", NULL); + uri = GetStringTableOption(g, tp, "Uri", NULL); + fn = GetStringTableOption(g, tp, "Filename", "rest.json"); +#if defined(MARIADB) + ftype = GetStringTableOption(g, tp, "Type", "JSON"); +#else // !MARIADB + // OEM tables must specify the file type + ftype = GetStringTableOption(g, tp, "Ftype", "JSON"); +#endif // !MARIADB + + // We used the file name relative to recorded datapath + strcat(strcat(strcat(strcpy(filename, "."), slash), db), slash); + strncat(filename, fn, _MAX_PATH); + + // Retrieve the file from the web and copy it locally + if (http && restGetFile(g, http, uri, filename)) { + // sprintf(g->Message, "Failed to get file at %s", http); + } else if (!stricmp(ftype, "XML")) + qrp = XMLColumns(g, db, tab, tp, info); + else if (!stricmp(ftype, "JSON")) + qrp = JSONColumns(g, db, NULL, tp, info); + else if (!stricmp(ftype, "CSV")) + qrp = CSVColumns(g, NULL, tp, info); + else + sprintf(g->Message, "Usupported file type %s", ftype); + + return qrp; +} // end of RESTColumns + +/* -------------------------- Class RESTDEF -------------------------- */ + +/***********************************************************************/ +/* DefineAM: define specific AM block values. */ +/***********************************************************************/ +bool RESTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) +{ + char filename[_MAX_PATH + 1]; + int rc = 0, n; + LPCSTR ftype; + +#if defined(MARIADB) + ftype = GetStringCatInfo(g, "Type", "JSON"); +#else // !MARIADB + // OEM tables must specify the file type + ftype = GetStringCatInfo(g, "Ftype", "JSON"); +#endif // !MARIADB + + if (trace(515)) + htrc("ftype = %s am = %s\n", ftype, SVP(am)); + + n = (!stricmp(ftype, "JSON")) ? 1 + : (!stricmp(ftype, "XML")) ? 2 + : (!stricmp(ftype, "CSV")) ? 3 : 0; + + if (n == 0) { + htrc("DefineAM: Unsupported REST table type %s", am); + sprintf(g->Message, "Unsupported REST table type %s", am); + return true; + } // endif n + + Http = GetStringCatInfo(g, "Http", NULL); + Uri = GetStringCatInfo(g, "Uri", NULL); + Fn = GetStringCatInfo(g, "Filename", "rest.json"); + + // We used the file name relative to recorded datapath + //PlugSetPath(filename, Fn, GetPath()); + strncat(strcpy(filename, GetPath()), Fn, _MAX_PATH); + + // Retrieve the file from the web and copy it locally + rc = restGetFile(g, Http, Uri, filename); + + if (trace(515)) + htrc("Return from restGetFile: rc=%d\n", rc); + + if (rc) + return true; + else switch (n) { + case 1: Tdp = new (g) JSONDEF; break; + case 2: Tdp = new (g) XMLDEF; break; + case 3: Tdp = new (g) CSVDEF; break; + default: Tdp = NULL; + } // endswitch n + + // Do make the table/view definition + if (Tdp && Tdp->Define(g, Cat, Name, Schema, "REST")) + Tdp = NULL; // Error occured + + if (trace(515)) + htrc("Tdp defined\n", rc); + + // Return true in case of error + return (Tdp == NULL); +} // end of DefineAM + +/***********************************************************************/ +/* GetTable: makes a new Table Description Block. */ +/***********************************************************************/ +PTDB RESTDEF::GetTable(PGLOBAL g, MODE m) +{ + if (trace(515)) + htrc("REST GetTable mode=%d\n", m); + + if (m != MODE_READ && m != MODE_READX) { + strcpy(g->Message, "REST tables are currently read only"); + return NULL; + } // endif m + + return Tdp->GetTable(g, m); // Leave file type do the job +} // end of GetTable + +/* ---------------------- End of Class RESTDEF ----------------------- */ diff --git a/storage/connect/tabrest.h b/storage/connect/tabrest.h new file mode 100644 index 00000000000..1725f256079 --- /dev/null +++ b/storage/connect/tabrest.h @@ -0,0 +1,29 @@ +/*************** TabRest H Declares Source Code File (.H) **************/ +/* Name: tabrest.h Version 1.0 */ +/* (C) Copyright to the author Olivier BERTRAND 2019 */ +/* This file contains the common tabrest classes declares. */ +/***********************************************************************/ +#pragma once + +/***********************************************************************/ +/* Restest table. */ +/***********************************************************************/ +class RESTDEF : public TABDEF { /* Table description */ +public: + // Constructor + RESTDEF(void) { Tdp = NULL; Http = Uri = Fn = NULL; } + + // Implementation + virtual const char *GetType(void) { return "REST"; } + + // Methods + virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff); + virtual PTDB GetTable(PGLOBAL g, MODE m); + +protected: + // Members + PRELDEF Tdp; + PCSZ Http; /* Web connection HTTP */ + PCSZ Uri; /* Web connection URI */ + PCSZ Fn; /* The intermediate file name */ +}; // end of class RESTDEF diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp index e194568ccf8..1150824464f 100644 --- a/storage/connect/tabtbl.cpp +++ b/storage/connect/tabtbl.cpp @@ -232,7 +232,7 @@ bool TDBTBL::InitTableList(PGLOBAL g) { int n; uint sln; - char *scs; + const char *scs; PTABLE tp, tabp; PCOL colp; PTBLDEF tdp = (PTBLDEF)To_Def; @@ -281,7 +281,7 @@ bool TDBTBL::InitTableList(PGLOBAL g) } // endfor tp - hc->get_table()->s->connect_string.str = scs; + hc->get_table()->s->connect_string.str = (char*)scs; hc->get_table()->s->connect_string.length = sln; //NumTables = n; diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp index d808bd5ecd4..19490d350e8 100644 --- a/storage/connect/tabxml.cpp +++ b/storage/connect/tabxml.cpp @@ -1880,7 +1880,7 @@ void XMULCOL::ReadColumn(PGLOBAL g) if (N > Tdbp->Limit) { N = Tdbp->Limit; - sprintf(g->Message, "Mutiple values limited to %d", Tdbp->Limit); + sprintf(g->Message, "Multiple values limited to %d", Tdbp->Limit); PushWarning(g, Tdbp); } // endif N diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc index d366e0222df..c25443ef7ef 100644 --- a/storage/connect/user_connect.cc +++ b/storage/connect/user_connect.cc @@ -11,7 +11,7 @@ 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file user_connect.cc diff --git a/storage/connect/user_connect.h b/storage/connect/user_connect.h index 983d9adc478..2670c5bcebc 100644 --- a/storage/connect/user_connect.h +++ b/storage/connect/user_connect.h @@ -11,7 +11,7 @@ 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** @file user_connect.h From 0043593b9d35ea505470cb83ffc166e2c1466e17 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sat, 24 Aug 2019 17:32:38 +0200 Subject: [PATCH 02/68] Fix xml(2)_mult.test result mismatch --- storage/connect/mysql-test/connect/r/xml2_mult.result | 8 ++++---- storage/connect/mysql-test/connect/r/xml_mult.result | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/storage/connect/mysql-test/connect/r/xml2_mult.result b/storage/connect/mysql-test/connect/r/xml2_mult.result index a9592e986c0..87d1118edd5 100644 --- a/storage/connect/mysql-test/connect/r/xml2_mult.result +++ b/storage/connect/mysql-test/connect/r/xml2_mult.result @@ -51,14 +51,14 @@ WEB XQuery Kick Start en Per Bothner 2003 49.99 WEB XQuery Kick Start en Kurt Cagle 2003 49.99 WEB Learning XML en Erik T. Ray 2003 39.95 Warnings: -Warning 1105 Mutiple values limited to 3 +Warning 1105 Multiple values limited to 3 # One line lost because the where clause is applied only on the first 3 rows SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; category title author price CHILDREN Harry Potter J K. Rowling 29.99 WEB XQuery Kick Start James McGovern 49.99 Warnings: -Warning 1105 Mutiple values limited to 3 +Warning 1105 Multiple values limited to 3 # # Testing concatenated values # @@ -91,12 +91,12 @@ CHILDREN Harry Potter en J K. Rowling 2005 29.99 WEB XQuery Kick Start en James McGovern, Per Bothner, Kurt Cagle, James Linn 2003 49.99 WEB Learning XML en Erik T. Ray 2003 39.95 Warnings: -Warning 1105 Mutiple values limited to 4 +Warning 1105 Multiple values limited to 4 # The where clause is applied on the concatenated column result SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; category title author price CHILDREN Harry Potter J K. Rowling 29.99 WEB XQuery Kick Start James McGovern, Per Bothner, Kurt Cagle, James Linn 49.99 Warnings: -Warning 1105 Mutiple values limited to 4 +Warning 1105 Multiple values limited to 4 DROP TABLE bookstore; diff --git a/storage/connect/mysql-test/connect/r/xml_mult.result b/storage/connect/mysql-test/connect/r/xml_mult.result index d89debadfab..9922b40060c 100644 --- a/storage/connect/mysql-test/connect/r/xml_mult.result +++ b/storage/connect/mysql-test/connect/r/xml_mult.result @@ -49,14 +49,14 @@ WEB XQuery Kick Start en Per Bothner 2003 49.99 WEB XQuery Kick Start en Kurt Cagle 2003 49.99 WEB Learning XML en Erik T. Ray 2003 39.95 Warnings: -Warning 1105 Mutiple values limited to 3 +Warning 1105 Multiple values limited to 3 # One line lost because the where clause is applied only on the first 3 rows SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; category title author price CHILDREN Harry Potter J K. Rowling 29.99 WEB XQuery Kick Start James McGovern 49.99 Warnings: -Warning 1105 Mutiple values limited to 3 +Warning 1105 Multiple values limited to 3 # # Testing concatenated values # @@ -89,12 +89,12 @@ CHILDREN Harry Potter en J K. Rowling 2005 29.99 WEB XQuery Kick Start en James McGovern, Per Bothner, Kurt Cagle, James Linn 2003 49.99 WEB Learning XML en Erik T. Ray 2003 39.95 Warnings: -Warning 1105 Mutiple values limited to 4 +Warning 1105 Multiple values limited to 4 # The where clause is applied on the concatenated column result SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%'; category title author price CHILDREN Harry Potter J K. Rowling 29.99 WEB XQuery Kick Start James McGovern, Per Bothner, Kurt Cagle, James Linn 49.99 Warnings: -Warning 1105 Mutiple values limited to 4 +Warning 1105 Multiple values limited to 4 DROP TABLE bookstore; From 425dc6d66f8c9786bb678527e4aa973da724d71b Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 10 Sep 2019 15:57:48 +0200 Subject: [PATCH 03/68] - Remove some incorrect compile flags Just keep the /MDd flag but only for Windows Debug REST compile modified: storage/connect/CMakeLists.txt - Add a trace to EvalColumns modified: storage/connect/connect.cc - Remove a file not belonging to CONNECT deleted: rest.h --- storage/connect/CMakeLists.txt | 9 +++++---- storage/connect/connect.cc | 5 ++++- storage/connect/rest.h | 33 --------------------------------- 3 files changed, 9 insertions(+), 38 deletions(-) delete mode 100644 storage/connect/rest.h diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index fd006e104c1..be5c7034c3b 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -68,10 +68,6 @@ ELSE(NOT UNIX) tabwmi.cpp tabwmi.h tabmac.cpp tabmac.h macutil.cpp macutil.h) # Add exception handling to the CONNECT project) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") - SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") - SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") - SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MD") - SET(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MD") SET(IPHLPAPI_LIBRARY iphlpapi.lib) IF(MSVC AND (CMAKE_CXX_COMPILER_ID MATCHES Clang)) # Connect does not work with clang-cl @@ -324,6 +320,11 @@ IF(CONNECT_WITH_REST) # If needed edit next line to set the path to libcpprest.so SET(REST_LIBRARY -lcpprest) MESSAGE (STATUS ${REST_LIBRARY}) + ELSE(NOT UNIX) +# Next line sets debug compile mode matching cpprest_2_10d.dll +# when it was binary installed (can be change later in Visual Studio) +# Comment it out if not needed depending on your cpprestsdk installation. + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") ENDIF(UNIX) SET(CONNECT_SOURCES ${CONNECT_SOURCES} tabrest.cpp restget.cpp tabrest.h) add_definitions(-DREST_SUPPORT) diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc index b1078de8eaa..461391d2896 100644 --- a/storage/connect/connect.cc +++ b/storage/connect/connect.cc @@ -16,7 +16,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /***********************************************************************/ -/* Author Olivier BERTRAND bertrandop@gmail.com 2004-2017 */ +/* Author Olivier BERTRAND bertrandop@gmail.com 2004-2019 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -389,6 +389,9 @@ RCODE EvalColumns(PGLOBAL g, PTDB tdbp, bool reset, bool mrr) try { for (colp = tdbp->GetColumns(); rc == RC_OK && colp; colp = colp->GetNext()) { + xtrc(2, "Going to read column %s of table %s\n", + colp->GetName(), tdbp->GetName()); + if (reset) colp->Reset(); diff --git a/storage/connect/rest.h b/storage/connect/rest.h deleted file mode 100644 index f1d77e0a279..00000000000 --- a/storage/connect/rest.h +++ /dev/null @@ -1,33 +0,0 @@ -/***********************************************************************/ -/* Definitions needed by the included files. */ -/***********************************************************************/ -#if !defined(MY_GLOBAL_H) -#define MY_GLOBAL_H -typedef unsigned int uint; -typedef unsigned int uint32; -typedef unsigned short ushort; -typedef unsigned long ulong; -typedef unsigned long DWORD; -typedef char *LPSTR; -typedef const char *LPCSTR; -typedef int BOOL; -#if defined(_WINDOWS) -typedef void *HANDLE; -#else -typedef int HANDLE; -#endif -typedef char *PSZ; -typedef const char *PCSZ; -typedef unsigned char BYTE; -typedef unsigned char uchar; -typedef long long longlong; -typedef unsigned long long ulonglong; -typedef char my_bool; -struct charset_info_st {}; -typedef const charset_info_st CHARSET_INFO; -#define FALSE 0 -#define TRUE 1 -#define Item char -#define MY_MAX(a,b) ((a>b)?(a):(b)) -#define MY_MIN(a,b) ((a Date: Mon, 14 Oct 2019 12:56:43 +0300 Subject: [PATCH 04/68] MDEV-19740: Fix C++11 violations caught by GCC 9.2.1 This is a backport of commit ec28f9532e92820f59fc7298465407069e289a5a to MariaDB Server 10.1. --- sql/item.h | 4 +--- sql/sql_list.h | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/sql/item.h b/sql/item.h index 7f6236269bd..fb11064f122 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2,7 +2,7 @@ #define SQL_ITEM_INCLUDED /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2009, 2018, MariaDB Corporation + Copyright (c) 2009, 2019, MariaDB Corporation. 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 @@ -611,8 +611,6 @@ class Item: public Value_source, public Type_std_attributes, public Type_handler { - Item(const Item &); /* Prevent use of these */ - void operator=(Item &); /** The index in the JOIN::join_tab array of the JOIN_TAB this Item is attached to. Items are attached (or 'pushed') to JOIN_TABs during optimization by the diff --git a/sql/sql_list.h b/sql/sql_list.h index 94e944d5ff6..94f6c1b03aa 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -1,6 +1,7 @@ #ifndef INCLUDES_MYSQL_SQL_LIST_H #define INCLUDES_MYSQL_SQL_LIST_H /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. + Copyright (c) 2019, MariaDB Corporation. 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 @@ -85,6 +86,14 @@ public: next= elements ? tmp.next : &first; } + SQL_I_List& operator=(const SQL_I_List &tmp) + { + elements= tmp.elements; + first= tmp.first; + next= tmp.next; + return *this; + } + inline void empty() { elements= 0; @@ -175,6 +184,13 @@ public: first == rhs.first && last == rhs.last; } + base_list& operator=(const base_list &rhs) + { + elements= rhs.elements; + first= rhs.first; + last= elements ? rhs.last : &first; + return *this; + } inline void empty() { elements=0; first= &end_of_list; last=&first;} inline base_list() { empty(); } @@ -189,9 +205,7 @@ public: */ inline base_list(const base_list &tmp) :Sql_alloc() { - elements= tmp.elements; - first= tmp.first; - last= elements ? tmp.last : &first; + *this= tmp; } /** Construct a deep copy of the argument in memory root mem_root. @@ -200,7 +214,7 @@ public: list_copy_and_replace_each_value after creating a copy. */ base_list(const base_list &rhs, MEM_ROOT *mem_root); - inline base_list(bool error) { } + inline base_list(bool) { } inline bool push_back(void *info) { if (((*last)=new list_node(info, &end_of_list))) @@ -512,7 +526,6 @@ template class List :public base_list { public: inline List() :base_list() {} - inline List(const List &tmp) :base_list(tmp) {} inline List(const List &tmp, MEM_ROOT *mem_root) : base_list(tmp, mem_root) {} inline bool push_back(T *a) { return base_list::push_back(a); } From ae702d76438d15c84e0e113031366b0a8da47b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 14 Oct 2019 16:38:28 +0300 Subject: [PATCH 05/68] MDEV-20813: Remove the buf_flush_init_for_writing() assertion Old InnoDB/XtraDB versions only initialized FIL_PAGE_TYPE for B-tree pages (to FIL_PAGE_INDEX), and left it uninitialized (possibly containing FIL_PAGE_INDEX) for others. In MySQL or MariaDB 5.5, the field is initialized on almost all pages, but still not all of them. In MariaDB 10.2 and later, buf_flush_init_for_writing() would initialize the FIL_PAGE_TYPE on such old pages, but only after passing the debug assertion that we are now removing from 10.1. There, we will be able to modify fil_crypt_rotate_page() so that it will skip the key rotation for pages that contain 0 in FIL_PAGE_TYPE. In MariaDB 10.1, there is no logic that would initialize FIL_PAGE_TYPE on data pages in old data files after an update. So, encryption key rotation may routinely cause page flushes on pages that contain 0 in FIL_PAGE_TYPE. --- storage/innobase/buf/buf0flu.cc | 1 - storage/xtradb/buf/buf0flu.cc | 1 - 2 files changed, 2 deletions(-) diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index f918b88a5ea..1325a938dd6 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -745,7 +745,6 @@ buf_flush_init_for_writing( ib_uint32_t checksum = 0 /* silence bogus gcc warning */; ut_ad(page); - ut_ad(!newest_lsn || fil_page_get_type(page)); if (page_zip_) { page_zip_des_t* page_zip; diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc index e4512cacff8..eccc7c281c1 100644 --- a/storage/xtradb/buf/buf0flu.cc +++ b/storage/xtradb/buf/buf0flu.cc @@ -787,7 +787,6 @@ buf_flush_init_for_writing( ib_uint32_t checksum = 0 /* silence bogus gcc warning */; ut_ad(page); - ut_ad(!newest_lsn || fil_page_get_type(page)); if (page_zip_) { page_zip_des_t* page_zip; From f989c0ce66aa50ac904c75ccbdb850c0daa0419f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 14 Oct 2019 17:26:21 +0300 Subject: [PATCH 06/68] MDEV-20813: Do not rotate keys for unallocated pages fil_crypt_rotate_page(): Skip the key rotation for pages that carry 0 in FIL_PAGE_TYPE. This avoids not only unnecessary writes, but also failures of the recently added debug assertion in buf_flush_init_for_writing() that the FIL_PAGE_TYPE should be nonzero. Note: the debug assertion can fail if the file was originally created before MySQL 5.5. In old InnoDB versions, FIL_PAGE_TYPE was only initialized for B-tree pages, to FIL_PAGE_INDEX. For any other pages, the field could be garbage, including FIL_PAGE_INDEX. In MariaDB 10.2 and later, buf_flush_init_for_writing() would initialize the FIL_PAGE_TYPE on such old pages, but only after passing the debug assertion that insists that pages have a nonzero FIL_PAGE_TYPE. Thus, the debug assertion at the start of buf_flush_init_for_writing() can fail when upgrading from very old debug files. This assertion is only present in debug builds, not release builds. --- storage/innobase/fil/fil0crypt.cc | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 918ffd77542..d1aca92ef62 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -1773,8 +1773,6 @@ fil_crypt_rotate_page( return; } - ut_d(const bool was_free = fseg_page_is_free(space, offset)); - mtr_t mtr; mtr.start(); if (buf_block_t* block = fil_crypt_get_page_throttle(state, @@ -1789,9 +1787,9 @@ fil_crypt_rotate_page( if (space->is_stopping()) { /* The tablespace is closing (in DROP TABLE or TRUNCATE TABLE or similar): avoid further access */ - } else if (!*reinterpret_cast(FIL_PAGE_OFFSET - + frame)) { - /* It looks like this page was never + } else if (!kv && !*reinterpret_cast + (&frame[FIL_PAGE_TYPE])) { + /* It looks like this page is not allocated. Because key rotation is accessing pages in a pattern that is unlike the normal B-tree and undo log access pattern, we cannot @@ -1801,9 +1799,20 @@ fil_crypt_rotate_page( tablespace latch before acquiring block->lock, then the fseg_page_is_free() information could be stale already. */ - ut_ad(was_free); - ut_ad(kv == 0); - ut_ad(page_get_space_id(frame) == 0); + + /* If the data file was originally created + before MariaDB 10.0 or MySQL 5.6, some + allocated data pages could carry 0 in + FIL_PAGE_TYPE. The FIL_PAGE_TYPE on those + pages will be updated in + buf_flush_init_for_writing() when the page + is modified the next time. + + Also, when the doublewrite buffer pages are + allocated on bootstrap in a non-debug build, + some dummy pages will be allocated, with 0 in + the FIL_PAGE_TYPE. Those pages should be + skipped from key rotation forever. */ } else if (fil_crypt_needs_rotation( crypt_data, kv, From 4d14785546022ea8dc4e249e0b57b55328a12876 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 9 Oct 2019 03:09:48 +0300 Subject: [PATCH 07/68] MDEV-20778 UBSAN: call to function free_rpl_filter() through pointer to incorrect function type Proper C-style type erasure is done via void*, not via char* or something else. free_key_cache() free_rpl_filter(): types were fixed to avoid function pointer type cast which is still undefined behavior. Note, that casting from void* to any other pointer type is safe and correct. --- sql/keycaches.cc | 13 ++++++------- sql/keycaches.h | 5 ++--- sql/mysqld.cc | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/sql/keycaches.cc b/sql/keycaches.cc index bc0f43a4d69..43ec85d707c 100644 --- a/sql/keycaches.cc +++ b/sql/keycaches.cc @@ -84,7 +84,7 @@ bool NAMED_ILIST::delete_element(const char *name, uint length, void (*free_elem DBUG_RETURN(1); } -void NAMED_ILIST::delete_elements(void (*free_element)(const char *name, uchar*)) +void NAMED_ILIST::delete_elements(void (*free_element)(const char *name, void*)) { NAMED_ILINK *element; DBUG_ENTER("NAMED_ILIST::delete_elements"); @@ -156,9 +156,9 @@ KEY_CACHE *get_or_create_key_cache(const char *name, uint length) } -void free_key_cache(const char *name, KEY_CACHE *key_cache) +void free_key_cache(const char *name, void *key_cache) { - end_key_cache(key_cache, 1); // Can never fail + end_key_cache(static_cast(key_cache), 1); // Can never fail my_free(key_cache); } @@ -220,13 +220,12 @@ Rpl_filter *get_or_create_rpl_filter(const char *name, uint length) return filter; } -void free_rpl_filter(const char *name, Rpl_filter *filter) +void free_rpl_filter(const char *name, void *filter) { - delete filter; - filter= 0; + delete static_cast(filter); } void free_all_rpl_filters() { - rpl_filters.delete_elements((void (*)(const char*, uchar*)) free_rpl_filter); + rpl_filters.delete_elements(free_rpl_filter); } diff --git a/sql/keycaches.h b/sql/keycaches.h index 99528682d0e..e06c8da3d0d 100644 --- a/sql/keycaches.h +++ b/sql/keycaches.h @@ -30,7 +30,7 @@ class NAMED_ILINK; class NAMED_ILIST: public I_List { public: - void delete_elements(void (*free_element)(const char*, uchar*)); + void delete_elements(void (*free_element)(const char*, void*)); bool delete_element(const char *name, uint length, void (*free_element)(const char*, uchar*)); }; @@ -42,7 +42,7 @@ extern NAMED_ILIST key_caches; KEY_CACHE *create_key_cache(const char *name, uint length); KEY_CACHE *get_key_cache(const LEX_STRING *cache_name); KEY_CACHE *get_or_create_key_cache(const char *name, uint length); -void free_key_cache(const char *name, KEY_CACHE *key_cache); +void free_key_cache(const char *name, void *key_cache); bool process_key_caches(process_key_cache_t func, void *param); /* For Rpl_filter */ @@ -52,7 +52,6 @@ extern NAMED_ILIST rpl_filters; Rpl_filter *create_rpl_filter(const char *name, uint length); Rpl_filter *get_rpl_filter(LEX_STRING *filter_name); Rpl_filter *get_or_create_rpl_filter(const char *name, uint length); -void free_rpl_filter(const char *name, Rpl_filter *filter); void free_all_rpl_filters(void); #endif /* KEYCACHES_INCLUDED */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 889072a4cf5..34e5704bcfe 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2232,7 +2232,7 @@ void clean_up(bool print_message) tdc_deinit(); mdl_destroy(); dflt_key_cache= 0; - key_caches.delete_elements((void (*)(const char*, uchar*)) free_key_cache); + key_caches.delete_elements(free_key_cache); wt_end(); multi_keycache_free(); sp_cache_end(); From c2854c7863aa01895febfb6503f542fce6825bd6 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 14 Oct 2019 16:45:51 +0200 Subject: [PATCH 08/68] MDEV-20466: SHOW PROCESSLIST truncates query text on \0 bytes Data should be sent with length. --- mysql-test/r/processlist.result | 1 + mysql-test/r/processlist_MDEV-20466.result | Bin 0 -> 775 bytes mysql-test/t/processlist.test | 2 ++ mysql-test/t/processlist_MDEV-20466.test | 35 +++++++++++++++++++++ sql/sql_show.cc | 8 +++-- 5 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 mysql-test/r/processlist_MDEV-20466.result create mode 100644 mysql-test/t/processlist_MDEV-20466.test diff --git a/mysql-test/r/processlist.result b/mysql-test/r/processlist.result index eb3af67c5bf..55d2425d269 100644 --- a/mysql-test/r/processlist.result +++ b/mysql-test/r/processlist.result @@ -17,3 +17,4 @@ select command, time < 5 from information_schema.processlist where id != connect command time < 5 Sleep 1 set debug_sync='reset'; +End of 5.5 tests diff --git a/mysql-test/r/processlist_MDEV-20466.result b/mysql-test/r/processlist_MDEV-20466.result new file mode 100644 index 0000000000000000000000000000000000000000..7120212d0f03a73094a9dd164838e3ef9a6a9e20 GIT binary patch literal 775 zcmbtSUvJYe5a-qX6esPWOoD0xwue=FD6O|fYMT*fR7glsnmCJD;_G~lO8E4g(}AE* zNW3Ju*!TN)cLtEwhQMp`Q0D|WI89yS!PmJ5V~eIMHNn>l*!5mdMrQ!3D{8(MYH0H( zJ}pgEfk*I8bCa(%9BOPdRE8f6x-&L+{hQF7+cMmAy6Q-Wuc6oY0Xb#PF>!OxAiq@c zd*1~q%t?BmyPSCg@_>$eX5t1G*Qa01sg1HEuJMCDJ{_X?dOBBQiN~W-oA0O^A^<^`^f$>gP z=ydiCjm>cHO>2H=P|@9HwqgSr^|lyKxosuqDR2M|Zj*QoZBNh5WT>}GnaJbO&6u#& zuf~85sL^^4uiu|fL;DG<#RF_-QJUSx$)7YQj;5oi6c0=)mPlTdJ2A($<$;LQv|1?7 zW<_Kx6!#7vc@1b3Erdh#Vi~J6+sxKdghdgbLLefIxZdW*8~Yf7DUhK~V;pW}YxNIM iLE6!%_@9J+Gya_u@OTo*|9AkBmyq}2a&mdxhS5)qp!L20 literal 0 HcmV?d00001 diff --git a/mysql-test/t/processlist.test b/mysql-test/t/processlist.test index a8f8a4ed64c..8a8995f43b0 100644 --- a/mysql-test/t/processlist.test +++ b/mysql-test/t/processlist.test @@ -50,3 +50,5 @@ select command, time < 5 from information_schema.processlist where id != connect disconnect con1; set debug_sync='reset'; + +--echo End of 5.5 tests diff --git a/mysql-test/t/processlist_MDEV-20466.test b/mysql-test/t/processlist_MDEV-20466.test new file mode 100644 index 00000000000..70b56d25d72 --- /dev/null +++ b/mysql-test/t/processlist_MDEV-20466.test @@ -0,0 +1,35 @@ +--echo # This test has a result that includes \0 byte. +--echo # Such a byte makes diff to treat the whole file as binary, +--echo # and to refuse to diff it. +--echo # That's why this test is put in a separate file, +--echo # so that diff would still work on results of other tests. + +source include/have_debug.inc; +source include/have_debug_sync.inc; + +--echo # +--echo # MDEV-20466: SHOW PROCESSLIST truncates query text on \0 bytes +--echo # + +connect (con1,localhost,root,,); + +#select * from information_schema.processlist; +connection con1; + +let $q= `select CONCAT("SELECT user FROM mysql.user WHERE user ='some", CHAR(0), "' or sleep (3)")`; + +SET DEBUG_SYNC= 'before_join_optimize SIGNAL in_sync'; +--send_eval $q; + +connection default; + +SET DEBUG_SYNC= 'now WAIT_FOR in_sync'; + +--replace_column 1 ID 3 HOST_NAME 6 TIME 9 TIME_MS +SHOW PROCESSLIST; + +disconnect con1; + +SET DEBUG_SYNC = 'RESET'; + +--echo End of 5.5 tests diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0cf992ce25b..998432e8443 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2278,8 +2278,12 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) else protocol->store_null(); protocol->store(thd_info->state_info, system_charset_info); - protocol->store(thd_info->query_string.str(), - thd_info->query_string.charset()); + if (thd_info->query_string.length()) + protocol->store(thd_info->query_string.str(), + thd_info->query_string.length(), + thd_info->query_string.charset()); + else + protocol->store_null(); if (!thd->variables.old_mode && !(thd->variables.old_behavior & OLD_MODE_NO_PROGRESS_INFO)) protocol->store(thd_info->progress, 3, &store_buffer); From 7ae0be25a605c04ad7b5576651f523952cce53b4 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 14 Oct 2019 15:07:21 +0300 Subject: [PATCH 09/68] MDEV-20812 Unexpected ER_ROW_IS_REFERENCED_2 upon DELETE from versioned table with FK MDEV-16210 original case was wrongly allowed versioned DELETE from referenced table where reference is by non-primary key. InnoDB UPDATE has optimization for new rows not changing its clustered index position. In this case InnoDB doesn't update all secondary indexes and misses the one holding the referenced key. The fix was to disable this optimization for versioned DELETE. In case of versioned DELETE we forcely update all secondary indexes and therefore check them for constraints. But the above fix raised another problem with versioned DELETE on foreign table side. In case when there was no corresponding record in referenced table (illegal foreign reference can be done with "set foreign_key_checks=off") there was spurious constraint check (because versioned DELETE is actually UPDATE) and hence the operation failed with constraint error. MDEV-16210 tried to fix the above problem by checking foreign table instead of referenced table and that at least was illegal. Constraint check is done by row_ins_check_foreign_constraint() no matter what kind of table is checked, referenced or foreign (controlled by check_ref argument). Referenced table is checked by row_upd_check_references_constraints(). Foreign table is checked by row_ins_check_foreign_constraints(). Current fix rolls back the wrong fix for the above problem and disables referenced table check for DELETE on foreign side by introducing `check_foreign` argument which when set to *false* skips row_ins_check_foreign_constraints() call. --- mysql-test/suite/versioning/r/foreign.result | 29 ++++++++++++++++++ mysql-test/suite/versioning/t/foreign.test | 32 ++++++++++++++++++++ storage/innobase/include/row0ins.h | 5 ++- storage/innobase/row/row0ins.cc | 19 +++++------- storage/innobase/row/row0upd.cc | 3 +- 5 files changed, 71 insertions(+), 17 deletions(-) diff --git a/mysql-test/suite/versioning/r/foreign.result b/mysql-test/suite/versioning/r/foreign.result index 6a9746b62e2..32b5e5cf3d8 100644 --- a/mysql-test/suite/versioning/r/foreign.result +++ b/mysql-test/suite/versioning/r/foreign.result @@ -398,3 +398,32 @@ Warning 1265 Data truncated for column 'f12' at row 7 SET timestamp = 9; REPLACE INTO t2 SELECT * FROM t2; DROP TABLE t1, t2; +# +# MDEV-16210 FK constraints on versioned tables use historical rows, which may cause constraint violation +# +create or replace table t1 (a int, key(a)) engine innodb with system versioning; +create or replace table t2 (b int, foreign key (b) references t1(a)) engine innodb; +insert into t1 values (1),(2); +insert into t2 values (1); +# DELETE from referenced table is not allowed +delete from t1 where a = 1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`a`)) +drop tables t2, t1; +# +# MDEV-20812 Unexpected ER_ROW_IS_REFERENCED_2 or server crash in row_ins_foreign_report_err upon DELETE from versioned table with FK +# +create or replace table t1 (x int primary key) engine innodb; +create or replace table t2 (x int, foreign key (x) references t1(x)) engine innodb with system versioning; +set foreign_key_checks= off; +insert into t2 values (1), (1); +set foreign_key_checks= on; +# DELETE from foreign table is allowed +delete from t2; +drop tables t2, t1; +create or replace table t1 (a int, key(a)) engine innodb; +insert into t1 values (1); +create or replace table t2 (b int, foreign key (b) references t1(a)) engine innodb with system versioning; +insert into t2 values (1), (1); +# DELETE from foreign table is allowed +delete from t2; +drop tables t2, t1; diff --git a/mysql-test/suite/versioning/t/foreign.test b/mysql-test/suite/versioning/t/foreign.test index 9f015630e0a..7493f99cba7 100644 --- a/mysql-test/suite/versioning/t/foreign.test +++ b/mysql-test/suite/versioning/t/foreign.test @@ -426,4 +426,36 @@ DROP TABLE t1, t2; --remove_file $datadir/test/t1.data.2 --remove_file $datadir/test/t2.data +--echo # +--echo # MDEV-16210 FK constraints on versioned tables use historical rows, which may cause constraint violation +--echo # +create or replace table t1 (a int, key(a)) engine innodb with system versioning; +create or replace table t2 (b int, foreign key (b) references t1(a)) engine innodb; +insert into t1 values (1),(2); +insert into t2 values (1); +--echo # DELETE from referenced table is not allowed +--error ER_ROW_IS_REFERENCED_2 +delete from t1 where a = 1; +drop tables t2, t1; + +--echo # +--echo # MDEV-20812 Unexpected ER_ROW_IS_REFERENCED_2 or server crash in row_ins_foreign_report_err upon DELETE from versioned table with FK +--echo # +create or replace table t1 (x int primary key) engine innodb; +create or replace table t2 (x int, foreign key (x) references t1(x)) engine innodb with system versioning; +set foreign_key_checks= off; +insert into t2 values (1), (1); +set foreign_key_checks= on; +--echo # DELETE from foreign table is allowed +delete from t2; +drop tables t2, t1; + +create or replace table t1 (a int, key(a)) engine innodb; +insert into t1 values (1); +create or replace table t2 (b int, foreign key (b) references t1(a)) engine innodb with system versioning; +insert into t2 values (1), (1); +--echo # DELETE from foreign table is allowed +delete from t2; +drop tables t2, t1; + --source suite/versioning/common_finish.inc diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h index 87a72d88eb6..9b6aac9c548 100644 --- a/storage/innobase/include/row0ins.h +++ b/storage/innobase/include/row0ins.h @@ -146,9 +146,8 @@ row_ins_sec_index_entry( dict_index_t* index, /*!< in: secondary index */ dtuple_t* entry, /*!< in/out: index entry to insert */ que_thr_t* thr, /*!< in: query thread */ - bool check_ref) /*!< in: TRUE if we want to check that - the referenced table is ok, FALSE if we - want to check the foreign key table */ + bool check_foreign = true) /*!< in: true if check + foreign table is needed, false otherwise */ MY_ATTRIBUTE((warn_unused_result)); /***********************************************************//** Inserts a row to a table. This is a high-level function used in diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 88deacbc823..4760960a441 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1988,10 +1988,7 @@ row_ins_check_foreign_constraints( dict_index_t* index, /*!< in: index */ bool pk, /*!< in: index->is_primary() */ dtuple_t* entry, /*!< in: index entry for index */ - que_thr_t* thr, /*!< in: query thread */ - bool check_ref = true) /*!< in: TRUE if we want to check that - the referenced table is ok, FALSE if we - want to check the foreign key table */ + que_thr_t* thr) /*!< in: query thread */ { dict_foreign_t* foreign; dberr_t err; @@ -2040,7 +2037,7 @@ row_ins_check_foreign_constraints( table from being dropped while the check is running. */ err = row_ins_check_foreign_constraint( - check_ref, foreign, table, entry, thr); + TRUE, foreign, table, entry, thr); if (referenced_table) { foreign->foreign_table->dec_fk_checks(); @@ -3271,9 +3268,8 @@ row_ins_sec_index_entry( dict_index_t* index, /*!< in: secondary index */ dtuple_t* entry, /*!< in/out: index entry to insert */ que_thr_t* thr, /*!< in: query thread */ - bool check_ref) /*!< in: true if we want to check that - the referenced table is ok, false if we - want to check the foreign key table */ + bool check_foreign) /*!< in: true if check + foreign table is needed, false otherwise */ { dberr_t err; mem_heap_t* offsets_heap; @@ -3284,10 +3280,9 @@ row_ins_sec_index_entry( DBUG_SET("-d,row_ins_sec_index_entry_timeout"); return(DB_LOCK_WAIT);}); - if (!index->table->foreign_set.empty()) { + if (check_foreign && !index->table->foreign_set.empty()) { err = row_ins_check_foreign_constraints(index->table, index, - false, entry, thr, - check_ref); + false, entry, thr); if (err != DB_SUCCESS) { return(err); @@ -3362,7 +3357,7 @@ row_ins_index_entry( if (index->is_primary()) { return row_ins_clust_index_entry(index, entry, thr, 0); } else { - return(row_ins_sec_index_entry(index, entry, thr, true)); + return row_ins_sec_index_entry(index, entry, thr); } } diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 64021b48ee2..ad94b649397 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -2529,8 +2529,7 @@ row_upd_sec_index_entry( ut_a(entry); /* Insert new index entry */ - err = row_ins_sec_index_entry(index, entry, thr, - node->is_delete != VERSIONED_DELETE); + err = row_ins_sec_index_entry(index, entry, thr, !node->is_delete); func_exit: mem_heap_free(heap); From 4ba763db77a954e355cdb90a7ef30572e2a4317b Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 15 Oct 2019 12:24:23 +0200 Subject: [PATCH 10/68] MDEV-13172: Wrong result / SELECT ... WHERE EXISTS ... (with UNIQUE Key) IS NULL or <=> with unique field does not mean unique row, because several NULL possible, so we can not convert to normal join in this case. --- mysql-test/r/subselect_sj.result | 26 ++++++++++++++++++++++++++ mysql-test/r/subselect_sj_jcl6.result | 26 ++++++++++++++++++++++++++ mysql-test/t/subselect_sj.test | 26 ++++++++++++++++++++++++++ sql/opt_subselect.cc | 12 ++++++++++-- 4 files changed, 88 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result index d0b8b626ba2..6f4f363326a 100644 --- a/mysql-test/r/subselect_sj.result +++ b/mysql-test/r/subselect_sj.result @@ -3186,5 +3186,31 @@ create table t1 (a1 varchar(25)); create table t2 (a2 varchar(25)) ; insert into t1 select 'xxx' from dual where 'xxx' in (select a2 from t2); drop table t1,t2; +# +# MDEV-13172: Wrong result / SELECT ... WHERE EXISTS ... (with UNIQUE Key) +# +CREATE TABLE `t1` ( +`Id` int(11) NOT NULL, +PRIMARY KEY (`Id`) +); +INSERT INTO `t1` (`Id`) VALUES (1); +CREATE TABLE `t2` ( +`t1_Id` int(11) NOT NULL DEFAULT 0, +`col1` int(11) DEFAULT NULL, +UNIQUE KEY `col1` (`col1`) +); +INSERT INTO `t2` (`t1_Id`, `col1`) VALUES (1, NULL), (1, NULL); +SELECT Id FROM t1 WHERE Id in (SELECT t1_Id FROM t2 WHERE t2.col1 IS NULL); +Id +1 +explain extended +SELECT Id FROM t1 WHERE Id in (SELECT t1_Id FROM t2 WHERE t2.col1 IS NULL); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 system PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t2 ref col1 col1 5 const 1 100.00 Using index condition; Using where +Warnings: +Note 1003 select 1 AS `Id` from (`test`.`t2`) where ((`test`.`t2`.`t1_Id` = 1) and isnull(`test`.`t2`.`col1`)) +DROP TABLE t1, t2; # End of 5.5 test set optimizer_switch=@subselect_sj_tmp; diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result index e9a8b7301f7..6b5cf9dea1c 100644 --- a/mysql-test/r/subselect_sj_jcl6.result +++ b/mysql-test/r/subselect_sj_jcl6.result @@ -3200,6 +3200,32 @@ create table t1 (a1 varchar(25)); create table t2 (a2 varchar(25)) ; insert into t1 select 'xxx' from dual where 'xxx' in (select a2 from t2); drop table t1,t2; +# +# MDEV-13172: Wrong result / SELECT ... WHERE EXISTS ... (with UNIQUE Key) +# +CREATE TABLE `t1` ( +`Id` int(11) NOT NULL, +PRIMARY KEY (`Id`) +); +INSERT INTO `t1` (`Id`) VALUES (1); +CREATE TABLE `t2` ( +`t1_Id` int(11) NOT NULL DEFAULT 0, +`col1` int(11) DEFAULT NULL, +UNIQUE KEY `col1` (`col1`) +); +INSERT INTO `t2` (`t1_Id`, `col1`) VALUES (1, NULL), (1, NULL); +SELECT Id FROM t1 WHERE Id in (SELECT t1_Id FROM t2 WHERE t2.col1 IS NULL); +Id +1 +explain extended +SELECT Id FROM t1 WHERE Id in (SELECT t1_Id FROM t2 WHERE t2.col1 IS NULL); +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 system PRIMARY NULL NULL NULL 1 100.00 +1 PRIMARY eq_ref distinct_key distinct_key 4 func 1 100.00 +2 MATERIALIZED t2 ref col1 col1 5 const 1 100.00 Using index condition; Using where +Warnings: +Note 1003 select 1 AS `Id` from (`test`.`t2`) where ((`test`.`t2`.`t1_Id` = 1) and isnull(`test`.`t2`.`col1`)) +DROP TABLE t1, t2; # End of 5.5 test set optimizer_switch=@subselect_sj_tmp; # diff --git a/mysql-test/t/subselect_sj.test b/mysql-test/t/subselect_sj.test index 6b59049bc4f..befa2c7af5a 100644 --- a/mysql-test/t/subselect_sj.test +++ b/mysql-test/t/subselect_sj.test @@ -2881,6 +2881,32 @@ insert into t1 select 'xxx' from dual where 'xxx' in (select a2 from t2); drop table t1,t2; + +--echo # +--echo # MDEV-13172: Wrong result / SELECT ... WHERE EXISTS ... (with UNIQUE Key) +--echo # + +CREATE TABLE `t1` ( + `Id` int(11) NOT NULL, + PRIMARY KEY (`Id`) +); + +INSERT INTO `t1` (`Id`) VALUES (1); + +CREATE TABLE `t2` ( + `t1_Id` int(11) NOT NULL DEFAULT 0, + `col1` int(11) DEFAULT NULL, + UNIQUE KEY `col1` (`col1`) +); + +INSERT INTO `t2` (`t1_Id`, `col1`) VALUES (1, NULL), (1, NULL); + +SELECT Id FROM t1 WHERE Id in (SELECT t1_Id FROM t2 WHERE t2.col1 IS NULL); +explain extended +SELECT Id FROM t1 WHERE Id in (SELECT t1_Id FROM t2 WHERE t2.col1 IS NULL); + +DROP TABLE t1, t2; + --echo # End of 5.5 test # The following command must be the last one the file diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index cb821325e57..f876129aed7 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2640,9 +2640,17 @@ bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables) { do /* For all equalities on all key parts */ { - /* Check if this is "t.keypart = expr(outer_tables) */ + /* + Check if this is "t.keypart = expr(outer_tables) + + Don't allow variants that can produce duplicates: + - Dont allow "ref or null" + - the keyuse (that is, the operation) must be null-rejecting, + unless the other expression is non-NULLable. + */ if (!(keyuse->used_tables & sj_inner_tables) && - !(keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL)) + !(keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL) && + (keyuse->null_rejecting || !keyuse->val->maybe_null)) { bound_parts |= 1 << keyuse->keypart; } From 7952f7720f967b43873e4fac13583984803fae3b Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 15 Oct 2019 20:26:40 +0300 Subject: [PATCH 11/68] MDEV-10748 Server crashes in ha_maria::implicit_commit Problem was in a combination of LOCK TABLES on several Aria tables followed by an ALTER TABLE. After the ALTER TABLE there was a force close + reopen of the alter table. The close failed because the table was still part of a transaction. Fixed by calling extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE) as part of closing the table, which ensures that the table is not anymore part of the current transaction. --- mysql-test/suite/maria/lock.result | 12 ++++++++++++ mysql-test/suite/maria/lock.test | 17 +++++++++++++++++ sql/sql_base.cc | 14 +++++++++++--- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/maria/lock.result b/mysql-test/suite/maria/lock.result index b7d5a9c220d..a1f533e80fb 100644 --- a/mysql-test/suite/maria/lock.result +++ b/mysql-test/suite/maria/lock.result @@ -109,4 +109,16 @@ ALTER TABLE t1 ADD UNIQUE KEY (f1); ERROR 23000: Duplicate entry 'foo' for key 'f1' ALTER TABLE t1 ADD KEY (f2); DROP TABLE t1; +# +# MDEV-10748 Server crashes in ha_maria::implicit_commit upon ALTER TABLE +# +CREATE TABLE t1 (a INT, b INT) ENGINE=Aria; +SELECT * FROM t1; +a b +CREATE TABLE t2 (c INT) ENGINE=Aria; +LOCK TABLE t2 READ, t1 WRITE; +ALTER TABLE t1 CHANGE b a INT; +ERROR 42S21: Duplicate column name 'a' +UNLOCK TABLES; +DROP TABLE t1, t2; # End of 10.2 tests diff --git a/mysql-test/suite/maria/lock.test b/mysql-test/suite/maria/lock.test index b22c9cc70d7..220e3839010 100644 --- a/mysql-test/suite/maria/lock.test +++ b/mysql-test/suite/maria/lock.test @@ -118,4 +118,21 @@ ALTER TABLE t1 ADD UNIQUE KEY (f1); ALTER TABLE t1 ADD KEY (f2); DROP TABLE t1; + +--echo # +--echo # MDEV-10748 Server crashes in ha_maria::implicit_commit upon ALTER TABLE +--echo # + +CREATE TABLE t1 (a INT, b INT) ENGINE=Aria; +SELECT * FROM t1; +CREATE TABLE t2 (c INT) ENGINE=Aria; + +LOCK TABLE t2 READ, t1 WRITE; +--error ER_DUP_FIELDNAME +ALTER TABLE t1 CHANGE b a INT; + +# Cleanup +UNLOCK TABLES; +DROP TABLE t1, t2; + --echo # End of 10.2 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7276467f188..761c4daa88b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2426,9 +2426,17 @@ Locked_tables_list::reopen_tables(THD *thd, bool need_reopen) { if (!table_list->table || !table_list->table->needs_reopen()) continue; - /* no need to remove the table from the TDC here, thus (TABLE*)1 */ - close_all_tables_for_name(thd, table_list->table->s, - HA_EXTRA_NOT_USED, (TABLE*)1); + for (TABLE **prev= &thd->open_tables; *prev; prev= &(*prev)->next) + { + if (*prev == table_list->table) + { + thd->locked_tables_list.unlink_from_list(thd, table_list, false); + mysql_lock_remove(thd, thd->lock, *prev); + (*prev)->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE); + close_thread_table(thd, prev); + break; + } + } DBUG_ASSERT(table_list->table == NULL); } else From b7bc8c3fcbe718717934b404963305c6772a5c23 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Tue, 15 Oct 2019 19:28:24 +0200 Subject: [PATCH 12/68] MDEV-20466: fix of test suite --- mysql-test/r/processlist.result | 6 ++++ mysql-test/r/processlist_MDEV-20466.result | Bin 775 -> 0 bytes mysql-test/t/processlist.test | 29 +++++++++++++++++ mysql-test/t/processlist_MDEV-20466.test | 35 --------------------- 4 files changed, 35 insertions(+), 35 deletions(-) delete mode 100644 mysql-test/r/processlist_MDEV-20466.result delete mode 100644 mysql-test/t/processlist_MDEV-20466.test diff --git a/mysql-test/r/processlist.result b/mysql-test/r/processlist.result index 55d2425d269..24802cb2425 100644 --- a/mysql-test/r/processlist.result +++ b/mysql-test/r/processlist.result @@ -17,4 +17,10 @@ select command, time < 5 from information_schema.processlist where id != connect command time < 5 Sleep 1 set debug_sync='reset'; +# +# MDEV-20466: SHOW PROCESSLIST truncates query text on \0 bytes +# +SET DEBUG_SYNC= 'before_join_optimize SIGNAL in_sync'; +SET DEBUG_SYNC= 'now WAIT_FOR in_sync'; +SET DEBUG_SYNC = 'RESET'; End of 5.5 tests diff --git a/mysql-test/r/processlist_MDEV-20466.result b/mysql-test/r/processlist_MDEV-20466.result deleted file mode 100644 index 7120212d0f03a73094a9dd164838e3ef9a6a9e20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 775 zcmbtSUvJYe5a-qX6esPWOoD0xwue=FD6O|fYMT*fR7glsnmCJD;_G~lO8E4g(}AE* zNW3Ju*!TN)cLtEwhQMp`Q0D|WI89yS!PmJ5V~eIMHNn>l*!5mdMrQ!3D{8(MYH0H( zJ}pgEfk*I8bCa(%9BOPdRE8f6x-&L+{hQF7+cMmAy6Q-Wuc6oY0Xb#PF>!OxAiq@c zd*1~q%t?BmyPSCg@_>$eX5t1G*Qa01sg1HEuJMCDJ{_X?dOBBQiN~W-oA0O^A^<^`^f$>gP z=ydiCjm>cHO>2H=P|@9HwqgSr^|lyKxosuqDR2M|Zj*QoZBNh5WT>}GnaJbO&6u#& zuf~85sL^^4uiu|fL;DG<#RF_-QJUSx$)7YQj;5oi6c0=)mPlTdJ2A($<$;LQv|1?7 zW<_Kx6!#7vc@1b3Erdh#Vi~J6+sxKdghdgbLLefIxZdW*8~Yf7DUhK~V;pW}YxNIM iLE6!%_@9J+Gya_u@OTo*|9AkBmyq}2a&mdxhS5)qp!L20 diff --git a/mysql-test/t/processlist.test b/mysql-test/t/processlist.test index 8a8995f43b0..52cb6b31919 100644 --- a/mysql-test/t/processlist.test +++ b/mysql-test/t/processlist.test @@ -51,4 +51,33 @@ select command, time < 5 from information_schema.processlist where id != connect disconnect con1; set debug_sync='reset'; +--echo # +--echo # MDEV-20466: SHOW PROCESSLIST truncates query text on \0 bytes +--echo # + +connect (con1,localhost,root,,); + +connection con1; + +let $q= `select CONCAT("SELECT user FROM mysql.user WHERE user ='some", CHAR(0), "' or sleep (30)")`; + +SET DEBUG_SYNC= 'before_join_optimize SIGNAL in_sync'; +--disable_query_log +--send_eval $q; +--enable_query_log +connection default; + +SET DEBUG_SYNC= 'now WAIT_FOR in_sync'; + +exec $MYSQL test -e "SHOW PROCESSLIST" > $MYSQLTEST_VARDIR/tmp/MDEV-20466.text; + +let SEARCH_FILE=$MYSQLTEST_VARDIR/tmp/MDEV-20466.text; +let SEARCH_PATTERN=sleep; +source include/search_pattern_in_file.inc; +remove_file $MYSQLTEST_VARDIR/tmp//MDEV-20466.text; + +disconnect con1; + +SET DEBUG_SYNC = 'RESET'; + --echo End of 5.5 tests diff --git a/mysql-test/t/processlist_MDEV-20466.test b/mysql-test/t/processlist_MDEV-20466.test deleted file mode 100644 index 70b56d25d72..00000000000 --- a/mysql-test/t/processlist_MDEV-20466.test +++ /dev/null @@ -1,35 +0,0 @@ ---echo # This test has a result that includes \0 byte. ---echo # Such a byte makes diff to treat the whole file as binary, ---echo # and to refuse to diff it. ---echo # That's why this test is put in a separate file, ---echo # so that diff would still work on results of other tests. - -source include/have_debug.inc; -source include/have_debug_sync.inc; - ---echo # ---echo # MDEV-20466: SHOW PROCESSLIST truncates query text on \0 bytes ---echo # - -connect (con1,localhost,root,,); - -#select * from information_schema.processlist; -connection con1; - -let $q= `select CONCAT("SELECT user FROM mysql.user WHERE user ='some", CHAR(0), "' or sleep (3)")`; - -SET DEBUG_SYNC= 'before_join_optimize SIGNAL in_sync'; ---send_eval $q; - -connection default; - -SET DEBUG_SYNC= 'now WAIT_FOR in_sync'; - ---replace_column 1 ID 3 HOST_NAME 6 TIME 9 TIME_MS -SHOW PROCESSLIST; - -disconnect con1; - -SET DEBUG_SYNC = 'RESET'; - ---echo End of 5.5 tests From 6cdde9ebbf59254a81f04961818577ffd203f9d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 16 Oct 2019 13:01:40 +0300 Subject: [PATCH 13/68] MDEV-20836 : Galera test failure on wsrep.variables Add one more wait to make sure all threads have been started. --- mysql-test/suite/wsrep/r/variables.result | 25 ++++++++++++----------- mysql-test/suite/wsrep/t/variables.test | 15 ++++++++------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result index 6314132ca6c..ebd6c41d9bc 100644 --- a/mysql-test/suite/wsrep/r/variables.result +++ b/mysql-test/suite/wsrep/r/variables.result @@ -190,14 +190,15 @@ wsrep_thread_count 0 # applier/rollbacker threads. SET GLOBAL wsrep_cluster_address= 'gcomm://'; # Wait for applier thread to get created 1. -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; -VARIABLE_VALUE +# Wait for applier thread to get created 2. +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; +EXPECT_1 1 -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; -VARIABLE_VALUE +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; +EXPECT_1 1 -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; -VARIABLE_VALUE +SELECT VARIABLE_VALUE AS EXPECT_2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; +EXPECT_2 2 SELECT @@global.wsrep_provider; @@global.wsrep_provider @@ -215,14 +216,14 @@ wsrep_thread_count 2 SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads; SET GLOBAL wsrep_slave_threads= 10; # Wait for 9 applier threads to get created. -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; -VARIABLE_VALUE +SELECT VARIABLE_VALUE AS EXPECT_10 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; +EXPECT_10 10 -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; -VARIABLE_VALUE +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; +EXPECT_1 1 -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; -VARIABLE_VALUE +SELECT VARIABLE_VALUE AS EXPECT_11 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; +EXPECT_11 11 SHOW STATUS LIKE 'threads_connected'; Variable_name Value diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index 5032398fc42..6caa5cff500 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -102,10 +102,13 @@ SET GLOBAL wsrep_cluster_address= 'gcomm://'; --echo # Wait for applier thread to get created 1. --let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; --source include/wait_condition.inc +--echo # Wait for applier thread to get created 2. +--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; +--source include/wait_condition.inc -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; --replace_regex /.*libgalera_smm.*/libgalera_smm.so/ SELECT @@global.wsrep_provider; @@ -121,9 +124,9 @@ SET GLOBAL wsrep_slave_threads= 10; --let $wait_condition = SELECT VARIABLE_VALUE = 10 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; --source include/wait_condition.inc -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_10 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_applier_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_rollbacker_thread_count'; +SELECT VARIABLE_VALUE AS EXPECT_11 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count'; SHOW STATUS LIKE 'threads_connected'; From 3ce14a66efc69a4ed9903ce121f5b0e9f469b12b Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 16 Oct 2019 18:40:31 +0300 Subject: [PATCH 14/68] Fixed bug in lock tables + alter table with Aria tables. MDEV-18451 Server crashes in maria_create_trn_for_mysql upon ALTER TABLE Problem was that when table was locked many times, not all instances where removed from the transaction by _ma_remove_table_from_trnman() --- mysql-test/r/kill.result | 1 - mysql-test/suite/maria/lock.result | 21 +++++++++++++++++++++ mysql-test/suite/maria/lock.test | 29 +++++++++++++++++++++++++++++ mysql-test/t/kill.test | 2 +- storage/maria/ma_state.c | 26 +++++++++++++++----------- 5 files changed, 66 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result index c2ad72e4240..e3fbb830df5 100644 --- a/mysql-test/r/kill.result +++ b/mysql-test/r/kill.result @@ -412,7 +412,6 @@ LOCK TABLES v1 READ, t2 WRITE, t1 WRITE; ALTER TABLE t1 CHANGE f1 f2 DOUBLE; Got one of the listed errors ALTER TABLE t2 DROP c; -ERROR 70100: Query execution was interrupted (max_statement_time exceeded) UNLOCK TABLES; DROP VIEW v1; DROP TABLE t1, t2; diff --git a/mysql-test/suite/maria/lock.result b/mysql-test/suite/maria/lock.result index a1f533e80fb..381f745b198 100644 --- a/mysql-test/suite/maria/lock.result +++ b/mysql-test/suite/maria/lock.result @@ -121,4 +121,25 @@ ALTER TABLE t1 CHANGE b a INT; ERROR 42S21: Duplicate column name 'a' UNLOCK TABLES; DROP TABLE t1, t2; +# +# MDEV-10748 Server crashes in ha_maria::implicit_commit upon ALTER TABLE +# +CREATE TABLE t1 (a INT) ENGINE=Aria; +CREATE TABLE t2 (b INT) ENGINE=Aria; +LOCK TABLES t1 WRITE, t2 AS t2a WRITE, t2 WRITE; +ALTER TABLE t2 CHANGE b c VARBINARY(30000), ALGORITHM=COPY; +UNLOCK TABLES; +DROP TABLE t1, t2; +# More complex test, from RQG +CREATE TABLE t1 (a INT) ENGINE=Aria; +CREATE TABLE t2 (b INT) ENGINE=Aria; +CREATE OR REPLACE VIEW v2 AS SELECT * FROM t2 ; +LOCK TABLES t1 WRITE, t2 AS t2a WRITE, v2 WRITE CONCURRENT, t2 WRITE; +ALTER TABLE t1 FORCE; +ALTER TABLE t2 CHANGE b c VARBINARY(30000), ALGORITHM=INPLACE; +ERROR 0A000: ALGORITHM=INPLACE is not supported for this operation. Try ALGORITHM=COPY +ALTER TABLE t2 CHANGE b c VARBINARY(30000), ALGORITHM=COPY; +UNLOCK TABLES; +DROP VIEW v2; +DROP TABLE t1, t2; # End of 10.2 tests diff --git a/mysql-test/suite/maria/lock.test b/mysql-test/suite/maria/lock.test index 220e3839010..9bac569de50 100644 --- a/mysql-test/suite/maria/lock.test +++ b/mysql-test/suite/maria/lock.test @@ -135,4 +135,33 @@ ALTER TABLE t1 CHANGE b a INT; UNLOCK TABLES; DROP TABLE t1, t2; +--echo # +--echo # MDEV-10748 Server crashes in ha_maria::implicit_commit upon ALTER TABLE +--echo # + +CREATE TABLE t1 (a INT) ENGINE=Aria; +CREATE TABLE t2 (b INT) ENGINE=Aria; + +LOCK TABLES t1 WRITE, t2 AS t2a WRITE, t2 WRITE; +ALTER TABLE t2 CHANGE b c VARBINARY(30000), ALGORITHM=COPY; +UNLOCK TABLES; +DROP TABLE t1, t2; + +--echo # More complex test, from RQG + +CREATE TABLE t1 (a INT) ENGINE=Aria; +CREATE TABLE t2 (b INT) ENGINE=Aria; +CREATE OR REPLACE VIEW v2 AS SELECT * FROM t2 ; + +LOCK TABLES t1 WRITE, t2 AS t2a WRITE, v2 WRITE CONCURRENT, t2 WRITE; + +ALTER TABLE t1 FORCE; +--error ER_ALTER_OPERATION_NOT_SUPPORTED +ALTER TABLE t2 CHANGE b c VARBINARY(30000), ALGORITHM=INPLACE; +ALTER TABLE t2 CHANGE b c VARBINARY(30000), ALGORITHM=COPY; + +UNLOCK TABLES; +DROP VIEW v2; +DROP TABLE t1, t2; + --echo # End of 10.2 tests diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index a188cee52f2..78de8a784f3 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -658,7 +658,7 @@ CREATE TABLE t2 (b INT, c INT); LOCK TABLES v1 READ, t2 WRITE, t1 WRITE; --error ER_BAD_FIELD_ERROR,ER_STATEMENT_TIMEOUT ALTER TABLE t1 CHANGE f1 f2 DOUBLE; ---error ER_STATEMENT_TIMEOUT +--error 0,ER_STATEMENT_TIMEOUT ALTER TABLE t2 DROP c; UNLOCK TABLES; DROP VIEW v1; diff --git a/storage/maria/ma_state.c b/storage/maria/ma_state.c index f6939c7103f..e90822fe500 100644 --- a/storage/maria/ma_state.c +++ b/storage/maria/ma_state.c @@ -455,7 +455,7 @@ my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit, MARIA_USED_TABLES *tables, *next; DBUG_ENTER("_ma_trnman_end_trans_hook"); DBUG_PRINT("enter", ("trn: %p used_tables: %p", trn, trn->used_tables)); - + for (tables= (MARIA_USED_TABLES*) trn->used_tables; tables; tables= next) @@ -572,6 +572,7 @@ void _ma_remove_table_from_trnman(MARIA_HA *info) TRN *trn= info->trn; MARIA_USED_TABLES *tables, **prev; MARIA_HA *handler, **prev_file; + uint unlinked= 0; DBUG_ENTER("_ma_remove_table_from_trnman"); DBUG_PRINT("enter", ("trn: %p used_tables: %p share: %p in_trans: %d", trn, trn->used_tables, share, share->in_trans)); @@ -580,7 +581,7 @@ void _ma_remove_table_from_trnman(MARIA_HA *info) if (trn == &dummy_transaction_object) DBUG_VOID_RETURN; - + /* First remove share from used_tables */ for (prev= (MARIA_USED_TABLES**) (char*) &trn->used_tables; (tables= *prev); @@ -594,7 +595,7 @@ void _ma_remove_table_from_trnman(MARIA_HA *info) break; } } - if (tables != 0) + if (!tables) { /* This can only happens in case of rename of intermediate table as @@ -603,18 +604,21 @@ void _ma_remove_table_from_trnman(MARIA_HA *info) DBUG_PRINT("warning", ("share: %p where not in used_tables_list", share)); } - /* unlink table from used_instances */ - for (prev_file= (MARIA_HA**) &trn->used_instances; - (handler= *prev_file); - prev_file= &handler->trn_next) + /* unlink all instances of the table from used_instances */ + prev_file= (MARIA_HA**) &trn->used_instances; + while ((handler= *prev_file)) { - if (handler == info) + if (handler->s == share) { - *prev_file= info->trn_next; - break; + unlinked++; + *prev_file= handler->trn_next; /* Remove instance */ } + else + prev_file= &handler->trn_next; /* Continue with next instance */ } - if (handler != 0) + + DBUG_PRINT("note", ("unlinked tables: %u", unlinked)); + if (!unlinked) { /* This can only happens in case of rename of intermediate table as From b56589eaf2c7dcaabcacfddd05fde44023287f29 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 16 Oct 2019 17:40:49 +0200 Subject: [PATCH 15/68] Some small changes. =================== - Fix unhandled throws, add some trace + typo modified: storage/connect/jdbconn.cpp modified: storage/connect/tabodbc.cpp modified: storage/connect/valblk.cpp modified: storage/connect/value.cpp --- storage/connect/jdbconn.cpp | 11 +- storage/connect/tabodbc.cpp | 6 +- storage/connect/valblk.cpp | 4 +- storage/connect/value.cpp | 587 ++++++++++++++++++------------------ 4 files changed, 311 insertions(+), 297 deletions(-) diff --git a/storage/connect/jdbconn.cpp b/storage/connect/jdbconn.cpp index e0aca3333e6..2cb75e0adc1 100644 --- a/storage/connect/jdbconn.cpp +++ b/storage/connect/jdbconn.cpp @@ -1196,9 +1196,14 @@ int JDBConn::GetResultSize(PCSZ sql, PCOL colp) if ((rc = ExecuteQuery(sql)) != RC_OK) return -1; - if ((rc = Fetch()) > 0) - SetColumnValue(1, NULL, colp->GetValue()); - else + if ((rc = Fetch()) > 0) { + try { + SetColumnValue(1, NULL, colp->GetValue()); + } catch (...) { + return -4; + } // end catch + + } else return -2; if ((rc = Fetch()) != 0) diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index 0fa117c3d2f..ba5c65e2c94 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -605,8 +605,10 @@ bool TDBODBC::OpenDB(PGLOBAL g) Cnp->InitValue(g); if ((n = Ocp->GetResultSize(Query->GetStr(), Cnp)) < 0) { - strcpy(g->Message, "Cannot get result size"); - return true; + char* msg = PlugDup(g, g->Message); + + sprintf(g->Message, "Get result size: %s (rc=%d)", msg, n); + return true; } else if (n) { Ocp->m_Rows = n; diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp index 73ca135691c..d6c4218265b 100644 --- a/storage/connect/valblk.cpp +++ b/storage/connect/valblk.cpp @@ -206,6 +206,7 @@ void VALBLK::ChkIndx(int n) { if (n < 0 || n >= Nval) { PGLOBAL& g = Global; + xtrc(1, "ChkIndx: n=%d Nval=%d\n", n, Nval); strcpy(g->Message, MSG(BAD_VALBLK_INDX)); throw Type; } // endif n @@ -216,7 +217,8 @@ void VALBLK::ChkTyp(PVAL v) { if (Check && (Type != v->GetType() || Unsigned != v->IsUnsigned())) { PGLOBAL& g = Global; - strcpy(g->Message, MSG(VALTYPE_NOMATCH)); + xtrc(1, "ChkTyp: Type=%d valType=%d\n", Type, v->GetType()); + strcpy(g->Message, MSG(VALTYPE_NOMATCH)); throw Type; } // endif Type diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index d9330a68a15..158495de26c 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -123,7 +123,7 @@ ulonglong CharToNumber(const char *p, int n, ulonglong maxval, case '+': p++; break; - } // endswitch *p + } // endswitch *p for (val = 0; p < p2 && (c = (uchar)(*p - '0')) < 10; p++) if (val > (maxval - c) / 10) { @@ -140,7 +140,7 @@ ulonglong CharToNumber(const char *p, int n, ulonglong maxval, /* GetTypeName: returns the PlugDB internal type name. */ /***********************************************************************/ PCSZ GetTypeName(int type) - { +{ PCSZ name; switch (type) { @@ -155,17 +155,17 @@ PCSZ GetTypeName(int type) case TYPE_BIN: name = "BINARY"; break; case TYPE_PCHAR: name = "PCHAR"; break; default: name = "UNKNOWN"; break; - } // endswitch type + } // endswitch type return name; - } // end of GetTypeName +} // end of GetTypeName /***********************************************************************/ /* GetTypeSize: returns the PlugDB internal type size. */ /***********************************************************************/ int GetTypeSize(int type, int len) { - switch (type) { + switch (type) { case TYPE_DECIM: case TYPE_BIN: case TYPE_STRING: len = len * sizeof(char); break; @@ -177,16 +177,16 @@ int GetTypeSize(int type, int len) case TYPE_TINY: len = sizeof(char); break; case TYPE_PCHAR: len = sizeof(char*); break; default: len = -1; - } // endswitch type + } // endswitch type return len; - } // end of GetTypeSize +} // end of GetTypeSize /***********************************************************************/ /* GetFormatType: returns the FORMAT character(s) according to type. */ /***********************************************************************/ const char *GetFormatType(int type) - { +{ const char *c = "X"; switch (type) { @@ -200,16 +200,16 @@ const char *GetFormatType(int type) case TYPE_DECIM: c = "M"; break; case TYPE_BIN: c = "B"; break; case TYPE_PCHAR: c = "P"; break; - } // endswitch type + } // endswitch type return c; - } // end of GetFormatType +} // end of GetFormatType /***********************************************************************/ /* GetFormatType: returns the FORMAT type according to character. */ /***********************************************************************/ int GetFormatType(char c) - { +{ int type = TYPE_ERROR; switch (c) { @@ -223,31 +223,31 @@ int GetFormatType(char c) case 'M': type = TYPE_DECIM; break; case 'B': type = TYPE_BIN; break; case 'P': type = TYPE_PCHAR; break; - } // endswitch type + } // endswitch type return type; - } // end of GetFormatType +} // end of GetFormatType /***********************************************************************/ /* IsTypeChar: returns true for character type(s). */ /***********************************************************************/ bool IsTypeChar(int type) - { +{ switch (type) { case TYPE_STRING: case TYPE_DECIM: case TYPE_BIN: return true; - } // endswitch type + } // endswitch type return false; - } // end of IsTypeChar +} // end of IsTypeChar /***********************************************************************/ /* IsTypeNum: returns true for numeric types. */ /***********************************************************************/ bool IsTypeNum(int type) - { +{ switch (type) { case TYPE_INT: case TYPE_BIGINT: @@ -258,16 +258,16 @@ bool IsTypeNum(int type) case TYPE_TINY: case TYPE_DECIM: return true; - } // endswitch type + } // endswitch type return false; - } // end of IsTypeNum +} // end of IsTypeNum /***********************************************************************/ /* GetFmt: returns the format to use with a typed value. */ /***********************************************************************/ const char *GetFmt(int type, bool un) - { +{ const char *fmt; switch (type) { @@ -278,10 +278,10 @@ const char *GetFmt(int type, bool un) case TYPE_DOUBLE: fmt = "%.*lf"; break; case TYPE_BIN: fmt = "%*x"; break; default: fmt = (un) ? "%u" : "%d"; break; - } // endswitch Type + } // endswitch Type return fmt; - } // end of GetFmt +} // end of GetFmt /***********************************************************************/ /* ConvertType: what this function does is to determine the type to */ @@ -293,7 +293,7 @@ const char *GetFmt(int type, bool un) /* IsType... functions so match does not prevent correct setting. */ /***********************************************************************/ int ConvertType(int target, int type, CONV kind, bool match) - { +{ switch (kind) { case CNV_CHAR: if (match && (!IsTypeChar(target) || !IsTypeChar(type))) @@ -326,15 +326,15 @@ int ConvertType(int target, int type, CONV kind, bool match) : (target == TYPE_STRING || type == TYPE_STRING) ? TYPE_STRING : (target == TYPE_TINY || type == TYPE_TINY) ? TYPE_TINY : TYPE_ERROR; - } // endswitch kind + } // endswitch kind - } // end of ConvertType +} // end of ConvertType /***********************************************************************/ /* AllocateConstant: allocates a constant Value. */ /***********************************************************************/ PVAL AllocateValue(PGLOBAL g, void *value, short type, short prec) - { +{ PVAL valp; if (trace(1)) @@ -362,18 +362,18 @@ PVAL AllocateValue(PGLOBAL g, void *value, short type, short prec) default: sprintf(g->Message, MSG(BAD_VALUE_TYPE), type); return NULL; - } // endswitch Type + } // endswitch Type valp->SetGlobal(g); return valp; - } // end of AllocateValue +} // end of AllocateValue /***********************************************************************/ /* Allocate a variable Value according to type, length and precision. */ /***********************************************************************/ PVAL AllocateValue(PGLOBAL g, int type, int len, int prec, bool uns, PCSZ fmt) - { +{ PVAL valp; switch (type) { @@ -423,18 +423,18 @@ PVAL AllocateValue(PGLOBAL g, int type, int len, int prec, default: sprintf(g->Message, MSG(BAD_VALUE_TYPE), type); return NULL; - } // endswitch type + } // endswitch type valp->SetGlobal(g); return valp; - } // end of AllocateValue +} // end of AllocateValue /***********************************************************************/ /* Allocate a constant Value converted to newtype. */ /* Can also be used to copy a Value eventually converted. */ /***********************************************************************/ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns) - { +{ PSZ p, sp; bool un = (uns < 0) ? false : (uns > 0) ? true : valp->IsUnsigned(); PVAL vp; @@ -495,13 +495,13 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns) default: sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype); return NULL; - } // endswitch type + } // endswitch type vp->SetNullable(valp->GetNullable()); vp->SetNull(valp->IsNull()); vp->SetGlobal(g); return vp; - } // end of AllocateValue +} // end of AllocateValue /* -------------------------- Class VALUE ---------------------------- */ @@ -509,7 +509,7 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns) /* Class VALUE protected constructor. */ /***********************************************************************/ VALUE::VALUE(int type, bool un) : Type(type) - { +{ Null = false; Nullable = false; Unsigned = un; @@ -517,13 +517,13 @@ VALUE::VALUE(int type, bool un) : Type(type) Prec = 0; Fmt = GetFmt(Type, Unsigned); Xfmt = GetXfmt(); - } // end of VALUE constructor +} // end of VALUE constructor /***********************************************************************/ /* VALUE GetXfmt: returns the extended format to use with typed value. */ /***********************************************************************/ const char *VALUE::GetXfmt(void) - { +{ const char *fmt; switch (Type) { @@ -537,7 +537,7 @@ const char *VALUE::GetXfmt(void) } // endswitch Type return fmt; - } // end of GetFmt +} // end of GetXFmt /***********************************************************************/ /* Returns a BYTE indicating the comparison between two values. */ @@ -545,20 +545,20 @@ const char *VALUE::GetXfmt(void) /* More than 1 bit can be set only in the case of TYPE_LIST. */ /***********************************************************************/ BYTE VALUE::TestValue(PVAL vp) - { +{ int n = CompareValue(vp); return (n > 0) ? 0x04 : (n < 0) ? 0x02 : 0x01; - } // end of TestValue +} // end of TestValue /***********************************************************************/ /* Compute a function on a string. */ /***********************************************************************/ bool VALUE::Compute(PGLOBAL g, PVAL *, int, OPVAL) - { +{ strcpy(g->Message, "Compute not implemented for this value type"); return true; - } // end of Compute +} // end of Compute /***********************************************************************/ /* Make file output of an object value. */ @@ -600,11 +600,11 @@ void VALUE::Prints(PGLOBAL g, char *ps, uint z) template TYPVAL::TYPVAL(TYPE n, int type, int prec, bool un) : VALUE(type, un) - { +{ Tval = n; Clen = sizeof(TYPE); Prec = prec; - } // end of TYPVAL constructor +} // end of TYPVAL constructor /***********************************************************************/ /* Return unsigned max value for the type. */ @@ -641,19 +641,19 @@ ulonglong TYPVAL::MaxVal(void) {return ULONGLONG_MAX;} /***********************************************************************/ template int TYPVAL::GetValLen(void) - { +{ char c[32]; - return sprintf(c, Fmt, Tval); - } // end of GetValLen + return snprintf(c, 32, Fmt, Tval); +} // end of GetValLen template <> int TYPVAL::GetValLen(void) - { +{ char c[32]; - return sprintf(c, Fmt, Prec, Tval); - } // end of GetValLen + return snprintf(c, 32, Fmt, Prec, Tval); +} // end of GetValLen /***********************************************************************/ /* TYPVAL SetValue: copy the value of another Value object. */ @@ -661,7 +661,7 @@ int TYPVAL::GetValLen(void) /***********************************************************************/ template bool TYPVAL::SetValue_pval(PVAL valp, bool chktype) - { +{ if (valp != this) { if (chktype && Type != valp->GetType()) return true; @@ -671,10 +671,10 @@ bool TYPVAL::SetValue_pval(PVAL valp, bool chktype) else Reset(); - } // endif valp + } // endif valp return false; - } // end of SetValue +} // end of SetValue template <> short TYPVAL::GetTypedValue(PVAL valp) @@ -717,7 +717,7 @@ uchar TYPVAL::GetTypedValue(PVAL valp) /***********************************************************************/ template bool TYPVAL::SetValue_char(const char *p, int n) - { +{ bool rc, minus; ulonglong maxval = MaxVal(); ulonglong val = CharToNumber(p, n, maxval, Unsigned, &minus, &rc); @@ -731,15 +731,15 @@ bool TYPVAL::SetValue_char(const char *p, int n) char buf[64]; htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"), GetTypeName(Type), Tval); - } // endif trace + } // endif trace Null = false; return rc; - } // end of SetValue +} // end of SetValue template <> bool TYPVAL::SetValue_char(const char *p, int n) - { +{ if (p && n > 0) { char buf[64]; @@ -760,14 +760,14 @@ bool TYPVAL::SetValue_char(const char *p, int n) } // endif p return false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* TYPVAL SetValue: fill a typed value from a string. */ /***********************************************************************/ template void TYPVAL::SetValue_psz(PCSZ s) - { +{ if (s) { SetValue_char(s, (int)strlen(s)); Null = false; @@ -776,17 +776,17 @@ void TYPVAL::SetValue_psz(PCSZ s) Null = Nullable; } // endif p - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* TYPVAL SetValue: set value with a TYPE extracted from a block. */ /***********************************************************************/ template void TYPVAL::SetValue_pvblk(PVBLK blk, int n) - { +{ Tval = GetTypedValue(blk, n); Null = false; - } // end of SetValue +} // end of SetValue template <> int TYPVAL::GetTypedValue(PVBLK blk, int n) @@ -852,7 +852,7 @@ void TYPVAL::SetBinValue(void *p) /***********************************************************************/ template bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) - { +{ // Test on length was removed here until a variable in column give the // real field length. For BIN files the field length logically cannot // be different from the variable length because no conversion is done. @@ -876,40 +876,41 @@ bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) Null = false; return false; - } // end of GetBinValue +} // end of GetBinValue /***********************************************************************/ /* TYPVAL ShowValue: get string representation of a typed value. */ /***********************************************************************/ template int TYPVAL::ShowValue(char *buf, int len) - { - return snprintf(buf, len + 1, Xfmt, len, Tval); - } // end of ShowValue +{ + return snprintf(buf, len, Xfmt, len, Tval); +} // end of ShowValue template <> int TYPVAL::ShowValue(char *buf, int len) - { +{ // TODO: use a more appropriate format to avoid possible truncation - return snprintf(buf, len + 1, Xfmt, len, Prec, Tval); - } // end of ShowValue + return snprintf(buf, len, Xfmt, len, Prec, Tval); +} // end of ShowValue /***********************************************************************/ /* TYPVAL GetCharString: get string representation of a typed value. */ /***********************************************************************/ template char *TYPVAL::GetCharString(char *p) - { +{ sprintf(p, Fmt, Tval); return p; - } // end of GetCharString +} // end of GetCharString template <> char *TYPVAL::GetCharString(char *p) - { - sprintf(p, Fmt, Prec, Tval); +{ + // Most callers use a 32 long buffer + snprintf(p, 32, Fmt, Prec, Tval); return p; - } // end of GetCharString +} // end of GetCharString #if 0 /***********************************************************************/ @@ -917,50 +918,50 @@ char *TYPVAL::GetCharString(char *p) /***********************************************************************/ template char *TYPVAL::GetShortString(char *p, int n) - { +{ sprintf(p, "%*hd", n, (short)Tval); return p; - } // end of GetShortString +} // end of GetShortString /***********************************************************************/ /* TYPVAL GetIntString: get int representation of a typed value. */ /***********************************************************************/ template char *TYPVAL::GetIntString(char *p, int n) - { +{ sprintf(p, "%*d", n, (int)Tval); return p; - } // end of GetIntString +} // end of GetIntString /***********************************************************************/ /* TYPVAL GetBigintString: get big int representation of a TYPE value.*/ /***********************************************************************/ template char *TYPVAL::GetBigintString(char *p, int n) - { +{ sprintf(p, "%*lld", n, (longlong)Tval); return p; - } // end of GetBigintString +} // end of GetBigintString /***********************************************************************/ /* TYPVAL GetFloatString: get double representation of a typed value. */ /***********************************************************************/ template char *TYPVAL::GetFloatString(char *p, int n, int prec) - { +{ sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Tval); return p; - } // end of GetFloatString +} // end of GetFloatString /***********************************************************************/ /* TYPVAL GetTinyString: get char representation of a typed value. */ /***********************************************************************/ template char *TYPVAL::GetTinyString(char *p, int n) - { +{ sprintf(p, "%*d", n, (int)(char)Tval); return p; - } // end of GetIntString +} // end of GetIntString #endif // 0 /***********************************************************************/ @@ -968,7 +969,7 @@ char *TYPVAL::GetTinyString(char *p, int n) /***********************************************************************/ template bool TYPVAL::IsEqual(PVAL vp, bool chktype) - { +{ if (this == vp) return true; else if (chktype && Type != vp->GetType()) @@ -980,7 +981,7 @@ bool TYPVAL::IsEqual(PVAL vp, bool chktype) else return (Tval == GetTypedValue(vp)); - } // end of IsEqual +} // end of IsEqual /***********************************************************************/ /* Compare values and returns 1, 0 or -1 according to comparison. */ @@ -988,7 +989,7 @@ bool TYPVAL::IsEqual(PVAL vp, bool chktype) /***********************************************************************/ template int TYPVAL::CompareValue(PVAL vp) - { +{ //assert(vp->GetType() == Type); // Process filtering on numeric values. @@ -998,7 +999,7 @@ int TYPVAL::CompareValue(PVAL vp) // htrc(" Comparing: val=%d,%d\n", Tval, n); return (Tval > n) ? 1 : (Tval < n) ? (-1) : 0; - } // end of CompareValue +} // end of CompareValue /***********************************************************************/ /* Return max type value if b is true, else min type value. */ @@ -1044,7 +1045,7 @@ uchar TYPVAL::MinMaxVal(bool b) /***********************************************************************/ template TYPE TYPVAL::SafeAdd(TYPE n1, TYPE n2) - { +{ PGLOBAL& g = Global; TYPE n = n1 + n2; @@ -1059,20 +1060,20 @@ TYPE TYPVAL::SafeAdd(TYPE n1, TYPE n2) } // endif's n2 return n; - } // end of SafeAdd +} // end of SafeAdd template <> inline double TYPVAL::SafeAdd(double n1, double n2) - { +{ return n1 + n2; - } // end of SafeAdd +} // end of SafeAdd /***********************************************************************/ /* SafeMult: multiply values and test whether overflow occurred. */ /***********************************************************************/ template TYPE TYPVAL::SafeMult(TYPE n1, TYPE n2) - { +{ PGLOBAL& g = Global; double n = (double)n1 * (double)n2; @@ -1087,20 +1088,20 @@ TYPE TYPVAL::SafeMult(TYPE n1, TYPE n2) } // endif's n2 return (TYPE)n; - } // end of SafeMult +} // end of SafeMult template <> inline double TYPVAL::SafeMult(double n1, double n2) - { +{ return n1 * n2; - } // end of SafeMult +} // end of SafeMult /***********************************************************************/ /* Compute defined functions for the type. */ /***********************************************************************/ template bool TYPVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) - { +{ bool rc = false; TYPE val[2]; @@ -1127,14 +1128,14 @@ bool TYPVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) default: rc = Compall(g, vp, np, op); break; - } // endswitch op + } // endswitch op return rc; - } // end of Compute +} // end of Compute template <> bool TYPVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) - { +{ bool rc = false; double val[2]; @@ -1152,17 +1153,17 @@ bool TYPVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) break; default: rc = Compall(g, vp, np, op); - } // endswitch op + } // endswitch op return rc; - } // end of Compute +} // end of Compute /***********************************************************************/ /* Compute a function for all types. */ /***********************************************************************/ template bool TYPVAL::Compall(PGLOBAL g, PVAL *vp, int np, OPVAL op) - { +{ TYPE val[2]; for (int i = 0; i < np; i++) @@ -1191,10 +1192,10 @@ bool TYPVAL::Compall(PGLOBAL g, PVAL *vp, int np, OPVAL op) // sprintf(g->Message, MSG(BAD_EXP_OPER), op); strcpy(g->Message, "Function not supported"); return true; - } // endswitch op + } // endswitch op return false; - } // end of Compall +} // end of Compall /***********************************************************************/ /* FormatValue: This function set vp (a STRING value) to the string */ @@ -1203,26 +1204,28 @@ bool TYPVAL::Compall(PGLOBAL g, PVAL *vp, int np, OPVAL op) /***********************************************************************/ template bool TYPVAL::FormatValue(PVAL vp, PCSZ fmt) - { - char *buf = (char*)vp->GetTo_Val(); // Should be big enough +{ + // This function is wrong and should never be called + assert(false); + char *buf = (char*)vp->GetTo_Val(); // Not big enough int n = sprintf(buf, fmt, Tval); return (n > vp->GetValLen()); - } // end of FormatValue +} // end of FormatValue /***********************************************************************/ /* TYPVAL SetFormat function (used to set SELECT output format). */ /***********************************************************************/ template bool TYPVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt) - { +{ char c[32]; fmt.Type[0] = *GetFormatType(Type); fmt.Length = sprintf(c, Fmt, Tval); fmt.Prec = Prec; return false; - } // end of SetConstFormat +} // end of SetConstFormat /* -------------------------- Class STRING --------------------------- */ @@ -1230,19 +1233,19 @@ bool TYPVAL::SetConstFormat(PGLOBAL g, FORMAT& fmt) /* STRING public constructor from a constant string. */ /***********************************************************************/ TYPVAL::TYPVAL(PSZ s, short c) : VALUE(TYPE_STRING) - { +{ Strp = s; Len = strlen(s); Clen = Len; Ci = (c == 1); - } // end of STRING constructor +} // end of STRING constructor /***********************************************************************/ /* STRING public constructor from char. */ /***********************************************************************/ TYPVAL::TYPVAL(PGLOBAL g, PSZ s, int n, int c) : VALUE(TYPE_STRING) - { +{ Len = (g) ? n : (s) ? strlen(s) : 0; if (!s) { @@ -1260,89 +1263,89 @@ TYPVAL::TYPVAL(PGLOBAL g, PSZ s, int n, int c) Clen = Len; Ci = (c != 0); - } // end of STRING constructor +} // end of STRING constructor /***********************************************************************/ /* Get the tiny value represented by the Strp string. */ /***********************************************************************/ char TYPVAL::GetTinyValue(void) - { +{ bool m; ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX8, false, &m); return (m && val < INT_MAX8) ? (char)(-(signed)val) : (char)val; - } // end of GetTinyValue +} // end of GetTinyValue /***********************************************************************/ /* Get the unsigned tiny value represented by the Strp string. */ /***********************************************************************/ uchar TYPVAL::GetUTinyValue(void) - { +{ return (uchar)CharToNumber(Strp, strlen(Strp), UINT_MAX8, true); - } // end of GetUTinyValue +} // end of GetUTinyValue /***********************************************************************/ /* Get the short value represented by the Strp string. */ /***********************************************************************/ short TYPVAL::GetShortValue(void) - { +{ bool m; ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX16, false, &m); return (m && val < INT_MAX16) ? (short)(-(signed)val) : (short)val; - } // end of GetShortValue +} // end of GetShortValue /***********************************************************************/ /* Get the unsigned short value represented by the Strp string. */ /***********************************************************************/ ushort TYPVAL::GetUShortValue(void) - { +{ return (ushort)CharToNumber(Strp, strlen(Strp), UINT_MAX16, true); - } // end of GetUshortValue +} // end of GetUshortValue /***********************************************************************/ /* Get the integer value represented by the Strp string. */ /***********************************************************************/ int TYPVAL::GetIntValue(void) - { +{ bool m; ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX32, false, &m); return (m && val < INT_MAX32) ? (int)(-(signed)val) : (int)val; - } // end of GetIntValue +} // end of GetIntValue /***********************************************************************/ /* Get the unsigned integer value represented by the Strp string. */ /***********************************************************************/ uint TYPVAL::GetUIntValue(void) - { +{ return (uint)CharToNumber(Strp, strlen(Strp), UINT_MAX32, true); - } // end of GetUintValue +} // end of GetUintValue /***********************************************************************/ /* Get the big integer value represented by the Strp string. */ /***********************************************************************/ longlong TYPVAL::GetBigintValue(void) - { +{ bool m; ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX64, false, &m); return (m && val < INT_MAX64) ? (-(signed)val) : (longlong)val; - } // end of GetBigintValue +} // end of GetBigintValue /***********************************************************************/ /* Get the unsigned big integer value represented by the Strp string. */ /***********************************************************************/ ulonglong TYPVAL::GetUBigintValue(void) - { +{ return CharToNumber(Strp, strlen(Strp), ULONGLONG_MAX, true); - } // end of GetUBigintValue +} // end of GetUBigintValue /***********************************************************************/ /* STRING SetValue: copy the value of another Value object. */ /***********************************************************************/ bool TYPVAL::SetValue_pval(PVAL valp, bool chktype) - { +{ if (valp != this) { if (chktype && (valp->GetType() != Type || valp->GetSize() > Len)) return true; @@ -1354,16 +1357,16 @@ bool TYPVAL::SetValue_pval(PVAL valp, bool chktype) else Reset(); - } // endif valp + } // endif valp return false; - } // end of SetValue_pval +} // end of SetValue_pval /***********************************************************************/ /* STRING SetValue: fill string with chars extracted from a line. */ /***********************************************************************/ bool TYPVAL::SetValue_char(const char *cp, int n) - { +{ bool rc = false; if (!cp || n == 0) { @@ -1389,16 +1392,16 @@ bool TYPVAL::SetValue_char(const char *cp, int n) Reset(); Null = false; - } // endif p + } // endif cp return rc; - } // end of SetValue_char +} // end of SetValue_char /***********************************************************************/ /* STRING SetValue: fill string with another string. */ /***********************************************************************/ void TYPVAL::SetValue_psz(PCSZ s) - { +{ if (!s) { Reset(); Null = Nullable; @@ -1407,26 +1410,26 @@ void TYPVAL::SetValue_psz(PCSZ s) Null = false; } // endif s - } // end of SetValue_psz +} // end of SetValue_psz /***********************************************************************/ /* STRING SetValue: fill string with a string extracted from a block. */ /***********************************************************************/ void TYPVAL::SetValue_pvblk(PVBLK blk, int n) - { +{ // STRBLK's can return a NULL pointer PSZ vp = blk->GetCharString(Strp, n); if (vp != Strp) SetValue_psz(vp); - } // end of SetValue_pvblk +} // end of SetValue_pvblk /***********************************************************************/ /* STRING SetValue: get the character representation of an integer. */ /***********************************************************************/ void TYPVAL::SetValue(int n) - { +{ char buf[16]; PGLOBAL& g = Global; int k = sprintf(buf, "%d", n); @@ -1438,13 +1441,13 @@ void TYPVAL::SetValue(int n) SetValue_psz(buf); Null = false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* STRING SetValue: get the character representation of an uint. */ /***********************************************************************/ void TYPVAL::SetValue(uint n) - { +{ char buf[16]; PGLOBAL& g = Global; int k = sprintf(buf, "%u", n); @@ -1456,31 +1459,31 @@ void TYPVAL::SetValue(uint n) SetValue_psz(buf); Null = false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* STRING SetValue: get the character representation of a short int. */ /***********************************************************************/ void TYPVAL::SetValue(short i) - { +{ SetValue((int)i); Null = false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* STRING SetValue: get the character representation of a ushort int. */ /***********************************************************************/ void TYPVAL::SetValue(ushort i) - { +{ SetValue((uint)i); Null = false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* STRING SetValue: get the character representation of a big integer.*/ /***********************************************************************/ void TYPVAL::SetValue(longlong n) - { +{ char buf[24]; PGLOBAL& g = Global; int k = sprintf(buf, "%lld", n); @@ -1492,13 +1495,13 @@ void TYPVAL::SetValue(longlong n) SetValue_psz(buf); Null = false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* STRING SetValue: get the character representation of a big integer.*/ /***********************************************************************/ void TYPVAL::SetValue(ulonglong n) - { +{ char buf[24]; PGLOBAL& g = Global; int k = sprintf(buf, "%llu", n); @@ -1510,13 +1513,13 @@ void TYPVAL::SetValue(ulonglong n) SetValue_psz(buf); Null = false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* STRING SetValue: get the character representation of a double. */ /***********************************************************************/ void TYPVAL::SetValue(double f) - { +{ char *p, buf[64]; PGLOBAL& g = Global; int k = sprintf(buf, "%lf", f); @@ -1535,33 +1538,33 @@ void TYPVAL::SetValue(double f) SetValue_psz(buf); Null = false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* STRING SetValue: get the character representation of a tiny int. */ /***********************************************************************/ void TYPVAL::SetValue(char c) - { +{ SetValue((int)c); Null = false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* STRING SetValue: get the character representation of a tiny int. */ /***********************************************************************/ void TYPVAL::SetValue(uchar c) - { +{ SetValue((uint)c); Null = false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* STRING SetBinValue: fill string with chars extracted from a line. */ /***********************************************************************/ void TYPVAL::SetBinValue(void *p) - { +{ SetValue_char((const char *)p, Len); - } // end of SetBinValue +} // end of SetBinValue /***********************************************************************/ /* GetBinValue: fill a buffer with the internal binary value. */ @@ -1570,7 +1573,7 @@ void TYPVAL::SetBinValue(void *p) /* Currently used by WriteColumn of binary files. */ /***********************************************************************/ bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) - { +{ int len = (Null) ? 0 : strlen(Strp); if (len > buflen) @@ -1581,7 +1584,7 @@ bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) } // endif go return false; - } // end of GetBinValue +} // end of GetBinValue /***********************************************************************/ /* STRING ShowValue: get string representation of a char value. */ @@ -1591,7 +1594,7 @@ int TYPVAL::ShowValue(char *buf, int buflen) int len = (Null) ? 0 : strlen(Strp); if (buf && buf != Strp) { - memset(buf, ' ', buflen + 1); + memset(buf, ' ', (size_t)buflen + 1); memcpy(buf, Strp, MY_MIN(len, buflen)); } // endif buf @@ -1602,15 +1605,15 @@ int TYPVAL::ShowValue(char *buf, int buflen) /* STRING GetCharString: get string representation of a char value. */ /***********************************************************************/ char *TYPVAL::GetCharString(char *) - { +{ return Strp; - } // end of GetCharString +} // end of GetCharString /***********************************************************************/ /* STRING compare value with another Value. */ /***********************************************************************/ bool TYPVAL::IsEqual(PVAL vp, bool chktype) - { +{ if (this == vp) return true; else if (chktype && Type != vp->GetType()) @@ -1625,14 +1628,14 @@ bool TYPVAL::IsEqual(PVAL vp, bool chktype) else // (!Ci) return !strcmp(Strp, vp->GetCharString(buf)); - } // end of IsEqual +} // end of IsEqual /***********************************************************************/ /* Compare values and returns 1, 0 or -1 according to comparison. */ /* This function is used for evaluation of numeric filters. */ /***********************************************************************/ int TYPVAL::CompareValue(PVAL vp) - { +{ int n; //assert(vp->GetType() == Type); @@ -1651,13 +1654,13 @@ int TYPVAL::CompareValue(PVAL vp) #endif // __WIN__ return (n > 0) ? 1 : (n < 0) ? -1 : 0; - } // end of CompareValue +} // end of CompareValue /***********************************************************************/ /* Compute a function on a string. */ /***********************************************************************/ bool TYPVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) - { +{ char *p[2], val[2][32]; int i; @@ -1704,7 +1707,7 @@ bool TYPVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) Null = false; return false; - } // end of Compute +} // end of Compute /***********************************************************************/ /* FormatValue: This function set vp (a STRING value) to the string */ @@ -1712,23 +1715,23 @@ bool TYPVAL::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op) /* This function assumes that the format matches the value type. */ /***********************************************************************/ bool TYPVAL::FormatValue(PVAL vp, PCSZ fmt) - { +{ char *buf = (char*)vp->GetTo_Val(); // Should be big enough int n = sprintf(buf, fmt, Strp); return (n > vp->GetValLen()); - } // end of FormatValue +} // end of FormatValue /***********************************************************************/ /* STRING SetFormat function (used to set SELECT output format). */ /***********************************************************************/ bool TYPVAL::SetConstFormat(PGLOBAL, FORMAT& fmt) - { +{ fmt.Type[0] = 'C'; fmt.Length = Len; fmt.Prec = 0; return false; - } // end of SetConstFormat +} // end of SetConstFormat /***********************************************************************/ /* Make string output of an object value. */ @@ -1748,38 +1751,38 @@ void TYPVAL::Prints(PGLOBAL g, char *ps, uint z) /* DECIMAL public constructor from a constant string. */ /***********************************************************************/ DECVAL::DECVAL(PSZ s) : TYPVAL(s) - { +{ if (s) { char *p = strchr(Strp, '.'); Prec = (p) ? (int)(Len - (p - Strp)) : 0; - } // endif s + } // endif s Type = TYPE_DECIM; - } // end of DECVAL constructor +} // end of DECVAL constructor /***********************************************************************/ /* DECIMAL public constructor from char. */ /***********************************************************************/ DECVAL::DECVAL(PGLOBAL g, PSZ s, int n, int prec, bool uns) : TYPVAL(g, s, n + (prec ? 1 : 0) + (uns ? 0 : 1), 0) - { +{ Prec = prec; Unsigned = uns; Type = TYPE_DECIM; - } // end of DECVAL constructor +} // end of DECVAL constructor /***********************************************************************/ /* DECIMAL: Check whether the numerica value is equal to 0. */ /***********************************************************************/ bool DECVAL::IsZero(void) - { +{ for (int i = 0; Strp[i]; i++) if (!strchr("0 +-.", Strp[i])) return false; return true; - } // end of IsZero +} // end of IsZero /***********************************************************************/ /* DECIMAL: Reset value to zero. */ @@ -1797,7 +1800,7 @@ void DECVAL::Reset(void) Strp[i++] = '0'; } while (i < Prec + 2); - } // endif Prec + } // endif Prec Strp[i] = 0; } // end of Reset @@ -1806,9 +1809,9 @@ void DECVAL::Reset(void) /* DECIMAL ShowValue: get string representation right justified. */ /***********************************************************************/ int DECVAL::ShowValue(char *buf, int len) - { +{ return snprintf(buf, len + 1, Xfmt, len, Strp); - } // end of ShowValue +} // end of ShowValue /***********************************************************************/ /* GetBinValue: fill a buffer with the internal binary value. */ @@ -1817,7 +1820,7 @@ int DECVAL::ShowValue(char *buf, int len) /* Currently used by WriteColumn of binary files. */ /***********************************************************************/ bool DECVAL::GetBinValue(void *buf, int buflen, bool go) - { +{ int len = (Null) ? 0 : strlen(Strp); if (len > buflen) @@ -1825,16 +1828,16 @@ bool DECVAL::GetBinValue(void *buf, int buflen, bool go) else if (go) { memset(buf, ' ', buflen - len); memcpy((char*)buf + buflen - len, Strp, len); - } // endif go + } // endif go return false; - } // end of GetBinValue +} // end of GetBinValue /***********************************************************************/ /* DECIMAL compare value with another Value. */ /***********************************************************************/ bool DECVAL::IsEqual(PVAL vp, bool chktype) - { +{ if (this == vp) return true; else if (chktype && Type != vp->GetType()) @@ -1845,14 +1848,14 @@ bool DECVAL::IsEqual(PVAL vp, bool chktype) char buf[64]; return !strcmp(Strp, vp->GetCharString(buf)); - } // end of IsEqual +} // end of IsEqual /***********************************************************************/ /* Compare values and returns 1, 0 or -1 according to comparison. */ /* This function is used for evaluation of numeric filters. */ /***********************************************************************/ int DECVAL::CompareValue(PVAL vp) - { +{ //assert(vp->GetType() == Type); // Process filtering on numeric values. @@ -1862,7 +1865,7 @@ int DECVAL::CompareValue(PVAL vp) // htrc(" Comparing: val=%d,%d\n", f, n); return (f > n) ? 1 : (f < n) ? (-1) : 0; - } // end of CompareValue +} // end of CompareValue /* -------------------------- Class BINVAL --------------------------- */ @@ -1870,7 +1873,7 @@ int DECVAL::CompareValue(PVAL vp) /* BINVAL public constructor from bytes. */ /***********************************************************************/ BINVAL::BINVAL(PGLOBAL g, void *p, int cl, int n) : VALUE(TYPE_BIN) - { +{ assert(g); Len = n; Clen = cl; @@ -1881,19 +1884,19 @@ BINVAL::BINVAL(PGLOBAL g, void *p, int cl, int n) : VALUE(TYPE_BIN) memcpy(Binp, p, MY_MIN(Len,Clen)); Chrp = NULL; - } // end of BINVAL constructor +} // end of BINVAL constructor /***********************************************************************/ /* BINVAL: Check whether the hexadecimal value is equal to 0. */ /***********************************************************************/ bool BINVAL::IsZero(void) - { +{ for (int i = 0; i < Len; i++) if (((char*)Binp)[i] != 0) return false; return true; - } // end of IsZero +} // end of IsZero /***********************************************************************/ /* BINVAL: Reset value to zero. */ @@ -1908,77 +1911,77 @@ void BINVAL::Reset(void) /* Get the tiny value pointed by Binp. */ /***********************************************************************/ char BINVAL::GetTinyValue(void) - { +{ return *(char*)Binp; - } // end of GetTinyValue +} // end of GetTinyValue /***********************************************************************/ /* Get the unsigned tiny value pointed by Binp. */ /***********************************************************************/ uchar BINVAL::GetUTinyValue(void) - { +{ return *(uchar*)Binp; - } // end of GetUTinyValue +} // end of GetUTinyValue /***********************************************************************/ /* Get the short value pointed by Binp. */ /***********************************************************************/ short BINVAL::GetShortValue(void) - { +{ if (Len >= 2) return *(short*)Binp; else return (short)GetTinyValue(); - } // end of GetShortValue +} // end of GetShortValue /***********************************************************************/ /* Get the unsigned short value pointed by Binp. */ /***********************************************************************/ ushort BINVAL::GetUShortValue(void) - { +{ return (ushort)GetShortValue(); - } // end of GetUshortValue +} // end of GetUshortValue /***********************************************************************/ /* Get the integer value pointed by Binp. */ /***********************************************************************/ int BINVAL::GetIntValue(void) - { +{ if (Len >= 4) return *(int*)Binp; else return (int)GetShortValue(); - } // end of GetIntValue +} // end of GetIntValue /***********************************************************************/ /* Get the unsigned integer value pointed by Binp. */ /***********************************************************************/ uint BINVAL::GetUIntValue(void) - { +{ return (uint)GetIntValue(); - } // end of GetUintValue +} // end of GetUintValue /***********************************************************************/ /* Get the big integer value pointed by Binp. */ /***********************************************************************/ longlong BINVAL::GetBigintValue(void) - { +{ if (Len >= 8) return *(longlong*)Binp; else return (longlong)GetIntValue(); - } // end of GetBigintValue +} // end of GetBigintValue /***********************************************************************/ /* Get the unsigned big integer value pointed by Binp. */ /***********************************************************************/ ulonglong BINVAL::GetUBigintValue(void) - { +{ return (ulonglong)GetBigintValue(); - } // end of GetUBigintValue +} // end of GetUBigintValue /***********************************************************************/ /* Get the double value pointed by Binp. */ @@ -1998,7 +2001,7 @@ double BINVAL::GetFloatValue(void) /* BINVAL SetValue: copy the value of another Value object. */ /***********************************************************************/ bool BINVAL::SetValue_pval(PVAL valp, bool chktype) - { +{ bool rc = false; if (valp != this) { @@ -2018,16 +2021,16 @@ bool BINVAL::SetValue_pval(PVAL valp, bool chktype) } else Reset(); - } // endif valp + } // endif valp return rc; - } // end of SetValue_pval +} // end of SetValue_pval /***********************************************************************/ /* BINVAL SetValue: fill value with chars extracted from a line. */ /***********************************************************************/ bool BINVAL::SetValue_char(const char *p, int n) - { +{ bool rc; if (p && n > 0) { @@ -2047,13 +2050,13 @@ bool BINVAL::SetValue_char(const char *p, int n) } // endif p return rc; - } // end of SetValue_char +} // end of SetValue_char /***********************************************************************/ /* BINVAL SetValue: fill value with another string. */ /***********************************************************************/ void BINVAL::SetValue_psz(PCSZ s) - { +{ if (s) { int len = Len; @@ -2068,13 +2071,13 @@ void BINVAL::SetValue_psz(PCSZ s) Null = Nullable; } // endif s - } // end of SetValue_psz +} // end of SetValue_psz /***********************************************************************/ /* BINVAL SetValue: fill value with bytes extracted from a block. */ /***********************************************************************/ void BINVAL::SetValue_pvblk(PVBLK blk, int n) - { +{ // STRBLK's can return a NULL pointer void *vp = blk->GetValPtrEx(n); @@ -2097,13 +2100,13 @@ void BINVAL::SetValue_pvblk(PVBLK blk, int n) Null = false; } // endif vp - } // end of SetValue_pvblk +} // end of SetValue_pvblk /***********************************************************************/ /* BINVAL SetValue: get the binary representation of an integer. */ /***********************************************************************/ void BINVAL::SetValue(int n) - { +{ if (Clen >= 4) { if (Len > 4) memset(Binp, 0, Len); @@ -2113,13 +2116,13 @@ void BINVAL::SetValue(int n) } else SetValue((short)n); - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* BINVAL SetValue: get the binary representation of an uint. */ /***********************************************************************/ void BINVAL::SetValue(uint n) - { +{ if (Clen >= 4) { if (Len > 4) memset(Binp, 0, Len); @@ -2129,13 +2132,13 @@ void BINVAL::SetValue(uint n) } else SetValue((ushort)n); - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* BINVAL SetValue: get the binary representation of a short int. */ /***********************************************************************/ void BINVAL::SetValue(short i) - { +{ if (Clen >= 2) { if (Len > 2) memset(Binp, 0, Len); @@ -2145,13 +2148,13 @@ void BINVAL::SetValue(short i) } else SetValue((char)i); - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* BINVAL SetValue: get the binary representation of a ushort int. */ /***********************************************************************/ void BINVAL::SetValue(ushort i) - { +{ if (Clen >= 2) { if (Len > 2) memset(Binp, 0, Len); @@ -2161,13 +2164,13 @@ void BINVAL::SetValue(ushort i) } else SetValue((uchar)i); - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* BINVAL SetValue: get the binary representation of a big integer. */ /***********************************************************************/ void BINVAL::SetValue(longlong n) - { +{ if (Clen >= 8) { if (Len > 8) memset(Binp, 0, Len); @@ -2177,13 +2180,13 @@ void BINVAL::SetValue(longlong n) } else SetValue((int)n); - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* BINVAL SetValue: get the binary representation of a big integer. */ /***********************************************************************/ void BINVAL::SetValue(ulonglong n) - { +{ if (Clen >= 8) { if (Len > 8) memset(Binp, 0, Len); @@ -2192,13 +2195,14 @@ void BINVAL::SetValue(ulonglong n) Len = 8; } else SetValue((uint)n); - } // end of SetValue + +} // end of SetValue /***********************************************************************/ /* BINVAL SetValue: get the binary representation of a double. */ /***********************************************************************/ void BINVAL::SetValue(double n) - { +{ if (Len > 8) memset(Binp, 0, Len); @@ -2211,40 +2215,40 @@ void BINVAL::SetValue(double n) } else Len = 0; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* BINVAL SetValue: get the character binary of a tiny int. */ /***********************************************************************/ void BINVAL::SetValue(char c) - { +{ if (Len > 1) memset(Binp, 0, Len); *((char*)Binp) = c; Len = 1; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* BINVAL SetValue: get the binary representation of a tiny int. */ /***********************************************************************/ void BINVAL::SetValue(uchar c) - { +{ if (Len > 1) memset(Binp, 0, Len); *((uchar*)Binp) = c; Len = 1; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* BINVAL SetBinValue: fill string with bytes extracted from a line. */ /***********************************************************************/ void BINVAL::SetBinValue(void *p) - { +{ memcpy(Binp, p, Clen); Len = Clen; - } // end of SetBinValue +} // end of SetBinValue /***********************************************************************/ /* GetBinValue: fill a buffer with the internal binary value. */ @@ -2253,7 +2257,7 @@ void BINVAL::SetBinValue(void *p) /* Currently used by WriteColumn of binary files. */ /***********************************************************************/ bool BINVAL::GetBinValue(void *buf, int buflen, bool go) - { +{ if (Len > buflen) return true; else if (go) { @@ -2262,7 +2266,7 @@ bool BINVAL::GetBinValue(void *buf, int buflen, bool go) } // endif go return false; - } // end of GetBinValue +} // end of GetBinValue /***********************************************************************/ /* BINVAL ShowValue: get string representation of a binary value. */ @@ -2278,19 +2282,19 @@ int BINVAL::ShowValue(char *buf, int len) /* BINVAL GetCharString: get string representation of a binary value. */ /***********************************************************************/ char *BINVAL::GetCharString(char *) - { +{ if (!Chrp) Chrp = (char*)PlugSubAlloc(Global, NULL, Clen * 2 + 1); sprintf(Chrp, GetXfmt(), Len, Binp); return Chrp; - } // end of GetCharString +} // end of GetCharString /***********************************************************************/ /* BINVAL compare value with another Value. */ /***********************************************************************/ bool BINVAL::IsEqual(PVAL vp, bool chktype) - { +{ if (this == vp) return true; else if (chktype && Type != vp->GetType()) @@ -2308,7 +2312,7 @@ bool BINVAL::IsEqual(PVAL vp, bool chktype) return false; return true; - } // end of IsEqual +} // end of IsEqual /***********************************************************************/ /* FormatValue: This function set vp (a STRING value) to the string */ @@ -2316,23 +2320,23 @@ bool BINVAL::IsEqual(PVAL vp, bool chktype) /* This function assumes that the format matches the value type. */ /***********************************************************************/ bool BINVAL::FormatValue(PVAL vp, PCSZ fmt) - { +{ char *buf = (char*)vp->GetTo_Val(); // Should be big enough int n = sprintf(buf, fmt, Len, Binp); return (n > vp->GetValLen()); - } // end of FormatValue +} // end of FormatValue /***********************************************************************/ /* BINVAL SetFormat function (used to set SELECT output format). */ /***********************************************************************/ bool BINVAL::SetConstFormat(PGLOBAL, FORMAT& fmt) - { +{ fmt.Type[0] = 'B'; fmt.Length = Clen; fmt.Prec = 0; return false; - } // end of SetConstFormat +} // end of SetConstFormat /* -------------------------- Class DTVAL ---------------------------- */ @@ -2341,7 +2345,7 @@ bool BINVAL::SetConstFormat(PGLOBAL, FORMAT& fmt) /***********************************************************************/ DTVAL::DTVAL(PGLOBAL g, int n, int prec, PCSZ fmt) : TYPVAL((int)0, TYPE_DATE) - { +{ if (!fmt) { Pdtp = NULL; Sdate = NULL; @@ -2351,37 +2355,37 @@ DTVAL::DTVAL(PGLOBAL g, int n, int prec, PCSZ fmt) SetFormat(g, fmt, n, prec); //Type = TYPE_DATE; - } // end of DTVAL constructor +} // end of DTVAL constructor /***********************************************************************/ /* DTVAL public constructor from int. */ /***********************************************************************/ DTVAL::DTVAL(int n) : TYPVAL(n, TYPE_DATE) - { +{ Pdtp = NULL; Len = 19; //Type = TYPE_DATE; Sdate = NULL; DefYear = 0; - } // end of DTVAL constructor +} // end of DTVAL constructor /***********************************************************************/ /* Set format so formatted dates can be converted on input/output. */ /***********************************************************************/ bool DTVAL::SetFormat(PGLOBAL g, PCSZ fmt, int len, int year) - { +{ Pdtp = MakeDateFormat(g, fmt, true, true, (year > 9999) ? 1 : 0); Sdate = (char*)PlugSubAlloc(g, NULL, len + 1); DefYear = (int)((year > 9999) ? (year - 10000) : year); Len = len; return false; - } // end of SetFormat +} // end of SetFormat /***********************************************************************/ /* Set format from the format of another date value. */ /***********************************************************************/ bool DTVAL::SetFormat(PGLOBAL g, PVAL valp) - { +{ DTVAL *vp; if (valp->GetType() != TYPE_DATE) { @@ -2395,14 +2399,14 @@ bool DTVAL::SetFormat(PGLOBAL g, PVAL valp) Sdate = (char*)PlugSubAlloc(g, NULL, Len + 1); DefYear = vp->DefYear; return false; - } // end of SetFormat +} // end of SetFormat /***********************************************************************/ /* We need TimeShift because the mktime C function does a correction */ /* for local time zone that we want to override for DB operations. */ /***********************************************************************/ void DTVAL::SetTimeShift(void) - { +{ struct tm dtm; memset(&dtm, 0, sizeof(dtm)); dtm.tm_mday=2; @@ -2414,7 +2418,7 @@ void DTVAL::SetTimeShift(void) if (trace(1)) htrc("DTVAL Shift=%d\n", Shift); - } // end of SetTimeShift +} // end of SetTimeShift // Added by Alexander Barkov static void TIME_to_localtime(struct tm *tm, const MYSQL_TIME *ltime) @@ -2444,7 +2448,7 @@ static struct tm *gmtime_mysql(const time_t *timep, struct tm *tm) /* extend the range of valid dates by accepting negative time values. */ /***********************************************************************/ struct tm *DTVAL::GetGmTime(struct tm *tm_buffer) - { +{ struct tm *datm; time_t t = (time_t)Tval; @@ -2463,7 +2467,7 @@ struct tm *DTVAL::GetGmTime(struct tm *tm_buffer) datm = gmtime_mysql(&t, tm_buffer); return datm; - } // end of GetGmTime +} // end of GetGmTime // Added by Alexander Barkov static time_t mktime_mysql(struct tm *ptm) @@ -2482,7 +2486,7 @@ static time_t mktime_mysql(struct tm *ptm) /* range of valid dates by accepting to set negative time values. */ /***********************************************************************/ bool DTVAL::MakeTime(struct tm *ptm) - { +{ int n, y = ptm->tm_year; time_t t = mktime_mysql(ptm); @@ -2498,7 +2502,7 @@ bool DTVAL::MakeTime(struct tm *ptm) for (n = 0; t == -1 && n < 20; n++) { ptm->tm_year += 4; t = mktime_mysql(ptm); - } // endfor t + } // endfor t if (t == -1) return true; @@ -2506,20 +2510,21 @@ bool DTVAL::MakeTime(struct tm *ptm) if ((t -= (n * FOURYEARS)) > 2000000000) return true; - } + } // endif t + Tval= (int) t; if (trace(2)) htrc("MakeTime Ival=%d\n", Tval); return false; - } // end of MakeTime +} // end of MakeTime /***********************************************************************/ /* Make a time_t datetime from its components (YY, MM, DD, hh, mm, ss) */ /***********************************************************************/ bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) - { +{ int i, m; int n; bool rc = false; @@ -2589,9 +2594,9 @@ bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) case 3: datm.tm_hour = n; break; case 4: datm.tm_min = n; break; case 5: datm.tm_sec = n; break; - } // endswitch i + } // endswitch i - } // endfor i + } // endfor i if (trace(2)) htrc("MakeDate datm=(%d,%d,%d,%d,%d,%d)\n", @@ -2607,14 +2612,14 @@ bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval) Tval = 0; return rc; - } // end of MakeDate +} // end of MakeDate /***********************************************************************/ /* DTVAL SetValue: copy the value of another Value object. */ /* This function allows conversion if chktype is false. */ /***********************************************************************/ bool DTVAL::SetValue_pval(PVAL valp, bool chktype) - { +{ if (valp != this) { if (chktype && Type != valp->GetType()) return true; @@ -2636,16 +2641,16 @@ bool DTVAL::SetValue_pval(PVAL valp, bool chktype) } else Reset(); - } // endif valp + } // endif valp return false; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* SetValue: convert chars extracted from a line to date value. */ /***********************************************************************/ bool DTVAL::SetValue_char(const char *p, int n) - { +{ bool rc= 0; if (Pdtp) { @@ -2661,7 +2666,7 @@ bool DTVAL::SetValue_char(const char *p, int n) n = Len; memcpy(Sdate, p, n); - } // endif n + } // endif n Sdate[n] = '\0'; @@ -2678,13 +2683,13 @@ bool DTVAL::SetValue_char(const char *p, int n) } // endif Pdtp return rc; - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* SetValue: convert a char string to date value. */ /***********************************************************************/ void DTVAL::SetValue_psz(PCSZ p) - { +{ if (Pdtp) { int ndv; int dval[6]; @@ -2704,13 +2709,13 @@ void DTVAL::SetValue_psz(PCSZ p) Null = (Nullable && Tval == 0); } // endif Pdtp - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* DTVAL SetValue: set value with a value extracted from a block. */ /***********************************************************************/ void DTVAL::SetValue_pvblk(PVBLK blk, int n) - { +{ if (Pdtp && !::IsTypeNum(blk->GetType())) { int ndv; int dval[6]; @@ -2720,13 +2725,13 @@ void DTVAL::SetValue_pvblk(PVBLK blk, int n) } else Tval = blk->GetIntValue(n); - } // end of SetValue +} // end of SetValue /***********************************************************************/ /* DTVAL GetCharString: get string representation of a date value. */ /***********************************************************************/ char *DTVAL::GetCharString(char *p) - { +{ if (Pdtp) { size_t n = 0; struct tm tm, *ptm= GetGmTime(&tm); @@ -2745,7 +2750,7 @@ char *DTVAL::GetCharString(char *p) //Null = false; ?????????????? return p; - } // end of GetCharString +} // end of GetCharString /***********************************************************************/ /* DTVAL ShowValue: get string representation of a date value. */ @@ -2783,7 +2788,7 @@ int DTVAL::ShowValue(char *buf, int len) /* Returns a member of the struct tm representation of the date. */ /***********************************************************************/ bool DTVAL::GetTmMember(OPVAL op, int& mval) - { +{ bool rc = false; struct tm tm, *ptm = GetGmTime(&tm); @@ -2796,10 +2801,10 @@ bool DTVAL::GetTmMember(OPVAL op, int& mval) case OP_QUART: mval = ptm->tm_mon / 3 + 1; break; default: rc = true; - } // endswitch op + } // endswitch op return rc; - } // end of GetTmMember +} // end of GetTmMember /***********************************************************************/ /* Calculates the week number of the year for the internal date value.*/ @@ -2810,7 +2815,7 @@ bool DTVAL::GetTmMember(OPVAL op, int& mval) /* the week that contains the January 4th. */ /***********************************************************************/ bool DTVAL::WeekNum(PGLOBAL g, int& nval) - { +{ // w is the start of the week SUN=0, MON=1, etc. int m, n, w = nval % 7; struct tm tm, *ptm = GetGmTime(&tm); @@ -2827,7 +2832,7 @@ bool DTVAL::WeekNum(PGLOBAL g, int& nval) // Everything should be Ok return false; - } // end of WeekNum +} // end of WeekNum #endif // 0 /***********************************************************************/ @@ -2836,7 +2841,7 @@ bool DTVAL::WeekNum(PGLOBAL g, int& nval) /* This function assumes that the format matches the value type. */ /***********************************************************************/ bool DTVAL::FormatValue(PVAL vp, PCSZ fmt) - { +{ char *buf = (char*)vp->GetTo_Val(); // Should be big enough struct tm tm, *ptm = GetGmTime(&tm); @@ -2853,6 +2858,6 @@ bool DTVAL::FormatValue(PVAL vp, PCSZ fmt) } else return true; - } // end of FormatValue +} // end of FormatValue /* -------------------------- End of Value --------------------------- */ From a00b713130626a6e91864fdee3f2b264cbe82ac6 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 16 Oct 2019 22:12:47 +0200 Subject: [PATCH 16/68] Fix wrong second parameter in snprintf --- storage/connect/value.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp index 158495de26c..df75722d0e8 100644 --- a/storage/connect/value.cpp +++ b/storage/connect/value.cpp @@ -884,14 +884,14 @@ bool TYPVAL::GetBinValue(void *buf, int buflen, bool go) template int TYPVAL::ShowValue(char *buf, int len) { - return snprintf(buf, len, Xfmt, len, Tval); + return snprintf(buf, len + 1, Xfmt, len, Tval); } // end of ShowValue template <> int TYPVAL::ShowValue(char *buf, int len) { // TODO: use a more appropriate format to avoid possible truncation - return snprintf(buf, len, Xfmt, len, Prec, Tval); + return snprintf(buf, len + 1, Xfmt, len, Prec, Tval); } // end of ShowValue /***********************************************************************/ From fa32d28f2f665f41aa2aad1c47ca49236a34d31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 17 Oct 2019 13:58:04 +0300 Subject: [PATCH 17/68] MDEV-20852 BtrBulk is unnecessarily holding dict_index_t::lock The BtrBulk class, which was introduced in MySQL 5.7, is by design the exclusive writer to an index. It is therefore unnecessary to acquire the dict_index_t::lock in that code. Holding the dict_index_t::lock would unnecessarily block other threads (SQL connections and the InnoDB purge threads) from buffering concurrent modifications to being-created secondary indexes. This fix is motivated by a change in MySQL 5.7.28: Bug #29008298 MYSQLD CRASHES ITSELF WHEN CREATING INDEX mysql/mysql-server@f9fb96c20f9d190f654e7aa2387255bf80fd6e45 PageBulk::init(), PageBulk::latch(): Never acquire m_index->lock. PageBulk::storeExt(): Remove some pointer indirection, and improve a debug assertion that seems to prove that some code is redundant. BtrBulk::pageCommit(): Assert that m_index->lock is not being held. btr_blob_log_check_t: Do not acquire m_index->lock if m_op == BTR_STORE_INSERT_BULK. Add UNIV_UNLIKELY hints around that condition. btr_store_big_rec_extern_fields(): Allow index->lock not to be held while op == BTR_STORE_INSERT_BULK. Add UNIV_UNLIKELY hints around that condition. --- storage/innobase/btr/btr0bulk.cc | 30 ++++++++++++++++-------------- storage/innobase/btr/btr0cur.cc | 24 +++++++++++++----------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index e414c50b923..262709bc679 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2014, 2019, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -51,7 +51,7 @@ PageBulk::init() m_heap = mem_heap_create(1000); m_mtr.start(); - mtr_x_lock(&m_index->lock, &m_mtr); + if (m_flush_observer) { m_mtr.set_log_mode(MTR_LOG_NO_REDO); m_mtr.set_flush_observer(m_flush_observer); @@ -611,22 +611,20 @@ PageBulk::storeExt( btr_pcur.pos_state = BTR_PCUR_IS_POSITIONED; btr_pcur.latch_mode = BTR_MODIFY_LEAF; btr_pcur.btr_cur.index = m_index; - - page_cur_t* page_cur = &btr_pcur.btr_cur.page_cur; - page_cur->index = m_index; - page_cur->rec = m_cur_rec; - page_cur->offsets = offsets; - page_cur->block = m_block; + btr_pcur.btr_cur.page_cur.index = m_index; + btr_pcur.btr_cur.page_cur.rec = m_cur_rec; + btr_pcur.btr_cur.page_cur.offsets = offsets; + btr_pcur.btr_cur.page_cur.block = m_block; dberr_t err = btr_store_big_rec_extern_fields( &btr_pcur, offsets, big_rec, &m_mtr, BTR_STORE_INSERT_BULK); - ut_ad(page_offset(m_cur_rec) == page_offset(page_cur->rec)); - /* Reset m_block and m_cur_rec from page cursor, because - block may be changed during blob insert. */ - m_block = page_cur->block; - m_cur_rec = page_cur->rec; + block may be changed during blob insert. (FIXME: Can it really?) */ + ut_ad(m_block == btr_pcur.btr_cur.page_cur.block); + + m_block = btr_pcur.btr_cur.page_cur.block; + m_cur_rec = btr_pcur.btr_cur.page_cur.rec; m_page = buf_block_get_frame(m_block); return(err); @@ -653,7 +651,7 @@ dberr_t PageBulk::latch() { m_mtr.start(); - mtr_x_lock(&m_index->lock, &m_mtr); + if (m_flush_observer) { m_mtr.set_log_mode(MTR_LOG_NO_REDO); m_mtr.set_flush_observer(m_flush_observer); @@ -758,6 +756,10 @@ BtrBulk::pageCommit( page_bulk->setNext(FIL_NULL); } + ut_ad(!rw_lock_own_flagged(&m_index->lock, + RW_LOCK_FLAG_X | RW_LOCK_FLAG_SX + | RW_LOCK_FLAG_S)); + /* Compress page if it's a compressed table. */ if (page_bulk->getPageZip() != NULL && !page_bulk->compress()) { return(pageSplit(page_bulk, next_page_bulk)); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 788b34bca62..8c9693bea47 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -6775,7 +6775,7 @@ struct btr_blob_log_check_t { ulint page_no = ULINT_UNDEFINED; FlushObserver* observer = m_mtr->get_flush_observer(); - if (m_op == BTR_STORE_INSERT_BULK) { + if (UNIV_UNLIKELY(m_op == BTR_STORE_INSERT_BULK)) { offs = page_offset(*m_rec); page_no = page_get_page_no( buf_block_get_frame(*m_block)); @@ -6798,14 +6798,13 @@ struct btr_blob_log_check_t { m_mtr->set_named_space(index->space); m_mtr->set_flush_observer(observer); - if (m_op == BTR_STORE_INSERT_BULK) { + if (UNIV_UNLIKELY(m_op == BTR_STORE_INSERT_BULK)) { page_id_t page_id(dict_index_get_space(index), page_no); page_size_t page_size(dict_table_page_size( index->table)); page_cur_t* page_cur = &m_pcur->btr_cur.page_cur; - mtr_x_lock(dict_index_get_lock(index), m_mtr); page_cur->block = btr_block_get( page_id, page_size, RW_X_LATCH, index, m_mtr); page_cur->rec = buf_block_get_frame(page_cur->block) @@ -6831,9 +6830,10 @@ struct btr_blob_log_check_t { *m_rec, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - ut_ad(mtr_memo_contains_flagged(m_mtr, - dict_index_get_lock(index), - MTR_MEMO_SX_LOCK | MTR_MEMO_X_LOCK)); + ut_ad((m_op == BTR_STORE_INSERT_BULK) + == !mtr_memo_contains_flagged(m_mtr, &index->lock, + MTR_MEMO_SX_LOCK + | MTR_MEMO_X_LOCK)); } }; @@ -6887,8 +6887,10 @@ btr_store_big_rec_extern_fields( ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_any_extern(offsets)); - ut_ad(mtr_memo_contains_flagged(btr_mtr, dict_index_get_lock(index), - MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK)); + ut_ad(op == BTR_STORE_INSERT_BULK + || mtr_memo_contains_flagged(btr_mtr, &index->lock, + MTR_MEMO_X_LOCK + | MTR_MEMO_SX_LOCK)); ut_ad(mtr_is_block_fix( btr_mtr, rec_block, MTR_MEMO_PAGE_X_FIX, index->table)); ut_ad(buf_block_get_frame(rec_block) == page_align(rec)); @@ -7014,7 +7016,7 @@ btr_store_big_rec_extern_fields( mtr_t *alloc_mtr; - if (op == BTR_STORE_INSERT_BULK) { + if (UNIV_UNLIKELY(op == BTR_STORE_INSERT_BULK)) { mtr_start(&mtr_bulk); mtr_bulk.set_spaces(mtr); alloc_mtr = &mtr_bulk; @@ -7036,7 +7038,7 @@ btr_store_big_rec_extern_fields( alloc_mtr->release_free_extents(r_extents); - if (op == BTR_STORE_INSERT_BULK) { + if (UNIV_UNLIKELY(op == BTR_STORE_INSERT_BULK)) { mtr_commit(&mtr_bulk); } @@ -7192,7 +7194,7 @@ btr_store_big_rec_extern_fields( } /* We compress a page when finish bulk insert.*/ - if (op != BTR_STORE_INSERT_BULK) { + if (UNIV_LIKELY(op != BTR_STORE_INSERT_BULK)) { page_zip_write_blob_ptr( page_zip, rec, index, offsets, field_no, &mtr); From fa929f7cdf71e351a64639815d84ae5d4f3dc053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 17 Oct 2019 17:12:23 +0300 Subject: [PATCH 18/68] Simplify row_undo_ins_remove_sec_low() Reduce the scope of some variables, remove a goto and a redundant assertion. For B-tree secondary indexes, this function can remove a delete-marked purgeable record, in case a row rollback of the INSERT was initiated due to an error in an earlier secondary index. --- storage/innobase/row/row0uins.cc | 52 ++++++++++++++------------------ 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index bc4e7d3c380..62a6f013255 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. 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 @@ -196,10 +196,8 @@ row_undo_ins_remove_sec_low( que_thr_t* thr) /*!< in: query thread */ { btr_pcur_t pcur; - btr_cur_t* btr_cur; dberr_t err = DB_SUCCESS; mtr_t mtr; - enum row_search_result search_result; const bool modify_leaf = mode == BTR_MODIFY_LEAF; row_mtr_start(&mtr, index, !modify_leaf); @@ -224,12 +222,15 @@ row_undo_ins_remove_sec_low( mode |= BTR_RTREE_UNDO_INS; } - search_result = row_search_index_entry(index, entry, mode, - &pcur, &mtr); - - switch (search_result) { + switch (row_search_index_entry(index, entry, mode, &pcur, &mtr)) { + case ROW_BUFFERED: + case ROW_NOT_DELETED_REF: + /* These are invalid outcomes, because the mode passed + to row_search_index_entry() did not include any of the + flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */ + ut_error; case ROW_NOT_FOUND: - goto func_exit; + break; case ROW_FOUND: if (dict_index_is_spatial(index) && rec_get_deleted_flag( @@ -239,31 +240,22 @@ row_undo_ins_remove_sec_low( << " is deleted marked on insert rollback."; ut_ad(0); } - break; - case ROW_BUFFERED: - case ROW_NOT_DELETED_REF: - /* These are invalid outcomes, because the mode passed - to row_search_index_entry() did not include any of the - flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */ - ut_error; + btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur); + + if (modify_leaf) { + err = btr_cur_optimistic_delete(btr_cur, 0, &mtr) + ? DB_SUCCESS : DB_FAIL; + } else { + /* Passing rollback=false here, because we are + deleting a secondary index record: the distinction + only matters when deleting a record that contains + externally stored columns. */ + btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0, + false, &mtr); + } } - btr_cur = btr_pcur_get_btr_cur(&pcur); - - if (modify_leaf) { - err = btr_cur_optimistic_delete(btr_cur, 0, &mtr) - ? DB_SUCCESS : DB_FAIL; - } else { - /* Passing rollback=false here, because we are - deleting a secondary index record: the distinction - only matters when deleting a record that contains - externally stored columns. */ - ut_ad(!dict_index_is_clust(index)); - btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0, - false, &mtr); - } -func_exit: btr_pcur_close(&pcur); func_exit_no_pcur: mtr_commit(&mtr); From de2186dd2f5937a56d799f55c33078a7ad8ebddc Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Thu, 17 Oct 2019 14:08:33 +0200 Subject: [PATCH 19/68] MDEV-20074: Lost connection on update trigger Instead of checking lex->sql_command which does not corect in case of triggers mark tables for insert. --- mysql-test/suite/sql_sequence/other.result | 91 ++++++++++++++ mysql-test/suite/sql_sequence/other.test | 136 +++++++++++++++++++++ sql/sp_head.cc | 6 +- sql/sql_base.cc | 27 ++-- sql/sql_lex.h | 2 + sql/sql_parse.cc | 15 +++ sql/sql_view.cc | 13 ++ sql/sql_yacc.yy | 13 +- sql/sql_yacc_ora.yy | 13 +- sql/table.h | 6 +- 10 files changed, 305 insertions(+), 17 deletions(-) diff --git a/mysql-test/suite/sql_sequence/other.result b/mysql-test/suite/sql_sequence/other.result index ff58e35772b..abc101b3c00 100644 --- a/mysql-test/suite/sql_sequence/other.result +++ b/mysql-test/suite/sql_sequence/other.result @@ -209,4 +209,95 @@ delete s,t1 from t1,s; ERROR HY000: Storage engine SEQUENCE of the table `test`.`s` doesn't have this option DROP SEQUENCE s; DROP TABLE t1; +# +# MDEV-20074: Lost connection on update trigger +# +# INSERT & table +create sequence s1 increment by 1 start with 1; +create table t1 (p_id integer, p_name varchar(128), p_first_name varchar(128)); +create table t2 (a_id integer default nextval(s1), a_p_name varchar(128), a_p_first_name varchar(128), t timestamp default current_timestamp); +insert into t1 values +(1, 'Luo','Frank'),(2, 'Xe','Emma'),(3, 'Li','Anna'),(4, 'Lun','Serg'),(5, 'Xu','Nils'),(6, 'Ja','Ute'),(7, 'Jin','Mike'),(8, 'Lio','Carl'),(9, 'Lang','Kevin'),(10, 'Ling','Lisa'),(11, 'Fang','Frank'),(12, 'Feng','Emma'),(13, 'Tuo','Anna'),(14, 'Tua','Serg'),(15, 'Moa','Nils'),(16, 'Hua','Ute'),(17, 'Xufa','Mike'),(18, 'Lulu','Carl'),(19, 'Hoho','Kevin'),(20, 'Tata','Lisa'); +CREATE TRIGGER tr_upd +BEFORE UPDATE on t1 +FOR EACH ROW +BEGIN +INSERT INTO t2(a_p_name, a_p_first_name) VALUES(old.p_name, old.p_first_name); +END; +$$ +update t1 set p_first_name='Yunxi' where p_id=1; +drop sequence s1; +drop table t1,t2; +# INSERT & view +create sequence s1 increment by 1 start with 1; +create table t1 (p_id integer, p_name varchar(128), p_first_name varchar(128)); +create table t2 (a_id integer default nextval(s1), a_p_name varchar(128), a_p_first_name varchar(128), t timestamp default current_timestamp); +create view v2 as select * from t2; +insert into t1 values +(1, 'Luo','Frank'),(2, 'Xe','Emma'),(3, 'Li','Anna'),(4, 'Lun','Serg'),(5, 'Xu','Nils'),(6, 'Ja','Ute'),(7, 'Jin','Mike'),(8, 'Lio','Carl'),(9, 'Lang','Kevin'),(10, 'Ling','Lisa'),(11, 'Fang','Frank'),(12, 'Feng','Emma'),(13, 'Tuo','Anna'),(14, 'Tua','Serg'),(15, 'Moa','Nils'),(16, 'Hua','Ute'),(17, 'Xufa','Mike'),(18, 'Lulu','Carl'),(19, 'Hoho','Kevin'),(20, 'Tata','Lisa'); +CREATE TRIGGER tr_upd +BEFORE UPDATE on t1 +FOR EACH ROW +BEGIN +INSERT INTO v2(a_p_name, a_p_first_name) VALUES(old.p_name, old.p_first_name); +END; +$$ +update t1 set p_first_name='Yunxi' where p_id=1; +drop view v2; +drop table t1,t2; +drop sequence s1; +# INSERT SELECT & view +create sequence s1 increment by 1 start with 1; +create table t1 (p_id integer, p_name varchar(128), p_first_name varchar(128)); +create table t2 (a_id integer default nextval(s1), a_p_name varchar(128), a_p_first_name varchar(128), t timestamp default current_timestamp); +create view v2 as select * from t2; +insert into t1 values +(1, 'Luo','Frank'),(2, 'Xe','Emma'),(3, 'Li','Anna'),(4, 'Lun','Serg'),(5, 'Xu','Nils'),(6, 'Ja','Ute'),(7, 'Jin','Mike'),(8, 'Lio','Carl'),(9, 'Lang','Kevin'),(10, 'Ling','Lisa'),(11, 'Fang','Frank'),(12, 'Feng','Emma'),(13, 'Tuo','Anna'),(14, 'Tua','Serg'),(15, 'Moa','Nils'),(16, 'Hua','Ute'),(17, 'Xufa','Mike'),(18, 'Lulu','Carl'),(19, 'Hoho','Kevin'),(20, 'Tata','Lisa'); +CREATE TRIGGER tr_upd +BEFORE UPDATE on t1 +FOR EACH ROW +BEGIN +INSERT INTO v2(a_p_name, a_p_first_name) SELECT old.p_name, old.p_first_name; +END; +$$ +update t1 set p_first_name='Yunxi' where p_id=1; +drop view v2; +drop table t1,t2; +drop sequence s1; +# REPLACE & view +create sequence s1 increment by 1 start with 1; +create table t1 (p_id integer, p_name varchar(128), p_first_name varchar(128)); +create table t2 (a_id integer default nextval(s1), a_p_name varchar(128), a_p_first_name varchar(128), t timestamp default current_timestamp); +create view v2 as select * from t2; +insert into t1 values +(1, 'Luo','Frank'),(2, 'Xe','Emma'),(3, 'Li','Anna'),(4, 'Lun','Serg'),(5, 'Xu','Nils'),(6, 'Ja','Ute'),(7, 'Jin','Mike'),(8, 'Lio','Carl'),(9, 'Lang','Kevin'),(10, 'Ling','Lisa'),(11, 'Fang','Frank'),(12, 'Feng','Emma'),(13, 'Tuo','Anna'),(14, 'Tua','Serg'),(15, 'Moa','Nils'),(16, 'Hua','Ute'),(17, 'Xufa','Mike'),(18, 'Lulu','Carl'),(19, 'Hoho','Kevin'),(20, 'Tata','Lisa'); +CREATE TRIGGER tr_upd +BEFORE UPDATE on t1 +FOR EACH ROW +BEGIN +REPLACE INTO v2(a_p_name, a_p_first_name) VALUES(old.p_name, old.p_first_name); +END; +$$ +update t1 set p_first_name='Yunxi' where p_id=1; +drop view v2; +drop table t1,t2; +drop sequence s1; +# REPLACE SELECT & view +create sequence s1 increment by 1 start with 1; +create table t1 (p_id integer, p_name varchar(128), p_first_name varchar(128)); +create table t2 (a_id integer default nextval(s1), a_p_name varchar(128), a_p_first_name varchar(128), t timestamp default current_timestamp); +create view v2 as select * from t2; +insert into t1 values +(1, 'Luo','Frank'),(2, 'Xe','Emma'),(3, 'Li','Anna'),(4, 'Lun','Serg'),(5, 'Xu','Nils'),(6, 'Ja','Ute'),(7, 'Jin','Mike'),(8, 'Lio','Carl'),(9, 'Lang','Kevin'),(10, 'Ling','Lisa'),(11, 'Fang','Frank'),(12, 'Feng','Emma'),(13, 'Tuo','Anna'),(14, 'Tua','Serg'),(15, 'Moa','Nils'),(16, 'Hua','Ute'),(17, 'Xufa','Mike'),(18, 'Lulu','Carl'),(19, 'Hoho','Kevin'),(20, 'Tata','Lisa'); +CREATE TRIGGER tr_upd +BEFORE UPDATE on t1 +FOR EACH ROW +BEGIN +REPLACE INTO v2(a_p_name, a_p_first_name) SELECT old.p_name, old.p_first_name; +END; +$$ +update t1 set p_first_name='Yunxi' where p_id=1; +drop view v2; +drop table t1,t2; +drop sequence s1; # End of 10.3 tests diff --git a/mysql-test/suite/sql_sequence/other.test b/mysql-test/suite/sql_sequence/other.test index 5759b195950..70c4efa40e5 100644 --- a/mysql-test/suite/sql_sequence/other.test +++ b/mysql-test/suite/sql_sequence/other.test @@ -179,4 +179,140 @@ DROP SEQUENCE s; DROP TABLE t1; +--echo # +--echo # MDEV-20074: Lost connection on update trigger +--echo # + +--echo # INSERT & table +create sequence s1 increment by 1 start with 1; +create table t1 (p_id integer, p_name varchar(128), p_first_name varchar(128)); +create table t2 (a_id integer default nextval(s1), a_p_name varchar(128), a_p_first_name varchar(128), t timestamp default current_timestamp); + +insert into t1 values +(1, 'Luo','Frank'),(2, 'Xe','Emma'),(3, 'Li','Anna'),(4, 'Lun','Serg'),(5, 'Xu','Nils'),(6, 'Ja','Ute'),(7, 'Jin','Mike'),(8, 'Lio','Carl'),(9, 'Lang','Kevin'),(10, 'Ling','Lisa'),(11, 'Fang','Frank'),(12, 'Feng','Emma'),(13, 'Tuo','Anna'),(14, 'Tua','Serg'),(15, 'Moa','Nils'),(16, 'Hua','Ute'),(17, 'Xufa','Mike'),(18, 'Lulu','Carl'),(19, 'Hoho','Kevin'),(20, 'Tata','Lisa'); + +DELIMITER $$; + +CREATE TRIGGER tr_upd +BEFORE UPDATE on t1 +FOR EACH ROW +BEGIN +INSERT INTO t2(a_p_name, a_p_first_name) VALUES(old.p_name, old.p_first_name); +END; +$$ +DELIMITER ;$$ + +update t1 set p_first_name='Yunxi' where p_id=1; + +drop sequence s1; +drop table t1,t2; + + +--echo # INSERT & view +create sequence s1 increment by 1 start with 1; +create table t1 (p_id integer, p_name varchar(128), p_first_name varchar(128)); +create table t2 (a_id integer default nextval(s1), a_p_name varchar(128), a_p_first_name varchar(128), t timestamp default current_timestamp); +create view v2 as select * from t2; + +insert into t1 values +(1, 'Luo','Frank'),(2, 'Xe','Emma'),(3, 'Li','Anna'),(4, 'Lun','Serg'),(5, 'Xu','Nils'),(6, 'Ja','Ute'),(7, 'Jin','Mike'),(8, 'Lio','Carl'),(9, 'Lang','Kevin'),(10, 'Ling','Lisa'),(11, 'Fang','Frank'),(12, 'Feng','Emma'),(13, 'Tuo','Anna'),(14, 'Tua','Serg'),(15, 'Moa','Nils'),(16, 'Hua','Ute'),(17, 'Xufa','Mike'),(18, 'Lulu','Carl'),(19, 'Hoho','Kevin'),(20, 'Tata','Lisa'); + +DELIMITER $$; + +CREATE TRIGGER tr_upd +BEFORE UPDATE on t1 +FOR EACH ROW +BEGIN +INSERT INTO v2(a_p_name, a_p_first_name) VALUES(old.p_name, old.p_first_name); +END; +$$ +DELIMITER ;$$ + +update t1 set p_first_name='Yunxi' where p_id=1; + +drop view v2; +drop table t1,t2; +drop sequence s1; + + +--echo # INSERT SELECT & view +create sequence s1 increment by 1 start with 1; +create table t1 (p_id integer, p_name varchar(128), p_first_name varchar(128)); +create table t2 (a_id integer default nextval(s1), a_p_name varchar(128), a_p_first_name varchar(128), t timestamp default current_timestamp); +create view v2 as select * from t2; + +insert into t1 values +(1, 'Luo','Frank'),(2, 'Xe','Emma'),(3, 'Li','Anna'),(4, 'Lun','Serg'),(5, 'Xu','Nils'),(6, 'Ja','Ute'),(7, 'Jin','Mike'),(8, 'Lio','Carl'),(9, 'Lang','Kevin'),(10, 'Ling','Lisa'),(11, 'Fang','Frank'),(12, 'Feng','Emma'),(13, 'Tuo','Anna'),(14, 'Tua','Serg'),(15, 'Moa','Nils'),(16, 'Hua','Ute'),(17, 'Xufa','Mike'),(18, 'Lulu','Carl'),(19, 'Hoho','Kevin'),(20, 'Tata','Lisa'); + +DELIMITER $$; + +CREATE TRIGGER tr_upd +BEFORE UPDATE on t1 +FOR EACH ROW +BEGIN +INSERT INTO v2(a_p_name, a_p_first_name) SELECT old.p_name, old.p_first_name; +END; +$$ +DELIMITER ;$$ + +update t1 set p_first_name='Yunxi' where p_id=1; + +drop view v2; +drop table t1,t2; +drop sequence s1; + + +--echo # REPLACE & view +create sequence s1 increment by 1 start with 1; +create table t1 (p_id integer, p_name varchar(128), p_first_name varchar(128)); +create table t2 (a_id integer default nextval(s1), a_p_name varchar(128), a_p_first_name varchar(128), t timestamp default current_timestamp); +create view v2 as select * from t2; + +insert into t1 values +(1, 'Luo','Frank'),(2, 'Xe','Emma'),(3, 'Li','Anna'),(4, 'Lun','Serg'),(5, 'Xu','Nils'),(6, 'Ja','Ute'),(7, 'Jin','Mike'),(8, 'Lio','Carl'),(9, 'Lang','Kevin'),(10, 'Ling','Lisa'),(11, 'Fang','Frank'),(12, 'Feng','Emma'),(13, 'Tuo','Anna'),(14, 'Tua','Serg'),(15, 'Moa','Nils'),(16, 'Hua','Ute'),(17, 'Xufa','Mike'),(18, 'Lulu','Carl'),(19, 'Hoho','Kevin'),(20, 'Tata','Lisa'); + +DELIMITER $$; + +CREATE TRIGGER tr_upd +BEFORE UPDATE on t1 +FOR EACH ROW +BEGIN +REPLACE INTO v2(a_p_name, a_p_first_name) VALUES(old.p_name, old.p_first_name); +END; +$$ +DELIMITER ;$$ + +update t1 set p_first_name='Yunxi' where p_id=1; + +drop view v2; +drop table t1,t2; +drop sequence s1; + + +--echo # REPLACE SELECT & view +create sequence s1 increment by 1 start with 1; +create table t1 (p_id integer, p_name varchar(128), p_first_name varchar(128)); +create table t2 (a_id integer default nextval(s1), a_p_name varchar(128), a_p_first_name varchar(128), t timestamp default current_timestamp); +create view v2 as select * from t2; + +insert into t1 values +(1, 'Luo','Frank'),(2, 'Xe','Emma'),(3, 'Li','Anna'),(4, 'Lun','Serg'),(5, 'Xu','Nils'),(6, 'Ja','Ute'),(7, 'Jin','Mike'),(8, 'Lio','Carl'),(9, 'Lang','Kevin'),(10, 'Ling','Lisa'),(11, 'Fang','Frank'),(12, 'Feng','Emma'),(13, 'Tuo','Anna'),(14, 'Tua','Serg'),(15, 'Moa','Nils'),(16, 'Hua','Ute'),(17, 'Xufa','Mike'),(18, 'Lulu','Carl'),(19, 'Hoho','Kevin'),(20, 'Tata','Lisa'); + +DELIMITER $$; + +CREATE TRIGGER tr_upd +BEFORE UPDATE on t1 +FOR EACH ROW +BEGIN +REPLACE INTO v2(a_p_name, a_p_first_name) SELECT old.p_name, old.p_first_name; +END; +$$ +DELIMITER ;$$ + +update t1 set p_first_name='Yunxi' where p_id=1; + +drop view v2; +drop table t1,t2; +drop sequence s1; + --echo # End of 10.3 tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 458955b2d6b..48166fac4c6 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -4652,6 +4652,7 @@ typedef struct st_sp_table uint lock_count; uint query_lock_count; uint8 trg_event_map; + my_bool for_insert_data; } SP_TABLE; @@ -4747,6 +4748,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) if (tab->query_lock_count > tab->lock_count) tab->lock_count++; tab->trg_event_map|= table->trg_event_map; + tab->for_insert_data|= table->for_insert_data; } else { @@ -4770,6 +4772,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) tab->lock_type= table->lock_type; tab->lock_count= tab->query_lock_count= 1; tab->trg_event_map= table->trg_event_map; + tab->for_insert_data= table->for_insert_data; if (my_hash_insert(&m_sptabs, (uchar *)tab)) return FALSE; } @@ -4853,7 +4856,8 @@ sp_head::add_used_tables_to_table_list(THD *thd, TABLE_LIST::PRELOCK_ROUTINE, belong_to_view, stab->trg_event_map, - query_tables_last_ptr); + query_tables_last_ptr, + stab->for_insert_data); tab_buff+= ALIGN_SIZE(sizeof(TABLE_LIST)); result= TRUE; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4bf894798de..4729612f2b0 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4420,9 +4420,11 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *tables) { TABLE_LIST *global_table_list= prelocking_ctx->query_tables; + DBUG_ENTER("add_internal_tables"); do { + DBUG_PRINT("info", ("table name: %s", tables->table_name.str)); /* Skip table if already in the list. Can happen with prepared statements */ @@ -4432,20 +4434,22 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); if (!tl) - return TRUE; + DBUG_RETURN(TRUE); tl->init_one_table_for_prelocking(&tables->db, &tables->table_name, NULL, tables->lock_type, TABLE_LIST::PRELOCK_NONE, 0, 0, - &prelocking_ctx->query_tables_last); + &prelocking_ctx->query_tables_last, + tables->for_insert_data); /* Store link to the new table_list that will be used by open so that Item_func_nextval() can find it */ tables->next_local= tl; + DBUG_PRINT("info", ("table name: %s added", tables->table_name.str)); } while ((tables= tables->next_global)); - return FALSE; + DBUG_RETURN(FALSE); } @@ -4476,6 +4480,7 @@ bool DML_prelocking_strategy:: handle_table(THD *thd, Query_tables_list *prelocking_ctx, TABLE_LIST *table_list, bool *need_prelocking) { + DBUG_ENTER("handle_table"); TABLE *table= table_list->table; /* We rely on a caller to check that table is going to be changed. */ DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE || @@ -4506,7 +4511,7 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx, { if (arena) thd->restore_active_arena(arena, &backup); - return TRUE; + DBUG_RETURN(TRUE); } *need_prelocking= TRUE; @@ -4534,7 +4539,8 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx, NULL, lock_type, TABLE_LIST::PRELOCK_FK, table_list->belong_to_view, op, - &prelocking_ctx->query_tables_last); + &prelocking_ctx->query_tables_last, + table_list->for_insert_data); } if (arena) thd->restore_active_arena(arena, &backup); @@ -4542,8 +4548,11 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx, } /* Open any tables used by DEFAULT (like sequence tables) */ + DBUG_PRINT("info", ("table: %p name: %s db: %s flags: %u", + table_list, table_list->table_name.str, + table_list->db.str, table_list->for_insert_data)); if (table->internal_tables && - ((sql_command_flags[thd->lex->sql_command] & CF_INSERTS_DATA) || + (table_list->for_insert_data || thd->lex->default_used)) { Query_arena *arena, backup; @@ -4556,10 +4565,10 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx, if (unlikely(error)) { *need_prelocking= TRUE; - return TRUE; + DBUG_RETURN(TRUE); } } - return FALSE; + DBUG_RETURN(FALSE); } @@ -4576,7 +4585,7 @@ bool open_and_lock_internal_tables(TABLE *table, bool lock_table) THD *thd= table->in_use; TABLE_LIST *tl; MYSQL_LOCK *save_lock,*new_lock; - DBUG_ENTER("open_internal_tables"); + DBUG_ENTER("open_and_lock_internal_tables"); /* remove pointer to old select_lex which is already destroyed */ for (tl= table->internal_tables ; tl ; tl= tl->next_global) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 3820ee5923d..8b6b2ca9df0 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -4060,6 +4060,8 @@ public: } bool tvc_finalize(); bool tvc_finalize_derived(); + + void mark_first_table_as_inserting(); }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e55f9aab35d..81eba0da8cb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3282,6 +3282,10 @@ mysql_execute_command(THD *thd) #endif DBUG_ENTER("mysql_execute_command"); + // check that we correctly marked first table for data insertion + DBUG_ASSERT(!(sql_command_flags[lex->sql_command] & CF_INSERTS_DATA) || + first_table->for_insert_data); + DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt); /* Each statement or replication event which might produce deadlock @@ -10200,3 +10204,14 @@ CHARSET_INFO *find_bin_collation(CHARSET_INFO *cs) } return cs; } + +void LEX::mark_first_table_as_inserting() +{ + TABLE_LIST *t= select_lex.table_list.first; + DBUG_ENTER("Query_tables_list::mark_tables_with_important_flags"); + DBUG_ASSERT(sql_command_flags[sql_command] & CF_INSERTS_DATA); + t->for_insert_data= TRUE; + DBUG_PRINT("info", ("table_list: %p name: %s db: %s command: %u", + t, t->table_name.str,t->db.str, sql_command)); + DBUG_VOID_RETURN; +} diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 0bde411a977..98c1e816f31 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1490,6 +1490,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, privileges of top_view */ tbl->grant.want_privilege= SELECT_ACL; + /* After unfolding the view we lose the list of tables referenced in it (we will have only a list of underlying tables in case of MERGE @@ -1540,6 +1541,18 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, views with subqueries in select list. */ view_main_select_tables= lex->select_lex.table_list.first; + /* + Mergeable view can be used for inserting, so we move the flag down + */ + if (table->for_insert_data) + { + for (TABLE_LIST *t= view_main_select_tables; + t; + t= t->next_local) + { + t->for_insert_data= TRUE; + } + } /* Let us set proper lock type for tables of the view's main diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 00ab03cba26..235be9b0f89 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7888,6 +7888,7 @@ alter: MYSQL_YYABORT; Lex->select_lex.db= (Lex->select_lex.table_list.first)->db; Lex->create_last_non_select_table= Lex->last_table(); + Lex->mark_first_table_as_inserting(); } alter_commands { @@ -13459,7 +13460,9 @@ insert: Lex->current_select= &Lex->select_lex; } insert_field_spec opt_insert_update - {} + { + Lex->mark_first_table_as_inserting(); + } ; replace: @@ -13476,7 +13479,9 @@ replace: Lex->current_select= &Lex->select_lex; } insert_field_spec - {} + { + Lex->mark_first_table_as_inserting(); + } ; insert_lock_option: @@ -14859,7 +14864,9 @@ load: opt_xml_rows_identified_by opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec opt_load_data_set_spec - {} + { + Lex->mark_first_table_as_inserting(); + } ; data_or_xml: diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index f33ef8cfc68..12ac95dedee 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -7825,6 +7825,7 @@ alter: MYSQL_YYABORT; Lex->select_lex.db= (Lex->select_lex.table_list.first)->db; Lex->create_last_non_select_table= Lex->last_table(); + Lex->mark_first_table_as_inserting(); } alter_commands { @@ -13420,7 +13421,9 @@ insert: Lex->current_select= &Lex->select_lex; } insert_field_spec opt_insert_update - {} + { + Lex->mark_first_table_as_inserting(); + } ; replace: @@ -13437,7 +13440,9 @@ replace: Lex->current_select= &Lex->select_lex; } insert_field_spec - {} + { + Lex->mark_first_table_as_inserting(); + } ; insert_lock_option: @@ -14826,7 +14831,9 @@ load: opt_xml_rows_identified_by opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec opt_load_data_set_spec - {} + { + Lex->mark_first_table_as_inserting(); + } ; data_or_xml: diff --git a/sql/table.h b/sql/table.h index 494d6628ebe..0a0f0aab77f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1985,7 +1985,8 @@ struct TABLE_LIST prelocking_types prelocking_type, TABLE_LIST *belong_to_view_arg, uint8 trg_event_map_arg, - TABLE_LIST ***last_ptr) + TABLE_LIST ***last_ptr, + my_bool insert_data) { init_one_table(db_arg, table_name_arg, alias_arg, lock_type_arg); @@ -2000,6 +2001,7 @@ struct TABLE_LIST **last_ptr= this; prev_global= *last_ptr; *last_ptr= &next_global; + for_insert_data= insert_data; } @@ -2411,6 +2413,8 @@ struct TABLE_LIST /* System Versioning */ vers_select_conds_t vers_conditions; + my_bool for_insert_data; + /** @brief Find the bottom in the chain of embedded table VIEWs. From e0b6294338fdfc8a4a8b42e6b199c588453be879 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 18 Oct 2019 10:24:53 +0400 Subject: [PATCH 20/68] MDEV-20855 Crash with PARTITION BY LIST and extended characters The code in convert_charset_partition_constant() did not take into account that the call for item->safe_charset_converter() can return NULL when conversion is not safe. Note, 10.2 was not affected. The test for NULL presents in 10.2, but it disappeared in 10.3 in a mistake. Restoring the test. --- mysql-test/main/partition_ucs2.result | 13 +++++++++++++ mysql-test/main/partition_ucs2.test | 19 +++++++++++++++++++ mysql-test/main/partition_utf8.result | 16 ++++++++++++++++ mysql-test/main/partition_utf8.test | 22 ++++++++++++++++++++++ sql/sql_partition.cc | 2 +- 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 mysql-test/main/partition_ucs2.result create mode 100644 mysql-test/main/partition_ucs2.test diff --git a/mysql-test/main/partition_ucs2.result b/mysql-test/main/partition_ucs2.result new file mode 100644 index 00000000000..ae2f3f15fa3 --- /dev/null +++ b/mysql-test/main/partition_ucs2.result @@ -0,0 +1,13 @@ +# +# Start of 10.3 tests +# +# +# MDEV-20855 Crash with PARTITION BY LIST and extended characters +# +SET NAMES utf8; +CREATE OR REPLACE TABLE t1 (a TIME) +PARTITION BY LIST COLUMNS (a) (PARTITION p0 VALUES IN (_ucs2 0x0411)); +ERROR HY000: This partition function is not allowed +# +# End of 10.3 tests +# diff --git a/mysql-test/main/partition_ucs2.test b/mysql-test/main/partition_ucs2.test new file mode 100644 index 00000000000..8af2b6196c6 --- /dev/null +++ b/mysql-test/main/partition_ucs2.test @@ -0,0 +1,19 @@ +--source include/have_partition.inc +--source include/have_ucs2.inc + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-20855 Crash with PARTITION BY LIST and extended characters +--echo # + +SET NAMES utf8; +--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED +CREATE OR REPLACE TABLE t1 (a TIME) + PARTITION BY LIST COLUMNS (a) (PARTITION p0 VALUES IN (_ucs2 0x0411)); + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/mysql-test/main/partition_utf8.result b/mysql-test/main/partition_utf8.result index 7718e651423..956ee790160 100644 --- a/mysql-test/main/partition_utf8.result +++ b/mysql-test/main/partition_utf8.result @@ -51,3 +51,19 @@ t1 CREATE TABLE `t1` ( insert into t1 values (''); insert into t1 values (_ucs2 0x2020); drop table t1; +# +# Start of 10.3 tests +# +# +# MDEV-20855 Crash with PARTITION BY LIST and extended characters +# +SET NAMES utf8; +CREATE OR REPLACE TABLE t1 (a CHAR(10)) CHARACTER SET latin1 +PARTITION BY LIST COLUMNS (a) (PARTITION p0 VALUES IN ('Б')); +ERROR HY000: This partition function is not allowed +CREATE OR REPLACE TABLE t1 (a TIME) +PARTITION BY LIST COLUMNS (a) (PARTITION p0 VALUES IN ('Б')); +ERROR HY000: This partition function is not allowed +# +# End of 10.3 tests +# diff --git a/mysql-test/main/partition_utf8.test b/mysql-test/main/partition_utf8.test index d3ad7ba671e..65050429a52 100644 --- a/mysql-test/main/partition_utf8.test +++ b/mysql-test/main/partition_utf8.test @@ -40,3 +40,25 @@ show create table t1; insert into t1 values (''); insert into t1 values (_ucs2 0x2020); drop table t1; + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-20855 Crash with PARTITION BY LIST and extended characters +--echo # + +SET NAMES utf8; + +--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED +CREATE OR REPLACE TABLE t1 (a CHAR(10)) CHARACTER SET latin1 + PARTITION BY LIST COLUMNS (a) (PARTITION p0 VALUES IN ('Б')); + +--error ER_PARTITION_FUNCTION_IS_NOT_ALLOWED +CREATE OR REPLACE TABLE t1 (a TIME) + PARTITION BY LIST COLUMNS (a) (PARTITION p0 VALUES IN ('Б')); + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index d23ee8583e3..00a78ce3199 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -146,7 +146,7 @@ Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs) item= item->safe_charset_converter(thd, cs); context->table_list= NULL; thd->where= "convert character set partition constant"; - if (item->fix_fields_if_needed(thd, (Item**)NULL)) + if (item && item->fix_fields_if_needed(thd, (Item**)NULL)) item= NULL; thd->where= save_where; context->table_list= save_list; From c9b5280371b0ceddb9a805f0bc4cd5265d9fab86 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Sat, 19 Oct 2019 10:01:26 +0200 Subject: [PATCH 21/68] MDEV-20466: fix of embedded test suite --- mysql-test/r/processlist.result | 6 ---- mysql-test/r/processlist_notembedded.result | 7 +++++ mysql-test/t/processlist.test | 29 ------------------ mysql-test/t/processlist_notembedded.test | 34 +++++++++++++++++++++ 4 files changed, 41 insertions(+), 35 deletions(-) create mode 100644 mysql-test/r/processlist_notembedded.result create mode 100644 mysql-test/t/processlist_notembedded.test diff --git a/mysql-test/r/processlist.result b/mysql-test/r/processlist.result index 24802cb2425..55d2425d269 100644 --- a/mysql-test/r/processlist.result +++ b/mysql-test/r/processlist.result @@ -17,10 +17,4 @@ select command, time < 5 from information_schema.processlist where id != connect command time < 5 Sleep 1 set debug_sync='reset'; -# -# MDEV-20466: SHOW PROCESSLIST truncates query text on \0 bytes -# -SET DEBUG_SYNC= 'before_join_optimize SIGNAL in_sync'; -SET DEBUG_SYNC= 'now WAIT_FOR in_sync'; -SET DEBUG_SYNC = 'RESET'; End of 5.5 tests diff --git a/mysql-test/r/processlist_notembedded.result b/mysql-test/r/processlist_notembedded.result new file mode 100644 index 00000000000..f5b2a310813 --- /dev/null +++ b/mysql-test/r/processlist_notembedded.result @@ -0,0 +1,7 @@ +# +# MDEV-20466: SHOW PROCESSLIST truncates query text on \0 bytes +# +SET DEBUG_SYNC= 'before_join_optimize SIGNAL in_sync'; +SET DEBUG_SYNC= 'now WAIT_FOR in_sync'; +SET DEBUG_SYNC = 'RESET'; +End of 5.5 tests diff --git a/mysql-test/t/processlist.test b/mysql-test/t/processlist.test index 52cb6b31919..8a8995f43b0 100644 --- a/mysql-test/t/processlist.test +++ b/mysql-test/t/processlist.test @@ -51,33 +51,4 @@ select command, time < 5 from information_schema.processlist where id != connect disconnect con1; set debug_sync='reset'; ---echo # ---echo # MDEV-20466: SHOW PROCESSLIST truncates query text on \0 bytes ---echo # - -connect (con1,localhost,root,,); - -connection con1; - -let $q= `select CONCAT("SELECT user FROM mysql.user WHERE user ='some", CHAR(0), "' or sleep (30)")`; - -SET DEBUG_SYNC= 'before_join_optimize SIGNAL in_sync'; ---disable_query_log ---send_eval $q; ---enable_query_log -connection default; - -SET DEBUG_SYNC= 'now WAIT_FOR in_sync'; - -exec $MYSQL test -e "SHOW PROCESSLIST" > $MYSQLTEST_VARDIR/tmp/MDEV-20466.text; - -let SEARCH_FILE=$MYSQLTEST_VARDIR/tmp/MDEV-20466.text; -let SEARCH_PATTERN=sleep; -source include/search_pattern_in_file.inc; -remove_file $MYSQLTEST_VARDIR/tmp//MDEV-20466.text; - -disconnect con1; - -SET DEBUG_SYNC = 'RESET'; - --echo End of 5.5 tests diff --git a/mysql-test/t/processlist_notembedded.test b/mysql-test/t/processlist_notembedded.test new file mode 100644 index 00000000000..dc970cf5709 --- /dev/null +++ b/mysql-test/t/processlist_notembedded.test @@ -0,0 +1,34 @@ +source include/have_debug.inc; +source include/have_debug_sync.inc; +source include/not_embedded.inc; + +--echo # +--echo # MDEV-20466: SHOW PROCESSLIST truncates query text on \0 bytes +--echo # + +connect (con1,localhost,root,,); + +connection con1; + +let $q= `select CONCAT("SELECT user FROM mysql.user WHERE user ='some", CHAR(0), "' or sleep (30)")`; + +SET DEBUG_SYNC= 'before_join_optimize SIGNAL in_sync'; +--disable_query_log +--send_eval $q; +--enable_query_log +connection default; + +SET DEBUG_SYNC= 'now WAIT_FOR in_sync'; + +exec $MYSQL test -e "SHOW PROCESSLIST" > $MYSQLTEST_VARDIR/tmp/MDEV-20466.text; + +let SEARCH_FILE=$MYSQLTEST_VARDIR/tmp/MDEV-20466.text; +let SEARCH_PATTERN=sleep; +source include/search_pattern_in_file.inc; +remove_file $MYSQLTEST_VARDIR/tmp//MDEV-20466.text; + +disconnect con1; + +SET DEBUG_SYNC = 'RESET'; + +--echo End of 5.5 tests From 412e3e6917233fe612354622a18b3f9cdf3a350c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 13 Sep 2019 09:52:30 +0200 Subject: [PATCH 22/68] MDEV-9546 mysqlaccess script shows an old version (which was vulnerable to CVE-2005-0004) update mysqlaccess version --- scripts/mysqlaccess.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mysqlaccess.sh b/scripts/mysqlaccess.sh index b75a8b74ece..6f2fb5aae7d 100644 --- a/scripts/mysqlaccess.sh +++ b/scripts/mysqlaccess.sh @@ -26,7 +26,7 @@ use Fcntl; BEGIN { # **************************** # static information... - $VERSION = "2.06, 20 Dec 2000"; + $VERSION = "2.10, 13 Sep 2019"; $0 =~ m%/([^/]+)$%o; $script = $1; $script = 'MySQLAccess' unless $script; From 719ac0ad4af0dd1e20dbc94eff8f8c9f786b3393 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 19 Oct 2019 09:32:11 +0200 Subject: [PATCH 23/68] crash in string-to-int conversion using a specially crafted strings one could overflow `shift` variable and cause a crash by dereferencing d10[-2147483648] (on a sufficiently old gcc). This is a correct fix and a test case for Bug #29723340: MYSQL SERVER CRASH AFTER SQL QUERY WITH DATA ?AST --- mysql-test/r/func_math.result | 40 +++++++++++++++++++++++++++++++++++ mysql-test/t/func_math.test | 25 ++++++++++++++++++++++ strings/ctype-simple.c | 18 ++++++++++++---- 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index 6edaa2e4d96..7e010297885 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -829,5 +829,45 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; # +# Bug #29723340: MYSQL SERVER CRASH AFTER SQL QUERY WITH DATA ?AST +# +create table t1(a int); +insert t1 values("1e-214748364"); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +insert t1 values("1e-2147483648"); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +insert t1 values("1e-21474836480"); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +insert t1 values("1e+214748364"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +insert t1 values("1e+2147483647"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +insert t1 values("1e+21474836470"); +Warnings: +Warning 1264 Out of range value for column 'a' at row 1 +set global max_allowed_packet= cast(2*1024*1024*1024+1024 as unsigned); +Warnings: +Warning 1292 Truncated incorrect max_allowed_packet value: '2147484672' +set @a=2147483647; +insert t1 values (concat('1', repeat('0', @a+18), 'e-', @a-1, '0')); +Warnings: +Warning 1301 Result of repeat() was larger than max_allowed_packet (1073741824) - truncated +set global max_allowed_packet=default; +select * from t1; +a +0 +0 +0 +2147483647 +2147483647 +2147483647 +NULL +drop table t1; +# # End of 5.5 tests # diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index 1b5fa519c09..aca81e96de1 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -614,6 +614,31 @@ SHOW CREATE TABLE t1; DROP TABLE t1; +--echo # +--echo # Bug #29723340: MYSQL SERVER CRASH AFTER SQL QUERY WITH DATA ?AST +--echo # + +create table t1(a int); +insert t1 values("1e-214748364"); +insert t1 values("1e-2147483648"); +insert t1 values("1e-21474836480"); +insert t1 values("1e+214748364"); +insert t1 values("1e+2147483647"); +insert t1 values("1e+21474836470"); + +# if max max_allowed_packet will ever be increased beyond 2GB, this could +# break again: +set global max_allowed_packet= cast(2*1024*1024*1024+1024 as unsigned); +connect foo,localhost,root; +set @a=2147483647; +insert t1 values (concat('1', repeat('0', @a+18), 'e-', @a-1, '0')); +disconnect foo; +connection default; +set global max_allowed_packet=default; + +select * from t1; +drop table t1; + --echo # --echo # End of 5.5 tests --echo # diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 5c9790966d8..ba446a7df54 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, SkySQL Ab. + Copyright (c) 2009, 2019, MariaDB Corporation. 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 @@ -1524,10 +1524,20 @@ exp: /* [ E [ ] ] */ if (++str == end) goto ret_sign; } - for (exponent= 0 ; - str < end && (ch= (uchar) (*str - '0')) < 10; - str++) + if (shift > 0 && !negative_exp) + goto ret_too_big; + for (exponent= 0 ; str < end && (ch= (uchar) (*str - '0')) < 10; str++) { + if (negative_exp) + { + if (exponent - shift > DIGITS_IN_ULONGLONG) + goto ret_zero; + } + else + { + if (exponent + shift > DIGITS_IN_ULONGLONG) + goto ret_too_big; + } exponent= exponent * 10 + ch; } shift+= negative_exp ? -exponent : exponent; From 28098420317bc2efe082df799c917babde879242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 19 Oct 2019 15:16:47 +0300 Subject: [PATCH 24/68] MDEV-20864 Introduce debug option innodb_change_buffer_dump To diagnose a hang in slow shutdown (innodb_fast_shutdown=0), let us introduce a Boolean startup option in debug builds that will cause the contents of the InnoDB change buffer to be dumped to the server error log at startup. --- mysql-test/suite/innodb/t/ibuf_not_empty.test | 2 +- .../suite/sys_vars/r/sysvars_innodb.result | 12 +++++++++++ storage/innobase/handler/ha_innodb.cc | 6 ++++++ storage/innobase/ibuf/ibuf0ibuf.cc | 21 +++++++++++++++++++ storage/innobase/include/dict0types.h | 4 +++- 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/t/ibuf_not_empty.test b/mysql-test/suite/innodb/t/ibuf_not_empty.test index a1a2da1f903..9ee0b180f44 100644 --- a/mysql-test/suite/innodb/t/ibuf_not_empty.test +++ b/mysql-test/suite/innodb/t/ibuf_not_empty.test @@ -41,7 +41,7 @@ INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; INSERT INTO t1 SELECT 0,b,c FROM t1; ---let $restart_parameters= --innodb-force-recovery=6 +--let $restart_parameters= --innodb-force-recovery=6 --innodb-change-buffer-dump --source include/restart_mysqld.inc --replace_regex /contains \d+ entries/contains #### entries/ diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index 1808cfb6ea3..65d47347a15 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -354,6 +354,18 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED +VARIABLE_NAME INNODB_CHANGE_BUFFER_DUMP +SESSION_VALUE NULL +DEFAULT_VALUE OFF +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BOOLEAN +VARIABLE_COMMENT Dump the change buffer at startup. +NUMERIC_MIN_VALUE NULL +NUMERIC_MAX_VALUE NULL +NUMERIC_BLOCK_SIZE NULL +ENUM_VALUE_LIST OFF,ON +READ_ONLY YES +COMMAND_LINE_ARGUMENT NONE VARIABLE_NAME INNODB_CHANGE_BUFFER_MAX_SIZE SESSION_VALUE NULL DEFAULT_VALUE 25 diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index a556b5875df..3ad12c455bf 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -20642,6 +20642,11 @@ static MYSQL_SYSVAR_ENUM(stats_method, srv_innodb_stats_method, NULL, NULL, SRV_STATS_NULLS_EQUAL, &innodb_stats_method_typelib); #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG +static MYSQL_SYSVAR_BOOL(change_buffer_dump, ibuf_dump, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Dump the change buffer at startup.", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug, PLUGIN_VAR_RQCMDARG, "Debug flags for InnoDB change buffering (0=none, 1=try to buffer)", @@ -21158,6 +21163,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(change_buffering), MYSQL_SYSVAR(change_buffer_max_size), #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG + MYSQL_SYSVAR(change_buffer_dump), MYSQL_SYSVAR(change_buffering_debug), MYSQL_SYSVAR(disable_background_merge), #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index d3fdd46c29b..e701271379e 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -188,6 +188,8 @@ access order rules. */ ibuf_use_t ibuf_use = IBUF_USE_ALL; #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG +/** Dump the change buffer at startup */ +my_bool ibuf_dump; /** Flag to control insert buffer debugging. */ uint ibuf_debug; #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ @@ -506,6 +508,25 @@ ibuf_init_at_db_start(void) #endif /* BTR_CUR_ADAPT */ ibuf->index->page = FSP_IBUF_TREE_ROOT_PAGE_NO; ut_d(ibuf->index->cached = TRUE); + +#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG + if (!ibuf_dump) { + return error; + } + ib::info() << "Dumping the change buffer"; + ibuf_mtr_start(&mtr); + btr_pcur_t pcur; + if (DB_SUCCESS == btr_pcur_open_at_index_side( + true, ibuf->index, BTR_SEARCH_LEAF, &pcur, + true, 0, &mtr)) { + while (btr_pcur_move_to_next_user_rec(&pcur, &mtr)) { + rec_print_old(stderr, btr_pcur_get_rec(&pcur)); + } + } + ibuf_mtr_commit(&mtr); + ib::info() << "Dumped the change buffer"; +#endif + return (error); } diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h index 93c2f570e54..bea08f398de 100644 --- a/storage/innobase/include/dict0types.h +++ b/storage/innobase/include/dict0types.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2017, MariaDB Corporation. +Copyright (c) 2013, 2019, MariaDB Corporation. 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 @@ -96,6 +96,8 @@ typedef ib_mutex_t DictSysMutex; #define TEMP_TABLE_PATH_PREFIX "/" TEMP_TABLE_PREFIX #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG +/** Dump the change buffer at startup */ +extern my_bool ibuf_dump; /** Flag to control insert buffer debugging. */ extern uint ibuf_debug; #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ From b62101f84be49013cf07f323c202606847dcc453 Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 14 Oct 2019 18:14:36 +0300 Subject: [PATCH 25/68] Fixes for binary logging --read-only mode - Any temporary tables created under read-only mode will never be logged to binary log. Any usage of these tables to update normal tables, even after read-only has been disabled, will use row base logging (as the temporary table will not be on the slave). - Analyze, check and repair table will not be logged in read-only mode. Other things: - Removed not used varaibles in MYSQL_BIN_LOG::flush_and_set_pending_rows_event. - Set table_share->table_creation_was_logged for all normal tables. - THD::binlog_query() now returns -1 if statement was not logged., This is used to update table_share->table_creation_was_logged. - Don't log admin statements in opt_readonly is set. - Table's that doesn't have table_creation_was_logged will set binlog format to row logging. - Removed not needed/wrong setting of table->s->table_creation_was_logged in create_table_from_items() --- mysql-test/suite/binlog/r/read_only.result | 109 ++++++++++++++++++ .../suite/binlog/r/read_only_statement.result | 109 ++++++++++++++++++ mysql-test/suite/binlog/t/read_only.inc | 74 ++++++++++++ mysql-test/suite/binlog/t/read_only.test | 2 + .../suite/binlog/t/read_only_statement.test | 2 + sql/log.cc | 3 +- sql/sp.cc | 2 +- sql/sql_acl.cc | 4 +- sql/sql_admin.cc | 6 +- sql/sql_class.cc | 38 ++++-- sql/sql_delete.cc | 4 +- sql/sql_insert.cc | 51 +++++--- sql/sql_lex.h | 8 ++ sql/sql_table.cc | 52 +++++---- sql/sql_update.cc | 4 +- sql/sql_view.cc | 2 +- sql/table.cc | 11 +- sql/table.h | 6 +- 18 files changed, 425 insertions(+), 62 deletions(-) create mode 100644 mysql-test/suite/binlog/r/read_only.result create mode 100644 mysql-test/suite/binlog/r/read_only_statement.result create mode 100644 mysql-test/suite/binlog/t/read_only.inc create mode 100644 mysql-test/suite/binlog/t/read_only.test create mode 100644 mysql-test/suite/binlog/t/read_only_statement.test diff --git a/mysql-test/suite/binlog/r/read_only.result b/mysql-test/suite/binlog/r/read_only.result new file mode 100644 index 00000000000..aa1893b56a3 --- /dev/null +++ b/mysql-test/suite/binlog/r/read_only.result @@ -0,0 +1,109 @@ +# +# MDEV-17863 DROP TEMPORARY TABLE creates a transaction in +# binary log on read only server +# MDEV-19074 Improved read_only mode for slaves with +# gtid_strict_mode enabled +# +create user test@localhost; +grant CREATE, DROP, INSERT, SELECT on *.* to test@localhost; +create table t1 (a int) engine=myisam; +insert into t1 values (1),(2); +reset master; +set global read_only=1; +# Ensure that optimize and analyze doesn't log to binary log +connect con1,localhost,test,,test; +insert into t1 values(3); +ERROR HY000: The MariaDB server is running with the --read-only option so it cannot execute this statement +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +repair table t1; +Table Op Msg_type Msg_text +test.t1 repair Error The MariaDB server is running with the --read-only option so it cannot execute this statement +test.t1 repair error Corrupt +optimize table t1; +ERROR HY000: The MariaDB server is running with the --read-only option so it cannot execute this statement +# Ensure that using temporary tables is not logged +create temporary table tmp1 (a int) engine=myisam; +insert into tmp1 values (1),(2); +update tmp1 set a=10 where a=2; +delete from tmp1 where a=1; +create temporary table tmp2 select * from t1; +select * from tmp1; +a +10 +select * from tmp2; +a +1 +2 +create temporary table tmp3 like t1; +create or replace temporary table tmp3 like t1; +alter table tmp2 add column (b int); +select * from tmp2; +a b +1 NULL +2 NULL +drop table tmp1,tmp2,tmp3; +# Clean up test connection +disconnect con1; +connection default; +# Execute some commands as root that should not be logged +optimize table t1; +Table Op Msg_type Msg_text +test.t1 optimize status Table is already up to date +repair table t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +# Changes to temporary tables created under readonly should not +# be logged +create temporary table tmp4 (a int) engine=myisam; +insert into tmp4 values (1),(2); +create temporary table tmp5 (a int) engine=myisam; +insert into tmp5 select * from tmp4; +alter table tmp5 add column (b int); +set global read_only=0; +insert into tmp4 values (3),(4); +insert into tmp5 values (10,3),(11,4); +select * from tmp4; +a +1 +2 +3 +4 +select * from tmp5; +a b +1 NULL +2 NULL +10 3 +11 4 +update tmp4 set a=10 where a=2; +delete from tmp4 where a=1; +create table t2 select * from tmp4; +alter table tmp5 add column (c int); +insert into tmp5 values (20,5,1),(21,5,2); +select * from tmp5; +a b c +1 NULL NULL +2 NULL NULL +10 3 NULL +11 4 NULL +20 5 1 +21 5 2 +drop table tmp4,tmp5; +# Check what is logged. Only the last create select should be row-logged +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE TABLE `t2` ( + `a` int(11) DEFAULT NULL +) +master-bin.000001 # Annotate_rows # # create table t2 select * from tmp4 +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +# Clean up +drop user test@localhost; +drop table t1,t2; diff --git a/mysql-test/suite/binlog/r/read_only_statement.result b/mysql-test/suite/binlog/r/read_only_statement.result new file mode 100644 index 00000000000..aa1893b56a3 --- /dev/null +++ b/mysql-test/suite/binlog/r/read_only_statement.result @@ -0,0 +1,109 @@ +# +# MDEV-17863 DROP TEMPORARY TABLE creates a transaction in +# binary log on read only server +# MDEV-19074 Improved read_only mode for slaves with +# gtid_strict_mode enabled +# +create user test@localhost; +grant CREATE, DROP, INSERT, SELECT on *.* to test@localhost; +create table t1 (a int) engine=myisam; +insert into t1 values (1),(2); +reset master; +set global read_only=1; +# Ensure that optimize and analyze doesn't log to binary log +connect con1,localhost,test,,test; +insert into t1 values(3); +ERROR HY000: The MariaDB server is running with the --read-only option so it cannot execute this statement +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +repair table t1; +Table Op Msg_type Msg_text +test.t1 repair Error The MariaDB server is running with the --read-only option so it cannot execute this statement +test.t1 repair error Corrupt +optimize table t1; +ERROR HY000: The MariaDB server is running with the --read-only option so it cannot execute this statement +# Ensure that using temporary tables is not logged +create temporary table tmp1 (a int) engine=myisam; +insert into tmp1 values (1),(2); +update tmp1 set a=10 where a=2; +delete from tmp1 where a=1; +create temporary table tmp2 select * from t1; +select * from tmp1; +a +10 +select * from tmp2; +a +1 +2 +create temporary table tmp3 like t1; +create or replace temporary table tmp3 like t1; +alter table tmp2 add column (b int); +select * from tmp2; +a b +1 NULL +2 NULL +drop table tmp1,tmp2,tmp3; +# Clean up test connection +disconnect con1; +connection default; +# Execute some commands as root that should not be logged +optimize table t1; +Table Op Msg_type Msg_text +test.t1 optimize status Table is already up to date +repair table t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +# Changes to temporary tables created under readonly should not +# be logged +create temporary table tmp4 (a int) engine=myisam; +insert into tmp4 values (1),(2); +create temporary table tmp5 (a int) engine=myisam; +insert into tmp5 select * from tmp4; +alter table tmp5 add column (b int); +set global read_only=0; +insert into tmp4 values (3),(4); +insert into tmp5 values (10,3),(11,4); +select * from tmp4; +a +1 +2 +3 +4 +select * from tmp5; +a b +1 NULL +2 NULL +10 3 +11 4 +update tmp4 set a=10 where a=2; +delete from tmp4 where a=1; +create table t2 select * from tmp4; +alter table tmp5 add column (c int); +insert into tmp5 values (20,5,1),(21,5,2); +select * from tmp5; +a b c +1 NULL NULL +2 NULL NULL +10 3 NULL +11 4 NULL +20 5 1 +21 5 2 +drop table tmp4,tmp5; +# Check what is logged. Only the last create select should be row-logged +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE TABLE `t2` ( + `a` int(11) DEFAULT NULL +) +master-bin.000001 # Annotate_rows # # create table t2 select * from tmp4 +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +# Clean up +drop user test@localhost; +drop table t1,t2; diff --git a/mysql-test/suite/binlog/t/read_only.inc b/mysql-test/suite/binlog/t/read_only.inc new file mode 100644 index 00000000000..75cd4a5dfb3 --- /dev/null +++ b/mysql-test/suite/binlog/t/read_only.inc @@ -0,0 +1,74 @@ +--echo # +--echo # MDEV-17863 DROP TEMPORARY TABLE creates a transaction in +--echo # binary log on read only server +--echo # MDEV-19074 Improved read_only mode for slaves with +--echo # gtid_strict_mode enabled +--echo # + +create user test@localhost; +grant CREATE, DROP, INSERT, SELECT on *.* to test@localhost; +create table t1 (a int) engine=myisam; +insert into t1 values (1),(2); +reset master; + +set global read_only=1; +--echo # Ensure that optimize and analyze doesn't log to binary log +connect (con1,localhost,test,,test); +--error ER_OPTION_PREVENTS_STATEMENT +insert into t1 values(3); +analyze table t1; +check table t1; +repair table t1; +--error ER_OPTION_PREVENTS_STATEMENT +optimize table t1; + +--echo # Ensure that using temporary tables is not logged +create temporary table tmp1 (a int) engine=myisam; +insert into tmp1 values (1),(2); +update tmp1 set a=10 where a=2; +delete from tmp1 where a=1; +create temporary table tmp2 select * from t1; +select * from tmp1; +select * from tmp2; +create temporary table tmp3 like t1; +create or replace temporary table tmp3 like t1; +alter table tmp2 add column (b int); +select * from tmp2; +drop table tmp1,tmp2,tmp3; + +--echo # Clean up test connection +disconnect con1; +connection default; + +--echo # Execute some commands as root that should not be logged +optimize table t1; +repair table t1; + +--echo # Changes to temporary tables created under readonly should not +--echo # be logged +create temporary table tmp4 (a int) engine=myisam; +insert into tmp4 values (1),(2); +create temporary table tmp5 (a int) engine=myisam; +insert into tmp5 select * from tmp4; +alter table tmp5 add column (b int); + +set global read_only=0; + +insert into tmp4 values (3),(4); +insert into tmp5 values (10,3),(11,4); +select * from tmp4; +select * from tmp5; +update tmp4 set a=10 where a=2; +delete from tmp4 where a=1; +create table t2 select * from tmp4; +alter table tmp5 add column (c int); +insert into tmp5 values (20,5,1),(21,5,2); +select * from tmp5; +drop table tmp4,tmp5; + +--echo # Check what is logged. Only the last create select should be row-logged +source include/show_binlog_events.inc; + +--echo # Clean up +drop user test@localhost; +drop table t1,t2; diff --git a/mysql-test/suite/binlog/t/read_only.test b/mysql-test/suite/binlog/t/read_only.test new file mode 100644 index 00000000000..14a4650b36f --- /dev/null +++ b/mysql-test/suite/binlog/t/read_only.test @@ -0,0 +1,2 @@ +--source include/have_binlog_format_mixed_or_row.inc +--source read_only.inc diff --git a/mysql-test/suite/binlog/t/read_only_statement.test b/mysql-test/suite/binlog/t/read_only_statement.test new file mode 100644 index 00000000000..a976854fbb2 --- /dev/null +++ b/mysql-test/suite/binlog/t/read_only_statement.test @@ -0,0 +1,2 @@ +--source include/have_binlog_format_statement.inc +--source read_only.inc diff --git a/sql/log.cc b/sql/log.cc index 63c781b3be7..fe8ec38bacd 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -5909,7 +5909,6 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, DBUG_ASSERT(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()); DBUG_PRINT("enter", ("event: %p", event)); - int error= 0; binlog_cache_mngr *const cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); @@ -5947,7 +5946,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, thd->binlog_set_pending_rows_event(event, is_transactional); - DBUG_RETURN(error); + DBUG_RETURN(0); } diff --git a/sql/sp.cc b/sql/sp.cc index 78efd6de95b..5661c6910cb 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1466,7 +1466,7 @@ log: /* Such a statement can always go directly to binlog, no trans cache */ if (thd->binlog_query(THD::STMT_QUERY_TYPE, log_query.ptr(), log_query.length(), - FALSE, FALSE, FALSE, 0)) + FALSE, FALSE, FALSE, 0) > 0) { my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), "binary log", -1); goto done; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ad35f872a46..c92dc3f9f71 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3354,7 +3354,7 @@ bool change_password(THD *thd, LEX_USER *user) DBUG_ASSERT(query_length); thd->clear_error(); result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length, - FALSE, FALSE, FALSE, 0); + FALSE, FALSE, FALSE, 0) > 0; } end: close_mysql_tables(thd); @@ -3516,7 +3516,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, DBUG_ASSERT(query_length); thd->clear_error(); result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length, - FALSE, FALSE, FALSE, 0); + FALSE, FALSE, FALSE, 0) > 0; } end: close_mysql_tables(thd); diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 1c1ab82e570..297733a00a7 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1314,7 +1314,7 @@ bool Sql_cmd_analyze_table::execute(THD *thd) "analyze", lock_type, 1, 0, 0, 0, &handler::ha_analyze, 0); /* ! we write after unlocking the table */ - if (!res && !m_lex->no_write_to_binlog) + if (!res && !m_lex->no_write_to_binlog && !opt_readonly) { /* Presumably, ANALYZE and binlog writing doesn't require synchronization @@ -1372,7 +1372,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd) "optimize", TL_WRITE, 1, 0, 0, 0, &handler::ha_optimize, 0); /* ! we write after unlocking the table */ - if (!res && !m_lex->no_write_to_binlog) + if (!res && !m_lex->no_write_to_binlog && !opt_readonly) { /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization @@ -1406,7 +1406,7 @@ bool Sql_cmd_repair_table::execute(THD *thd) &handler::ha_repair, &view_repair); /* ! we write after unlocking the table */ - if (!res && !m_lex->no_write_to_binlog) + if (!res && !m_lex->no_write_to_binlog && !opt_readonly) { /* Presumably, REPAIR and binlog writing doesn't require synchronization diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 3d42d6bedb0..0fc74eff19f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -6026,7 +6026,16 @@ int THD::decide_logging_format(TABLE_LIST *tables) if (table->placeholder()) continue; - handler::Table_flags const flags= table->table->file->ha_table_flags(); + handler::Table_flags flags= table->table->file->ha_table_flags(); + if (!table->table->s->table_creation_was_logged) + { + /* + This is a temporary table which was not logged in the binary log. + Disable statement logging to enforce row level logging. + */ + DBUG_ASSERT(table->table->s->tmp_table); + flags&= ~HA_BINLOG_STMT_CAPABLE; + } DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx", table->table_name.str, flags)); @@ -6248,9 +6257,16 @@ int THD::decide_logging_format(TABLE_LIST *tables) { /* 5. Error: Cannot modify table that uses a storage engine - limited to row-logging when binlog_format = STATEMENT + limited to row-logging when binlog_format = STATEMENT, except + if all tables that are updated are temporary tables */ - if (IF_WSREP((!WSREP(this) || wsrep_exec_mode == LOCAL_STATE),1)) + if (!lex->stmt_writes_to_non_temp_table()) + { + /* As all updated tables are temporary, nothing will be logged */ + set_current_stmt_binlog_format_row(); + } + else if (IF_WSREP((!WSREP(this) || + wsrep_exec_mode == LOCAL_STATE),1)) { my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), ""); } @@ -7177,11 +7193,12 @@ void THD::issue_unsafe_warnings() @see decide_logging_format + @retval < 0 No logging of query (ok) @retval 0 Success - - @retval nonzero If there is a failure when writing the query (e.g., - write failure), then the error code is returned. + @retval > 0 If there is a failure when writing the query (e.g., + write failure), then the error code is returned. */ + int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, ulong query_len, bool is_trans, bool direct, bool suppress_use, int errcode) @@ -7207,7 +7224,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, The current statement is to be ignored, and not written to the binlog. Do not call issue_unsafe_warnings(). */ - DBUG_RETURN(0); + DBUG_RETURN(-1); } /* @@ -7223,7 +7240,10 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, { int error; if (unlikely(error= binlog_flush_pending_rows_event(TRUE, is_trans))) + { + DBUG_ASSERT(error > 0); DBUG_RETURN(error); + } } /* @@ -7266,7 +7286,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, ("is_current_stmt_binlog_format_row: %d", is_current_stmt_binlog_format_row())); if (is_current_stmt_binlog_format_row()) - DBUG_RETURN(0); + DBUG_RETURN(-1); /* Fall through */ /* @@ -7307,7 +7327,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, } binlog_table_maps= 0; - DBUG_RETURN(error); + DBUG_RETURN(error >= 0 ? error : 1); } case THD::QUERY_TYPE_COUNT: diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index bec90dcf4e1..e3d17174b8b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -851,7 +851,7 @@ cleanup: transactional_table, FALSE, FALSE, errcode); - if (log_result) + if (log_result > 0) { error=1; } @@ -1522,7 +1522,7 @@ bool multi_delete::send_eof() if (unlikely(thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_tables, FALSE, FALSE, - errcode)) && + errcode) > 0) && !normal_tables) { local_error=1; // Log write failed: roll back the SQL statement diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 59cc88f9db3..d928dfbc3ae 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1186,13 +1186,13 @@ values_loop_end: else if (thd->binlog_query(THD::ROW_QUERY_TYPE, log_query.c_ptr(), log_query.length(), transactional_table, FALSE, FALSE, - errcode)) + errcode) > 0) error= 1; } else if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_table, FALSE, FALSE, - errcode)) + errcode) > 0) error= 1; } } @@ -3931,6 +3931,7 @@ bool select_insert::prepare_eof() int error; bool const trans_table= table->file->has_transactions(); bool changed; + bool binary_logged= 0; killed_state killed_status= thd->killed; DBUG_ENTER("select_insert::prepare_eof"); @@ -3978,18 +3979,22 @@ bool select_insert::prepare_eof() (likely(!error) || thd->transaction.stmt.modified_non_trans_table)) { int errcode= 0; + int res; if (likely(!error)) thd->clear_error(); else errcode= query_error_code(thd, killed_status == NOT_KILLED); - if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query(), thd->query_length(), - trans_table, FALSE, FALSE, errcode)) + res= thd->binlog_query(THD::ROW_QUERY_TYPE, + thd->query(), thd->query_length(), + trans_table, FALSE, FALSE, errcode); + if (res > 0) { table->file->ha_release_auto_increment(); DBUG_RETURN(true); } + binary_logged= res == 0 || !table->s->tmp_table; } + table->s->table_creation_was_logged|= binary_logged; table->file->ha_release_auto_increment(); if (unlikely(error)) @@ -4040,8 +4045,9 @@ bool select_insert::send_eof() DBUG_RETURN(res); } -void select_insert::abort_result_set() { - +void select_insert::abort_result_set() +{ + bool binary_logged= 0; DBUG_ENTER("select_insert::abort_result_set"); /* If the creation of the table failed (due to a syntax error, for @@ -4093,16 +4099,20 @@ void select_insert::abort_result_set() { if(WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) { int errcode= query_error_code(thd, thd->killed == NOT_KILLED); + int res; /* error of writing binary log is ignored */ - (void) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), - thd->query_length(), - transactional_table, FALSE, FALSE, errcode); + res= thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), + thd->query_length(), + transactional_table, FALSE, FALSE, errcode); + binary_logged= res == 0 || !table->s->tmp_table; } if (changed) query_cache_invalidate3(thd, table, 1); } DBUG_ASSERT(transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table); + + table->s->table_creation_was_logged|= binary_logged; table->file->ha_release_auto_increment(); } @@ -4173,6 +4183,7 @@ TABLE *select_create::create_table_from_items(THD *thd, /* Add selected items to field list */ List_iterator_fast it(*items); Item *item; + bool save_table_creation_was_logged; DBUG_ENTER("select_create::create_table_from_items"); tmp_table.s= &share; @@ -4326,6 +4337,14 @@ TABLE *select_create::create_table_from_items(THD *thd, table->reginfo.lock_type=TL_WRITE; hooks->prelock(&table, 1); // Call prelock hooks + + /* + Ensure that decide_logging_format(), called by mysql_lock_tables(), works + with temporary tables that will be logged later if needed. + */ + save_table_creation_was_logged= table->s->table_creation_was_logged; + table->s->table_creation_was_logged= 1; + /* mysql_lock_tables() below should never fail with request to reopen table since it won't wait for the table lock (we have exclusive metadata lock on @@ -4349,6 +4368,7 @@ TABLE *select_create::create_table_from_items(THD *thd, DBUG_RETURN(0); /* purecov: end */ } + table->s->table_creation_was_logged= save_table_creation_was_logged; DBUG_RETURN(table); } @@ -4554,7 +4574,7 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) /* is_trans */ TRUE, /* direct */ FALSE, /* suppress_use */ FALSE, - errcode); + errcode) > 0; } ha_fake_trx_id(thd); @@ -4667,8 +4687,6 @@ bool select_create::send_eof() } #endif /* WITH_WSREP */ } - else if (!thd->is_current_stmt_binlog_format_row()) - table->s->table_creation_was_logged= 1; /* exit_done must only be set after last potential call to @@ -4754,7 +4772,8 @@ void select_create::abort_result_set() if (table) { bool tmp_table= table->s->tmp_table; - + bool table_creation_was_logged= (!tmp_table || + table->s->table_creation_was_logged); if (tmp_table) { DBUG_ASSERT(saved_tmp_table_share); @@ -4783,7 +4802,9 @@ void select_create::abort_result_set() /* Remove logging of drop, create + insert rows */ binlog_reset_cache(thd); /* Original table was deleted. We have to log it */ - log_drop_table(thd, &create_table->db, &create_table->table_name, tmp_table); + if (table_creation_was_logged) + log_drop_table(thd, &create_table->db, &create_table->table_name, + tmp_table); } } DBUG_VOID_RETURN; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 8b6b2ca9df0..03e73e23d3d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2018,6 +2018,14 @@ public: ((1U << STMT_READS_TEMP_TRANS_TABLE) | (1U << STMT_WRITES_TEMP_TRANS_TABLE))) != 0); } + inline bool stmt_writes_to_non_temp_table() + { + DBUG_ENTER("THD::stmt_writes_to_non_temp_table"); + + DBUG_RETURN((stmt_accessed_table_flag & + ((1U << STMT_WRITES_TRANS_TABLE) | + (1U << STMT_WRITES_NON_TRANS_TABLE)))); + } /** Checks if a temporary non-transactional table is about to be accessed diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c2c26222a82..ebf268fe8c8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1993,7 +1993,7 @@ int write_bin_log(THD *thd, bool clear_error, errcode= query_error_code(thd, TRUE); error= thd->binlog_query(THD::STMT_QUERY_TYPE, query, query_length, is_trans, FALSE, FALSE, - errcode); + errcode) > 0; thd_proc_info(thd, 0); } return error; @@ -2616,12 +2616,12 @@ err: #ifdef WITH_WSREP thd->wsrep_skip_wsrep_GTID = true; #endif /* WITH_WSREP */ - error |= thd->binlog_query(THD::STMT_QUERY_TYPE, - built_non_trans_tmp_query.ptr(), - built_non_trans_tmp_query.length(), - FALSE, FALSE, - is_drop_tmp_if_exists_added, - 0); + error |= (thd->binlog_query(THD::STMT_QUERY_TYPE, + built_non_trans_tmp_query.ptr(), + built_non_trans_tmp_query.length(), + FALSE, FALSE, + is_drop_tmp_if_exists_added, + 0) > 0); } if (trans_tmp_table_deleted) { @@ -2631,12 +2631,12 @@ err: #ifdef WITH_WSREP thd->wsrep_skip_wsrep_GTID = true; #endif /* WITH_WSREP */ - error |= thd->binlog_query(THD::STMT_QUERY_TYPE, - built_trans_tmp_query.ptr(), - built_trans_tmp_query.length(), - TRUE, FALSE, - is_drop_tmp_if_exists_added, - 0); + error |= (thd->binlog_query(THD::STMT_QUERY_TYPE, + built_trans_tmp_query.ptr(), + built_trans_tmp_query.length(), + TRUE, FALSE, + is_drop_tmp_if_exists_added, + 0) > 0); } if (non_tmp_table_deleted) { @@ -2648,11 +2648,11 @@ err: #ifdef WITH_WSREP thd->wsrep_skip_wsrep_GTID = false; #endif /* WITH_WSREP */ - error |= thd->binlog_query(THD::STMT_QUERY_TYPE, - built_query.ptr(), - built_query.length(), - TRUE, FALSE, FALSE, - error_code); + error |= (thd->binlog_query(THD::STMT_QUERY_TYPE, + built_query.ptr(), + built_query.length(), + TRUE, FALSE, FALSE, + error_code) > 0); } } } @@ -2738,7 +2738,7 @@ bool log_drop_table(THD *thd, const LEX_CSTRING *db_name, "failed CREATE OR REPLACE */")); error= thd->binlog_query(THD::STMT_QUERY_TYPE, query.ptr(), query.length(), - FALSE, FALSE, temporary_table, 0); + FALSE, FALSE, temporary_table, 0) > 0; DBUG_RETURN(error); } @@ -5215,9 +5215,13 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, } err: - /* In RBR we don't need to log CREATE TEMPORARY TABLE */ - if (!result && thd->is_current_stmt_binlog_format_row() && create_info->tmp_table()) + /* In RBR or readonly server we don't need to log CREATE TEMPORARY TABLE */ + if (!result && create_info->tmp_table() && + (thd->is_current_stmt_binlog_format_row() || opt_readonly)) + { + /* Note that table->s->table_creation_was_logged is not set! */ DBUG_RETURN(result); + } if (create_info->tmp_table()) thd->transaction.stmt.mark_created_temp_table(); @@ -5234,11 +5238,13 @@ err: */ thd->locked_tables_list.unlock_locked_table(thd, mdl_ticket); } - else if (likely(!result) && create_info->tmp_table() && create_info->table) + else if (likely(!result) && create_info->table) { /* - Remember that tmp table creation was logged so that we know if + Remember that table creation was logged so that we know if we should log a delete of it. + If create_info->table was not set, it's a normal table and + table_creation_was_logged will be set when the share is created. */ create_info->table->s->table_creation_was_logged= 1; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 18ab69d3557..32adc4420b3 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1156,7 +1156,7 @@ update_end: if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), - transactional_table, FALSE, FALSE, errcode)) + transactional_table, FALSE, FALSE, errcode) > 0) { error=1; // Rollback update } @@ -2885,7 +2885,7 @@ bool multi_update::send_eof() if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_tables, FALSE, - FALSE, errcode)) + FALSE, errcode) > 0) local_error= 1; // Rollback update thd->set_current_stmt_binlog_format(save_binlog_format); } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 98c1e816f31..1ab72fad17b 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -698,7 +698,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, thd->reset_unsafe_warnings(); if (thd->binlog_query(THD::STMT_QUERY_TYPE, buff.ptr(), buff.length(), FALSE, FALSE, FALSE, - errcode)) + errcode) > 0) res= TRUE; } diff --git a/sql/table.cc b/sql/table.cc index 34523767eb4..0e713f60d21 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -675,7 +675,11 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags) frmlen= read_length + sizeof(head); share->init_from_binary_frm_image(thd, false, buf, frmlen); - error_given= true; // init_from_binary_frm_image has already called my_error() + /* + Don't give any additional errors. If there would be a problem, + init_from_binary_frm_image would call my_error() itself. + */ + error_given= true; my_free(buf); goto err_not_open; @@ -684,6 +688,9 @@ err: mysql_file_close(file, MYF(MY_WME)); err_not_open: + /* Mark that table was created earlier and thus should have been logged */ + share->table_creation_was_logged= 1; + if (unlikely(share->error && !error_given)) { share->open_errno= my_errno; @@ -2838,6 +2845,8 @@ ret: sql_copy); DBUG_RETURN(HA_ERR_GENERIC); } + /* Treat the table as normal table from binary logging point of view */ + table_creation_was_logged= 1; DBUG_RETURN(0); } diff --git a/sql/table.h b/sql/table.h index 0a0f0aab77f..64a49fb2596 100644 --- a/sql/table.h +++ b/sql/table.h @@ -732,16 +732,20 @@ struct TABLE_SHARE bool null_field_first; bool system; /* Set if system table (one record) */ bool not_usable_by_query_cache; + /* + This is used by log tables, for tables that have their own internal + binary logging or for tables that doesn't support statement or row logging + */ bool no_replicate; bool crashed; bool is_view; bool can_cmp_whole_record; + /* This is set for temporary tables where CREATE was binary logged */ bool table_creation_was_logged; bool non_determinstic_insert; bool vcols_need_refixing; bool has_update_default_function; bool can_do_row_logging; /* 1 if table supports RBR */ - ulong table_map_id; /* for row-based replication */ /* From 67687d06bf70bb832495ba4785f00e31afb0c647 Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 14 Oct 2019 18:22:27 +0300 Subject: [PATCH 26/68] Simplify TABLE::decide_logging_format() - Use local variables table and share to simplify code - Use sql_command_flags to detect what kind of command was used - Added CF_DELETES_DATA to simplify detecton of delete commands - Removed duplicate error in create_table_from_items(). --- sql/sql_class.cc | 68 ++++++++++++++++++++++++----------------------- sql/sql_class.h | 5 ++++ sql/sql_insert.cc | 5 +++- sql/sql_parse.cc | 5 ++-- 4 files changed, 47 insertions(+), 36 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0fc74eff19f..f79d8828fcd 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -49,7 +49,7 @@ #include #include #include -#ifdef __WIN__ +#ifdef __WIN__0 #include #endif #include @@ -6021,26 +6021,31 @@ int THD::decide_logging_format(TABLE_LIST *tables) Get the capabilities vector for all involved storage engines and mask out the flags for the binary log. */ - for (TABLE_LIST *table= tables; table; table= table->next_global) + for (TABLE_LIST *tbl= tables; tbl; tbl= tbl->next_global) { - if (table->placeholder()) + TABLE *table; + TABLE_SHARE *share; + handler::Table_flags flags; + if (tbl->placeholder()) continue; - handler::Table_flags flags= table->table->file->ha_table_flags(); - if (!table->table->s->table_creation_was_logged) + table= tbl->table; + share= table->s; + flags= table->file->ha_table_flags(); + if (!share->table_creation_was_logged) { /* This is a temporary table which was not logged in the binary log. Disable statement logging to enforce row level logging. */ - DBUG_ASSERT(table->table->s->tmp_table); + DBUG_ASSERT(share->tmp_table); flags&= ~HA_BINLOG_STMT_CAPABLE; } DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx", - table->table_name.str, flags)); + tbl->table_name.str, flags)); - if (table->table->s->no_replicate) + if (share->no_replicate) { /* The statement uses a table that is not replicated. @@ -6058,44 +6063,44 @@ int THD::decide_logging_format(TABLE_LIST *tables) */ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE); - if (table->lock_type >= TL_WRITE_ALLOW_WRITE) + if (tbl->lock_type >= TL_WRITE_ALLOW_WRITE) { non_replicated_tables_count++; continue; } } - if (table == lex->first_not_own_table()) + if (tbl == lex->first_not_own_table()) found_first_not_own_table= true; replicated_tables_count++; - if (table->prelocking_placeholder != TABLE_LIST::PRELOCK_FK) + if (tbl->prelocking_placeholder != TABLE_LIST::PRELOCK_FK) { - if (table->lock_type <= TL_READ_NO_INSERT) + if (tbl->lock_type <= TL_READ_NO_INSERT) has_read_tables= true; - else if (table->table->found_next_number_field && - (table->lock_type >= TL_WRITE_ALLOW_WRITE)) + else if (table->found_next_number_field && + (tbl->lock_type >= TL_WRITE_ALLOW_WRITE)) { has_auto_increment_write_tables= true; has_auto_increment_write_tables_not_first= found_first_not_own_table; - if (table->table->s->next_number_keypart != 0) + if (share->next_number_keypart != 0) has_write_table_auto_increment_not_first_in_pk= true; } } - if (table->lock_type >= TL_WRITE_ALLOW_WRITE) + if (tbl->lock_type >= TL_WRITE_ALLOW_WRITE) { bool trans; if (prev_write_table && prev_write_table->file->ht != - table->table->file->ht) + table->file->ht) multi_write_engine= TRUE; - if (table->table->s->non_determinstic_insert && + if (share->non_determinstic_insert && !(sql_command_flags[lex->sql_command] & CF_SCHEMA_CHANGE)) has_write_tables_with_unsafe_statements= true; - trans= table->table->file->has_transactions(); + trans= table->file->has_transactions(); - if (table->table->s->tmp_table) + if (share->tmp_table) lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TEMP_TRANS_TABLE : LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE); else @@ -6106,17 +6111,16 @@ int THD::decide_logging_format(TABLE_LIST *tables) flags_write_some_set |= flags; is_write= TRUE; - prev_write_table= table->table; + prev_write_table= table; } flags_access_some_set |= flags; - if (lex->sql_command != SQLCOM_CREATE_TABLE || - (lex->sql_command == SQLCOM_CREATE_TABLE && lex->tmp_table())) + if (lex->sql_command != SQLCOM_CREATE_TABLE || lex->tmp_table()) { - my_bool trans= table->table->file->has_transactions(); + my_bool trans= table->file->has_transactions(); - if (table->table->s->tmp_table) + if (share->tmp_table) lex->set_stmt_accessed_table(trans ? LEX::STMT_READS_TEMP_TRANS_TABLE : LEX::STMT_READS_TEMP_NON_TRANS_TABLE); else @@ -6125,10 +6129,10 @@ int THD::decide_logging_format(TABLE_LIST *tables) } if (prev_access_table && prev_access_table->file->ht != - table->table->file->ht) + table->file->ht) multi_access_engine= TRUE; - prev_access_table= table->table; + prev_access_table= table; } if (wsrep_binlog_format() != BINLOG_FORMAT_ROW) @@ -6335,10 +6339,8 @@ int THD::decide_logging_format(TABLE_LIST *tables) "ROW" : "STATEMENT")); if (variables.binlog_format == BINLOG_FORMAT_ROW && - (lex->sql_command == SQLCOM_UPDATE || - lex->sql_command == SQLCOM_UPDATE_MULTI || - lex->sql_command == SQLCOM_DELETE || - lex->sql_command == SQLCOM_DELETE_MULTI)) + (sql_command_flags[lex->sql_command] & + (CF_UPDATES_DATA | CF_DELETES_DATA))) { String table_names; /* @@ -6358,8 +6360,8 @@ int THD::decide_logging_format(TABLE_LIST *tables) } if (!table_names.is_empty()) { - bool is_update= (lex->sql_command == SQLCOM_UPDATE || - lex->sql_command == SQLCOM_UPDATE_MULTI); + bool is_update= MY_TEST(sql_command_flags[lex->sql_command] & + CF_UPDATES_DATA); /* Replace the last ',' with '.' for table_names */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 7e7ed42f1aa..43c902e84ef 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6336,6 +6336,11 @@ public: /* Bits in server_command_flags */ +/** + Statement that deletes existing rows (DELETE, DELETE_MULTI) +*/ +#define CF_DELETES_DATA (1U << 24) + /** Skip the increase of the global query id counter. Commonly set for commands that are stateless (won't cause any change on the server diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index d928dfbc3ae..334b6b2d667 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -4357,8 +4357,11 @@ TABLE *select_create::create_table_from_items(THD *thd, /* This can happen in innodb when you get a deadlock when using same table in insert and select or when you run out of memory. + It can also happen if there was a conflict in + THD::decide_logging_format() */ - my_error(ER_CANT_LOCK, MYF(0), my_errno); + if (!thd->is_error()) + my_error(ER_CANT_LOCK, MYF(0), my_errno); if (*lock) { mysql_unlock_tables(thd, *lock); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 81eba0da8cb..00573c56577 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -605,11 +605,12 @@ void init_update_queries(void) CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED | - CF_SP_BULK_SAFE; + CF_SP_BULK_SAFE | CF_DELETES_DATA; sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | - CF_CAN_BE_EXPLAINED; + CF_CAN_BE_EXPLAINED | + CF_DELETES_DATA; sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE | From 7def2877e3d7bd5335a0a53c20c01948407ab775 Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 20 Oct 2019 11:52:20 +0300 Subject: [PATCH 27/68] Write error message if aria_log.??????? files are missing This can happen if one uses a backup where not all aria_log.* files are copied or if the last one is too short. In this case the data files will contain data that is not in the logs and recovery will fail. Other things: - Fixed tprint() to not print extra new line to debug trace --- storage/maria/ma_blockrec.c | 6 ++++-- storage/maria/ma_key_recover.c | 5 +++-- storage/maria/ma_loghandler.c | 31 +++++++++++++++++++++++++++++++ storage/maria/ma_loghandler.h | 2 ++ storage/maria/ma_recovery.c | 4 ++-- storage/maria/ma_recovery.h | 2 ++ storage/maria/ma_recovery_util.c | 11 +++++++---- storage/maria/maria_def.h | 1 + 8 files changed, 52 insertions(+), 10 deletions(-) diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 1cf154d440e..2fe2f13f17c 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -6394,6 +6394,7 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn, } else if (lsn_korr(buff) >= lsn) /* Test if already applied */ { + check_skipped_lsn(info, lsn_korr(buff), 1, page); /* Fix bitmap, just in case */ empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET); if (!enough_free_entries_on_page(share, buff)) @@ -6561,6 +6562,7 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn, Note that in case the page is not anymore a head or tail page a future redo will fix the bitmap. */ + check_skipped_lsn(info, lsn_korr(buff), 1, page); if ((uint) (buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == page_type) { empty_space= uint2korr(buff+EMPTY_SPACE_OFFSET); @@ -6731,6 +6733,7 @@ uint _ma_apply_redo_free_head_or_tail(MARIA_HA *info, LSN lsn, if (lsn_korr(buff) >= lsn) { /* Already applied */ + check_skipped_lsn(info, lsn_korr(buff), 1, page); pagecache_unlock_by_link(share->pagecache, page_link.link, PAGECACHE_LOCK_WRITE_UNLOCK, PAGECACHE_UNPIN, LSN_IMPOSSIBLE, @@ -6908,8 +6911,7 @@ uint _ma_apply_redo_insert_row_blobs(MARIA_HA *info, if (lsn_korr(buff) >= lsn) { /* Already applied */ - DBUG_PRINT("info", ("already applied %llu >= %llu", - lsn_korr(buff), lsn)); + check_skipped_lsn(info, lsn_korr(buff), 1, page); pagecache_unlock_by_link(share->pagecache, page_link.link, PAGECACHE_LOCK_WRITE_UNLOCK, PAGECACHE_UNPIN, LSN_IMPOSSIBLE, diff --git a/storage/maria/ma_key_recover.c b/storage/maria/ma_key_recover.c index ee2734548f4..afa69fce444 100644 --- a/storage/maria/ma_key_recover.c +++ b/storage/maria/ma_key_recover.c @@ -777,7 +777,7 @@ uint _ma_apply_redo_index_new_page(MARIA_HA *info, LSN lsn, else if (lsn_korr(buff) >= lsn) { /* Already applied */ - DBUG_PRINT("info", ("Page is up to date, skipping redo")); + check_skipped_lsn(info, lsn_korr(buff), 0, root_page); result= 0; goto err; } @@ -865,6 +865,7 @@ uint _ma_apply_redo_index_free_page(MARIA_HA *info, if (lsn_korr(buff) >= lsn) { /* Already applied */ + check_skipped_lsn(info, lsn_korr(buff), 0, page); result= 0; goto err; } @@ -966,7 +967,7 @@ uint _ma_apply_redo_index(MARIA_HA *info, if (lsn_korr(buff) >= lsn) { /* Already applied */ - DBUG_PRINT("info", ("Page is up to date, skipping redo")); + check_skipped_lsn(info, lsn_korr(buff), 0, page_pos); result= 0; goto err; } diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c index 01395068762..9443e7bc506 100644 --- a/storage/maria/ma_loghandler.c +++ b/storage/maria/ma_loghandler.c @@ -19,6 +19,9 @@ #include "ma_key_recover.h" /* For some in-write hooks */ #include "ma_checkpoint.h" #include "ma_servicethread.h" +#include "ma_recovery.h" +#include "ma_loghandler_lsn.h" +#include "ma_recovery_util.h" /* On Windows, neither my_open() nor mysql_file_sync() work for directories. @@ -7903,6 +7906,34 @@ static my_bool translog_sync_files(uint32 min, uint32 max, } +/** + check_skipped_lsn + + Check if lsn skipped in redo is ok +*/ + +void check_skipped_lsn(MARIA_HA *info, LSN lsn, my_bool index_file, + pgcache_page_no_t page) +{ + if (lsn <= log_descriptor.horizon) + { + DBUG_PRINT("info", ("Page is up to date, skipping redo")); + } + else + { + /* Give error, but don't flood the log */ + if (skipped_lsn_err_count++ < 10 && ! info->s->redo_error_given++) + { + eprint(tracef, "Table %s has wrong LSN: " LSN_FMT " on page: %llu", + (index_file ? info->s->data_file_name.str : + info->s->index_file_name.str), + LSN_IN_PARTS(lsn), (ulonglong) page); + recovery_found_crashed_tables++; + } + } +} + + /* @brief Flushes buffers with LSNs in them less or equal address diff --git a/storage/maria/ma_loghandler.h b/storage/maria/ma_loghandler.h index ef0f46c9465..b236fdc7ebe 100644 --- a/storage/maria/ma_loghandler.h +++ b/storage/maria/ma_loghandler.h @@ -384,6 +384,8 @@ int translog_soft_sync_start(void); void translog_soft_sync_end(void); void translog_sync(); void translog_set_group_commit_interval(uint32 interval); +extern void check_skipped_lsn(MARIA_HA *info, LSN lsn, my_bool index_file, + pgcache_page_no_t page); /* all the rest added because of recovery; should we make diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index a293b6a786b..f14bab970a9 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -57,8 +57,7 @@ static my_bool trns_created; static ulong skipped_undo_phase; static ulonglong now; /**< for tracking execution time of phases */ static void (*save_error_handler_hook)(uint, const char *,myf); -static uint recovery_warnings; /**< count of warnings */ -static uint recovery_found_crashed_tables; +static ulong recovery_warnings; /**< count of warnings */ HASH tables_to_redo; /* For maria_read_log */ ulong maria_recovery_force_crash_counter; TrID max_long_trid= 0; /**< max long trid seen by REDO phase */ @@ -291,6 +290,7 @@ int maria_apply_log(LSN from_lsn, LSN end_lsn, DBUG_ASSERT(apply == MARIA_LOG_APPLY || !should_run_undo_phase); DBUG_ASSERT(!maria_multi_threaded); recovery_warnings= recovery_found_crashed_tables= 0; + skipped_lsn_err_count= 0; maria_recovery_changed_data= 0; /* checkpoints can happen only if TRNs have been built */ DBUG_ASSERT(should_run_undo_phase || !take_checkpoints); diff --git a/storage/maria/ma_recovery.h b/storage/maria/ma_recovery.h index 8084ce03f3b..0a75479365f 100644 --- a/storage/maria/ma_recovery.h +++ b/storage/maria/ma_recovery.h @@ -33,4 +33,6 @@ int maria_apply_log(LSN lsn, LSN lsn_end, enum maria_apply_log_way apply, /* Table of tables to recover */ extern HASH tables_to_redo; extern ulong maria_recovery_force_crash_counter; +extern ulong recovery_found_crashed_tables; +extern uint skipped_lsn_err_count; C_MODE_END diff --git a/storage/maria/ma_recovery_util.c b/storage/maria/ma_recovery_util.c index 3b617f625f0..fe43d812600 100644 --- a/storage/maria/ma_recovery_util.c +++ b/storage/maria/ma_recovery_util.c @@ -51,6 +51,8 @@ LSN checkpoint_start= LSN_IMPOSSIBLE; my_bool procent_printed; FILE *tracef; /**< trace file for debugging */ +ulong recovery_found_crashed_tables; +uint skipped_lsn_err_count; /** @brief Prints to a trace file if it is not NULL */ void tprint(FILE *trace_file __attribute__ ((unused)), @@ -59,11 +61,12 @@ void tprint(FILE *trace_file __attribute__ ((unused)), va_list args; #ifndef DBUG_OFF { - char buff[1024], *end; + char buff[1024]; + size_t length; va_start(args, format); - vsnprintf(buff, sizeof(buff)-1, format, args); - if (*(end= strend(buff)) == '\n') - *end= 0; /* Don't print end \n */ + length= my_vsnprintf(buff, sizeof(buff)-1, format, args); + if (length && buff[length-1] == '\n') + buff[length-1]= 0; /* Don't print end \n */ DBUG_PRINT("info", ("%s", buff)); va_end(args); } diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index c6c5d008e38..919dc831c75 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -500,6 +500,7 @@ typedef struct st_maria_share my_bool have_versioning; my_bool key_del_used; /* != 0 if key_del is locked */ my_bool deleting; /* we are going to delete this table */ + my_bool redo_error_given; /* Used during recovery */ THR_LOCK lock; void (*lock_restore_status)(void *); /** From 06d2e1d828140d887adb68b05c85d5107baf816c Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Mon, 21 Oct 2019 17:17:09 +0300 Subject: [PATCH 28/68] read-only slave using statement replication should replicate tmp tables Relates to MDEV-17863 DROP TEMPORARY TABLE creates a transaction in binary log on read only server Other things: - Fixed that insert into normal_table select from tmp_table is replicated as row events if tmp_table doesn't exists on slave. --- mysql-test/suite/binlog/r/read_only.result | 21 +++++++- .../suite/binlog/r/read_only_statement.result | 21 +++++++- mysql-test/suite/binlog/t/read_only.inc | 7 ++- mysql-test/suite/rpl/r/rpl_read_only2.result | 53 +++++++++++++++++++ mysql-test/suite/rpl/t/rpl_read_only2.test | 30 +++++++++++ sql/sql_admin.cc | 6 +-- sql/sql_class.cc | 2 + sql/sql_table.cc | 2 +- 8 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_read_only2.result create mode 100644 mysql-test/suite/rpl/t/rpl_read_only2.test diff --git a/mysql-test/suite/binlog/r/read_only.result b/mysql-test/suite/binlog/r/read_only.result index aa1893b56a3..8aaad55684b 100644 --- a/mysql-test/suite/binlog/r/read_only.result +++ b/mysql-test/suite/binlog/r/read_only.result @@ -46,6 +46,8 @@ select * from tmp2; a b 1 NULL 2 NULL +insert into t1 select a+100 from tmp2; +ERROR HY000: The MariaDB server is running with the --read-only option so it cannot execute this statement drop table tmp1,tmp2,tmp3; # Clean up test connection disconnect con1; @@ -92,8 +94,20 @@ a b c 11 4 NULL 20 5 1 21 5 2 +insert into t1 select a+200 from tmp5; +select * from t1; +a +1 +2 +201 +202 +210 +211 +220 +221 drop table tmp4,tmp5; -# Check what is logged. Only the last create select should be row-logged +# Check what is logged. Only last create select and the insert...select's should be +# row-logged include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Gtid # # BEGIN GTID #-#-# @@ -104,6 +118,11 @@ master-bin.000001 # Annotate_rows # # create table t2 select * from tmp4 master-bin.000001 # Table_map # # table_id: # (test.t2) master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Annotate_rows # # insert into t1 select a+200 from tmp5 +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT # Clean up drop user test@localhost; drop table t1,t2; diff --git a/mysql-test/suite/binlog/r/read_only_statement.result b/mysql-test/suite/binlog/r/read_only_statement.result index aa1893b56a3..8aaad55684b 100644 --- a/mysql-test/suite/binlog/r/read_only_statement.result +++ b/mysql-test/suite/binlog/r/read_only_statement.result @@ -46,6 +46,8 @@ select * from tmp2; a b 1 NULL 2 NULL +insert into t1 select a+100 from tmp2; +ERROR HY000: The MariaDB server is running with the --read-only option so it cannot execute this statement drop table tmp1,tmp2,tmp3; # Clean up test connection disconnect con1; @@ -92,8 +94,20 @@ a b c 11 4 NULL 20 5 1 21 5 2 +insert into t1 select a+200 from tmp5; +select * from t1; +a +1 +2 +201 +202 +210 +211 +220 +221 drop table tmp4,tmp5; -# Check what is logged. Only the last create select should be row-logged +# Check what is logged. Only last create select and the insert...select's should be +# row-logged include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Gtid # # BEGIN GTID #-#-# @@ -104,6 +118,11 @@ master-bin.000001 # Annotate_rows # # create table t2 select * from tmp4 master-bin.000001 # Table_map # # table_id: # (test.t2) master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Annotate_rows # # insert into t1 select a+200 from tmp5 +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT # Clean up drop user test@localhost; drop table t1,t2; diff --git a/mysql-test/suite/binlog/t/read_only.inc b/mysql-test/suite/binlog/t/read_only.inc index 75cd4a5dfb3..37f1cb3b2b8 100644 --- a/mysql-test/suite/binlog/t/read_only.inc +++ b/mysql-test/suite/binlog/t/read_only.inc @@ -34,6 +34,8 @@ create temporary table tmp3 like t1; create or replace temporary table tmp3 like t1; alter table tmp2 add column (b int); select * from tmp2; +--error ER_OPTION_PREVENTS_STATEMENT +insert into t1 select a+100 from tmp2; drop table tmp1,tmp2,tmp3; --echo # Clean up test connection @@ -64,9 +66,12 @@ create table t2 select * from tmp4; alter table tmp5 add column (c int); insert into tmp5 values (20,5,1),(21,5,2); select * from tmp5; +insert into t1 select a+200 from tmp5; +select * from t1; drop table tmp4,tmp5; ---echo # Check what is logged. Only the last create select should be row-logged +--echo # Check what is logged. Only last create select and the insert...select's should be +--echo # row-logged source include/show_binlog_events.inc; --echo # Clean up diff --git a/mysql-test/suite/rpl/r/rpl_read_only2.result b/mysql-test/suite/rpl/r/rpl_read_only2.result new file mode 100644 index 00000000000..c457f49e67d --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_read_only2.result @@ -0,0 +1,53 @@ +include/master-slave.inc +[connection master] +# +# Ensure that read-only slave logs temporary table statements under statement based +# replication. This is related to MDEV-17863. +# +connection slave; +set global read_only=1; +connection master; +create table t1(a int) engine=MyISAM; +create temporary table tmp1 (a int) engine=MyISAM; +insert into t1 values(1); +insert into tmp1 values (2); +insert into t1 select * from tmp1; +insert into t1 values(3); +select * from t1; +a +1 +2 +3 +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +drop table t1; +drop temporary table tmp1; +connection slave; +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t1(a int) engine=MyISAM +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create temporary table tmp1 (a int) engine=MyISAM +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; insert into t1 values(1) +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; insert into tmp1 values (2) +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; insert into t1 select * from tmp1 +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; insert into t1 values(3) +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; analyze table t1 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # DROP TEMPORARY TABLE IF EXISTS `test`.`tmp1` /* generated by server */ +set global read_only=0; +connection master; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_read_only2.test b/mysql-test/suite/rpl/t/rpl_read_only2.test new file mode 100644 index 00000000000..da825c8fc7f --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_read_only2.test @@ -0,0 +1,30 @@ +--source include/have_binlog_format_statement.inc +--source include/master-slave.inc + +--echo # +--echo # Ensure that read-only slave logs temporary table statements under statement based +--echo # replication. This is related to MDEV-17863. +--echo # + +connection slave; +set global read_only=1; + +connection master; + +create table t1(a int) engine=MyISAM; +create temporary table tmp1 (a int) engine=MyISAM; +insert into t1 values(1); +insert into tmp1 values (2); +insert into t1 select * from tmp1; +insert into t1 values(3); +select * from t1; +analyze table t1; +drop table t1; +drop temporary table tmp1; + +sync_slave_with_master; +--source include/show_binlog_events.inc +set global read_only=0; +connection master; + +--source include/rpl_end.inc diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 297733a00a7..dde194053b9 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1314,7 +1314,7 @@ bool Sql_cmd_analyze_table::execute(THD *thd) "analyze", lock_type, 1, 0, 0, 0, &handler::ha_analyze, 0); /* ! we write after unlocking the table */ - if (!res && !m_lex->no_write_to_binlog && !opt_readonly) + if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread)) { /* Presumably, ANALYZE and binlog writing doesn't require synchronization @@ -1372,7 +1372,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd) "optimize", TL_WRITE, 1, 0, 0, 0, &handler::ha_optimize, 0); /* ! we write after unlocking the table */ - if (!res && !m_lex->no_write_to_binlog && !opt_readonly) + if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread)) { /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization @@ -1406,7 +1406,7 @@ bool Sql_cmd_repair_table::execute(THD *thd) &handler::ha_repair, &view_repair); /* ! we write after unlocking the table */ - if (!res && !m_lex->no_write_to_binlog && !opt_readonly) + if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread)) { /* Presumably, REPAIR and binlog writing doesn't require synchronization diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f79d8828fcd..9875f0cd14a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -6040,6 +6040,8 @@ int THD::decide_logging_format(TABLE_LIST *tables) */ DBUG_ASSERT(share->tmp_table); flags&= ~HA_BINLOG_STMT_CAPABLE; + /* We can only use row logging */ + set_current_stmt_binlog_format_row(); } DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx", diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ebf268fe8c8..8eb0b078bd1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5217,7 +5217,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, err: /* In RBR or readonly server we don't need to log CREATE TEMPORARY TABLE */ if (!result && create_info->tmp_table() && - (thd->is_current_stmt_binlog_format_row() || opt_readonly)) + (thd->is_current_stmt_binlog_format_row() || (opt_readonly && !thd->slave_thread))) { /* Note that table->s->table_creation_was_logged is not set! */ DBUG_RETURN(result); From 716d396bb3b4814de3c00c46f98317c45a33551e Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Mon, 21 Oct 2019 18:41:58 +0300 Subject: [PATCH 29/68] Remove \n from DBUG_PRINT statements --- sql/log.cc | 2 +- sql/rpl_rli.cc | 2 +- sql/semisync_master.cc | 2 +- sql/sql_lex.cc | 2 +- sql/sql_lex.h | 2 +- sql/sql_load.cc | 2 +- sql/sql_prepare.cc | 4 ++-- sql/wsrep_mysqld.cc | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index fe8ec38bacd..900cc1b8197 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -7690,7 +7690,7 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry) mysql_mutex_unlock(&LOCK_prepare_ordered); DEBUG_SYNC(orig_entry->thd, "commit_after_release_LOCK_prepare_ordered"); - DBUG_PRINT("info", ("Queued for group commit as %s\n", + DBUG_PRINT("info", ("Queued for group commit as %s", (orig_queue == NULL) ? "leader" : "participant")); DBUG_RETURN(orig_queue == NULL); } diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 5a99de52462..78c541d4721 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1561,7 +1561,7 @@ scan_one_gtid_slave_pos_table(THD *thd, HASH *hash, DYNAMIC_ARRAY *array, sub_id= (ulonglong)table->field[1]->val_int(); server_id= (uint32)table->field[2]->val_int(); seq_no= (ulonglong)table->field[3]->val_int(); - DBUG_PRINT("info", ("Read slave state row: %u-%u-%lu sub_id=%lu\n", + DBUG_PRINT("info", ("Read slave state row: %u-%u-%lu sub_id=%lu", (unsigned)domain_id, (unsigned)server_id, (ulong)seq_no, (ulong)sub_id)); diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc index f9fb4d9147d..b239a9776a7 100644 --- a/sql/semisync_master.cc +++ b/sql/semisync_master.cc @@ -806,7 +806,7 @@ int Repl_semi_sync_master::commit_trx(const char* trx_wait_binlog_name, if (!get_master_enabled() || !is_on()) goto l_end; - DBUG_PRINT("semisync", ("%s: wait pos (%s, %lu), repl(%d)\n", + DBUG_PRINT("semisync", ("%s: wait pos (%s, %lu), repl(%d)", "Repl_semi_sync_master::commit_trx", trx_wait_binlog_name, (ulong)trx_wait_binlog_pos, (int)is_on())); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d3c98115659..3e5411c3428 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -7314,7 +7314,7 @@ uint binlog_unsafe_map[256]; #define UNSAFE(a, b, c) \ { \ - DBUG_PRINT("unsafe_mixed_statement", ("SETTING BASE VALUES: %s, %s, %02X\n", \ + DBUG_PRINT("unsafe_mixed_statement", ("SETTING BASE VALUES: %s, %s, %02X", \ LEX::stmt_accessed_table_string(a), \ LEX::stmt_accessed_table_string(b), \ c)); \ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 03e73e23d3d..87eea6c0a8b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2077,7 +2077,7 @@ public: unsafe= (binlog_unsafe_map[stmt_accessed_table_flag] & condition); #if !defined(DBUG_OFF) - DBUG_PRINT("LEX::is_mixed_stmt_unsafe", ("RESULT %02X %02X %02X\n", condition, + DBUG_PRINT("LEX::is_mixed_stmt_unsafe", ("RESULT %02X %02X %02X", condition, binlog_unsafe_map[stmt_accessed_table_flag], (binlog_unsafe_map[stmt_accessed_table_flag] & condition))); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 1459c50ba9e..d5692196457 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -2063,7 +2063,7 @@ int READ_INFO::read_xml(THD *thd) chr= read_value(delim, &value); if (attribute.length() > 0 && value.length() > 0) { - DBUG_PRINT("read_xml", ("lev:%i att:%s val:%s\n", + DBUG_PRINT("read_xml", ("lev:%i att:%s val:%s", level + 1, attribute.c_ptr_safe(), value.c_ptr_safe())); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d734c9ab588..da6ec106208 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3274,7 +3274,7 @@ void mysql_sql_stmt_execute(THD *thd) /* Query text for binary, general or slow log, if any of them is open */ String expanded_query; DBUG_ENTER("mysql_sql_stmt_execute"); - DBUG_PRINT("info", ("EXECUTE: %.*s\n", (int) name->length, name->str)); + DBUG_PRINT("info", ("EXECUTE: %.*s", (int) name->length, name->str)); if (!(stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) { @@ -3512,7 +3512,7 @@ void mysql_sql_stmt_close(THD *thd) { Prepared_statement* stmt; LEX_CSTRING *name= &thd->lex->prepared_stmt_name; - DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", (int) name->length, + DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s", (int) name->length, name->str)); if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name))) diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 08adaac0e85..9ad7a6e3bbc 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -2091,7 +2091,7 @@ pthread_handler_t start_wsrep_THD(void *arg) need to know the start of the stack so that we could check for stack overruns. */ - DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld\n", + DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld", (long long)thd->thread_id)); /* now that we've called my_thread_init(), it is safe to call DBUG_* */ From 803d0521a29807793967671c9e568070fcb3efb2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 16 Jun 2019 01:25:03 +0200 Subject: [PATCH 30/68] compilation failure on ppc with -DCMAKE_BUILD_TYPE=Debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit if ${CRC32_LIBRARY} target has no COMPILE_FLAGS yet, GET_TARGET_PROPERTY returns COMPILE_FLAGS-NOTFOUND, which doesn't work very well when it's later fed back into COMPILE_FLAGS. GET_PROPERTY() returns an empty string in this case. Cherry-picked from 10.4 - 13e8f728ec83133b990ed21404cbac1d8a0bc74c Signed-off-by: Vicențiu Ciorbaru --- extra/crc32-vpmsum/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/crc32-vpmsum/CMakeLists.txt b/extra/crc32-vpmsum/CMakeLists.txt index 31c09a97d6a..b4adebdadf5 100644 --- a/extra/crc32-vpmsum/CMakeLists.txt +++ b/extra/crc32-vpmsum/CMakeLists.txt @@ -2,7 +2,7 @@ ADD_CONVENIENCE_LIBRARY(${CRC32_LIBRARY} $ $ Date: Thu, 24 Oct 2019 21:20:53 +0300 Subject: [PATCH 31/68] Clean up innodb.innodb_stats_persistent The test was marked big for no apparent reason. Usw wait_all_purged.inc in the canonical way, and make use of the sequence engine. --- .../innodb/r/innodb_stats_persistent.result | 29 +++++++----------- .../innodb/t/innodb_stats_persistent.test | 30 +++++++------------ 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_stats_persistent.result b/mysql-test/suite/innodb/r/innodb_stats_persistent.result index 41893bf47c1..e8534e7e8f3 100644 --- a/mysql-test/suite/innodb/r/innodb_stats_persistent.result +++ b/mysql-test/suite/innodb/r/innodb_stats_persistent.result @@ -1,22 +1,15 @@ +SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; +SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; SET @saved_include_delete_marked = @@GLOBAL.innodb_stats_include_delete_marked; SET GLOBAL innodb_stats_include_delete_marked = ON; SET @saved_traditional = @@GLOBAL.innodb_stats_traditional; SET GLOBAL innodb_stats_traditional=false; SET @saved_modified_counter = @@GLOBAL.innodb_stats_modified_counter; SET GLOBAL innodb_stats_modified_counter=1; -CREATE TABLE t0 (id SERIAL, val INT UNSIGNED NOT NULL, KEY(val)) +CREATE TABLE t1 (id SERIAL, val INT UNSIGNED NOT NULL, KEY(val)) ENGINE=INNODB STATS_PERSISTENT=1,STATS_AUTO_RECALC=1; -CREATE TABLE t1 LIKE t0; -CREATE TABLE t2 LIKE t0; -INSERT INTO t0 (val) VALUES (4); -INSERT INTO t0 (val) SELECT 4 FROM t0; -INSERT INTO t0 (val) SELECT 4 FROM t0; -INSERT INTO t0 (val) SELECT 4 FROM t0; -INSERT INTO t0 (val) SELECT 4 FROM t0; -INSERT INTO t1 SELECT * FROM t0; -SELECT COUNT(*) FROM t1; -COUNT(*) -16 +CREATE TABLE t2 LIKE t1; +INSERT INTO t1 (val) SELECT 4 FROM seq_1_to_16; ANALYZE TABLE t1; Table Op Msg_type Msg_text test.t1 analyze status OK @@ -48,7 +41,7 @@ COUNT(*) 0 connection default; BEGIN; -INSERT INTO t2 SELECT * FROM t0; +INSERT INTO t2 (val) SELECT 4 FROM seq_1_to_16; # The INSERT will show up before COMMIT. EXPLAIN SELECT * FROM t2 WHERE val=4; id select_type table type possible_keys key key_len ref rows Extra @@ -65,17 +58,14 @@ connection con1; EXPLAIN SELECT * FROM t2 WHERE val=4; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref val val 4 const 1 Using index -SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; -SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; InnoDB 0 transactions not purged -SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; # After COMMIT and purge, the DELETE must show up. EXPLAIN SELECT * FROM t1 WHERE val=4; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref val val 4 const 1 Using index SET GLOBAL innodb_stats_include_delete_marked = OFF; BEGIN; -INSERT INTO t1 SELECT * FROM t0; +INSERT INTO t1 (val) SELECT 4 FROM seq_1_to_16; EXPLAIN SELECT * FROM t1 WHERE val=4; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref val val 4 const 16 Using index @@ -84,7 +74,7 @@ EXPLAIN SELECT * FROM t1 WHERE val=4; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref val val 4 const 1 Using index BEGIN; -INSERT INTO t1 SELECT * FROM t0; +INSERT INTO t1 (val) SELECT 4 FROM seq_1_to_16; COMMIT; EXPLAIN SELECT * FROM t1 WHERE val=4; id select_type table type possible_keys key key_len ref rows Extra @@ -110,7 +100,8 @@ COUNT(*) 16 disconnect con1; connection default; -DROP TABLE t0,t1,t2; +DROP TABLE t1,t2; SET GLOBAL innodb_stats_include_delete_marked = @saved_include_delete_marked; SET GLOBAL innodb_stats_traditional = @saved_traditional; SET GLOBAL innodb_stats_modified_counter = @saved_modified_counter; +SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; diff --git a/mysql-test/suite/innodb/t/innodb_stats_persistent.test b/mysql-test/suite/innodb/t/innodb_stats_persistent.test index 652b201c4b4..f79ae37e8de 100644 --- a/mysql-test/suite/innodb/t/innodb_stats_persistent.test +++ b/mysql-test/suite/innodb/t/innodb_stats_persistent.test @@ -1,6 +1,8 @@ --source include/have_innodb.inc ---source include/big_test.inc +--source include/have_sequence.inc +SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; +SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; SET @saved_include_delete_marked = @@GLOBAL.innodb_stats_include_delete_marked; SET GLOBAL innodb_stats_include_delete_marked = ON; SET @saved_traditional = @@GLOBAL.innodb_stats_traditional; @@ -8,19 +10,11 @@ SET GLOBAL innodb_stats_traditional=false; SET @saved_modified_counter = @@GLOBAL.innodb_stats_modified_counter; SET GLOBAL innodb_stats_modified_counter=1; -CREATE TABLE t0 (id SERIAL, val INT UNSIGNED NOT NULL, KEY(val)) +CREATE TABLE t1 (id SERIAL, val INT UNSIGNED NOT NULL, KEY(val)) ENGINE=INNODB STATS_PERSISTENT=1,STATS_AUTO_RECALC=1; -CREATE TABLE t1 LIKE t0; -CREATE TABLE t2 LIKE t0; +CREATE TABLE t2 LIKE t1; -INSERT INTO t0 (val) VALUES (4); -INSERT INTO t0 (val) SELECT 4 FROM t0; -INSERT INTO t0 (val) SELECT 4 FROM t0; -INSERT INTO t0 (val) SELECT 4 FROM t0; -INSERT INTO t0 (val) SELECT 4 FROM t0; - -INSERT INTO t1 SELECT * FROM t0; -SELECT COUNT(*) FROM t1; +INSERT INTO t1 (val) SELECT 4 FROM seq_1_to_16; ANALYZE TABLE t1; connect(con1, localhost, root,,); @@ -46,7 +40,7 @@ SELECT COUNT(*) FROM t1; connection default; BEGIN; -INSERT INTO t2 SELECT * FROM t0; +INSERT INTO t2 (val) SELECT 4 FROM seq_1_to_16; --echo # The INSERT will show up before COMMIT. EXPLAIN SELECT * FROM t2 WHERE val=4; @@ -57,21 +51,18 @@ SELECT COUNT(*) FROM t2; connection con1; EXPLAIN SELECT * FROM t2 WHERE val=4; -SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; -SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; --source include/wait_all_purged.inc -SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; --echo # After COMMIT and purge, the DELETE must show up. EXPLAIN SELECT * FROM t1 WHERE val=4; SET GLOBAL innodb_stats_include_delete_marked = OFF; BEGIN; -INSERT INTO t1 SELECT * FROM t0; +INSERT INTO t1 (val) SELECT 4 FROM seq_1_to_16; EXPLAIN SELECT * FROM t1 WHERE val=4; ROLLBACK; EXPLAIN SELECT * FROM t1 WHERE val=4; BEGIN; -INSERT INTO t1 SELECT * FROM t0; +INSERT INTO t1 (val) SELECT 4 FROM seq_1_to_16; COMMIT; EXPLAIN SELECT * FROM t1 WHERE val=4; BEGIN; @@ -89,7 +80,8 @@ disconnect con1; connection default; -DROP TABLE t0,t1,t2; +DROP TABLE t1,t2; SET GLOBAL innodb_stats_include_delete_marked = @saved_include_delete_marked; SET GLOBAL innodb_stats_traditional = @saved_traditional; SET GLOBAL innodb_stats_modified_counter = @saved_modified_counter; +SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; From bd22650bbcb3d4d64da186311fd04fb935096cd2 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Wed, 23 Oct 2019 17:00:12 +0530 Subject: [PATCH 32/68] MDEV-19073 FTS row mismatch after crash recovery InnoDB stores synced_doc_id + 1 value in FTS_CONFIG table. But while reading the synced doc id from FTS_CONFIG table after restart, InnoDB should read synced_doc_id - 1 to get the actual synced doc id value. --- .../suite/innodb_fts/r/crash_recovery.result | 36 ++++++++++++ .../suite/innodb_fts/t/crash_recovery.test | 55 +++++++++++++++++++ storage/innobase/fts/fts0fts.cc | 4 ++ storage/xtradb/fts/fts0fts.cc | 4 ++ 4 files changed, 99 insertions(+) diff --git a/mysql-test/suite/innodb_fts/r/crash_recovery.result b/mysql-test/suite/innodb_fts/r/crash_recovery.result index e21631471d2..648128424a8 100644 --- a/mysql-test/suite/innodb_fts/r/crash_recovery.result +++ b/mysql-test/suite/innodb_fts/r/crash_recovery.result @@ -67,6 +67,31 @@ INSERT INTO articles VALUES BEGIN; INSERT INTO articles VALUES (100, 200, 'MySQL Tutorial','DBMS stands for DataBase ...'); +# +# MDEV-19073 FTS row mismatch after crash recovery +# +CREATE TABLE mdev19073(id SERIAL, title VARCHAR(200), body TEXT, +FULLTEXT(title,body)) ENGINE=InnoDB; +INSERT INTO mdev19073 (title, body) VALUES +('MySQL Tutorial', 'DBMS stands for Database...'); +CREATE FULLTEXT INDEX idx ON mdev19073(title, body); +CREATE TABLE mdev19073_2 LIKE mdev19073; +INSERT INTO mdev19073_2 (title, body) VALUES +('MySQL Tutorial', 'DBMS stands for Database...'); +INSERT INTO mdev19073 (title, body) VALUES +('MariaDB Tutorial', 'DB means Database ...'); +INSERT INTO mdev19073_2 (title, body) VALUES +('MariaDB Tutorial', 'DB means Database ...'); +SELECT * FROM mdev19073 WHERE MATCH (title, body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +id title body +1 MySQL Tutorial DBMS stands for Database... +2 MariaDB Tutorial DB means Database ... +SELECT * FROM mdev19073_2 WHERE MATCH (title, body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +id title body +1 MySQL Tutorial DBMS stands for Database... +2 MariaDB Tutorial DB means Database ... # Kill and restart INSERT INTO articles VALUES (8, 12, 'MySQL Tutorial','DBMS stands for DataBase ...'); SELECT * FROM articles WHERE MATCH (title, body) @@ -76,3 +101,14 @@ id FTS_DOC_ID title body 1 10 MySQL Tutorial DBMS stands for DataBase ... 8 12 MySQL Tutorial DBMS stands for DataBase ... DROP TABLE articles; +SELECT * FROM mdev19073 WHERE MATCH (title, body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +id title body +1 MySQL Tutorial DBMS stands for Database... +2 MariaDB Tutorial DB means Database ... +SELECT * FROM mdev19073_2 WHERE MATCH (title, body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +id title body +1 MySQL Tutorial DBMS stands for Database... +2 MariaDB Tutorial DB means Database ... +DROP TABLE mdev19073, mdev19073_2; diff --git a/mysql-test/suite/innodb_fts/t/crash_recovery.test b/mysql-test/suite/innodb_fts/t/crash_recovery.test index ec055930672..861dfdfd658 100644 --- a/mysql-test/suite/innodb_fts/t/crash_recovery.test +++ b/mysql-test/suite/innodb_fts/t/crash_recovery.test @@ -6,6 +6,7 @@ --source include/have_innodb.inc # The embedded server tests do not support restarting. --source include/not_embedded.inc +--source include/maybe_debug.inc # Following are test for crash recovery on FTS index, the first scenario # is for bug Bug #14586855 INNODB: FAILING ASSERTION: (DICT_INDEX_GET_N_UNIQUE( @@ -62,13 +63,17 @@ INSERT INTO articles (title,body) VALUES ('MySQL vs. YourSQL','In the following database comparison ...'), ('MySQL Security','When configured properly, MySQL ...'); +connect(dml, localhost, root,,); BEGIN; INSERT INTO articles (title,body) VALUES ('MySQL Tutorial','DBMS stands for DataBase ...'); +connection default; --source include/kill_and_restart_mysqld.inc +disconnect dml; + # This insert will re-initialize the Doc ID counter, it should not crash INSERT INTO articles (title,body) VALUES ('MySQL Tutorial','DBMS stands for DataBase ...'); @@ -101,12 +106,55 @@ INSERT INTO articles VALUES (5, 6, 'MySQL vs. YourSQL','In the following database comparison ...'), (7, 4, 'MySQL Security','When configured properly, MySQL ...'); +connect(dml, localhost, root,,); BEGIN; INSERT INTO articles VALUES (100, 200, 'MySQL Tutorial','DBMS stands for DataBase ...'); +connect(dml2, localhost, root,,); + +--echo # +--echo # MDEV-19073 FTS row mismatch after crash recovery +--echo # + +CREATE TABLE mdev19073(id SERIAL, title VARCHAR(200), body TEXT, + FULLTEXT(title,body)) ENGINE=InnoDB; +INSERT INTO mdev19073 (title, body) VALUES + ('MySQL Tutorial', 'DBMS stands for Database...'); +CREATE FULLTEXT INDEX idx ON mdev19073(title, body); +CREATE TABLE mdev19073_2 LIKE mdev19073; +if ($have_debug) +{ +--disable_query_log +SET @saved_dbug = @@debug_dbug; +SET DEBUG_DBUG = '+d,fts_instrument_sync_debug'; +--enable_query_log +} +INSERT INTO mdev19073_2 (title, body) VALUES + ('MySQL Tutorial', 'DBMS stands for Database...'); +if ($have_debug) +{ +--disable_query_log +SET DEBUG_DBUG = @saved_dbug; +--enable_query_log +} + +INSERT INTO mdev19073 (title, body) VALUES + ('MariaDB Tutorial', 'DB means Database ...'); +INSERT INTO mdev19073_2 (title, body) VALUES + ('MariaDB Tutorial', 'DB means Database ...'); + +# Should return 2 rows +SELECT * FROM mdev19073 WHERE MATCH (title, body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +SELECT * FROM mdev19073_2 WHERE MATCH (title, body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); + +connection default; --source include/kill_and_restart_mysqld.inc +disconnect dml; +disconnect dml2; # This would re-initialize the FTS index and do the re-tokenization # of above records @@ -116,3 +164,10 @@ SELECT * FROM articles WHERE MATCH (title, body) AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); DROP TABLE articles; + +# Should return 2 rows +SELECT * FROM mdev19073 WHERE MATCH (title, body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +SELECT * FROM mdev19073_2 WHERE MATCH (title, body) +AGAINST ('Database' IN NATURAL LANGUAGE MODE); +DROP TABLE mdev19073, mdev19073_2; diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 1cf5c818a9e..6dbe5e0e2a0 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -2739,6 +2739,10 @@ retry: } if (read_only) { + /* InnoDB stores actual synced_doc_id value + 1 in + FTS_CONFIG table. Reduce the value by 1 while reading + after startup. */ + if (*doc_id) *doc_id -= 1; goto func_exit; } diff --git a/storage/xtradb/fts/fts0fts.cc b/storage/xtradb/fts/fts0fts.cc index 1cf5c818a9e..6dbe5e0e2a0 100644 --- a/storage/xtradb/fts/fts0fts.cc +++ b/storage/xtradb/fts/fts0fts.cc @@ -2739,6 +2739,10 @@ retry: } if (read_only) { + /* InnoDB stores actual synced_doc_id value + 1 in + FTS_CONFIG table. Reduce the value by 1 while reading + after startup. */ + if (*doc_id) *doc_id -= 1; goto func_exit; } From a41d429765c7ddb528b9b438c68b25ff55d3bd55 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 22 Oct 2019 12:05:42 +0530 Subject: [PATCH 33/68] MDEV-20621 FULLTEXT INDEX activity causes InnoDB hang - fts_optimize_thread() uses dict_table_t object instead of table id. So that it doesn't acquire dict_sys->mutex. It leads to remove the hang of dict_sys->mutex between fts_optimize_thread() and other threads. - in_queue to indicate whether the table is in fts_optimize_queue. It is protected by fts_optimize_wq->mutex to avoid any race condition. - fts_optimize_init() adds the fts table to the fts_optimize_wq --- storage/innobase/dict/dict0load.cc | 7 +- storage/innobase/fts/fts0opt.cc | 174 ++++++++++++--------------- storage/innobase/include/fts0fts.h | 16 +-- storage/innobase/include/fts0opt.h | 3 + storage/innobase/include/ut0wqueue.h | 33 ++--- storage/innobase/ut/ut0wqueue.cc | 22 ++-- storage/xtradb/dict/dict0load.cc | 7 +- storage/xtradb/fts/fts0opt.cc | 174 ++++++++++++--------------- storage/xtradb/include/fts0fts.h | 16 +-- storage/xtradb/include/fts0opt.h | 3 + storage/xtradb/include/ut0wqueue.h | 33 ++--- storage/xtradb/ut/ut0wqueue.cc | 22 ++-- 12 files changed, 246 insertions(+), 264 deletions(-) diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index dd9ddc5f20e..3a6851cff89 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -46,6 +46,7 @@ Created 4/24/1996 Heikki Tuuri #include "dict0priv.h" #include "ha_prototypes.h" /* innobase_casedn_str() */ #include "fts0priv.h" +#include "fts0opt.h" /** Following are the InnoDB system tables. The positions in this array are referenced by enum dict_system_table_id. */ @@ -2548,8 +2549,12 @@ func_exit: FTS */ fts_optimize_remove_table(table); fts_free(table); - } else { + } else if (fts_optimize_wq) { fts_optimize_add_table(table); + } else { + /* fts_optimize_thread is not started yet. + So make the table as non-evictable from cache. */ + dict_table_move_from_lru_to_non_lru(table); } } diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 3c15b514102..7f498443544 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -34,6 +34,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang #include "ut0wqueue.h" #include "srv0start.h" #include "zlib.h" +#include "fts0opt.h" #ifndef UNIV_NONINL #include "fts0types.ic" @@ -41,7 +42,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang #endif /** The FTS optimize thread's work queue. */ -static ib_wqueue_t* fts_optimize_wq; +ib_wqueue_t* fts_optimize_wq; /** The FTS vector to store fts_slot_t */ static ib_vector_t* fts_slots; @@ -169,8 +170,8 @@ struct fts_encode_t { /** We use this information to determine when to start the optimize cycle for a table. */ struct fts_slot_t { - /** table identifier, or 0 if the slot is empty */ - table_id_t table_id; + /** table, or NULL if the slot is unused */ + dict_table_t* table; /** whether this slot is being processed */ bool running; @@ -2456,14 +2457,7 @@ fts_optimize_table_bk( return(DB_SUCCESS); } - dict_table_t* table = dict_table_open_on_id( - slot->table_id, FALSE, DICT_TABLE_OP_NORMAL); - - if (!table) { - slot->last_run = now; - return DB_SUCCESS; - } - + dict_table_t* table = slot->table; dberr_t error; if (fil_table_accessible(table) @@ -2483,8 +2477,6 @@ fts_optimize_table_bk( error = DB_SUCCESS; } - dict_table_close(table, FALSE, FALSE); - return(error); } /*********************************************************************//** @@ -2627,11 +2619,13 @@ UNIV_INTERN void fts_optimize_add_table(dict_table_t* table) msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table); - ib_wqueue_add(fts_optimize_wq, msg, msg->heap); + mutex_enter(&fts_optimize_wq->mutex); + + ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true); - mutex_enter(&table->fts->bg_threads_mutex); table->fts->in_queue = true; - mutex_exit(&table->fts->bg_threads_mutex); + + mutex_exit(&fts_optimize_wq->mutex); } /**********************************************************************//** @@ -2648,7 +2642,7 @@ fts_optimize_remove_table( fts_msg_del_t* remove; /* if the optimize system not yet initialized, return */ - if (!fts_optimize_is_init()) { + if (!fts_optimize_wq) { return; } @@ -2660,12 +2654,10 @@ fts_optimize_remove_table( return; } - fts_t* fts = table->fts; - mutex_enter(&fts->bg_threads_mutex); - bool is_in_optimize_queue = fts->in_queue; - mutex_exit(&fts->bg_threads_mutex); + mutex_enter(&fts_optimize_wq->mutex); - if (!is_in_optimize_queue) { + if (!table->fts->in_queue) { + mutex_exit(&fts_optimize_wq->mutex); return; } @@ -2681,15 +2673,17 @@ fts_optimize_remove_table( remove->event = event; msg->ptr = remove; - ib_wqueue_add(fts_optimize_wq, msg, msg->heap); + ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true); + + mutex_exit(&fts_optimize_wq->mutex); os_event_wait(event); os_event_free(event); - mutex_enter(&fts->bg_threads_mutex); - fts->in_queue = false; - mutex_exit(&fts->bg_threads_mutex); + ut_d(mutex_enter(&fts_optimize_wq->mutex)); + ut_ad(!table->fts->in_queue); + ut_d(mutex_exit(&fts_optimize_wq->mutex)); } /** Send sync fts cache for the table. @@ -2700,10 +2694,9 @@ fts_optimize_request_sync_table( dict_table_t* table) { fts_msg_t* msg; - table_id_t* table_id; /* if the optimize system not yet initialized, return */ - if (!fts_optimize_is_init()) { + if (!fts_optimize_wq) { return; } @@ -2715,39 +2708,36 @@ fts_optimize_request_sync_table( return; } - msg = fts_optimize_create_msg(FTS_MSG_SYNC_TABLE, NULL); + msg = fts_optimize_create_msg(FTS_MSG_SYNC_TABLE, table); - table_id = static_cast( - mem_heap_alloc(msg->heap, sizeof(table_id_t))); - *table_id = table->id; - msg->ptr = table_id; + mutex_enter(&fts_optimize_wq->mutex); - ib_wqueue_add(fts_optimize_wq, msg, msg->heap); + ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true); - mutex_enter(&table->fts->bg_threads_mutex); table->fts->in_queue = true; - mutex_exit(&table->fts->bg_threads_mutex); + + mutex_exit(&fts_optimize_wq->mutex); } /** Add a table to fts_slots if it doesn't already exist. */ static bool fts_optimize_new_table(dict_table_t* table) { + ut_ad(table); + ulint i; fts_slot_t* slot; fts_slot_t* empty = NULL; - const table_id_t table_id = table->id; - ut_ad(table_id); /* Search for duplicates, also find a free slot if one exists. */ for (i = 0; i < ib_vector_size(fts_slots); ++i) { slot = static_cast(ib_vector_get(fts_slots, i)); - if (!slot->table_id) { + if (!slot->table) { empty = slot; - } else if (slot->table_id == table_id) { + } else if (slot->table == table) { /* Already exists in our optimize queue. */ - return(FALSE); + return false; } } @@ -2756,37 +2746,36 @@ static bool fts_optimize_new_table(dict_table_t* table) memset(slot, 0x0, sizeof(*slot)); - slot->table_id = table->id; - slot->running = false; - - return(TRUE); + slot->table = table; + return true; } /** Remove a table from fts_slots if it exists. @param[in,out] table table to be removed from fts_slots */ static bool fts_optimize_del_table(const dict_table_t* table) { - const table_id_t table_id = table->id; - ut_ad(table_id); - for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) { fts_slot_t* slot; slot = static_cast(ib_vector_get(fts_slots, i)); - if (slot->table_id == table_id) { + if (slot->table == table) { if (fts_enable_diag_print) { ib_logf(IB_LOG_LEVEL_INFO, "FTS Optimize Removing table %s", table->name); } - slot->table_id = 0; - return(TRUE); + mutex_enter(&fts_optimize_wq->mutex); + slot->table->fts->in_queue = false; + mutex_exit(&fts_optimize_wq->mutex); + + slot->table = NULL; + return true; } } - return(FALSE); + return false; } /**********************************************************************//** @@ -2800,7 +2789,7 @@ static ulint fts_optimize_how_many() for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) { const fts_slot_t* slot = static_cast( ib_vector_get_const(fts_slots, i)); - if (slot->table_id == 0) { + if (!slot->table) { continue; } @@ -2836,22 +2825,14 @@ static bool fts_is_sync_needed() const fts_slot_t* slot = static_cast( ib_vector_get_const(fts_slots, i)); - if (slot->table_id == 0) { + if (!slot->table) { continue; } - dict_table_t* table = dict_table_open_on_id( - slot->table_id, FALSE, DICT_TABLE_OP_NORMAL); - if (!table) { - continue; + if (slot->table->fts && slot->table->fts->cache) { + total_memory += slot->table->fts->cache->total_size; } - if (table->fts && table->fts->cache) { - total_memory += table->fts->cache->total_size; - } - - dict_table_close(table, FALSE, FALSE); - if (total_memory > fts_max_total_cache_size) { return(true); } @@ -2861,22 +2842,16 @@ static bool fts_is_sync_needed() } /** Sync fts cache of a table -@param[in] table_id table id */ -static void fts_optimize_sync_table(table_id_t table_id) +@param[in,out] table table to be synced */ +static void fts_optimize_sync_table(dict_table_t* table) { - if (dict_table_t* table = dict_table_open_on_id( - table_id, FALSE, DICT_TABLE_OP_NORMAL)) { - if (fil_table_accessible(table) - && table->fts && table->fts->cache) { - fts_sync_table(table, true, false, false); - } - - DBUG_EXECUTE_IF( - "ib_optimize_wq_hang", - os_thread_sleep(6000000);); - - dict_table_close(table, FALSE, FALSE); + if (fil_table_accessible(table) + && table->fts && table->fts->cache) { + fts_sync_table(table, true, false, false); } + + DBUG_EXECUTE_IF("ib_optimize_wq_hang", + os_thread_sleep(6000000);); } /**********************************************************************//** @@ -2918,7 +2893,7 @@ fts_optimize_thread( ib_vector_get(fts_slots, current)); /* Handle the case of empty slots. */ - if (slot->table_id) { + if (slot->table) { slot->running = true; fts_optimize_table_bk(slot); } @@ -2978,7 +2953,7 @@ fts_optimize_thread( os_thread_sleep(300000);); fts_optimize_sync_table( - *static_cast(msg->ptr)); + static_cast(msg->ptr)); break; default: @@ -2997,8 +2972,8 @@ fts_optimize_thread( fts_slot_t* slot = static_cast( ib_vector_get(fts_slots, i)); - if (table_id_t table_id = slot->table_id) { - fts_optimize_sync_table(table_id); + if (slot->table) { + fts_optimize_sync_table(slot->table); } } } @@ -3028,24 +3003,35 @@ fts_optimize_init(void) ut_ad(!srv_read_only_mode); /* For now we only support one optimize thread. */ - ut_a(!fts_optimize_is_init()); + ut_a(!fts_optimize_wq); fts_optimize_wq = ib_wqueue_create(); ut_a(fts_optimize_wq != NULL); last_check_sync_time = time(NULL); - os_thread_create(fts_optimize_thread, fts_optimize_wq, NULL); -} + /* Add fts tables to fts slots which could be skipped + during dict_load_table() because fts_optimize_thread + wasn't even started. */ + mutex_enter(&dict_sys->mutex); -/**********************************************************************//** -Check whether the work queue is initialized. -@return TRUE if optimze queue is initialized. */ -UNIV_INTERN -ibool -fts_optimize_is_init(void) -/*======================*/ -{ - return(fts_optimize_wq != NULL); + for (dict_table_t* table = UT_LIST_GET_FIRST(dict_sys->table_LRU); + table != NULL; + table = UT_LIST_GET_NEXT(table_LRU, table)) { + + if (!table->fts || !dict_table_has_fts_index(table)) { + continue; + } + + /* fts_optimize_thread is not started yet. So there is no + need to acqquire fts_optimize_wq->mutex for adding the fts + table to the fts slots. */ + ut_ad(!table->can_be_evicted); + fts_optimize_new_table(table); + table->fts->in_queue = true; + } + + mutex_exit(&dict_sys->mutex); + os_thread_create(fts_optimize_thread, fts_optimize_wq, NULL); } /**********************************************************************//** diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index 5c50e381f91..3beddd68722 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -285,9 +285,6 @@ struct fts_t { fts_add_wq. */ ib_mutex_t bg_threads_mutex; - /* Wheter the table was added to fts_optimize_wq(); - protected by bg_threads mutex */ - unsigned in_queue:1; /* Whether the ADDED table record sync-ed after crash recovery; protected by bg_threads mutex */ unsigned added_synced:1; @@ -310,6 +307,11 @@ struct fts_t { ib_vector_t* indexes; /*!< Vector of FTS indexes, this is mainly for caching purposes. */ + + /* Whether the table was added to fts_optimize_wq(); + protected by fts_optimize_wq mutex */ + bool in_queue; + mem_heap_t* fts_heap; /*!< heap for fts_t allocation */ }; @@ -631,14 +633,6 @@ void fts_optimize_init(void); /*====================*/ -/**********************************************************************//** -Check whether the work queue is initialized. -@return TRUE if optimze queue is initialized. */ -UNIV_INTERN -ibool -fts_optimize_is_init(void); -/*======================*/ - /****************************************************************//** Drops index ancillary tables for a FTS index @return DB_SUCCESS or error code */ diff --git a/storage/innobase/include/fts0opt.h b/storage/innobase/include/fts0opt.h index e8bd4be95b7..29bb14e2f64 100644 --- a/storage/innobase/include/fts0opt.h +++ b/storage/innobase/include/fts0opt.h @@ -25,6 +25,9 @@ Created 2011-02-15 Jimmy Yang #ifndef INNODB_FTS0OPT_H #define INNODB_FTS0OPT_H +/** The FTS optimize thread's work queue. */ +extern ib_wqueue_t* fts_optimize_wq; + /******************************************************************** Callback function to fetch the rows in an FTS INDEX record. */ UNIV_INTERN diff --git a/storage/innobase/include/ut0wqueue.h b/storage/innobase/include/ut0wqueue.h index b81b78530ca..4b0014e3091 100644 --- a/storage/innobase/include/ut0wqueue.h +++ b/storage/innobase/include/ut0wqueue.h @@ -56,16 +56,15 @@ ib_wqueue_free( /*===========*/ ib_wqueue_t* wq); /*!< in: work queue */ -/****************************************************************//** -Add a work item to the queue. */ +/** Add a work item to the queue. +@param[in,out] wq work queue +@param[in] item work item +@param[in,out] heap memory heap to use for allocating list node +@param[in] wq_locked work queue mutex locked */ UNIV_INTERN void -ib_wqueue_add( -/*==========*/ - ib_wqueue_t* wq, /*!< in: work queue */ - void* item, /*!< in: work item */ - mem_heap_t* heap); /*!< in: memory heap to use for allocating the - list node */ +ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap, + bool wq_locked = false); /** Check if queue is empty. @param wq wait queue @@ -107,14 +106,16 @@ ib_wqueue_len( /*==========*/ ib_wqueue_t* wq); /*mutex); + if (!wq_locked) { + mutex_enter(&wq->mutex); + } ib_list_add_last(wq->items, item, heap); os_event_set(wq->event); - mutex_exit(&wq->mutex); + if (!wq_locked) { + mutex_exit(&wq->mutex); + } } /****************************************************************//** diff --git a/storage/xtradb/dict/dict0load.cc b/storage/xtradb/dict/dict0load.cc index ae89ed79b76..292a1752771 100644 --- a/storage/xtradb/dict/dict0load.cc +++ b/storage/xtradb/dict/dict0load.cc @@ -46,6 +46,7 @@ Created 4/24/1996 Heikki Tuuri #include "dict0priv.h" #include "ha_prototypes.h" /* innobase_casedn_str() */ #include "fts0priv.h" +#include "fts0opt.h" /** Following are the InnoDB system tables. The positions in this array are referenced by enum dict_system_table_id. */ @@ -2570,8 +2571,12 @@ func_exit: FTS */ fts_optimize_remove_table(table); fts_free(table); - } else { + } else if (fts_optimize_wq) { fts_optimize_add_table(table); + } else { + /* fts_optimize_thread is not started yet. + So make the table as non-evictable from cache. */ + dict_table_move_from_lru_to_non_lru(table); } } diff --git a/storage/xtradb/fts/fts0opt.cc b/storage/xtradb/fts/fts0opt.cc index 4472482da81..7f498443544 100644 --- a/storage/xtradb/fts/fts0opt.cc +++ b/storage/xtradb/fts/fts0opt.cc @@ -34,6 +34,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang #include "ut0wqueue.h" #include "srv0start.h" #include "zlib.h" +#include "fts0opt.h" #ifndef UNIV_NONINL #include "fts0types.ic" @@ -41,7 +42,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang #endif /** The FTS optimize thread's work queue. */ -static ib_wqueue_t* fts_optimize_wq; +ib_wqueue_t* fts_optimize_wq; /** The FTS vector to store fts_slot_t */ static ib_vector_t* fts_slots; @@ -169,8 +170,8 @@ struct fts_encode_t { /** We use this information to determine when to start the optimize cycle for a table. */ struct fts_slot_t { - /** table identifier, or 0 if the slot is empty */ - table_id_t table_id; + /** table, or NULL if the slot is unused */ + dict_table_t* table; /** whether this slot is being processed */ bool running; @@ -2456,14 +2457,7 @@ fts_optimize_table_bk( return(DB_SUCCESS); } - dict_table_t* table = dict_table_open_on_id( - slot->table_id, FALSE, DICT_TABLE_OP_NORMAL); - - if (!table) { - slot->last_run = now; - return DB_SUCCESS; - } - + dict_table_t* table = slot->table; dberr_t error; if (fil_table_accessible(table) @@ -2483,8 +2477,6 @@ fts_optimize_table_bk( error = DB_SUCCESS; } - dict_table_close(table, FALSE, FALSE); - return(error); } /*********************************************************************//** @@ -2627,11 +2619,13 @@ UNIV_INTERN void fts_optimize_add_table(dict_table_t* table) msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table); - ib_wqueue_add(fts_optimize_wq, msg, msg->heap); + mutex_enter(&fts_optimize_wq->mutex); + + ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true); - mutex_enter(&table->fts->bg_threads_mutex); table->fts->in_queue = true; - mutex_exit(&table->fts->bg_threads_mutex); + + mutex_exit(&fts_optimize_wq->mutex); } /**********************************************************************//** @@ -2648,7 +2642,7 @@ fts_optimize_remove_table( fts_msg_del_t* remove; /* if the optimize system not yet initialized, return */ - if (!fts_optimize_is_init()) { + if (!fts_optimize_wq) { return; } @@ -2660,12 +2654,10 @@ fts_optimize_remove_table( return; } - fts_t* fts = table->fts; - mutex_enter(&fts->bg_threads_mutex); - bool is_in_optimize_queue = fts->in_queue; - mutex_exit(&fts->bg_threads_mutex); + mutex_enter(&fts_optimize_wq->mutex); - if (!is_in_optimize_queue) { + if (!table->fts->in_queue) { + mutex_exit(&fts_optimize_wq->mutex); return; } @@ -2681,15 +2673,17 @@ fts_optimize_remove_table( remove->event = event; msg->ptr = remove; - ib_wqueue_add(fts_optimize_wq, msg, msg->heap); + ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true); + + mutex_exit(&fts_optimize_wq->mutex); os_event_wait(event); os_event_free(event); - mutex_enter(&fts->bg_threads_mutex); - fts->in_queue = false; - mutex_exit(&fts->bg_threads_mutex); + ut_d(mutex_enter(&fts_optimize_wq->mutex)); + ut_ad(!table->fts->in_queue); + ut_d(mutex_exit(&fts_optimize_wq->mutex)); } /** Send sync fts cache for the table. @@ -2700,10 +2694,9 @@ fts_optimize_request_sync_table( dict_table_t* table) { fts_msg_t* msg; - table_id_t* table_id; /* if the optimize system not yet initialized, return */ - if (!fts_optimize_is_init()) { + if (!fts_optimize_wq) { return; } @@ -2715,39 +2708,36 @@ fts_optimize_request_sync_table( return; } - msg = fts_optimize_create_msg(FTS_MSG_SYNC_TABLE, NULL); + msg = fts_optimize_create_msg(FTS_MSG_SYNC_TABLE, table); - table_id = static_cast( - mem_heap_alloc(msg->heap, sizeof(table_id_t))); - *table_id = table->id; - msg->ptr = table_id; + mutex_enter(&fts_optimize_wq->mutex); - ib_wqueue_add(fts_optimize_wq, msg, msg->heap); + ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true); - mutex_enter(&table->fts->bg_threads_mutex); table->fts->in_queue = true; - mutex_exit(&table->fts->bg_threads_mutex); + + mutex_exit(&fts_optimize_wq->mutex); } /** Add a table to fts_slots if it doesn't already exist. */ static bool fts_optimize_new_table(dict_table_t* table) { + ut_ad(table); + ulint i; fts_slot_t* slot; fts_slot_t* empty = NULL; - const table_id_t table_id = table->id; - ut_ad(table_id); /* Search for duplicates, also find a free slot if one exists. */ for (i = 0; i < ib_vector_size(fts_slots); ++i) { slot = static_cast(ib_vector_get(fts_slots, i)); - if (!slot->table_id) { + if (!slot->table) { empty = slot; - } else if (slot->table_id == table_id) { + } else if (slot->table == table) { /* Already exists in our optimize queue. */ - return(FALSE); + return false; } } @@ -2756,37 +2746,36 @@ static bool fts_optimize_new_table(dict_table_t* table) memset(slot, 0x0, sizeof(*slot)); - slot->table_id = table->id; - slot->running = false; - - return(TRUE); + slot->table = table; + return true; } /** Remove a table from fts_slots if it exists. @param[in,out] table table to be removed from fts_slots */ static bool fts_optimize_del_table(const dict_table_t* table) { - const table_id_t table_id = table->id; - ut_ad(table_id); - for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) { fts_slot_t* slot; slot = static_cast(ib_vector_get(fts_slots, i)); - if (slot->table_id == table_id) { + if (slot->table == table) { if (fts_enable_diag_print) { ib_logf(IB_LOG_LEVEL_INFO, "FTS Optimize Removing table %s", table->name); } - slot->table_id = 0; - return(TRUE); + mutex_enter(&fts_optimize_wq->mutex); + slot->table->fts->in_queue = false; + mutex_exit(&fts_optimize_wq->mutex); + + slot->table = NULL; + return true; } } - return(FALSE); + return false; } /**********************************************************************//** @@ -2800,7 +2789,7 @@ static ulint fts_optimize_how_many() for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) { const fts_slot_t* slot = static_cast( ib_vector_get_const(fts_slots, i)); - if (slot->table_id == 0) { + if (!slot->table) { continue; } @@ -2836,22 +2825,14 @@ static bool fts_is_sync_needed() const fts_slot_t* slot = static_cast( ib_vector_get_const(fts_slots, i)); - if (slot->table_id == 0) { + if (!slot->table) { continue; } - dict_table_t* table = dict_table_open_on_id( - slot->table_id, FALSE, DICT_TABLE_OP_NORMAL); - if (!table) { - continue; + if (slot->table->fts && slot->table->fts->cache) { + total_memory += slot->table->fts->cache->total_size; } - if (table->fts && table->fts->cache) { - total_memory += table->fts->cache->total_size; - } - - dict_table_close(table, FALSE, FALSE); - if (total_memory > fts_max_total_cache_size) { return(true); } @@ -2861,22 +2842,16 @@ static bool fts_is_sync_needed() } /** Sync fts cache of a table -@param[in] table_id table id */ -static void fts_optimize_sync_table(table_id_t table_id) +@param[in,out] table table to be synced */ +static void fts_optimize_sync_table(dict_table_t* table) { - if (dict_table_t* table = dict_table_open_on_id( - table_id, FALSE, DICT_TABLE_OP_NORMAL)) { - if (fil_table_accessible(table) - && table->fts && table->fts->cache) { - fts_sync_table(table, true, false, false); - } - - DBUG_EXECUTE_IF( - "ib_optimize_wq_hang", - os_thread_sleep(6000000);); - - dict_table_close(table, FALSE, FALSE); + if (fil_table_accessible(table) + && table->fts && table->fts->cache) { + fts_sync_table(table, true, false, false); } + + DBUG_EXECUTE_IF("ib_optimize_wq_hang", + os_thread_sleep(6000000);); } /**********************************************************************//** @@ -2918,7 +2893,7 @@ fts_optimize_thread( ib_vector_get(fts_slots, current)); /* Handle the case of empty slots. */ - if (slot->table_id) { + if (slot->table) { slot->running = true; fts_optimize_table_bk(slot); } @@ -2978,7 +2953,7 @@ fts_optimize_thread( os_thread_sleep(300000);); fts_optimize_sync_table( - *static_cast(msg->ptr)); + static_cast(msg->ptr)); break; default: @@ -2997,8 +2972,8 @@ fts_optimize_thread( fts_slot_t* slot = static_cast( ib_vector_get(fts_slots, i)); - if (table_id_t table_id = slot->table_id) { - fts_optimize_sync_table(table_id); + if (slot->table) { + fts_optimize_sync_table(slot->table); } } } @@ -3028,24 +3003,35 @@ fts_optimize_init(void) ut_ad(!srv_read_only_mode); /* For now we only support one optimize thread. */ - ut_a(!fts_optimize_is_init()); + ut_a(!fts_optimize_wq); fts_optimize_wq = ib_wqueue_create(); ut_a(fts_optimize_wq != NULL); last_check_sync_time = time(NULL); - os_thread_create(fts_optimize_thread, fts_optimize_wq, NULL); -} + /* Add fts tables to fts slots which could be skipped + during dict_load_table() because fts_optimize_thread + wasn't even started. */ + mutex_enter(&dict_sys->mutex); -/**********************************************************************//** -Check whether the work queue is initialized. -@return TRUE if optimze queue is initialized. */ -UNIV_INTERN -ibool -fts_optimize_is_init(void) -/*======================*/ -{ - return(fts_optimize_wq != NULL); + for (dict_table_t* table = UT_LIST_GET_FIRST(dict_sys->table_LRU); + table != NULL; + table = UT_LIST_GET_NEXT(table_LRU, table)) { + + if (!table->fts || !dict_table_has_fts_index(table)) { + continue; + } + + /* fts_optimize_thread is not started yet. So there is no + need to acqquire fts_optimize_wq->mutex for adding the fts + table to the fts slots. */ + ut_ad(!table->can_be_evicted); + fts_optimize_new_table(table); + table->fts->in_queue = true; + } + + mutex_exit(&dict_sys->mutex); + os_thread_create(fts_optimize_thread, fts_optimize_wq, NULL); } /**********************************************************************//** diff --git a/storage/xtradb/include/fts0fts.h b/storage/xtradb/include/fts0fts.h index 9c70157a0c8..714f811db27 100644 --- a/storage/xtradb/include/fts0fts.h +++ b/storage/xtradb/include/fts0fts.h @@ -285,9 +285,6 @@ struct fts_t { fts_add_wq. */ ib_mutex_t bg_threads_mutex; - /* Whether the table was added to fts_optimize_wq(); - protected by bg_threads mutex */ - unsigned in_queue:1; /* Whether the ADDED table record sync-ed afer crash recovery; protected by bg_threads mutex */ unsigned added_synced:1; @@ -310,6 +307,11 @@ struct fts_t { ib_vector_t* indexes; /*!< Vector of FTS indexes, this is mainly for caching purposes. */ + + /* Whether the table was added to fts_optimize_wq(); + protected by fts_optimize_wq mutex */ + bool in_queue; + mem_heap_t* fts_heap; /*!< heap for fts_t allocation */ }; @@ -631,14 +633,6 @@ void fts_optimize_init(void); /*====================*/ -/**********************************************************************//** -Check whether the work queue is initialized. -@return TRUE if optimze queue is initialized. */ -UNIV_INTERN -ibool -fts_optimize_is_init(void); -/*======================*/ - /****************************************************************//** Drops index ancillary tables for a FTS index @return DB_SUCCESS or error code */ diff --git a/storage/xtradb/include/fts0opt.h b/storage/xtradb/include/fts0opt.h index e8bd4be95b7..29bb14e2f64 100644 --- a/storage/xtradb/include/fts0opt.h +++ b/storage/xtradb/include/fts0opt.h @@ -25,6 +25,9 @@ Created 2011-02-15 Jimmy Yang #ifndef INNODB_FTS0OPT_H #define INNODB_FTS0OPT_H +/** The FTS optimize thread's work queue. */ +extern ib_wqueue_t* fts_optimize_wq; + /******************************************************************** Callback function to fetch the rows in an FTS INDEX record. */ UNIV_INTERN diff --git a/storage/xtradb/include/ut0wqueue.h b/storage/xtradb/include/ut0wqueue.h index 9bd58609205..4b0014e3091 100644 --- a/storage/xtradb/include/ut0wqueue.h +++ b/storage/xtradb/include/ut0wqueue.h @@ -56,16 +56,15 @@ ib_wqueue_free( /*===========*/ ib_wqueue_t* wq); /*!< in: work queue */ -/****************************************************************//** -Add a work item to the queue. */ +/** Add a work item to the queue. +@param[in,out] wq work queue +@param[in] item work item +@param[in,out] heap memory heap to use for allocating list node +@param[in] wq_locked work queue mutex locked */ UNIV_INTERN void -ib_wqueue_add( -/*==========*/ - ib_wqueue_t* wq, /*!< in: work queue */ - void* item, /*!< in: work item */ - mem_heap_t* heap); /*!< in: memory heap to use for allocating the - list node */ +ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap, + bool wq_locked = false); /** Check if queue is empty. @param wq wait queue @@ -99,7 +98,6 @@ ib_wqueue_nowait( /*=============*/ ib_wqueue_t* wq); /*mutex); + if (!wq_locked) { + mutex_enter(&wq->mutex); + } ib_list_add_last(wq->items, item, heap); os_event_set(wq->event); - mutex_exit(&wq->mutex); + if (!wq_locked) { + mutex_exit(&wq->mutex); + } } /****************************************************************//** From 42ada91542184861d9d7c6540500f27a81f1f6c4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 10 Sep 2019 17:24:34 +0200 Subject: [PATCH 34/68] cleanup: RAII helper for swapping of thd->security_ctx --- sql/sql_class.h | 16 ++++++++++++++++ sql/sql_parse.cc | 31 ++++++------------------------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 109b6610271..e3719f1c0fe 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5967,6 +5967,22 @@ class Sql_mode_save sql_mode_t old_mode; // SQL mode saved at construction time. }; +class Switch_to_definer_security_ctx +{ + public: + Switch_to_definer_security_ctx(THD *thd, TABLE_LIST *table) : + m_thd(thd), m_sctx(thd->security_ctx) + { + if (table->security_ctx) + thd->security_ctx= table->security_ctx; + } + ~Switch_to_definer_security_ctx() { m_thd->security_ctx = m_sctx; } + + private: + THD *m_thd; + Security_context *m_sctx; +}; + #endif /* MYSQL_SERVER */ #endif /* SQL_CLASS_INCLUDED */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fa04eb6727c..4939e884c84 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6617,11 +6617,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, bool check_single_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables, bool no_errors) { - Security_context * backup_ctx= thd->security_ctx; - - /* we need to switch to the saved context (if any) */ - if (all_tables->security_ctx) - thd->security_ctx= all_tables->security_ctx; + Switch_to_definer_security_ctx backup_sctx(thd, all_tables); const char *db_name; if ((all_tables->view || all_tables->field_translation) && @@ -6634,20 +6630,15 @@ bool check_single_table_access(THD *thd, ulong privilege, &all_tables->grant.privilege, &all_tables->grant.m_internal, 0, no_errors)) - goto deny; + return 1; /* Show only 1 table for check_grant */ if (!(all_tables->belong_to_view && (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && check_grant(thd, privilege, all_tables, FALSE, 1, no_errors)) - goto deny; + return 1; - thd->security_ctx= backup_ctx; return 0; - -deny: - thd->security_ctx= backup_ctx; - return 1; } /** @@ -6822,7 +6813,6 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, { TABLE_LIST *org_tables= tables; TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); - Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx; uint i= 0; /* The check that first_not_own_table is not reached is for the case when @@ -6834,12 +6824,9 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, { TABLE_LIST *const table_ref= tables->correspondent_table ? tables->correspondent_table : tables; + Switch_to_definer_security_ctx backup_ctx(thd, table_ref); ulong want_access= requirements; - if (table_ref->security_ctx) - sctx= table_ref->security_ctx; - else - sctx= backup_ctx; /* Register access for view underlying table. @@ -6850,7 +6837,7 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, if (table_ref->schema_table_reformed) { if (check_show_access(thd, table_ref)) - goto deny; + return 1; continue; } @@ -6860,21 +6847,15 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, if (table_ref->is_anonymous_derived_table()) continue; - thd->security_ctx= sctx; - if (check_access(thd, want_access, table_ref->get_db_name(), &table_ref->grant.privilege, &table_ref->grant.m_internal, 0, no_errors)) - goto deny; + return 1; } - thd->security_ctx= backup_ctx; return check_grant(thd,requirements,org_tables, any_combination_of_privileges_will_do, number, no_errors); -deny: - thd->security_ctx= backup_ctx; - return TRUE; } From be780c05559731e09aed2e8a06f93a72d5d51b7f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 10 Sep 2019 19:15:32 +0200 Subject: [PATCH 35/68] fix CONNECT engine to issue the correct error message --- storage/connect/ha_connect.cc | 35 +-- .../connect/mysql-test/connect/r/grant.result | 174 ++++++------ .../mysql-test/connect/r/grant2.result | 258 ++++++++--------- .../mysql-test/connect/r/ini_grant.result | 26 +- .../mysql-test/connect/r/mysql_grant.result | 24 +- .../mysql-test/connect/r/xml2_grant.result | 30 +- .../mysql-test/connect/r/xml_grant.result | 30 +- .../connect/mysql-test/connect/t/grant.inc | 30 +- .../connect/mysql-test/connect/t/grant.test | 24 +- .../connect/mysql-test/connect/t/grant2.test | 260 +++++++++--------- .../mysql-test/connect/t/ini_grant.test | 26 +- .../mysql-test/connect/t/mysql_grant.test | 24 +- 12 files changed, 460 insertions(+), 481 deletions(-) diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index a3ea363226e..e096d453246 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -4503,34 +4503,13 @@ bool ha_connect::check_privileges(THD *thd, PTOS options, char *dbn, bool quick) case TAB_DIR: case TAB_ZIP: case TAB_OEM: -#ifdef NO_EMBEDDED_ACCESS_CHECKS - return false; - #endif - - /* - Check FILE_ACL - If table or table->mdl_ticket is NULL - it's a DLL, e.g. CREATE TABLE. - if the table has an MDL_EXCLUSIVE lock - it's a DDL too, e.g. the - insert step of CREATE ... SELECT. - - Otherwise it's a DML, the table was normally opened, locked, - privilege were already checked, and table->grant.privilege is set. - With SQL SECURITY DEFINER, table->grant.privilege has definer's privileges. - - Unless we're in prelocking mode, in this case table->grant.privilege - is only checked in start_stmt(), not in external_lock(). - */ - if (!table || !table->mdl_ticket || table->mdl_ticket->get_type() == MDL_EXCLUSIVE) - return check_access(thd, FILE_ACL, db, NULL, NULL, 0, 0); - - if ((!quick && thd->lex->requires_prelocking()) || table->grant.privilege & FILE_ACL) - return false; - - status_var_increment(thd->status_var.access_denied_errors); - my_error(access_denied_error_code(thd->password), MYF(0), - thd->security_ctx->priv_user, thd->security_ctx->priv_host, - (thd->password ? ER(ER_YES) : ER(ER_NO))); - return true; + if (table && table->pos_in_table_list) // if SELECT + { + Switch_to_definer_security_ctx backup_ctx(thd, table->pos_in_table_list); + return check_global_access(thd, FILE_ACL); + } + else + return check_global_access(thd, FILE_ACL); case TAB_ODBC: case TAB_JDBC: case TAB_MONGO: diff --git a/storage/connect/mysql-test/connect/r/grant.result b/storage/connect/mysql-test/connect/r/grant.result index 9fff2c84705..eeecfde9df4 100644 --- a/storage/connect/mysql-test/connect/r/grant.result +++ b/storage/connect/mysql-test/connect/r/grant.result @@ -15,7 +15,7 @@ fname VARCHAR(256) NOT NULL, ftype CHAR(4) NOT NULL, size DOUBLE(12,0) NOT NULL flag=5 ) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*.*'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -35,19 +35,19 @@ SELECT user(); user() user@localhost SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO t1 VALUES (); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM t1 WHERE path='xxx'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 SET path='yyy' WHERE path='xxx'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation # Testing a VIEW created with FILE privileges but accessed with no FILE connection default; SELECT user(); @@ -59,13 +59,13 @@ SELECT user(); user() user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1 VALUES (1,1,1,1); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1 SET path=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation disconnect user; connection default; SELECT user(); @@ -112,7 +112,7 @@ a DROP VIEW v1; DROP TABLE t1; CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -124,23 +124,23 @@ SELECT user(); user() user@localhost INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation # Testing a VIEW created with FILE privileges but accessed with no FILE connection default; SELECT user(); @@ -152,13 +152,13 @@ SELECT user(); user() user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -174,7 +174,7 @@ SELECT user(); user() user@localhost ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; disconnect user; @@ -217,7 +217,7 @@ a DROP VIEW v1; DROP TABLE t1; CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -229,23 +229,23 @@ SELECT user(); user() user@localhost INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation # Testing a VIEW created with FILE privileges but accessed with no FILE connection default; SELECT user(); @@ -257,13 +257,13 @@ SELECT user(); user() user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -279,7 +279,7 @@ SELECT user(); user() user@localhost ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; disconnect user; @@ -322,7 +322,7 @@ a DROP VIEW v1; DROP TABLE t1; CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -334,23 +334,23 @@ SELECT user(); user() user@localhost INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation # Testing a VIEW created with FILE privileges but accessed with no FILE connection default; SELECT user(); @@ -362,13 +362,13 @@ SELECT user(); user() user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -384,7 +384,7 @@ SELECT user(); user() user@localhost ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; disconnect user; @@ -427,7 +427,7 @@ a DROP VIEW v1; DROP TABLE t1; CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -439,23 +439,23 @@ SELECT user(); user() user@localhost INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation # Testing a VIEW created with FILE privileges but accessed with no FILE connection default; SELECT user(); @@ -467,13 +467,13 @@ SELECT user(); user() user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -489,7 +489,7 @@ SELECT user(); user() user@localhost ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; disconnect user; @@ -532,7 +532,7 @@ a DROP VIEW v1; DROP TABLE t1; CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -544,23 +544,23 @@ SELECT user(); user() user@localhost INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation # Testing a VIEW created with FILE privileges but accessed with no FILE connection default; SELECT user(); @@ -572,13 +572,13 @@ SELECT user(); user() user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -594,7 +594,7 @@ SELECT user(); user() user@localhost ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; disconnect user; diff --git a/storage/connect/mysql-test/connect/r/grant2.result b/storage/connect/mysql-test/connect/r/grant2.result index 73e41f49256..2e20dc39596 100644 --- a/storage/connect/mysql-test/connect/r/grant2.result +++ b/storage/connect/mysql-test/connect/r/grant2.result @@ -21,12 +21,12 @@ SELECT * FROM v1_definer; a 10 SELECT * FROM v1_baddefiner; -ERROR 28000: Access denied for user 'root'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connect user,localhost,user,,; SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation SELECT * FROM v1_invoker; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation SELECT * FROM v1_definer; a 10 @@ -44,9 +44,9 @@ UPDATE v1_invoker SET a=12; UPDATE v1_definer SET a=13; connection user; UPDATE t1 SET a=21; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_invoker SET a=22; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_definer SET a=23; connection default; DROP VIEW v1_invoker, v1_definer; @@ -62,9 +62,9 @@ INSERT INTO v1_invoker VALUES (12); INSERT INTO v1_definer VALUES (13); connection user; INSERT INTO t1 VALUES (21); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1_invoker VALUES (22); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1_definer VALUES (23); connection default; DROP VIEW v1_invoker, v1_definer; @@ -83,9 +83,9 @@ REPLACE INTO v1_definer VALUES (13); ERROR 42000: CONNECT Unsupported command connection user; REPLACE INTO t1 VALUES (21); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation REPLACE INTO v1_invoker VALUES (22); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation REPLACE INTO v1_definer VALUES (23); ERROR 42000: CONNECT Unsupported command connection default; @@ -102,9 +102,9 @@ DELETE FROM v1_invoker WHERE a=12; DELETE FROM v1_definer WHERE a=13; connection user; DELETE FROM t1 WHERE a=21; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1_invoker WHERE a=22; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1_definer WHERE a=23; connection default; DROP VIEW v1_invoker, v1_definer; @@ -120,9 +120,9 @@ LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker; LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer; connection user; LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer; connection default; DROP VIEW v1_invoker, v1_definer; @@ -135,7 +135,7 @@ TRUNCATE TABLE t1; INSERT INTO t1 VALUES (11); connection user; TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing SQLCOM_DROP_TABLE @@ -144,7 +144,7 @@ CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; INSERT INTO t1 VALUES (10); connection user; DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing SQLCOM_DROP_VIEW @@ -165,7 +165,7 @@ DROP TABLE t1; # Testing SQLCOM_CREATE_TABLE connection user; CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; # Testing SQLCOM_LOCK_TABLES connection default; @@ -187,13 +187,13 @@ LOCK TABLE v1_definer WRITE; UNLOCK TABLES; connection user; LOCK TABLE t1 READ; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation LOCK TABLE t1 WRITE; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation LOCK TABLE v1_invoker READ; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation LOCK TABLE v1_invoker WRITE; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation LOCK TABLE v1_definer READ; UNLOCK TABLES; LOCK TABLE v1_definer WRITE; @@ -264,93 +264,93 @@ UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; connection user; UPDATE t1 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t2 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t2 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t2 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t2 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t2 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t2 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t2 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t3 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t3 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t3 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE t3 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t3 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE t3 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t3 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v1_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v1_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v1_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v2_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v2_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; connection default; DROP VIEW v1_invoker, v1_definer, v2_invoker, v2_definer; @@ -418,93 +418,93 @@ DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a; DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a; connection user; DELETE a1 FROM t1 a1,t1 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t1 a1,t2 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t1 a1,t3 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t1 a1,v1_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t1 a1,v1_definer a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t1 a1,v2_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t1 a1,v2_definer a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t2 a1,t1 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t2 a1,t2 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t2 a1,t3 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t2 a1,v1_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t2 a1,v1_definer a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t2 a1,v2_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t2 a1,v2_definer a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t3 a1,t1 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t3 a1,t2 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t3 a1,t3 a2 WHERE a1.a=a2.a; DELETE a1 FROM t3 a1,v1_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t3 a1,v1_definer a2 WHERE a1.a=a2.a; DELETE a1 FROM t3 a1,v2_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM t3 a1,v2_definer a2 WHERE a1.a=a2.a; DELETE a1 FROM v1_invoker a1,t1 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_invoker a1,t2 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_invoker a1,t3 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_invoker a1,v1_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_invoker a1,v1_definer a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_invoker a1,v2_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_invoker a1,v2_definer a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_definer a1,t1 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_definer a1,t2 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_definer a1,t3 a2 WHERE a1.a=a2.a; DELETE a1 FROM v1_definer a1,v1_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_definer a1,v1_definer a2 WHERE a1.a=a2.a; DELETE a1 FROM v1_definer a1,v2_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v1_definer a1,v2_definer a2 WHERE a1.a=a2.a; DELETE a1 FROM v2_invoker a1,t1 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_invoker a1,t2 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_invoker a1,t3 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_invoker a1,v1_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_invoker a1,v1_definer a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_invoker a1,v2_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_invoker a1,v2_definer a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_definer a1,t1 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_definer a1,t2 a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_definer a1,t3 a2 WHERE a1.a=a2.a; DELETE a1 FROM v2_definer a1,v1_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_definer a1,v1_definer a2 WHERE a1.a=a2.a; DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a; connection default; DROP VIEW v1_invoker, v1_definer, v2_invoker, v2_definer; @@ -521,9 +521,9 @@ CREATE VIEW v2 AS SELECT * FROM v1_definer; DROP VIEW v2; connection user; CREATE VIEW v2 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v2 AS SELECT * FROM v1_invoker; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v2 AS SELECT * FROM v1_definer; DROP VIEW v2; connection default; @@ -546,21 +546,21 @@ INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20; INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20; connection user; INSERT INTO t1 SELECT * FROM t1 WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO t1 SELECT * FROM v1_invoker WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO t1 SELECT * FROM v1_definer WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1_invoker SELECT * FROM t1 WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1_invoker SELECT * FROM v1_definer WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20; connection default; DROP VIEW v1_invoker, v1_definer; @@ -591,17 +591,17 @@ REPLACE INTO v1_definer SELECT * FROM v1_definer WHERE a=20; ERROR 42000: CONNECT Unsupported command connection user; REPLACE INTO t1 SELECT * FROM t1 WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation REPLACE INTO t1 SELECT * FROM v1_invoker WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation REPLACE INTO t1 SELECT * FROM v1_definer WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation REPLACE INTO v1_invoker SELECT * FROM t1 WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation REPLACE INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation REPLACE INTO v1_invoker SELECT * FROM v1_definer WHERE a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation REPLACE INTO v1_definer SELECT * FROM t1 WHERE a=20; ERROR 42000: CONNECT Unsupported command REPLACE INTO v1_definer SELECT * FROM v1_invoker WHERE a=20; @@ -624,7 +624,7 @@ t2 CREATE TABLE `t2` ( RENAME TABLE t2 TO t1; connection user; RENAME TABLE t1 TO t2; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing SQLCOM_ALTER_TABLE (for ALTER..RENAME) @@ -640,7 +640,7 @@ t2 CREATE TABLE `t2` ( ALTER TABLE t2 RENAME TO t1; connection user; ALTER TABLE t1 RENAME TO t2; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing SQLCOM_ALTER_TABLE (changing ENGINE to non-CONNECT) @@ -653,7 +653,7 @@ CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; INSERT INTO t1 VALUES (10); connection user; ALTER TABLE t1 ENGINE=MyISAM; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing SQLCOM_ALTER_TABLE (changing ENGINE to CONNECT) @@ -669,7 +669,7 @@ CREATE TABLE t1 (a INT) ENGINE=MyISAM; INSERT INTO t1 VALUES (10); connection user; ALTER TABLE t1 ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing SQLCOM_OPTIMIZE @@ -682,7 +682,7 @@ test.t1 optimize status OK connection user; OPTIMIZE TABLE t1; Table Op Msg_type Msg_text -test.t1 optimize Error Access denied for user 'user'@'localhost' (using password: NO) +test.t1 optimize Error Access denied; you need (at least one of) the FILE privilege(s) for this operation test.t1 optimize Error Got error 122 'This operation requires the FILE privilege' from CONNECT test.t1 optimize error Corrupt connection default; @@ -696,7 +696,7 @@ Warnings: Warning 1105 This is an outward table, table data were not modified. connection user; ALTER TABLE t1 ADD c INT; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing SQLCOM_ALTER_TABLE (removing columns) @@ -708,7 +708,7 @@ Warnings: Warning 1105 This is an outward table, table data were not modified. connection user; ALTER TABLE t1 DROP c; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing SQLCOM_ALTER_TABLE (adding keys) @@ -718,7 +718,7 @@ INSERT INTO t1 VALUES (10,10); ALTER TABLE t1 ADD KEY(a); connection user; ALTER TABLE t1 ADD KEY(b); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing SQLCOM_ALTER_TABLE (removing keys) @@ -728,7 +728,7 @@ INSERT INTO t1 VALUES (10,10); ALTER TABLE t1 DROP KEY a; connection user; ALTER TABLE t1 DROP KEY b; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing SQLCOM_CREATE_INDEX and SQLCOM_DROP_INDEX @@ -740,9 +740,9 @@ DROP INDEX a ON t1; CREATE INDEX a ON t1 (a); connection user; CREATE INDEX b ON t1 (b); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DROP INDEX a ON t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; # Testing stored procedures @@ -757,10 +757,10 @@ DROP TABLE t1; CALL p_invoker(); DROP TABLE t1; CALL p_baddefiner(); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection user; CALL p_invoker(); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CALL p_definer(); connection default; DROP TABLE t1; diff --git a/storage/connect/mysql-test/connect/r/ini_grant.result b/storage/connect/mysql-test/connect/r/ini_grant.result index 8cbf88123fb..96d5e192c7d 100644 --- a/storage/connect/mysql-test/connect/r/ini_grant.result +++ b/storage/connect/mysql-test/connect/r/ini_grant.result @@ -34,7 +34,7 @@ sec val DROP VIEW v1; DROP TABLE t1; CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -46,21 +46,21 @@ SELECT user(); user() user@localhost INSERT INTO t1 VALUES ('sec2','val2'); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 SET val='val11'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation # Testing a VIEW created with FILE privileges but accessed with no FILE connection default; SELECT user(); @@ -72,13 +72,13 @@ SELECT user(); user() user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1 VALUES ('sec3','val3'); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1 SET val='val11'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation disconnect user; connection default; DROP VIEW v1; diff --git a/storage/connect/mysql-test/connect/r/mysql_grant.result b/storage/connect/mysql-test/connect/r/mysql_grant.result index 11a3dbba36c..83a906afed5 100644 --- a/storage/connect/mysql-test/connect/r/mysql_grant.result +++ b/storage/connect/mysql-test/connect/r/mysql_grant.result @@ -11,7 +11,7 @@ SELECT user(); user() user@localhost CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL OPTION_LIST='host=localhost,user=root1,port=PORT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -29,19 +29,19 @@ SELECT user(); user() user@localhost SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO t1 VALUES ('xxx'); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM t1 WHERE a='xxx'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 SET a='yyy' WHERE a='xxx'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation # Testing a VIEW created with FILE privileges but accessed with no FILE connection default; SELECT user(); @@ -53,13 +53,13 @@ SELECT user(); user() user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation disconnect user; connection default; SELECT user(); diff --git a/storage/connect/mysql-test/connect/r/xml2_grant.result b/storage/connect/mysql-test/connect/r/xml2_grant.result index 817d3f5bf57..a6e6c150b59 100644 --- a/storage/connect/mysql-test/connect/r/xml2_grant.result +++ b/storage/connect/mysql-test/connect/r/xml2_grant.result @@ -35,7 +35,7 @@ a DROP VIEW v1; DROP TABLE t1; CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -47,23 +47,23 @@ SELECT user(); user() user@localhost INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation # Testing a VIEW created with FILE privileges but accessed with no FILE connection default; SELECT user(); @@ -75,13 +75,13 @@ SELECT user(); user() user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -97,7 +97,7 @@ SELECT user(); user() user@localhost ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; disconnect user; diff --git a/storage/connect/mysql-test/connect/r/xml_grant.result b/storage/connect/mysql-test/connect/r/xml_grant.result index 950ae4a3b35..f1a6ad101cb 100644 --- a/storage/connect/mysql-test/connect/r/xml_grant.result +++ b/storage/connect/mysql-test/connect/r/xml_grant.result @@ -33,7 +33,7 @@ a DROP VIEW v1; DROP TABLE t1; CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row' FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -45,23 +45,23 @@ SELECT user(); user() user@localhost INSERT INTO t1 VALUES (10); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE t1 SET a=20; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation TRUNCATE TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 READONLY=1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation ALTER TABLE t1 FILE_NAME='t2.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DROP TABLE t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation CREATE VIEW v1 AS SELECT * FROM t1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation # Testing a VIEW created with FILE privileges but accessed with no FILE connection default; SELECT user(); @@ -73,13 +73,13 @@ SELECT user(); user() user@localhost SELECT * FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation INSERT INTO v1 VALUES (2); -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation UPDATE v1 SET a=123; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation DELETE FROM v1; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; SELECT user(); user() @@ -95,7 +95,7 @@ SELECT user(); user() user@localhost ALTER TABLE t1 FILE_NAME='t1.EXT'; -ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO) +ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation connection default; DROP TABLE t1; disconnect user; diff --git a/storage/connect/mysql-test/connect/t/grant.inc b/storage/connect/mysql-test/connect/t/grant.inc index 6580c845b56..ef6e0cec297 100644 --- a/storage/connect/mysql-test/connect/t/grant.inc +++ b/storage/connect/mysql-test/connect/t/grant.inc @@ -25,7 +25,7 @@ DROP TABLE t1; # Making sure DROP erased the data file --error 1 --remove_file $MYSQLD_DATADIR/test/t1.$FILE_EXT ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR --eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT $TABLE_OPTIONS FILE_NAME='t1.EXT' --connection default SELECT user(); @@ -33,23 +33,23 @@ SELECT user(); INSERT INTO t1 VALUES (10); --connection user SELECT user(); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO t1 VALUES (10); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 SET a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE FROM t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR TRUNCATE TABLE t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 READONLY=1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 FILE_NAME='t2.EXT'; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DROP TABLE t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CREATE VIEW v1 AS SELECT * FROM t1; --echo # Testing a VIEW created with FILE privileges but accessed with no FILE --connection default @@ -57,13 +57,13 @@ SELECT user(); CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1; --connection user SELECT user(); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM v1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO v1 VALUES (2); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1 SET a=123; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE FROM v1; --connection default SELECT user(); @@ -74,7 +74,7 @@ DROP TABLE t1; INSERT INTO t1 VALUES (10); --connection user SELECT user(); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 FILE_NAME='t1.EXT'; --connection default DROP TABLE t1; diff --git a/storage/connect/mysql-test/connect/t/grant.test b/storage/connect/mysql-test/connect/t/grant.test index 15523d11ad9..5e07b7af369 100644 --- a/storage/connect/mysql-test/connect/t/grant.test +++ b/storage/connect/mysql-test/connect/t/grant.test @@ -11,7 +11,7 @@ REVOKE FILE ON *.* FROM user@localhost; --connect(user,localhost,user,,) --connection user SELECT user(); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CREATE TABLE t1 ( path VARCHAR(256) NOT NULL flag=1, fname VARCHAR(256) NOT NULL, @@ -33,19 +33,19 @@ SELECT fname, ftype, size FROM t1 WHERE size>0; --connection user SELECT user(); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO t1 VALUES (); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE FROM t1 WHERE path='xxx'; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 SET path='yyy' WHERE path='xxx'; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR TRUNCATE TABLE t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 READONLY=1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CREATE VIEW v1 AS SELECT * FROM t1; --echo # Testing a VIEW created with FILE privileges but accessed with no FILE @@ -54,13 +54,13 @@ SELECT user(); CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1; --connection user SELECT user(); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM v1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO v1 VALUES (1,1,1,1); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1 SET path=123; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE FROM v1; --disconnect user diff --git a/storage/connect/mysql-test/connect/t/grant2.test b/storage/connect/mysql-test/connect/t/grant2.test index 8e7d9453e70..351eb97f11a 100644 --- a/storage/connect/mysql-test/connect/t/grant2.test +++ b/storage/connect/mysql-test/connect/t/grant2.test @@ -23,13 +23,13 @@ CREATE DEFINER=user@localhost SQL SECURITY DEFINER VIEW v1_baddefiner AS SELECT SELECT * FROM t1; SELECT * FROM v1_invoker; SELECT * FROM v1_definer; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM v1_baddefiner; --connect(user,localhost,user,,) ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM v1_invoker; SELECT * FROM v1_definer; --connection default @@ -47,9 +47,9 @@ UPDATE t1 SET a=11; UPDATE v1_invoker SET a=12; UPDATE v1_definer SET a=13; --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 SET a=21; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_invoker SET a=22; UPDATE v1_definer SET a=23; --connection default @@ -67,9 +67,9 @@ INSERT INTO t1 VALUES (11); INSERT INTO v1_invoker VALUES (12); INSERT INTO v1_definer VALUES (13); --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO t1 VALUES (21); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO v1_invoker VALUES (22); INSERT INTO v1_definer VALUES (23); --connection default @@ -79,7 +79,7 @@ DROP TABLE t1; --echo # Testing SQLCOM_REPLACE # REPLACE is not supported by ConnectSE, so we're testing the difference -# between ER_ACCESS_DENIED_ERROR vs ER_NOT_ALLOWED_COMMAND +# between ER_SPECIFIC_ACCESS_DENIED_ERROR vs ER_NOT_ALLOWED_COMMAND --connection default CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; INSERT INTO t1 VALUES (10); @@ -92,9 +92,9 @@ REPLACE INTO v1_invoker VALUES (12); --error ER_NOT_ALLOWED_COMMAND REPLACE INTO v1_definer VALUES (13); --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR REPLACE INTO t1 VALUES (21); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR REPLACE INTO v1_invoker VALUES (22); --error ER_NOT_ALLOWED_COMMAND REPLACE INTO v1_definer VALUES (23); @@ -113,9 +113,9 @@ DELETE FROM t1 WHERE a=11; DELETE FROM v1_invoker WHERE a=12; DELETE FROM v1_definer WHERE a=13; --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE FROM t1 WHERE a=21; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE FROM v1_invoker WHERE a=22; DELETE FROM v1_definer WHERE a=23; --connection default @@ -137,10 +137,10 @@ CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1; --eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer --connection user --replace_result $MTR_SUITE_DIR MTR_SUITE_DIR ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR --eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE t1 --replace_result $MTR_SUITE_DIR MTR_SUITE_DIR ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR --eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker --replace_result $MTR_SUITE_DIR MTR_SUITE_DIR --eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer @@ -156,7 +156,7 @@ INSERT INTO t1 VALUES (10); TRUNCATE TABLE t1; INSERT INTO t1 VALUES (11); --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR TRUNCATE TABLE t1; --connection default DROP TABLE t1; @@ -168,7 +168,7 @@ DROP TABLE t1; CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; INSERT INTO t1 VALUES (10); --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DROP TABLE t1; --connection default DROP TABLE t1; @@ -193,7 +193,7 @@ DROP TABLE t1; --echo # Testing SQLCOM_CREATE_TABLE --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; --connection default @@ -216,13 +216,13 @@ UNLOCK TABLES; LOCK TABLE v1_definer WRITE; UNLOCK TABLES; --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR LOCK TABLE t1 READ; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR LOCK TABLE t1 WRITE; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR LOCK TABLE v1_invoker READ; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR LOCK TABLE v1_invoker WRITE; LOCK TABLE v1_definer READ; UNLOCK TABLES; @@ -299,108 +299,108 @@ UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; --connection user # All queries with t1 should fail ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; # All queries with t2 should fail ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t2 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t2 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t2 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t2 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t2 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t2 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t2 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; # t3 does not need FILE_ALC ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t3 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t3 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; # This is OK: UPDATE t3 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t3 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; # This is OK: UPDATE t3 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t3 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; # This is OK: UPDATE t3 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; # All queries with v1_invoker should fail ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; # v1_definer does not need FILE_ACL from the invoker ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v1_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v1_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v1_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; # All queries with v2_invoker should fail ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; # v2_definer does not need FILE_ACL from the invoker ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v2_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v2_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a; UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a; @@ -476,108 +476,108 @@ DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a; --connection user # All queries with t1 should fail ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t1 a1,t1 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t1 a1,t2 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t1 a1,t3 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t1 a1,v1_invoker a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t1 a1,v1_definer a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t1 a1,v2_invoker a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t1 a1,v2_definer a2 WHERE a1.a=a2.a; # All queries with t2 should fail ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t2 a1,t1 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t2 a1,t2 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t2 a1,t3 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t2 a1,v1_invoker a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t2 a1,v1_definer a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t2 a1,v2_invoker a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t2 a1,v2_definer a2 WHERE a1.a=a2.a; # t3 does not need FILE_ALC ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t3 a1,t1 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t3 a1,t2 a2 WHERE a1.a=a2.a; # This is OK: DELETE a1 FROM t3 a1,t3 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t3 a1,v1_invoker a2 WHERE a1.a=a2.a; # This is OK: DELETE a1 FROM t3 a1,v1_definer a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM t3 a1,v2_invoker a2 WHERE a1.a=a2.a; # This is OK: DELETE a1 FROM t3 a1,v2_definer a2 WHERE a1.a=a2.a; # All queries with v1_invoker should fail ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_invoker a1,t1 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_invoker a1,t2 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_invoker a1,t3 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_invoker a1,v1_invoker a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_invoker a1,v1_definer a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_invoker a1,v2_invoker a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_invoker a1,v2_definer a2 WHERE a1.a=a2.a; # v1_definer does not need FILE_ACL from the invoker ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_definer a1,t1 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_definer a1,t2 a2 WHERE a1.a=a2.a; DELETE a1 FROM v1_definer a1,t3 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_definer a1,v1_invoker a2 WHERE a1.a=a2.a; DELETE a1 FROM v1_definer a1,v1_definer a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v1_definer a1,v2_invoker a2 WHERE a1.a=a2.a; DELETE a1 FROM v1_definer a1,v2_definer a2 WHERE a1.a=a2.a; # All queries with v2_invoker should fail ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_invoker a1,t1 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_invoker a1,t2 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_invoker a1,t3 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_invoker a1,v1_invoker a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_invoker a1,v1_definer a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_invoker a1,v2_invoker a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_invoker a1,v2_definer a2 WHERE a1.a=a2.a; # v2_definer does not need FILE_ACL from the invoker ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_definer a1,t1 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_definer a1,t2 a2 WHERE a1.a=a2.a; DELETE a1 FROM v2_definer a1,t3 a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_definer a1,v1_invoker a2 WHERE a1.a=a2.a; DELETE a1 FROM v2_definer a1,v1_definer a2 WHERE a1.a=a2.a; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a; DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a; @@ -598,9 +598,9 @@ DROP VIEW v2; CREATE VIEW v2 AS SELECT * FROM v1_definer; DROP VIEW v2; --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CREATE VIEW v2 AS SELECT * FROM t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CREATE VIEW v2 AS SELECT * FROM v1_invoker; CREATE VIEW v2 AS SELECT * FROM v1_definer; DROP VIEW v2; @@ -625,21 +625,21 @@ INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20; INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20; INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20; --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO t1 SELECT * FROM t1 WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO t1 SELECT * FROM v1_invoker WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO t1 SELECT * FROM v1_definer WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO v1_invoker SELECT * FROM t1 WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO v1_invoker SELECT * FROM v1_definer WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20; # This is OK: INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20; @@ -650,7 +650,7 @@ DROP TABLE t1; --echo # Testing SQLCOM_REPLACE_SELECT # REPLACE is not supported by CONNECT -# so we're testing ER_NOT_ALLOWED_COMMAND vs ER_ACCESS_DENIED_ERROR here +# so we're testing ER_NOT_ALLOWED_COMMAND vs ER_SPECIFIC_ACCESS_DENIED_ERROR here --connection default CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; INSERT INTO t1 VALUES (10); @@ -676,17 +676,17 @@ REPLACE INTO v1_definer SELECT * FROM v1_invoker WHERE a=20; REPLACE INTO v1_definer SELECT * FROM v1_definer WHERE a=20; --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR REPLACE INTO t1 SELECT * FROM t1 WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR REPLACE INTO t1 SELECT * FROM v1_invoker WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR REPLACE INTO t1 SELECT * FROM v1_definer WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR REPLACE INTO v1_invoker SELECT * FROM t1 WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR REPLACE INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR REPLACE INTO v1_invoker SELECT * FROM v1_definer WHERE a=20; --error ER_NOT_ALLOWED_COMMAND REPLACE INTO v1_definer SELECT * FROM t1 WHERE a=20; @@ -708,7 +708,7 @@ SHOW CREATE TABLE t2; RENAME TABLE t2 TO t1; --connection user # TODO: Perhaps FILE_ACL is needed for RENAME. Discuss with Oliver. ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR RENAME TABLE t1 TO t2; --connection default DROP TABLE t1; @@ -723,7 +723,7 @@ SHOW CREATE TABLE t2; ALTER TABLE t2 RENAME TO t1; --connection user # TODO: Perhaps FILE_ACL is not needed for ALTER..RENAME. Discuss with Olivier. ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 RENAME TO t2; --connection default DROP TABLE t1; @@ -739,7 +739,7 @@ DROP TABLE t1; CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; INSERT INTO t1 VALUES (10); --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 ENGINE=MyISAM; --connection default DROP TABLE t1; @@ -756,7 +756,7 @@ DROP TABLE t1; CREATE TABLE t1 (a INT) ENGINE=MyISAM; INSERT INTO t1 VALUES (10); --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; --connection default DROP TABLE t1; @@ -779,7 +779,7 @@ CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix'; INSERT INTO t1 VALUES (10); ALTER TABLE t1 ADD b INT; --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 ADD c INT; --connection default DROP TABLE t1; @@ -791,7 +791,7 @@ CREATE TABLE t1 (a INT,b INT,c INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1. INSERT INTO t1 VALUES (10,10,10); ALTER TABLE t1 DROP b; --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 DROP c; --connection default DROP TABLE t1; @@ -803,7 +803,7 @@ CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FI INSERT INTO t1 VALUES (10,10); ALTER TABLE t1 ADD KEY(a); --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 ADD KEY(b); --connection default DROP TABLE t1; @@ -816,7 +816,7 @@ CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL, KEY a(a), KEY b(b)) ENGINE=CONNE INSERT INTO t1 VALUES (10,10); ALTER TABLE t1 DROP KEY a; --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 DROP KEY b; --connection default DROP TABLE t1; @@ -831,9 +831,9 @@ CREATE INDEX a ON t1 (a); DROP INDEX a ON t1; CREATE INDEX a ON t1 (a); --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CREATE INDEX b ON t1 (b); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DROP INDEX a ON t1; --connection default DROP TABLE t1; @@ -852,11 +852,11 @@ CALL p_definer(); DROP TABLE t1; CALL p_invoker(); DROP TABLE t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CALL p_baddefiner(); --connection user ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CALL p_invoker(); CALL p_definer(); diff --git a/storage/connect/mysql-test/connect/t/ini_grant.test b/storage/connect/mysql-test/connect/t/ini_grant.test index b0ddcb57979..bbf85e5f794 100644 --- a/storage/connect/mysql-test/connect/t/ini_grant.test +++ b/storage/connect/mysql-test/connect/t/ini_grant.test @@ -29,7 +29,7 @@ DROP TABLE t1; # Making sure DROP erased the data file --error 1 --remove_file $MYSQLD_DATADIR/test/t1.ini ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT'; --connection default SELECT user(); @@ -37,21 +37,21 @@ CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CON INSERT INTO t1 VALUES ('sec1','val1'); --connection user SELECT user(); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO t1 VALUES ('sec2','val2'); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 SET val='val11'; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE FROM t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR TRUNCATE TABLE t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 READONLY=1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DROP TABLE t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CREATE VIEW v1 AS SELECT * FROM t1; --echo # Testing a VIEW created with FILE privileges but accessed with no FILE --connection default @@ -59,13 +59,13 @@ SELECT user(); CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1; --connection user SELECT user(); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM v1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO v1 VALUES ('sec3','val3'); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1 SET val='val11'; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE FROM v1; --disconnect user --connection default diff --git a/storage/connect/mysql-test/connect/t/mysql_grant.test b/storage/connect/mysql-test/connect/t/mysql_grant.test index 7d3d05cb8fd..30737258a1f 100644 --- a/storage/connect/mysql-test/connect/t/mysql_grant.test +++ b/storage/connect/mysql-test/connect/t/mysql_grant.test @@ -27,7 +27,7 @@ set sql_mode=default; --connection user SELECT user(); --replace_result $PORT PORT ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR --eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL OPTION_LIST='host=localhost,user=root1,port=$PORT' --connection default SELECT user(); @@ -38,19 +38,19 @@ INSERT INTO t1remote VALUES (10),(20),(30); SELECT * FROM t1; --connection user SELECT user(); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO t1 VALUES ('xxx'); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE FROM t1 WHERE a='xxx'; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE t1 SET a='yyy' WHERE a='xxx'; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR TRUNCATE TABLE t1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR ALTER TABLE t1 READONLY=1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR CREATE VIEW v1 AS SELECT * FROM t1; --echo # Testing a VIEW created with FILE privileges but accessed with no FILE @@ -59,13 +59,13 @@ SELECT user(); CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1; --connection user SELECT user(); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR SELECT * FROM v1; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR INSERT INTO v1 VALUES (2); ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR UPDATE v1 SET a=123; ---error ER_ACCESS_DENIED_ERROR +--error ER_SPECIFIC_ACCESS_DENIED_ERROR DELETE FROM v1; --disconnect user From c075c7a861e4d6062d02ac07fe496f9021601b50 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 10 Sep 2019 17:31:10 +0200 Subject: [PATCH 36/68] MDEV-20549 SQL SECURITY DEFINER does not work for INFORMATION_SCHEMA tables switch to definer privileges when populating I_S tables --- mysql-test/r/information_schema_db.result | 79 +++++ .../suite/funcs_1/r/is_basics_mixed.result | 2 +- .../suite/funcs_1/t/is_basics_mixed.test | 5 +- .../innodb/r/information_schema_grants.result | 304 +++++++++++++++++ .../innodb/t/information_schema_grants.opt | 33 ++ .../innodb/t/information_schema_grants.test | 311 ++++++++++++++++++ mysql-test/t/information_schema_db.test | 44 +++ sql/sql_show.cc | 1 + 8 files changed, 776 insertions(+), 3 deletions(-) create mode 100644 mysql-test/suite/innodb/r/information_schema_grants.result create mode 100644 mysql-test/suite/innodb/t/information_schema_grants.opt create mode 100644 mysql-test/suite/innodb/t/information_schema_grants.test diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index ca1ab45b98b..6cc158a567e 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -244,3 +244,82 @@ connection user1; disconnect user1; connection default; set global sql_mode=default; +create user foo@localhost; +grant select on test.* to foo@localhost; +create procedure rootonly() select 1; +create sql security definer view v1d as select current_user(),user from information_schema.processlist; +create sql security invoker view v1i as select current_user(),user from information_schema.processlist; +create sql security definer view v2d as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%'; +create sql security invoker view v2i as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%'; +create sql security definer view v3d as select schema_name from information_schema.schemata where schema_name like '%mysql%'; +create sql security invoker view v3i as select schema_name from information_schema.schemata where schema_name like '%mysql%'; +create sql security definer view v4d as select routine_name from information_schema.routines where routine_schema='test'; +create sql security invoker view v4i as select routine_name from information_schema.routines where routine_schema='test'; +create sql security definer view v5d as select view_definition > '' from information_schema.views where table_name='v1d'; +create sql security invoker view v5i as select view_definition > '' from information_schema.views where table_name='v1d'; +connect foo,localhost,foo; +select * from v1d; +current_user() user +root@localhost root +root@localhost root +select * from v1i; +current_user() user +foo@localhost foo +select * from v2d; +table_name +user +select * from v2i; +table_name +select * from v3d; +schema_name +mysql +select * from v3i; +schema_name +select * from v4d; +routine_name +rootonly +select * from v4i; +routine_name +select * from v5d; +view_definition > '' +1 +select * from v5i; +view_definition > '' +0 +connection default; +select * from v1d; +current_user() user +root@localhost foo +root@localhost root +select * from v1i; +current_user() user +root@localhost foo +root@localhost root +select * from v2d; +table_name +user +select * from v2i; +table_name +user +select * from v3d; +schema_name +mysql +select * from v3i; +schema_name +mysql +select * from v4d; +routine_name +rootonly +select * from v4i; +routine_name +rootonly +select * from v5d; +view_definition > '' +1 +select * from v5i; +view_definition > '' +1 +disconnect foo; +drop view v1d, v1i, v2d, v2i, v3d, v3i, v4d, v4i, v5d, v5i; +drop user foo@localhost; +drop procedure rootonly; diff --git a/mysql-test/suite/funcs_1/r/is_basics_mixed.result b/mysql-test/suite/funcs_1/r/is_basics_mixed.result index 2d14ada4f89..770435475a3 100644 --- a/mysql-test/suite/funcs_1/r/is_basics_mixed.result +++ b/mysql-test/suite/funcs_1/r/is_basics_mixed.result @@ -337,7 +337,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE SELECT * FROM information_schema.schema_privileges WHERE table_schema = 'information_schema'; GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE -CREATE VIEW db_datadict.v2 AS +CREATE SQL SECURITY INVOKER VIEW db_datadict.v2 AS SELECT TABLE_SCHEMA,TABLE_NAME,TABLE_TYPE FROM information_schema.tables WHERE table_schema = 'db_datadict'; SELECT TABLE_SCHEMA,TABLE_NAME,TABLE_TYPE diff --git a/mysql-test/suite/funcs_1/t/is_basics_mixed.test b/mysql-test/suite/funcs_1/t/is_basics_mixed.test index c0b03a84478..2bbd751a010 100644 --- a/mysql-test/suite/funcs_1/t/is_basics_mixed.test +++ b/mysql-test/suite/funcs_1/t/is_basics_mixed.test @@ -281,8 +281,9 @@ WHERE table_schema = 'information_schema'; # 2. This user (testuser1) is also able to GRANT the SELECT privilege # on this VIEW to another user (testuser2). # 3. The other user (testuser2) must be able to SELECT on this VIEW -# but gets a different result set than testuser1. -CREATE VIEW db_datadict.v2 AS +# but gets a different result set than testuser1, if the view +# has SQL SECURITY INVOKER. +CREATE SQL SECURITY INVOKER VIEW db_datadict.v2 AS SELECT TABLE_SCHEMA,TABLE_NAME,TABLE_TYPE FROM information_schema.tables WHERE table_schema = 'db_datadict'; SELECT TABLE_SCHEMA,TABLE_NAME,TABLE_TYPE diff --git a/mysql-test/suite/innodb/r/information_schema_grants.result b/mysql-test/suite/innodb/r/information_schema_grants.result new file mode 100644 index 00000000000..6ef1ce170cd --- /dev/null +++ b/mysql-test/suite/innodb/r/information_schema_grants.result @@ -0,0 +1,304 @@ +select plugin_name,plugin_status as 'Must be ACTIVE' from information_schema.plugins where plugin_name like 'inno%' and plugin_status!='ACTIVE'; +plugin_name Must be ACTIVE +create user select_only@localhost; +grant select on *.* to select_only@localhost; +connect select_only,localhost,select_only; +connection default; +create sql security invoker view i_buffer_page as select * from information_schema.innodb_buffer_page; +create sql security definer view d_buffer_page as select * from information_schema.innodb_buffer_page; +create sql security invoker view i_buffer_page_lru as select * from information_schema.innodb_buffer_page_lru; +create sql security definer view d_buffer_page_lru as select * from information_schema.innodb_buffer_page_lru; +create sql security invoker view i_buffer_pool_stats as select * from information_schema.innodb_buffer_pool_stats; +create sql security definer view d_buffer_pool_stats as select * from information_schema.innodb_buffer_pool_stats; +create sql security invoker view i_cmp as select * from information_schema.innodb_cmp; +create sql security definer view d_cmp as select * from information_schema.innodb_cmp; +create sql security invoker view i_cmp_per_index as select * from information_schema.innodb_cmp_per_index; +create sql security definer view d_cmp_per_index as select * from information_schema.innodb_cmp_per_index; +create sql security invoker view i_cmp_per_index_reset as select * from information_schema.innodb_cmp_per_index_reset; +create sql security definer view d_cmp_per_index_reset as select * from information_schema.innodb_cmp_per_index_reset; +create sql security invoker view i_cmp_reset as select * from information_schema.innodb_cmp_reset; +create sql security definer view d_cmp_reset as select * from information_schema.innodb_cmp_reset; +create sql security invoker view i_cmpmem as select * from information_schema.innodb_cmpmem; +create sql security definer view d_cmpmem as select * from information_schema.innodb_cmpmem; +create sql security invoker view i_cmpmem_reset as select * from information_schema.innodb_cmpmem_reset; +create sql security definer view d_cmpmem_reset as select * from information_schema.innodb_cmpmem_reset; +create sql security invoker view i_ft_being_deleted as select * from information_schema.innodb_ft_being_deleted; +create sql security definer view d_ft_being_deleted as select * from information_schema.innodb_ft_being_deleted; +create sql security invoker view i_ft_config as select * from information_schema.innodb_ft_config; +create sql security definer view d_ft_config as select * from information_schema.innodb_ft_config; +create sql security invoker view i_ft_default_stopword as select * from information_schema.innodb_ft_default_stopword; +create sql security definer view d_ft_default_stopword as select * from information_schema.innodb_ft_default_stopword; +create sql security invoker view i_ft_deleted as select * from information_schema.innodb_ft_deleted; +create sql security definer view d_ft_deleted as select * from information_schema.innodb_ft_deleted; +create sql security invoker view i_ft_index_cache as select * from information_schema.innodb_ft_index_cache; +create sql security definer view d_ft_index_cache as select * from information_schema.innodb_ft_index_cache; +create sql security invoker view i_ft_index_table as select * from information_schema.innodb_ft_index_table; +create sql security definer view d_ft_index_table as select * from information_schema.innodb_ft_index_table; +create sql security invoker view i_lock_waits as select * from information_schema.innodb_lock_waits; +create sql security definer view d_lock_waits as select * from information_schema.innodb_lock_waits; +create sql security invoker view i_locks as select * from information_schema.innodb_locks; +create sql security definer view d_locks as select * from information_schema.innodb_locks; +create sql security invoker view i_metrics as select * from information_schema.innodb_metrics; +create sql security definer view d_metrics as select * from information_schema.innodb_metrics; +create sql security invoker view i_mutexes as select * from information_schema.innodb_mutexes; +create sql security definer view d_mutexes as select * from information_schema.innodb_mutexes; +create sql security invoker view i_sys_columns as select * from information_schema.innodb_sys_columns; +create sql security definer view d_sys_columns as select * from information_schema.innodb_sys_columns; +create sql security invoker view i_sys_datafiles as select * from information_schema.innodb_sys_datafiles; +create sql security definer view d_sys_datafiles as select * from information_schema.innodb_sys_datafiles; +create sql security invoker view i_sys_fields as select * from information_schema.innodb_sys_fields; +create sql security definer view d_sys_fields as select * from information_schema.innodb_sys_fields; +create sql security invoker view i_sys_foreign as select * from information_schema.innodb_sys_foreign; +create sql security definer view d_sys_foreign as select * from information_schema.innodb_sys_foreign; +create sql security invoker view i_sys_foreign_cols as select * from information_schema.innodb_sys_foreign_cols; +create sql security definer view d_sys_foreign_cols as select * from information_schema.innodb_sys_foreign_cols; +create sql security invoker view i_sys_indexes as select * from information_schema.innodb_sys_indexes; +create sql security definer view d_sys_indexes as select * from information_schema.innodb_sys_indexes; +create sql security invoker view i_sys_semaphore_waits as select * from information_schema.innodb_sys_semaphore_waits; +create sql security definer view d_sys_semaphore_waits as select * from information_schema.innodb_sys_semaphore_waits; +create sql security invoker view i_sys_tables as select * from information_schema.innodb_sys_tables; +create sql security definer view d_sys_tables as select * from information_schema.innodb_sys_tables; +create sql security invoker view i_sys_tablespaces as select * from information_schema.innodb_sys_tablespaces; +create sql security definer view d_sys_tablespaces as select * from information_schema.innodb_sys_tablespaces; +create sql security invoker view i_sys_tablestats as select * from information_schema.innodb_sys_tablestats; +create sql security definer view d_sys_tablestats as select * from information_schema.innodb_sys_tablestats; +create sql security invoker view i_sys_virtual as select * from information_schema.innodb_sys_virtual; +create sql security definer view d_sys_virtual as select * from information_schema.innodb_sys_virtual; +create sql security invoker view i_tablespaces_encryption as select * from information_schema.innodb_tablespaces_encryption; +create sql security definer view d_tablespaces_encryption as select * from information_schema.innodb_tablespaces_encryption; +create sql security invoker view i_tablespaces_scrubbing as select * from information_schema.innodb_tablespaces_scrubbing; +create sql security definer view d_tablespaces_scrubbing as select * from information_schema.innodb_tablespaces_scrubbing; +create sql security invoker view i_trx as select * from information_schema.innodb_trx; +create sql security definer view d_trx as select * from information_schema.innodb_trx; +connection select_only; +select count(*) > -1 from information_schema.innodb_buffer_page; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_buffer_page; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_buffer_page; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_buffer_page_lru; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_buffer_page_lru; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_buffer_page_lru; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_buffer_pool_stats; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_buffer_pool_stats; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_buffer_pool_stats; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_cmp; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_cmp; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_cmp; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_cmp_per_index; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_cmp_per_index; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_cmp_per_index; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_cmp_per_index_reset; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_cmp_per_index_reset; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_cmp_per_index_reset; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_cmp_reset; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_cmp_reset; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_cmp_reset; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_cmpmem; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_cmpmem; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_cmpmem; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_cmpmem_reset; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_cmpmem_reset; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_cmpmem_reset; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_ft_being_deleted; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_ft_being_deleted; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_ft_being_deleted; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_ft_config; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_ft_config; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_ft_config; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_ft_default_stopword; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_ft_deleted; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_ft_deleted; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_ft_deleted; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_ft_index_cache; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_ft_index_cache; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_ft_index_cache; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_ft_index_table; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_ft_index_table; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_ft_index_table; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_lock_waits; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_lock_waits; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_lock_waits; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_locks; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_locks; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_locks; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_metrics; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_metrics; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_metrics; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_mutexes; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_mutexes; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_mutexes; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_columns; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_columns; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_columns; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_datafiles; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_datafiles; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_datafiles; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_fields; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_fields; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_fields; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_foreign; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_foreign; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_foreign; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_foreign_cols; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_foreign_cols; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_foreign_cols; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_indexes; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_indexes; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_indexes; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_semaphore_waits; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_semaphore_waits; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_semaphore_waits; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_tables; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_tables; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_tables; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_tablespaces; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_tablespaces; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_tablespaces; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_tablestats; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_tablestats; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_tablestats; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_sys_virtual; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_sys_virtual; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_sys_virtual; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_tablespaces_encryption; +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation +select count(*) > -1 from i_tablespaces_encryption; +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation +select count(*) > -1 from d_tablespaces_encryption; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_tablespaces_scrubbing; +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation +select count(*) > -1 from i_tablespaces_scrubbing; +ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation +select count(*) > -1 from d_tablespaces_scrubbing; +count(*) > -1 +1 +select count(*) > -1 from information_schema.innodb_trx; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from i_trx; +ERROR 42000: Access denied; you need (at least one of) the PROCESS privilege(s) for this operation +select count(*) > -1 from d_trx; +count(*) > -1 +1 +connection default; +drop database test; +create database test; +drop user select_only@localhost; diff --git a/mysql-test/suite/innodb/t/information_schema_grants.opt b/mysql-test/suite/innodb/t/information_schema_grants.opt new file mode 100644 index 00000000000..ce08c46f047 --- /dev/null +++ b/mysql-test/suite/innodb/t/information_schema_grants.opt @@ -0,0 +1,33 @@ +--enable-plugin-innodb-trx +--enable-plugin-innodb-locks +--enable-plugin-innodb-lock-waits +--enable-plugin-innodb-cmp +--enable-plugin-innodb-cmp-reset +--enable-plugin-innodb-cmpmem +--enable-plugin-innodb-cmpmem-reset +--enable-plugin-innodb-cmp-per-index +--enable-plugin-innodb-cmp-per-index-reset +--enable-plugin-innodb-buffer-page +--enable-plugin-innodb-buffer-page-lru +--enable-plugin-innodb-buffer-pool-stats +--enable-plugin-innodb-metrics +--enable-plugin-innodb-ft-default-stopword +--enable-plugin-innodb-ft-deleted +--enable-plugin-innodb-ft-being-deleted +--enable-plugin-innodb-ft-config +--enable-plugin-innodb-ft-index-cache +--enable-plugin-innodb-ft-index-table +--enable-plugin-innodb-sys-tables +--enable-plugin-innodb-sys-tablestats +--enable-plugin-innodb-sys-indexes +--enable-plugin-innodb-sys-columns +--enable-plugin-innodb-sys-fields +--enable-plugin-innodb-sys-foreign +--enable-plugin-innodb-sys-foreign-cols +--enable-plugin-innodb-sys-tablespaces +--enable-plugin-innodb-sys-datafiles +--enable-plugin-innodb-sys-virtual +--enable-plugin-innodb-mutexes +--enable-plugin-innodb-sys-semaphore-waits +--enable-plugin-innodb-tablespaces-encryption +--enable-plugin-innodb-tablespaces-scrubbing diff --git a/mysql-test/suite/innodb/t/information_schema_grants.test b/mysql-test/suite/innodb/t/information_schema_grants.test new file mode 100644 index 00000000000..34565f76352 --- /dev/null +++ b/mysql-test/suite/innodb/t/information_schema_grants.test @@ -0,0 +1,311 @@ +source include/have_innodb.inc; +source include/not_embedded.inc; + +# make sure we've enabled everything: +select plugin_name,plugin_status as 'Must be ACTIVE' from information_schema.plugins where plugin_name like 'inno%' and plugin_status!='ACTIVE'; + +create user select_only@localhost; +grant select on *.* to select_only@localhost; + +connect select_only,localhost,select_only; +connection default; + +create sql security invoker view i_buffer_page as select * from information_schema.innodb_buffer_page; +create sql security definer view d_buffer_page as select * from information_schema.innodb_buffer_page; + +create sql security invoker view i_buffer_page_lru as select * from information_schema.innodb_buffer_page_lru; +create sql security definer view d_buffer_page_lru as select * from information_schema.innodb_buffer_page_lru; + +create sql security invoker view i_buffer_pool_stats as select * from information_schema.innodb_buffer_pool_stats; +create sql security definer view d_buffer_pool_stats as select * from information_schema.innodb_buffer_pool_stats; + +create sql security invoker view i_cmp as select * from information_schema.innodb_cmp; +create sql security definer view d_cmp as select * from information_schema.innodb_cmp; + +create sql security invoker view i_cmp_per_index as select * from information_schema.innodb_cmp_per_index; +create sql security definer view d_cmp_per_index as select * from information_schema.innodb_cmp_per_index; + +create sql security invoker view i_cmp_per_index_reset as select * from information_schema.innodb_cmp_per_index_reset; +create sql security definer view d_cmp_per_index_reset as select * from information_schema.innodb_cmp_per_index_reset; + +create sql security invoker view i_cmp_reset as select * from information_schema.innodb_cmp_reset; +create sql security definer view d_cmp_reset as select * from information_schema.innodb_cmp_reset; + +create sql security invoker view i_cmpmem as select * from information_schema.innodb_cmpmem; +create sql security definer view d_cmpmem as select * from information_schema.innodb_cmpmem; + +create sql security invoker view i_cmpmem_reset as select * from information_schema.innodb_cmpmem_reset; +create sql security definer view d_cmpmem_reset as select * from information_schema.innodb_cmpmem_reset; + +create sql security invoker view i_ft_being_deleted as select * from information_schema.innodb_ft_being_deleted; +create sql security definer view d_ft_being_deleted as select * from information_schema.innodb_ft_being_deleted; + +create sql security invoker view i_ft_config as select * from information_schema.innodb_ft_config; +create sql security definer view d_ft_config as select * from information_schema.innodb_ft_config; + +create sql security invoker view i_ft_default_stopword as select * from information_schema.innodb_ft_default_stopword; +create sql security definer view d_ft_default_stopword as select * from information_schema.innodb_ft_default_stopword; + +create sql security invoker view i_ft_deleted as select * from information_schema.innodb_ft_deleted; +create sql security definer view d_ft_deleted as select * from information_schema.innodb_ft_deleted; + +create sql security invoker view i_ft_index_cache as select * from information_schema.innodb_ft_index_cache; +create sql security definer view d_ft_index_cache as select * from information_schema.innodb_ft_index_cache; + +create sql security invoker view i_ft_index_table as select * from information_schema.innodb_ft_index_table; +create sql security definer view d_ft_index_table as select * from information_schema.innodb_ft_index_table; + +create sql security invoker view i_lock_waits as select * from information_schema.innodb_lock_waits; +create sql security definer view d_lock_waits as select * from information_schema.innodb_lock_waits; + +create sql security invoker view i_locks as select * from information_schema.innodb_locks; +create sql security definer view d_locks as select * from information_schema.innodb_locks; + +create sql security invoker view i_metrics as select * from information_schema.innodb_metrics; +create sql security definer view d_metrics as select * from information_schema.innodb_metrics; + +create sql security invoker view i_mutexes as select * from information_schema.innodb_mutexes; +create sql security definer view d_mutexes as select * from information_schema.innodb_mutexes; + +create sql security invoker view i_sys_columns as select * from information_schema.innodb_sys_columns; +create sql security definer view d_sys_columns as select * from information_schema.innodb_sys_columns; + +create sql security invoker view i_sys_datafiles as select * from information_schema.innodb_sys_datafiles; +create sql security definer view d_sys_datafiles as select * from information_schema.innodb_sys_datafiles; + +create sql security invoker view i_sys_fields as select * from information_schema.innodb_sys_fields; +create sql security definer view d_sys_fields as select * from information_schema.innodb_sys_fields; + +create sql security invoker view i_sys_foreign as select * from information_schema.innodb_sys_foreign; +create sql security definer view d_sys_foreign as select * from information_schema.innodb_sys_foreign; + +create sql security invoker view i_sys_foreign_cols as select * from information_schema.innodb_sys_foreign_cols; +create sql security definer view d_sys_foreign_cols as select * from information_schema.innodb_sys_foreign_cols; + +create sql security invoker view i_sys_indexes as select * from information_schema.innodb_sys_indexes; +create sql security definer view d_sys_indexes as select * from information_schema.innodb_sys_indexes; + +create sql security invoker view i_sys_semaphore_waits as select * from information_schema.innodb_sys_semaphore_waits; +create sql security definer view d_sys_semaphore_waits as select * from information_schema.innodb_sys_semaphore_waits; + +create sql security invoker view i_sys_tables as select * from information_schema.innodb_sys_tables; +create sql security definer view d_sys_tables as select * from information_schema.innodb_sys_tables; + +create sql security invoker view i_sys_tablespaces as select * from information_schema.innodb_sys_tablespaces; +create sql security definer view d_sys_tablespaces as select * from information_schema.innodb_sys_tablespaces; + +create sql security invoker view i_sys_tablestats as select * from information_schema.innodb_sys_tablestats; +create sql security definer view d_sys_tablestats as select * from information_schema.innodb_sys_tablestats; + +create sql security invoker view i_sys_virtual as select * from information_schema.innodb_sys_virtual; +create sql security definer view d_sys_virtual as select * from information_schema.innodb_sys_virtual; + +create sql security invoker view i_tablespaces_encryption as select * from information_schema.innodb_tablespaces_encryption; +create sql security definer view d_tablespaces_encryption as select * from information_schema.innodb_tablespaces_encryption; + +create sql security invoker view i_tablespaces_scrubbing as select * from information_schema.innodb_tablespaces_scrubbing; +create sql security definer view d_tablespaces_scrubbing as select * from information_schema.innodb_tablespaces_scrubbing; + +create sql security invoker view i_trx as select * from information_schema.innodb_trx; +create sql security definer view d_trx as select * from information_schema.innodb_trx; + +connection select_only; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_buffer_page; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_buffer_page; +select count(*) > -1 from d_buffer_page; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_buffer_page_lru; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_buffer_page_lru; +select count(*) > -1 from d_buffer_page_lru; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_buffer_pool_stats; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_buffer_pool_stats; +select count(*) > -1 from d_buffer_pool_stats; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_cmp; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_cmp; +select count(*) > -1 from d_cmp; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_cmp_per_index; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_cmp_per_index; +select count(*) > -1 from d_cmp_per_index; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_cmp_per_index_reset; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_cmp_per_index_reset; +select count(*) > -1 from d_cmp_per_index_reset; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_cmp_reset; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_cmp_reset; +select count(*) > -1 from d_cmp_reset; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_cmpmem; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_cmpmem; +select count(*) > -1 from d_cmpmem; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_cmpmem_reset; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_cmpmem_reset; +select count(*) > -1 from d_cmpmem_reset; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_ft_being_deleted; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_ft_being_deleted; +select count(*) > -1 from d_ft_being_deleted; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_ft_config; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_ft_config; +select count(*) > -1 from d_ft_config; + +# non-privileged table +select count(*) > -1 from information_schema.innodb_ft_default_stopword; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_ft_deleted; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_ft_deleted; +select count(*) > -1 from d_ft_deleted; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_ft_index_cache; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_ft_index_cache; +select count(*) > -1 from d_ft_index_cache; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_ft_index_table; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_ft_index_table; +select count(*) > -1 from d_ft_index_table; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_lock_waits; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_lock_waits; +select count(*) > -1 from d_lock_waits; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_locks; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_locks; +select count(*) > -1 from d_locks; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_metrics; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_metrics; +select count(*) > -1 from d_metrics; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_mutexes; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_mutexes; +select count(*) > -1 from d_mutexes; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_columns; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_columns; +select count(*) > -1 from d_sys_columns; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_datafiles; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_datafiles; +select count(*) > -1 from d_sys_datafiles; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_fields; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_fields; +select count(*) > -1 from d_sys_fields; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_foreign; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_foreign; +select count(*) > -1 from d_sys_foreign; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_foreign_cols; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_foreign_cols; +select count(*) > -1 from d_sys_foreign_cols; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_indexes; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_indexes; +select count(*) > -1 from d_sys_indexes; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_semaphore_waits; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_semaphore_waits; +select count(*) > -1 from d_sys_semaphore_waits; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_tables; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_tables; +select count(*) > -1 from d_sys_tables; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_tablespaces; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_tablespaces; +select count(*) > -1 from d_sys_tablespaces; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_tablestats; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_tablestats; +select count(*) > -1 from d_sys_tablestats; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_sys_virtual; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_sys_virtual; +select count(*) > -1 from d_sys_virtual; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_tablespaces_encryption; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_tablespaces_encryption; +select count(*) > -1 from d_tablespaces_encryption; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_tablespaces_scrubbing; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_tablespaces_scrubbing; +select count(*) > -1 from d_tablespaces_scrubbing; + +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from information_schema.innodb_trx; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +select count(*) > -1 from i_trx; +select count(*) > -1 from d_trx; + +connection default; +drop database test; +create database test; +drop user select_only@localhost; diff --git a/mysql-test/t/information_schema_db.test b/mysql-test/t/information_schema_db.test index 70ad9b5b920..d6d4e9a4d43 100644 --- a/mysql-test/t/information_schema_db.test +++ b/mysql-test/t/information_schema_db.test @@ -255,3 +255,47 @@ disconnect user1; connection default; set global sql_mode=default; + +# +# MDEV-20549 SQL SECURITY DEFINER does not work for INFORMATION_SCHEMA tables +# + +create user foo@localhost; +grant select on test.* to foo@localhost; +create procedure rootonly() select 1; +create sql security definer view v1d as select current_user(),user from information_schema.processlist; +create sql security invoker view v1i as select current_user(),user from information_schema.processlist; +create sql security definer view v2d as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%'; +create sql security invoker view v2i as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%'; +create sql security definer view v3d as select schema_name from information_schema.schemata where schema_name like '%mysql%'; +create sql security invoker view v3i as select schema_name from information_schema.schemata where schema_name like '%mysql%'; +create sql security definer view v4d as select routine_name from information_schema.routines where routine_schema='test'; +create sql security invoker view v4i as select routine_name from information_schema.routines where routine_schema='test'; +create sql security definer view v5d as select view_definition > '' from information_schema.views where table_name='v1d'; +create sql security invoker view v5i as select view_definition > '' from information_schema.views where table_name='v1d'; +connect foo,localhost,foo; +select * from v1d; +select * from v1i; +select * from v2d; +select * from v2i; +select * from v3d; +select * from v3i; +select * from v4d; +select * from v4i; +select * from v5d; +select * from v5i; +connection default; +select * from v1d; +select * from v1i; +select * from v2d; +select * from v2i; +select * from v3d; +select * from v3i; +select * from v4d; +select * from v4i; +select * from v5d; +select * from v5i; +disconnect foo; +drop view v1d, v1i, v2d, v2i, v3d, v3i, v4d, v4i, v5d, v5i; +drop user foo@localhost; +drop procedure rootonly; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 4bc9870f422..8fc0784b77f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -8429,6 +8429,7 @@ bool get_schema_tables_result(JOIN *join, cond= tab->cache_select->cond; } + Switch_to_definer_security_ctx backup_ctx(thd, table_list); if (table_list->schema_table->fill_table(thd, table_list, cond)) { result= 1; From 8bb6b9c63445c733890749ee387aba1c5014cc1c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 18 Sep 2019 14:00:32 +0200 Subject: [PATCH 37/68] gis2 test no longer exists after 3fe38574fbdd --- mysql-test/collections/10.0-compatible.list | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/collections/10.0-compatible.list b/mysql-test/collections/10.0-compatible.list index 4778bde3b78..cccf5b7c0e8 100644 --- a/mysql-test/collections/10.0-compatible.list +++ b/mysql-test/collections/10.0-compatible.list @@ -202,7 +202,6 @@ main.function_defaults_innodb main.gcc296 main.get_diagnostics main.gis -main.gis2 main.gis-alter_table_online main.gis-precise main.gis-rt-precise From c13519312bebc3104510d84157894b7477c09a78 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 25 Oct 2019 17:17:32 +0200 Subject: [PATCH 38/68] MDEV-20799 DROP Virtual Column crashes MariaDB use the correct table for evaluating virtual columns in the InnoDB ALTER TABLE. --- .../suite/vcol/r/vcol_keys_innodb.result | 15 +++++++++++++++ mysql-test/suite/vcol/t/vcol_keys_innodb.opt | 1 + mysql-test/suite/vcol/t/vcol_keys_innodb.test | 18 ++++++++++++++++++ storage/innobase/row/row0merge.cc | 2 +- 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/vcol/t/vcol_keys_innodb.opt diff --git a/mysql-test/suite/vcol/r/vcol_keys_innodb.result b/mysql-test/suite/vcol/r/vcol_keys_innodb.result index c6c05429978..c327b369ea3 100644 --- a/mysql-test/suite/vcol/r/vcol_keys_innodb.result +++ b/mysql-test/suite/vcol/r/vcol_keys_innodb.result @@ -269,3 +269,18 @@ index(col_char,vcol_blob(64)) insert ignore into t1 (pk) values (1),(2); update t1 set col_char = 'foo' where pk = 1; drop table t1; +create table t1 ( +id int not null primary key, +a varchar(200), +b varchar(200), +c int, +va char(200) generated always as (ucase(a)) virtual, +vb char(200) generated always as (ucase(b)) virtual, +key (c,va,vb) +) engine=innodb; +insert t1 (id,a,c) select seq,seq,seq from seq_1_to_330; +select IF(@@innodb_sort_buffer_size < count(*)*200, 'GOOD', 'WRONG SIZE') from t1; +IF(@@innodb_sort_buffer_size < count(*)*200, 'GOOD', 'WRONG SIZE') +GOOD +alter table t1 drop column va; +drop table t1; diff --git a/mysql-test/suite/vcol/t/vcol_keys_innodb.opt b/mysql-test/suite/vcol/t/vcol_keys_innodb.opt new file mode 100644 index 00000000000..778b4443d4f --- /dev/null +++ b/mysql-test/suite/vcol/t/vcol_keys_innodb.opt @@ -0,0 +1 @@ +--innodb-sort-buffer-size=64k diff --git a/mysql-test/suite/vcol/t/vcol_keys_innodb.test b/mysql-test/suite/vcol/t/vcol_keys_innodb.test index 58fb8378ac7..c475dd71a69 100644 --- a/mysql-test/suite/vcol/t/vcol_keys_innodb.test +++ b/mysql-test/suite/vcol/t/vcol_keys_innodb.test @@ -117,3 +117,21 @@ create table t1 ( insert ignore into t1 (pk) values (1),(2); update t1 set col_char = 'foo' where pk = 1; drop table t1; + +# +# MDEV-20799 DROP Virtual Column crashes MariaDB +# +--source include/have_sequence.inc +create table t1 ( + id int not null primary key, + a varchar(200), + b varchar(200), + c int, + va char(200) generated always as (ucase(a)) virtual, + vb char(200) generated always as (ucase(b)) virtual, + key (c,va,vb) +) engine=innodb; +insert t1 (id,a,c) select seq,seq,seq from seq_1_to_330; +select IF(@@innodb_sort_buffer_size < count(*)*200, 'GOOD', 'WRONG SIZE') from t1; +alter table t1 drop column va; +drop table t1; diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 7fba9817b11..b9f32b16bc5 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -2568,7 +2568,7 @@ write_buffers: buf, fts_index, old_table, new_table, psort_info, row, ext, &doc_id, conv_heap, - &err, &v_heap, table, trx)))) { + &err, &v_heap, eval_table, trx)))) { /* An empty buffer should have enough room for at least one record. */ ut_error; From cb14d2e1a5f682a413943294b8137d35ba948a1d Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Mon, 28 Oct 2019 13:29:46 +0530 Subject: [PATCH 39/68] Follow up fix for MDEV-16871 --- sql/mysqld.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index af439d46788..fcb3390e0ff 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4777,7 +4777,6 @@ static int init_common_variables() return 1; } - global_system_variables.in_subquery_conversion_threshold= IN_SUBQUERY_CONVERSION_THRESHOLD; #ifdef WITH_WSREP /* From 396313d301b3567aeadd04ae6a9322da2adc0a8b Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Wed, 22 May 2019 01:54:47 -0700 Subject: [PATCH 40/68] MDEV-14448: Ctrl-C should not exit the client --- client/mysql.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 50d45696a5c..86ee22e5e6a 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1368,12 +1368,21 @@ sig_handler handle_sigint(int sig) char kill_buffer[40]; MYSQL *kill_mysql= NULL; - /* terminate if no query being executed, or we already tried interrupting */ - if (!executing_query || (interrupted_query == 2)) + /* Terminate if we already tried interrupting. */ + if (interrupted_query == 2) { tee_fprintf(stdout, "Ctrl-C -- exit!\n"); goto err; } + /* If no query being executed, don't exit. */ + if (!executing_query) + { + tee_fprintf(stdout, "Ctrl-C\n"); + rl_on_new_line(); // Regenerate the prompt on a newline + rl_replace_line("", 0); // Clear the previous text + rl_redisplay(); + return; + } kill_mysql= mysql_init(kill_mysql); if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password, From 2cc360bdf2a47f968140f5b75c7668f999b36612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 28 Oct 2019 16:03:00 +0200 Subject: [PATCH 41/68] Remove bogus advice Ever since MariaDB 10.0 (and MySQL 5.6.8), the innodb_log_file_size and innodb_log_files_in_group can be changed between server restarts, and the redo log files will be resized on server startup if needed. --- debian/additions/my.cnf | 2 -- 1 file changed, 2 deletions(-) diff --git a/debian/additions/my.cnf b/debian/additions/my.cnf index d30ec182c8b..22103ec09c9 100644 --- a/debian/additions/my.cnf +++ b/debian/additions/my.cnf @@ -131,8 +131,6 @@ max_binlog_size = 100M # InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/. # Read the manual for more InnoDB related options. There are many! default_storage_engine = InnoDB -# you can't just change log file size, requires special procedure -#innodb_log_file_size = 50M innodb_buffer_pool_size = 256M innodb_log_buffer_size = 8M innodb_file_per_table = 1 From 2d82ae5ba3a5c0837238f112f73236e1573bc3c9 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 28 Oct 2019 17:01:32 +0000 Subject: [PATCH 42/68] MDEV-20825 : Innodb does not start if GetDiskFreeSpace() fails. Ignore GetDiskFreeSpace() errors in os_file_get_status_win32 The call is only used to calculate filesystem block size, and this in turn is only shown in information_schema.sys_tablespaces.FS_BLOCK_SIZE. There is no other use of this field, it does not affect any Innodb functionality --- storage/innobase/os/os0file.cc | 38 +++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 6d40d45412f..fc411dad564 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -4749,19 +4749,23 @@ os_file_get_status_win32( CloseHandle(fh); } } + stat_info->block_size = 0; + /* What follows, is calculation of FS block size, which is not important + (it is just shown in I_S innodb tables). The error to calculate it will be ignored.*/ char volname[MAX_PATH]; BOOL result = GetVolumePathName(path, volname, MAX_PATH); - + static bool warned_once = false; if (!result) { - - ib::error() - << "os_file_get_status_win32: " - << "Failed to get the volume path name for: " - << path - << "- OS error number " << GetLastError(); - - return(DB_FAIL); + if (!warned_once) { + ib::warn() + << "os_file_get_status_win32: " + << "Failed to get the volume path name for: " + << path + << "- OS error number " << GetLastError(); + warned_once = true; + } + return(DB_SUCCESS); } DWORD sectorsPerCluster; @@ -4777,15 +4781,15 @@ os_file_get_status_win32( &totalNumberOfClusters); if (!result) { - - ib::error() - << "GetDiskFreeSpace(" << volname << ",...) " - << "failed " - << "- OS error number " << GetLastError(); - - return(DB_FAIL); + if (!warned_once) { + ib::warn() + << "GetDiskFreeSpace(" << volname << ",...) " + << "failed " + << "- OS error number " << GetLastError(); + warned_once = true; + } + return(DB_SUCCESS); } - stat_info->block_size = bytesPerSector * sectorsPerCluster; } else { stat_info->type = OS_FILE_TYPE_UNKNOWN; From 814534745b92dfbc27886358c0def3059ef04539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 29 Oct 2019 17:11:34 +0200 Subject: [PATCH 43/68] MDEV-20917 InnoDB is passing NULL to nonnull function parameters mem_heap_dup(): Avoid mem_heap_alloc() and memcpy() of data=NULL, len=0. trx_undo_report_insert_virtual(), trx_undo_page_report_insert(), trx_undo_page_report_modify(): Avoid memcpy(ptr, NULL, 0). dfield_data_is_binary_equal(): Correctly handle data=NULL, len=0. This clean-up was motivated by WITH_UBSAN, and no bug related to this was observed in the wild. It should be noted that undefined behaviour such as memcpy(ptr, NULL, 0) could allow compilers to perform unsafe optimizations, like it was the case in commit fc168c3a5e58d8b364a2e87e0d876a261ec7fced (MDEV-15587). --- storage/innobase/include/data0data.h | 2 +- storage/innobase/include/data0data.ic | 2 +- storage/innobase/include/mem0mem.h | 27 +++++++++++------- storage/innobase/mem/mem0mem.cc | 15 +--------- storage/innobase/trx/trx0rec.cc | 41 +++++++++++++++------------ 5 files changed, 42 insertions(+), 45 deletions(-) diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h index db321626368..33d03c8a2c9 100644 --- a/storage/innobase/include/data0data.h +++ b/storage/innobase/include/data0data.h @@ -168,7 +168,7 @@ dfield_data_is_binary_equal( const dfield_t* field, /*!< in: field */ ulint len, /*!< in: data length or UNIV_SQL_NULL */ const byte* data) /*!< in: data */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); + MY_ATTRIBUTE((nonnull(1), warn_unused_result)); /*********************************************************************//** Gets info bits in a data tuple. diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic index f6d067bcc8e..295c786a583 100644 --- a/storage/innobase/include/data0data.ic +++ b/storage/innobase/include/data0data.ic @@ -223,7 +223,7 @@ dfield_data_is_binary_equal( const byte* data) /*!< in: data */ { return(len == dfield_get_len(field) - && (len == UNIV_SQL_NULL + && (!len || len == UNIV_SQL_NULL || !memcmp(dfield_get_data(field), data, len))); } diff --git a/storage/innobase/include/mem0mem.h b/storage/innobase/include/mem0mem.h index 0b291e6f365..22c0a04e170 100644 --- a/storage/innobase/include/mem0mem.h +++ b/storage/innobase/include/mem0mem.h @@ -228,7 +228,22 @@ mem_strdupl( const char* str, /*!< in: string to be copied */ ulint len); /*!< in: length of str, in bytes */ -/** Duplicates a NUL-terminated string, allocated from a memory heap. +/** Duplicate a block of data, allocated from a memory heap. +@param[in] heap memory heap where string is allocated +@param[in] data block of data to be copied +@param[in] len length of data, in bytes +@return own: a copy of data */ +inline +void* +mem_heap_dup(mem_heap_t* heap, const void* data, size_t len) +{ + ut_ad(data || !len); + return UNIV_LIKELY(data != NULL) + ? memcpy(mem_heap_alloc(heap, len), data, len) + : NULL; +} + +/** Duplicate a NUL-terminated string, allocated from a memory heap. @param[in] heap memory heap where string is allocated @param[in] str string to be copied @return own: a copy of the string */ @@ -259,16 +274,6 @@ mem_heap_strcat( const char* s1, /*!< in: string 1 */ const char* s2); /*!< in: string 2 */ -/**********************************************************************//** -Duplicate a block of data, allocated from a memory heap. -@return own: a copy of the data */ -void* -mem_heap_dup( -/*=========*/ - mem_heap_t* heap, /*!< in: memory heap where copy is allocated */ - const void* data, /*!< in: data to be copied */ - ulint len); /*!< in: length of data, in bytes */ - /****************************************************************//** A simple sprintf replacement that dynamically allocates the space for the formatted string from the given heap. This supports a very limited set of diff --git a/storage/innobase/mem/mem0mem.cc b/storage/innobase/mem/mem0mem.cc index e53d200b776..557bc864e27 100644 --- a/storage/innobase/mem/mem0mem.cc +++ b/storage/innobase/mem/mem0mem.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. 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 @@ -41,19 +41,6 @@ mem_heap_strdup( return(static_cast(mem_heap_dup(heap, str, strlen(str) + 1))); } -/**********************************************************************//** -Duplicate a block of data, allocated from a memory heap. -@return own: a copy of the data */ -void* -mem_heap_dup( -/*=========*/ - mem_heap_t* heap, /*!< in: memory heap where copy is allocated */ - const void* data, /*!< in: data to be copied */ - ulint len) /*!< in: length of data, in bytes */ -{ - return(memcpy(mem_heap_alloc(heap, len), data, len)); -} - /**********************************************************************//** Concatenate two strings and return the result, using a memory heap. @return own: the result */ diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 3bf5e1d6fcf..e23f29fa735 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -412,9 +412,15 @@ trx_undo_report_insert_virtual( const dfield_t* vfield = dtuple_get_nth_v_field( row, col->v_pos); - ulint flen = vfield->len; + switch (ulint flen = vfield->len) { + case 0: case UNIV_SQL_NULL: + if (trx_undo_left(undo_page, *ptr) < 5) { + return(false); + } - if (flen != UNIV_SQL_NULL) { + *ptr += mach_write_compressed(*ptr, flen); + break; + default: ulint max_len = dict_max_v_field_len_store_undo( table, col_no); @@ -429,15 +435,8 @@ trx_undo_report_insert_virtual( } *ptr += mach_write_compressed(*ptr, flen); - ut_memcpy(*ptr, vfield->data, flen); + memcpy(*ptr, vfield->data, flen); *ptr += flen; - } else { - if (trx_undo_left(undo_page, *ptr) < 5) { - - return(false); - } - - *ptr += mach_write_compressed(*ptr, flen); } } } @@ -506,13 +505,16 @@ trx_undo_page_report_insert( ptr += mach_write_compressed(ptr, flen); - if (flen != UNIV_SQL_NULL) { + switch (flen) { + case 0: case UNIV_SQL_NULL: + break; + default: if (trx_undo_left(undo_page, ptr) < flen) { return(0); } - ut_memcpy(ptr, dfield_get_data(field), flen); + memcpy(ptr, dfield_get_data(field), flen); ptr += flen; } } @@ -981,7 +983,7 @@ trx_undo_page_report_modify( return(0); } - ut_memcpy(ptr, field, flen); + memcpy(ptr, field, flen); ptr += flen; } } @@ -1123,7 +1125,7 @@ trx_undo_page_report_modify( return(0); } - ut_memcpy(ptr, field, flen); + memcpy(ptr, field, flen); ptr += flen; } @@ -1149,7 +1151,7 @@ trx_undo_page_report_modify( return(0); } - ut_memcpy(ptr, field, flen); + memcpy(ptr, field, flen); ptr += flen; } } @@ -1305,7 +1307,7 @@ trx_undo_page_report_modify( return(0); } - ut_memcpy(ptr, field, flen); + memcpy(ptr, field, flen); ptr += flen; } @@ -1391,14 +1393,17 @@ already_logged: ptr += mach_write_compressed(ptr, flen); - if (flen != UNIV_SQL_NULL) { + switch (flen) { + case 0: case UNIV_SQL_NULL: + break; + default: if (trx_undo_left(undo_page, ptr) < flen) { return(0); } - ut_memcpy(ptr, field, flen); + memcpy(ptr, field, flen); ptr += flen; } } From bef843b97f2e91859f2a08845822d619e769f89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 29 Oct 2019 18:20:32 +0200 Subject: [PATCH 44/68] MDEV-20917 InnoDB is passing NULL to nonnull function parameters mem_heap_dup(): Avoid mem_heap_alloc() and memcpy() of data=NULL, len=0. trx_undo_report_insert_virtual(), trx_undo_page_report_insert(), trx_undo_page_report_modify(): Avoid memcpy(ptr, NULL, 0). dfield_data_is_binary_equal(): Correctly handle data=NULL, len=0. rec_init_offsets_temp(): Do allow def_val=NULL in the interface. This clean-up was motivated by WITH_UBSAN, and no bug related to this was observed in the wild. It should be noted that undefined behaviour such as memcpy(ptr, NULL, 0) could allow compilers to perform unsafe optimizations, like it was the case in commit fc168c3a5e58d8b364a2e87e0d876a261ec7fced (MDEV-15587). --- storage/innobase/include/data0data.h | 2 +- storage/innobase/include/data0data.ic | 2 +- storage/innobase/include/mem0mem.h | 5 +++- storage/innobase/include/rem0rec.h | 2 +- storage/innobase/mem/mem0mem.cc | 2 +- storage/innobase/trx/trx0rec.cc | 40 +++++++++++++++------------ 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h index fbbdd3b8f2d..706d65a4469 100644 --- a/storage/innobase/include/data0data.h +++ b/storage/innobase/include/data0data.h @@ -168,7 +168,7 @@ dfield_data_is_binary_equal( const dfield_t* field, /*!< in: field */ ulint len, /*!< in: data length or UNIV_SQL_NULL */ const byte* data) /*!< in: data */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); + MY_ATTRIBUTE((nonnull(1), warn_unused_result)); /*********************************************************************//** Gets info bits in a data tuple. diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic index be0186d53fe..92be8f8c589 100644 --- a/storage/innobase/include/data0data.ic +++ b/storage/innobase/include/data0data.ic @@ -225,7 +225,7 @@ dfield_data_is_binary_equal( { ut_ad(len != UNIV_SQL_DEFAULT); return(len == dfield_get_len(field) - && (len == UNIV_SQL_NULL + && (!len || len == UNIV_SQL_NULL || !memcmp(dfield_get_data(field), data, len))); } diff --git a/storage/innobase/include/mem0mem.h b/storage/innobase/include/mem0mem.h index 6d0f95cba19..fa22b3d3086 100644 --- a/storage/innobase/include/mem0mem.h +++ b/storage/innobase/include/mem0mem.h @@ -237,7 +237,10 @@ inline void* mem_heap_dup(mem_heap_t* heap, const void* data, size_t len) { - return(memcpy(mem_heap_alloc(heap, len), data, len)); + ut_ad(data || !len); + return UNIV_LIKELY(data != NULL) + ? memcpy(mem_heap_alloc(heap, len), data, len) + : NULL; } /** Duplicate a NUL-terminated string, allocated from a memory heap. diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index 54f50058140..0c49c223e10 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -983,7 +983,7 @@ rec_init_offsets_temp( ulint n_core, const dict_col_t::def_t*def_val, rec_comp_status_t status = REC_STATUS_ORDINARY) - MY_ATTRIBUTE((nonnull)); + MY_ATTRIBUTE((nonnull(1,2,3))); /** Determine the offset to each field in temporary file. @param[in] rec temporary file record @param[in] index index of that the record belongs to diff --git a/storage/innobase/mem/mem0mem.cc b/storage/innobase/mem/mem0mem.cc index 929bffb881c..759308faac8 100644 --- a/storage/innobase/mem/mem0mem.cc +++ b/storage/innobase/mem/mem0mem.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. 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 diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 44b9f056770..901dd90c005 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -421,9 +421,15 @@ trx_undo_report_insert_virtual( const dfield_t* vfield = dtuple_get_nth_v_field( row, col->v_pos); - ulint flen = vfield->len; + switch (ulint flen = vfield->len) { + case 0: case UNIV_SQL_NULL: + if (trx_undo_left(undo_block, *ptr) < 5) { + return(false); + } - if (flen != UNIV_SQL_NULL) { + *ptr += mach_write_compressed(*ptr, flen); + break; + default: ulint max_len = dict_max_v_field_len_store_undo( table, col_no); @@ -438,14 +444,8 @@ trx_undo_report_insert_virtual( } *ptr += mach_write_compressed(*ptr, flen); - ut_memcpy(*ptr, vfield->data, flen); + memcpy(*ptr, vfield->data, flen); *ptr += flen; - } else { - if (trx_undo_left(undo_block, *ptr) < 5) { - return(false); - } - - *ptr += mach_write_compressed(*ptr, flen); } } } @@ -524,13 +524,16 @@ trx_undo_page_report_insert( ptr += mach_write_compressed(ptr, flen); - if (flen != UNIV_SQL_NULL) { + switch (flen) { + case 0: case UNIV_SQL_NULL: + break; + default: if (trx_undo_left(undo_block, ptr) < flen) { return(0); } - ut_memcpy(ptr, dfield_get_data(field), flen); + memcpy(ptr, dfield_get_data(field), flen); ptr += flen; } } @@ -998,7 +1001,7 @@ trx_undo_page_report_modify( return(0); } - ut_memcpy(ptr, field, flen); + memcpy(ptr, field, flen); ptr += flen; } } @@ -1129,7 +1132,7 @@ trx_undo_page_report_modify( return(0); } - ut_memcpy(ptr, field, flen); + memcpy(ptr, field, flen); ptr += flen; } @@ -1154,7 +1157,7 @@ trx_undo_page_report_modify( return(0); } - ut_memcpy(ptr, field, flen); + memcpy(ptr, field, flen); ptr += flen; } } @@ -1303,7 +1306,7 @@ trx_undo_page_report_modify( return(0); } - ut_memcpy(ptr, field, flen); + memcpy(ptr, field, flen); ptr += flen; } @@ -1388,13 +1391,16 @@ already_logged: ptr += mach_write_compressed(ptr, flen); - if (flen != UNIV_SQL_NULL) { + switch (flen) { + case 0: case UNIV_SQL_NULL: + break; + default: if (trx_undo_left(undo_block, ptr) < flen) { return(0); } - ut_memcpy(ptr, field, flen); + memcpy(ptr, field, flen); ptr += flen; } } From 84088d9458d2119889149c614993b18d67711a5b Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 29 Oct 2019 21:56:24 +0300 Subject: [PATCH 45/68] add .clang-format file for InnoDB --- storage/innobase/.clang-format | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 storage/innobase/.clang-format diff --git a/storage/innobase/.clang-format b/storage/innobase/.clang-format new file mode 100644 index 00000000000..54f7b47bc88 --- /dev/null +++ b/storage/innobase/.clang-format @@ -0,0 +1,11 @@ +UseTab: Always +TabWidth: 8 +IndentWidth: 8 +ContinuationIndentWidth: 8 +BreakBeforeBinaryOperators: All +PointerAlignment: Left +BreakBeforeBraces: Custom +ColumnLimit: 79 +BraceWrapping: + AfterFunction: true +AccessModifierOffset: -8 From bc8a9ab5f32a73e7e41680f98ba516611bc00ce0 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 29 Oct 2019 23:02:03 +0300 Subject: [PATCH 46/68] remove unused struct members --- dbug/dbug.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/dbug/dbug.c b/dbug/dbug.c index 3035895648e..54eebfe55a5 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -226,11 +226,8 @@ typedef struct _db_code_state_ { const char *file; /* Name of current user file */ struct _db_stack_frame_ *framep; /* Pointer to current frame */ struct settings *stack; /* debugging settings */ - const char *jmpfunc; /* Remember current function for setjmp */ - const char *jmpfile; /* Remember current file for setjmp */ int lineno; /* Current debugger output line number */ uint level; /* Current function nesting level */ - int jmplevel; /* Remember nesting level at setjmp() */ /* * The following variables are used to hold the state information From 20b72a3fad45bd8fc0bf6987fcec0c21b4f36885 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 30 Oct 2019 00:47:50 +0100 Subject: [PATCH 47/68] compilation fix for Windows --- client/mysql.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/mysql.cc b/client/mysql.cc index 86ee22e5e6a..7329f2298ab 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1378,9 +1378,11 @@ sig_handler handle_sigint(int sig) if (!executing_query) { tee_fprintf(stdout, "Ctrl-C\n"); +#ifdef HAVE_READLINE rl_on_new_line(); // Regenerate the prompt on a newline rl_replace_line("", 0); // Clear the previous text rl_redisplay(); +#endif return; } From 44b0c8697135be4139c4431bbf02fbf4433e058f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Oct 2019 06:42:51 +0200 Subject: [PATCH 48/68] Clean up ut_strlcpy(), ut_strlcpy_rev() ut_strlcpy(): Replace with the standard function strncpy(). ut_strlcpy_rev(): Define in the same compilation unit where the only caller resides. Avoid unnecessary definition in non-debug builds. --- storage/innobase/include/ut0mem.h | 24 +-------------- storage/innobase/mem/mem0mem.cc | 11 +++++++ storage/innobase/trx/trx0trx.cc | 3 +- storage/innobase/ut/ut0mem.cc | 50 +------------------------------ 4 files changed, 15 insertions(+), 73 deletions(-) diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h index 49777495cae..32d557d4f2a 100644 --- a/storage/innobase/include/ut0mem.h +++ b/storage/innobase/include/ut0mem.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, MariaDB Corporation. 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 @@ -83,29 +84,6 @@ UNIV_INLINE int ut_strcmp(const char* str1, const char* str2); -/**********************************************************************//** -Copies up to size - 1 characters from the NUL-terminated string src to -dst, NUL-terminating the result. Returns strlen(src), so truncation -occurred if the return value >= size. -@return strlen(src) */ -ulint -ut_strlcpy( -/*=======*/ - char* dst, /*!< in: destination buffer */ - const char* src, /*!< in: source buffer */ - ulint size); /*!< in: size of destination buffer */ - -/**********************************************************************//** -Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last -(size - 1) bytes of src, not the first. -@return strlen(src) */ -ulint -ut_strlcpy_rev( -/*===========*/ - char* dst, /*!< in: destination buffer */ - const char* src, /*!< in: source buffer */ - ulint size); /*!< in: size of destination buffer */ - /******************************************************************** Concatenate 3 strings.*/ char* diff --git a/storage/innobase/mem/mem0mem.cc b/storage/innobase/mem/mem0mem.cc index 557bc864e27..bcdb115812c 100644 --- a/storage/innobase/mem/mem0mem.cc +++ b/storage/innobase/mem/mem0mem.cc @@ -240,6 +240,17 @@ mem_heap_validate( ut_ad(size == heap->total_size); } + +/** Copy the tail of a string. +@param[in,out] dst destination buffer +@param[in] src string whose tail to copy +@param[in] size size of dst buffer, in bytes, including NUL terminator +@return strlen(src) */ +static void ut_strlcpy_rev(char* dst, const char* src, ulint size) +{ + size_t src_size = strlen(src), n = std::min(src_size, size - 1); + memcpy(dst, src + src_size - n, n + 1); +} #endif /* UNIV_DEBUG */ /***************************************************************//** diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 869fe08a6ba..7e72b909e2d 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -72,7 +72,8 @@ trx_set_detailed_error( trx_t* trx, /*!< in: transaction struct */ const char* msg) /*!< in: detailed error message */ { - ut_strlcpy(trx->detailed_error, msg, MAX_DETAILED_ERROR_LEN); + strncpy(trx->detailed_error, msg, MAX_DETAILED_ERROR_LEN - 1); + trx->detailed_error[MAX_DETAILED_ERROR_LEN - 1] = '\0'; } /*************************************************************//** diff --git a/storage/innobase/ut/ut0mem.cc b/storage/innobase/ut/ut0mem.cc index 32a90accd21..faade827283 100644 --- a/storage/innobase/ut/ut0mem.cc +++ b/storage/innobase/ut/ut0mem.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, MariaDB Corporation. 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 @@ -24,55 +25,6 @@ Created 5/11/1994 Heikki Tuuri *************************************************************************/ #include "ut0mem.h" -#include "os0thread.h" -#include "srv0srv.h" -#include - -/**********************************************************************//** -Copies up to size - 1 characters from the NUL-terminated string src to -dst, NUL-terminating the result. Returns strlen(src), so truncation -occurred if the return value >= size. -@return strlen(src) */ -ulint -ut_strlcpy( -/*=======*/ - char* dst, /*!< in: destination buffer */ - const char* src, /*!< in: source buffer */ - ulint size) /*!< in: size of destination buffer */ -{ - ulint src_size = strlen(src); - - if (size != 0) { - ulint n = ut_min(src_size, size - 1); - - memcpy(dst, src, n); - dst[n] = '\0'; - } - - return(src_size); -} - -/**********************************************************************//** -Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last -(size - 1) bytes of src, not the first. -@return strlen(src) */ -ulint -ut_strlcpy_rev( -/*===========*/ - char* dst, /*!< in: destination buffer */ - const char* src, /*!< in: source buffer */ - ulint size) /*!< in: size of destination buffer */ -{ - ulint src_size = strlen(src); - - if (size != 0) { - ulint n = ut_min(src_size, size - 1); - - memcpy(dst, src + src_size - n, n + 1); - } - - return(src_size); -} /******************************************************************** Concatenate 3 strings.*/ From 36a969437845ce9f47a9e6d91514ddc7e00ca83a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 29 Oct 2019 13:11:34 +0200 Subject: [PATCH 49/68] MDEV-18562 [ERROR] InnoDB: WSREP: referenced FK check fail: Lock wait index Lock wait can happen on secondary index when doing FK checks for wsrep. We should just return error to upper layer and applier will retry operation when needed. --- include/mysql/service_wsrep.h | 4 +-- sql/wsrep_dummy.cc | 4 +-- sql/wsrep_mysqld.cc | 48 ++++++++++++++++----------------- storage/innobase/row/row0upd.cc | 14 ++++++++-- 4 files changed, 40 insertions(+), 30 deletions(-) diff --git a/include/mysql/service_wsrep.h b/include/mysql/service_wsrep.h index 3b01d983c06..923ba57fcdc 100644 --- a/include/mysql/service_wsrep.h +++ b/include/mysql/service_wsrep.h @@ -99,7 +99,7 @@ extern struct wsrep_service_st { enum wsrep_conflict_state (*wsrep_thd_get_conflict_state_func)(MYSQL_THD); my_bool (*wsrep_thd_is_BF_func)(MYSQL_THD , my_bool); my_bool (*wsrep_thd_is_wsrep_func)(MYSQL_THD thd); - char * (*wsrep_thd_query_func)(THD *thd); + const char * (*wsrep_thd_query_func)(THD *thd); enum wsrep_query_state (*wsrep_thd_query_state_func)(THD *thd); const char * (*wsrep_thd_query_state_str_func)(THD *thd); int (*wsrep_thd_retry_counter_func)(THD *thd); @@ -182,7 +182,7 @@ extern long wsrep_protocol_version; bool wsrep_consistency_check(THD *thd); bool wsrep_prepare_key(const unsigned char* cache_key, size_t cache_key_len, const unsigned char* row_id, size_t row_id_len, struct wsrep_buf* key, size_t* key_len); -char *wsrep_thd_query(THD *thd); +const char *wsrep_thd_query(THD *thd); const char *wsrep_thd_conflict_state_str(THD *thd); const char *wsrep_thd_exec_mode_str(THD *thd); const char *wsrep_thd_query_state_str(THD *thd); diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc index 2d0a8bcdfa9..b98dd1e5790 100644 --- a/sql/wsrep_dummy.cc +++ b/sql/wsrep_dummy.cc @@ -101,8 +101,8 @@ enum wsrep_conflict_state wsrep_thd_get_conflict_state(THD *) my_bool wsrep_thd_is_wsrep(THD *) { return 0; } -char *wsrep_thd_query(THD *) -{ return 0; } +const char *wsrep_thd_query(THD *) +{ return "NULL"; } enum wsrep_query_state wsrep_thd_query_state(THD *) { return QUERY_IDLE; } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 12a9dc35a6a..5e2e48fd15d 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1594,25 +1594,6 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, } } -static const char* wsrep_get_query_or_msg(const THD* thd) -{ - switch(thd->lex->sql_command) - { - case SQLCOM_CREATE_USER: - return "CREATE USER"; - case SQLCOM_GRANT: - return "GRANT"; - case SQLCOM_REVOKE: - return "REVOKE"; - case SQLCOM_SET_OPTION: - if (thd->lex->definer) - return "SET PASSWORD"; - /* fallthrough */ - default: - return thd->query(); - } -} - /* returns: 0: statement was replicated as TOI @@ -1636,7 +1617,7 @@ static int wsrep_TOI_begin(THD *thd, char *db_, char *table_, } WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), - thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd)); + thd->wsrep_exec_mode, wsrep_thd_query(thd)); switch (thd->lex->sql_command) { @@ -1716,13 +1697,13 @@ static void wsrep_TOI_end(THD *thd) { wsrep_to_isolation--; WSREP_DEBUG("TO END: %lld, %d: %s", (long long)wsrep_thd_trx_seqno(thd), - thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd)); + thd->wsrep_exec_mode, wsrep_thd_query(thd)); wsrep_set_SE_checkpoint(thd->wsrep_trx_meta.gtid.uuid, thd->wsrep_trx_meta.gtid.seqno); WSREP_DEBUG("TO END: %lld, update seqno", (long long)wsrep_thd_trx_seqno(thd)); - + if (WSREP_OK == (ret = wsrep->to_execute_end(wsrep, thd->thread_id))) { WSREP_DEBUG("TO END: %lld", (long long)wsrep_thd_trx_seqno(thd)); } @@ -2674,9 +2655,28 @@ extern "C" query_id_t wsrep_thd_query_id(THD *thd) } -char *wsrep_thd_query(THD *thd) +const char *wsrep_thd_query(THD *thd) { - return (thd) ? thd->query() : NULL; + if (thd) + { + switch(thd->lex->sql_command) + { + case SQLCOM_CREATE_USER: + return "CREATE USER"; + case SQLCOM_GRANT: + return "GRANT"; + case SQLCOM_REVOKE: + return "REVOKE"; + case SQLCOM_SET_OPTION: + if (thd->lex->definer) + return "SET PASSWORD"; + /* fallthrough */ + default: + if (thd->query()) + return thd->query(); + } + } + return "NULL"; } diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 021e3d69f8a..db4b7b18269 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -2472,17 +2472,27 @@ row_upd_sec_index_entry( case DB_NO_REFERENCED_ROW: err = DB_SUCCESS; break; + case DB_LOCK_WAIT: + if (wsrep_debug) { + ib::warn() << "WSREP: sec index FK lock wait" + << " index " << index->name + << " table " << index->table->name + << " query " << wsrep_thd_query(trx->mysql_thd); + } + break; case DB_DEADLOCK: if (wsrep_debug) { ib::warn() << "WSREP: sec index FK check fail for deadlock" << " index " << index->name - << " table " << index->table->name; + << " table " << index->table->name + << " query " << wsrep_thd_query(trx->mysql_thd); } break; default: ib::error() << "WSREP: referenced FK check fail: " << ut_strerr(err) << " index " << index->name - << " table " << index->table->name; + << " table " << index->table->name + << " query " << wsrep_thd_query(trx->mysql_thd); break; } From cd1c10859d77d967aec8590fa9de4d17ed480dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 29 Oct 2019 13:13:31 +0200 Subject: [PATCH 50/68] Fix test cases that use debug galera library. Changes to be committed: modified: mysql-test/suite/galera/r/MW-369.result modified: mysql-test/suite/galera/r/MW-402.result modified: mysql-test/suite/galera/r/galera#500.result modified: mysql-test/suite/galera/r/galera_gcs_fragment.result modified: mysql-test/suite/galera/r/mysql-wsrep#332.result --- mysql-test/suite/galera/r/MW-369.result | 49 +++++++++++++++++-- mysql-test/suite/galera/r/MW-402.result | 8 +-- mysql-test/suite/galera/r/galera#500.result | 4 ++ .../suite/galera/r/galera_gcs_fragment.result | 13 ++++- .../suite/galera/r/mysql-wsrep#332.result | 34 +++++++++++-- 5 files changed, 97 insertions(+), 11 deletions(-) diff --git a/mysql-test/suite/galera/r/MW-369.result b/mysql-test/suite/galera/r/MW-369.result index 516904d1b2a..9e209529db3 100644 --- a/mysql-test/suite/galera/r/MW-369.result +++ b/mysql-test/suite/galera/r/MW-369.result @@ -3,23 +3,32 @@ CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ; INSERT INTO p VALUES (1, 0); INSERT INTO p VALUES (2, 0); +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; DELETE FROM p WHERE f1 = 1; +connection node_1a; SET SESSION wsrep_sync_wait = 0; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; INSERT INTO c VALUES (1, 1); +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; COMMIT; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_1; +ERROR 40001: Deadlock: wsrep aborted transaction +connection node_2; SELECT * FROM p; f1 f2 1 0 @@ -29,6 +38,7 @@ f1 p_id 1 1 DROP TABLE c; DROP TABLE p; +connection node_1; CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, @@ -36,22 +46,30 @@ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ; INSERT INTO p VALUES (1, 0); INSERT INTO p VALUES (2, 0); INSERT INTO c VALUES (1, 1, 0); +connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; UPDATE p SET f2 = 1 WHERE f1 = 1; +connection node_1a; SET SESSION wsrep_sync_wait = 0; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; UPDATE c SET f2 = 1 WHERE f1 = 1; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; COMMIT; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +connection node_2; SELECT * FROM p; f1 f2 1 1 @@ -61,28 +79,37 @@ f1 p_id f2 1 1 1 DROP TABLE c; DROP TABLE p; +connection node_1; CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ; INSERT INTO p VALUES (1, 0); INSERT INTO p VALUES (2, 0); INSERT INTO c VALUES (1, 1); +connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; UPDATE p SET f2 = 1 WHERE f1 = 1; +connection node_1a; SET SESSION wsrep_sync_wait = 0; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; DELETE FROM c WHERE f1 = 1; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; COMMIT; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +connection node_2; SELECT * FROM p; f1 f2 1 1 @@ -95,23 +122,31 @@ CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER UNIQUE KEY) ENGINE=INNODB; CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f2)) ; INSERT INTO p VALUES (1, 0); +connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; UPDATE p SET f2 = 1 WHERE f1 = 1; +connection node_1a; SET SESSION wsrep_sync_wait = 0; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; INSERT INTO c VALUES (1, 0);; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; COMMIT; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_1; +ERROR 40001: Deadlock: wsrep aborted transaction +connection node_2; SELECT * FROM p; f1 f2 1 0 @@ -127,23 +162,31 @@ ON DELETE CASCADE) ; INSERT INTO p VALUES (1, 0); INSERT INTO p VALUES (2, 0); INSERT INTO c VALUES (1, 1, 0); +connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; DELETE FROM p WHERE f1 = 1; +connection node_1a; SET SESSION wsrep_sync_wait = 0; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; UPDATE c SET f2 = 1 WHERE f1 = 1; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; COMMIT; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_1; +ERROR 40001: Deadlock: wsrep aborted transaction +connection node_2; SELECT * FROM p; f1 f2 1 0 diff --git a/mysql-test/suite/galera/r/MW-402.result b/mysql-test/suite/galera/r/MW-402.result index 9be98d629fb..9f04984adc8 100644 --- a/mysql-test/suite/galera/r/MW-402.result +++ b/mysql-test/suite/galera/r/MW-402.result @@ -30,7 +30,7 @@ SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; connection node_1; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +ERROR 40001: Deadlock: wsrep aborted transaction connection node_2; SELECT * FROM p; f1 f2 @@ -70,7 +70,7 @@ SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; connection node_1; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +ERROR 40001: Deadlock: wsrep aborted transaction connection node_2; SELECT * FROM p; f1 f2 @@ -112,7 +112,7 @@ SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; connection node_1; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +ERROR 40001: Deadlock: wsrep aborted transaction connection node_2; SELECT * FROM p; f1 f2 @@ -145,7 +145,7 @@ SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; connection node_1; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +ERROR 40001: Deadlock: wsrep aborted transaction connection node_2; SELECT * FROM p; f1 f2 diff --git a/mysql-test/suite/galera/r/galera#500.result b/mysql-test/suite/galera/r/galera#500.result index 6a07d0359a4..7ba02c56053 100644 --- a/mysql-test/suite/galera/r/galera#500.result +++ b/mysql-test/suite/galera/r/galera#500.result @@ -1,10 +1,14 @@ +connection node_2; SET SESSION wsrep_sync_wait = 0; SET GLOBAL wsrep_provider_options="gmcast.isolate=2"; +connection node_1; SET SESSION wsrep_sync_wait = 0; SHOW STATUS LIKE 'wsrep_cluster_status'; Variable_name Value wsrep_cluster_status non-Primary SET SESSION wsrep_sync_wait = default; SET GLOBAL wsrep_provider_options="pc.bootstrap=1"; +connection node_2; SET SESSION wsrep_on=0; +connection node_2; CALL mtr.add_suppression("WSREP: exception from gcomm, backend must be restarted: Gcomm backend termination was requested by setting gmcast.isolate=2."); diff --git a/mysql-test/suite/galera/r/galera_gcs_fragment.result b/mysql-test/suite/galera/r/galera_gcs_fragment.result index 0c9c1819f60..90d36146eeb 100644 --- a/mysql-test/suite/galera/r/galera_gcs_fragment.result +++ b/mysql-test/suite/galera/r/galera_gcs_fragment.result @@ -1,24 +1,35 @@ +connection node_1; +connection node_2; CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 TEXT); +connection node_2; SET GLOBAL wsrep_cluster_address=''; +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET SESSION wsrep_sync_wait=0; SET GLOBAL wsrep_provider_options = 'dbug=d,gcs_core_after_frag_send'; +connection node_1; SET SESSION wsrep_retry_autocommit=0; INSERT INTO t1 VALUES (1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_2; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; INSERT INTO t1 VALUES (2, "bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); +connection node_1a; SET GLOBAL wsrep_provider_options = 'signal=gcs_core_after_frag_send'; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_1; +ERROR 40001: Deadlock: wsrep aborted transaction INSERT INTO t1 VALUES (3, "cccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); SELECT * FROM t1; f1 f2 2 bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 3 cccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +connection node_2; SELECT * FROM t1; f1 f2 2 bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 3 cccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +connection node_1; DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/mysql-wsrep#332.result b/mysql-test/suite/galera/r/mysql-wsrep#332.result index 8667f5e9c41..3986e4ab940 100644 --- a/mysql-test/suite/galera/r/mysql-wsrep#332.result +++ b/mysql-test/suite/galera/r/mysql-wsrep#332.result @@ -1,26 +1,36 @@ +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection node_1; CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER) ENGINE=INNODB; INSERT INTO p VALUES (1, 0); INSERT INTO p VALUES (2, 0); INSERT INTO c VALUES (1, 1); INSERT INTO c VALUES (2, 2); +connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; UPDATE p SET f1 = f1 + 100; +connection node_1a; SET SESSION wsrep_sync_wait = 0; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; ALTER TABLE c ADD FOREIGN KEY (p_id) REFERENCES p(f1); +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; COMMIT; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_1; +ERROR 40001: Deadlock: wsrep aborted transaction +connection node_2; SELECT * FROM p; f1 f2 1 0 @@ -31,6 +41,7 @@ f1 p_id 2 2 DROP TABLE c; DROP TABLE p; +connection node_1; CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id1 INTEGER, p_id2 INTEGER) ENGINE=INNODB; @@ -38,23 +49,31 @@ INSERT INTO p1 VALUES (1, 0), (2, 0); INSERT INTO p2 VALUES (1, 0), (2, 0); INSERT INTO c VALUES (1, 1, 1); INSERT INTO c VALUES (2, 2, 2); +connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; UPDATE p1 SET f1 = f1 + 100; +connection node_1a; SET SESSION wsrep_sync_wait = 0; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; ALTER TABLE c ADD FOREIGN KEY (p_id1) REFERENCES p1(f1), ADD FOREIGN KEY (p_id2) REFERENCES p2(f1); +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; COMMIT; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_1; +ERROR 40001: Deadlock: wsrep aborted transaction +connection node_2; SELECT * FROM p1; f1 f2 1 0 @@ -70,6 +89,7 @@ f1 p_id1 p_id2 DROP TABLE c; DROP TABLE p1; DROP TABLE p2; +connection node_1; CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id1 INTEGER, p_id2 INTEGER) ENGINE=INNODB; @@ -77,23 +97,31 @@ INSERT INTO p1 VALUES (1, 0), (2, 0); INSERT INTO p2 VALUES (1, 0), (2, 0); INSERT INTO c VALUES (1, 1, 1); INSERT INTO c VALUES (2, 2, 2); +connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; UPDATE p2 SET f1 = f1 + 100; +connection node_1a; SET SESSION wsrep_sync_wait = 0; SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; ALTER TABLE c ADD FOREIGN KEY (p_id1) REFERENCES p1(f1), ADD FOREIGN KEY (p_id2) REFERENCES p2(f1); +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; COMMIT; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug='; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_1; +ERROR 40001: Deadlock: wsrep aborted transaction +connection node_2; SELECT * FROM p1; f1 f2 1 0 From afb4878703e71307af0fe8723f8ab10e8d4e0288 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Tue, 25 Jun 2019 15:52:05 +0400 Subject: [PATCH 51/68] MDEV-18783 - Server crash in hp_rb_make_key In debug build, whenever MEMORY table instance gets closed it performs consistency check without protection. It may cause server crash if executed concurrently with DML. Moved consistency check to ha_heap::external_lock(F_UNLCK), so that it is protected by THR_LOCK. --- storage/heap/ha_heap.cc | 4 ++++ storage/heap/hp_close.c | 6 ------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index a1b8db34453..60a41cc52e7 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -453,6 +453,10 @@ int ha_heap::reset_auto_increment(ulonglong value) int ha_heap::external_lock(THD *thd, int lock_type) { +#ifndef DBUG_OFF + if (lock_type == F_UNLCK && file->s->changed && heap_check_heap(file, 0)) + return HA_ERR_CRASHED; +#endif return 0; // No external locking } diff --git a/storage/heap/hp_close.c b/storage/heap/hp_close.c index 092048a7c1c..82d6186340a 100644 --- a/storage/heap/hp_close.c +++ b/storage/heap/hp_close.c @@ -35,12 +35,6 @@ int hp_close(register HP_INFO *info) { int error=0; DBUG_ENTER("hp_close"); -#ifndef DBUG_OFF - if (info->s->changed && heap_check_heap(info,0)) - { - error=my_errno=HA_ERR_CRASHED; - } -#endif info->s->changed=0; if (info->open_list.data) heap_open_list=list_delete(heap_open_list,&info->open_list); From a7e3008ab3d368c2e2957b346647a7656d638e5c Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 30 Oct 2019 12:53:25 +0300 Subject: [PATCH 52/68] MDEV-20926 UBSAN: load of value 165, which is not a valid value for type bool Basicaly it's an uninitialized read. 165 is 0xa5 which comes from TRASH_ALLOC() Fix by calling a class ctor which initializes problematic TMP_TABLE_PARAM::force_copy_fields field --- sql/sql_show.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d8f65c74448..c63b8b0f8a8 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7708,8 +7708,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL); field_count++; } - TMP_TABLE_PARAM *tmp_table_param = - (TMP_TABLE_PARAM*) (thd->alloc(sizeof(TMP_TABLE_PARAM))); + TMP_TABLE_PARAM *tmp_table_param = new TMP_TABLE_PARAM; tmp_table_param->init(); tmp_table_param->table_charset= cs; tmp_table_param->field_count= field_count; From a3553a1387315f69551793b9baec4d8f91f51fcf Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 30 Oct 2019 11:15:05 +0100 Subject: [PATCH 53/68] 5.6.45-86.1 --- .../cmake_modules/TokuMergeLibs.cmake | 2 +- .../cmake_modules/TokuThirdParty.cmake | 34 ---- .../PerconaFT/portability/CMakeLists.txt | 1 - .../scripts/run-nightly-coverage-tests.bash | 2 +- .../scripts/run-nightly-drd-tests.bash | 2 +- .../scripts/run-nightly-release-tests.bash | 2 +- storage/tokudb/ha_tokudb.cc | 3 +- storage/tokudb/ha_tokudb.h | 3 +- storage/tokudb/hatoku_cmp.cc | 8 +- storage/tokudb/tests/math_test_int.cc | 156 +++++++++++++----- storage/tokudb/tests/math_test_uint.cc | 84 +++++++--- storage/tokudb/tests/sint_test.cc | 1 - storage/tokudb/tests/tokudb_buffer_test.cc | 11 +- storage/tokudb/tests/uint_test.cc | 1 - storage/tokudb/tests/vlq_test.cc | 9 +- storage/tokudb/tests/vlq_test_uint32.cc | 15 +- storage/tokudb/tests/vlq_test_uint64.cc | 15 +- storage/tokudb/tokudb_buffer.h | 4 +- storage/tokudb/tokudb_math.h | 6 +- 19 files changed, 228 insertions(+), 131 deletions(-) diff --git a/storage/tokudb/PerconaFT/cmake_modules/TokuMergeLibs.cmake b/storage/tokudb/PerconaFT/cmake_modules/TokuMergeLibs.cmake index e1da095fc00..f2462afdb45 100644 --- a/storage/tokudb/PerconaFT/cmake_modules/TokuMergeLibs.cmake +++ b/storage/tokudb/PerconaFT/cmake_modules/TokuMergeLibs.cmake @@ -6,7 +6,7 @@ FUNCTION(TOKU_GET_DEPENDEND_OS_LIBS target result) IF(deps) FOREACH(lib ${deps}) # Filter out keywords for used for debug vs optimized builds - IF(NOT lib MATCHES "general" AND NOT lib MATCHES "debug" AND NOT lib MATCHES "optimized") + IF(TARGET ${lib}) GET_TARGET_PROPERTY(lib_location ${lib} LOCATION) IF(NOT lib_location) SET(ret ${ret} ${lib}) diff --git a/storage/tokudb/PerconaFT/cmake_modules/TokuThirdParty.cmake b/storage/tokudb/PerconaFT/cmake_modules/TokuThirdParty.cmake index b707f368431..b312111a3a2 100644 --- a/storage/tokudb/PerconaFT/cmake_modules/TokuThirdParty.cmake +++ b/storage/tokudb/PerconaFT/cmake_modules/TokuThirdParty.cmake @@ -1,39 +1,5 @@ include(ExternalProject) -if (NOT DEFINED LIBJEMALLOC) - ## add jemalloc with an external project - set(JEMALLOC_SOURCE_DIR "${TokuDB_SOURCE_DIR}/third_party/jemalloc" CACHE FILEPATH "Where to find jemalloc sources.") - if (EXISTS "${JEMALLOC_SOURCE_DIR}/configure") - set(jemalloc_configure_opts "CC=${CMAKE_C_COMPILER}" "--with-jemalloc-prefix=" "--with-private-namespace=tokudb_jemalloc_internal_" "--enable-cc-silence") - option(JEMALLOC_DEBUG "Build jemalloc with --enable-debug." OFF) - if (JEMALLOC_DEBUG) - list(APPEND jemalloc_configure_opts --enable-debug) - endif () - ExternalProject_Add(build_jemalloc - PREFIX jemalloc - SOURCE_DIR "${JEMALLOC_SOURCE_DIR}" - CONFIGURE_COMMAND - "${JEMALLOC_SOURCE_DIR}/configure" ${jemalloc_configure_opts} - "--prefix=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/jemalloc" - ) - - add_library(jemalloc STATIC IMPORTED GLOBAL) - set_target_properties(jemalloc PROPERTIES IMPORTED_LOCATION - "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/jemalloc/lib/libjemalloc_pic.a") - add_dependencies(jemalloc build_jemalloc) - add_library(jemalloc_nopic STATIC IMPORTED GLOBAL) - set_target_properties(jemalloc_nopic PROPERTIES IMPORTED_LOCATION - "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/jemalloc/lib/libjemalloc.a") - add_dependencies(jemalloc_nopic build_jemalloc) - - # detect when we are being built as a subproject - if (NOT DEFINED MYSQL_PROJECT_NAME_DOCSTRING) - install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/jemalloc/lib" DESTINATION . - COMPONENT tokukv_libs_extra) - endif () - endif () -endif () - ## add lzma with an external project set(xz_configure_opts --with-pic --enable-static) if (APPLE) diff --git a/storage/tokudb/PerconaFT/portability/CMakeLists.txt b/storage/tokudb/PerconaFT/portability/CMakeLists.txt index f24cf84a829..f7a731bfb5a 100644 --- a/storage/tokudb/PerconaFT/portability/CMakeLists.txt +++ b/storage/tokudb/PerconaFT/portability/CMakeLists.txt @@ -20,7 +20,6 @@ target_link_libraries(${LIBTOKUPORTABILITY} LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT add_library(tokuportability_static_conv STATIC ${tokuportability_srcs}) set_target_properties(tokuportability_static_conv PROPERTIES POSITION_INDEPENDENT_CODE ON) -add_dependencies(tokuportability_static_conv build_jemalloc) set(tokuportability_source_libs tokuportability_static_conv ${LIBJEMALLOC} ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_SYSTEM_LIBS}) toku_merge_static_libs(${LIBTOKUPORTABILITY}_static ${LIBTOKUPORTABILITY}_static "${tokuportability_source_libs}") diff --git a/storage/tokudb/PerconaFT/scripts/run-nightly-coverage-tests.bash b/storage/tokudb/PerconaFT/scripts/run-nightly-coverage-tests.bash index cd5743cddf2..3daa87ce03c 100755 --- a/storage/tokudb/PerconaFT/scripts/run-nightly-coverage-tests.bash +++ b/storage/tokudb/PerconaFT/scripts/run-nightly-coverage-tests.bash @@ -26,7 +26,7 @@ if [ ! -d build ] ; then -D RUN_LONG_TESTS=ON \ -D TOKUDB_DATA=$tokudbdir/../tokudb.data \ .. - ninja build_jemalloc build_lzma build_snappy + ninja build_lzma build_snappy popd fi diff --git a/storage/tokudb/PerconaFT/scripts/run-nightly-drd-tests.bash b/storage/tokudb/PerconaFT/scripts/run-nightly-drd-tests.bash index 3c688581385..1ef819d8e37 100755 --- a/storage/tokudb/PerconaFT/scripts/run-nightly-drd-tests.bash +++ b/storage/tokudb/PerconaFT/scripts/run-nightly-drd-tests.bash @@ -25,7 +25,7 @@ if [ ! -d build ] ; then -D RUN_LONG_TESTS=ON \ -D TOKUDB_DATA=$tokudbdir/../tokudb.data \ .. - ninja build_jemalloc build_lzma build_snappy + ninja build_lzma build_snappy popd fi diff --git a/storage/tokudb/PerconaFT/scripts/run-nightly-release-tests.bash b/storage/tokudb/PerconaFT/scripts/run-nightly-release-tests.bash index 80938bad8a6..c1039a0b28f 100755 --- a/storage/tokudb/PerconaFT/scripts/run-nightly-release-tests.bash +++ b/storage/tokudb/PerconaFT/scripts/run-nightly-release-tests.bash @@ -25,7 +25,7 @@ if [ ! -d build ] ; then -D RUN_LONG_TESTS=ON \ -D TOKUDB_DATA=$tokudbdir/../tokudb.data \ .. - ninja build_jemalloc build_lzma build_snappy + ninja build_lzma build_snappy popd fi diff --git a/storage/tokudb/ha_tokudb.cc b/storage/tokudb/ha_tokudb.cc index 251b8183ae5..32f3e77cf13 100644 --- a/storage/tokudb/ha_tokudb.cc +++ b/storage/tokudb/ha_tokudb.cc @@ -1075,7 +1075,8 @@ static inline int tokudb_generate_row(DB* dest_db, } buff = (uchar *)dest_key->data; - assert_always(buff != NULL && max_key_len > 0); + assert_always(buff != nullptr); + assert_always(max_key_len > 0); } else { assert_unreachable(); } diff --git a/storage/tokudb/ha_tokudb.h b/storage/tokudb/ha_tokudb.h index 6257583e754..1d1ea92868d 100644 --- a/storage/tokudb/ha_tokudb.h +++ b/storage/tokudb/ha_tokudb.h @@ -387,7 +387,8 @@ inline void TOKUDB_SHARE::init_cardinality_counts( assert_debug(_mutex.is_owned_by_me()); // can not change number of keys live - assert_always(_rec_per_key == NULL && _rec_per_keys == 0); + assert_always(_rec_per_key == nullptr); + assert_always(_rec_per_keys == 0); _rec_per_keys = rec_per_keys; _rec_per_key = rec_per_key; } diff --git a/storage/tokudb/hatoku_cmp.cc b/storage/tokudb/hatoku_cmp.cc index f064a125649..16393aa43b6 100644 --- a/storage/tokudb/hatoku_cmp.cc +++ b/storage/tokudb/hatoku_cmp.cc @@ -954,9 +954,8 @@ static inline int tokudb_compare_two_hidden_keys( const void* saved_key_data, const uint32_t saved_key_size ) { - assert_always( - (new_key_size >= TOKUDB_HIDDEN_PRIMARY_KEY_LENGTH) && - (saved_key_size >= TOKUDB_HIDDEN_PRIMARY_KEY_LENGTH)); + assert_always(new_key_size >= TOKUDB_HIDDEN_PRIMARY_KEY_LENGTH); + assert_always(saved_key_size >= TOKUDB_HIDDEN_PRIMARY_KEY_LENGTH); ulonglong a = hpk_char_to_num((uchar *) new_key_data); ulonglong b = hpk_char_to_num((uchar *) saved_key_data); return a < b ? -1 : (a > b ? 1 : 0); @@ -2534,7 +2533,8 @@ static uint32_t create_toku_secondary_key_pack_descriptor ( bool is_col_in_pk = false; if (bitmap_is_set(&kc_info->key_filters[pk_index],field_index)) { - assert_always(!has_hpk && prim_key != NULL); + assert_always(!has_hpk); + assert_always(prim_key != nullptr); is_col_in_pk = true; } else { diff --git a/storage/tokudb/tests/math_test_int.cc b/storage/tokudb/tests/math_test_int.cc index 10085dbd704..3313bdf5895 100644 --- a/storage/tokudb/tests/math_test_int.cc +++ b/storage/tokudb/tests/math_test_int.cc @@ -54,16 +54,20 @@ static void test_int8() { assert(over); else if (m < -max) assert(over); - else - assert(!over && n == m); + else { + assert(!over); + assert(n == m); + } n = int_sub(x, y, 8, &over); m = x - y; if (m > max-1) assert(over); else if (m < -max) assert(over); - else - assert(!over && n == m); + else { + assert(!over); + asset(n == m); + } } } } @@ -82,16 +86,20 @@ static void test_int16() { assert(over); else if (m < -max) assert(over); - else - assert(!over && n == m); + else { + assert(!over); + assert(n == m); + } n = int_sub(x, y, 16, &over); m = x - y; if (m > max-1) assert(over); else if (m < -max) assert(over); - else - assert(!over && n == m); + else { + assert(!over); + assert(n == m); + } } } } @@ -104,20 +112,42 @@ static void test_int24() { s = int_add(1, (1ULL<<23)-1, 24, &over); assert(over); s = int_add((1ULL<<23)-1, 1, 24, &over); assert(over); - s = int_sub(-1, (1ULL<<23), 24, &over); assert(!over && s == (1ULL<<23)-1); + s = int_sub(-1, (1ULL<<23), 24, &over); + assert(!over); + assert(s == (1ULL<<23)-1); s = int_sub((1ULL<<23), 1, 24, &over); assert(over); - s = int_add(0, 0, 24, &over); assert(!over && s == 0); - s = int_sub(0, 0, 24, &over); assert(!over && s == 0); - s = int_add(0, -1, 24, &over); assert(!over && s == -1); - s = int_sub(0, 1, 24, &over); assert(!over && s == -1); - s = int_add(0, (1ULL<<23), 24, &over); assert(!over && (s & ((1ULL<<24)-1)) == (1ULL<<23)); - s = int_sub(0, (1ULL<<23)-1, 24, &over); assert(!over && (s & ((1ULL<<24)-1)) == (1ULL<<23)+1); + s = int_add(0, 0, 24, &over); + assert(!over); + assert(s == 0); + s = int_sub(0, 0, 24, &over); + assert(!over); + assert(s == 0); + s = int_add(0, -1, 24, &over); + assert(!over); + assert(s == -1); + s = int_sub(0, 1, 24, &over); + assert(!over); + assert(s == -1); + s = int_add(0, (1ULL<<23), 24, &over); + assert(!over); + assert((s & ((1ULL<<24)-1)) == (1ULL<<23)); + s = int_sub(0, (1ULL<<23)-1, 24, &over); + assert(!over); + assert((s & ((1ULL<<24)-1)) == (1ULL<<23)+1); - s = int_add(-1, 0, 24, &over); assert(!over && s == -1); - s = int_add(-1, 1, 24, &over); assert(!over && s == 0); - s = int_sub(-1, -1, 24, &over); assert(!over && s == 0); - s = int_sub(-1, (1ULL<<23)-1, 24, &over); assert(!over && (s & ((1ULL<<24)-1)) == (1ULL<<23)); + s = int_add(-1, 0, 24, &over); + assert(!over); + assert(s == -1); + s = int_add(-1, 1, 24, &over); + assert(!over); + assert(s == 0); + s = int_sub(-1, -1, 24, &over); + assert(!over); + assert(s == 0); + s = int_sub(-1, (1ULL<<23)-1, 24, &over); + assert(!over); + assert((s & ((1ULL<<24)-1)) == (1ULL<<23)); } static void test_int32() { @@ -128,20 +158,42 @@ static void test_int32() { s = int_add(1, (1ULL<<31)-1, 32, &over); assert(over); s = int_add((1ULL<<31)-1, 1, 32, &over); assert(over); - s = int_sub(-1, (1ULL<<31), 32, &over); assert(s == (1ULL<<31)-1 && !over); + s = int_sub(-1, (1ULL<<31), 32, &over); + assert(s == (1ULL<<31)-1); + assert(!over); s = int_sub((1ULL<<31), 1, 32, &over); assert(over); - s = int_add(0, 0, 32, &over); assert(s == 0 && !over); - s = int_sub(0, 0, 32, &over); assert(s == 0 && !over); - s = int_add(0, -1, 32, &over); assert(s == -1 && !over); - s = int_sub(0, 1, 32, &over); assert(s == -1 && !over); - s = int_add(0, (1ULL<<31), 32, &over); assert((s & ((1ULL<<32)-1)) == (1ULL<<31) && !over); - s = int_sub(0, (1ULL<<31)-1, 32, &over); assert((s & ((1ULL<<32)-1)) == (1ULL<<31)+1 && !over); + s = int_add(0, 0, 32, &over); + assert(s == 0); + assert(!over); + s = int_sub(0, 0, 32, &over); + assert(s == 0); + assert(!over); + s = int_add(0, -1, 32, &over); + assert(s == -1); + assert(!over); + s = int_sub(0, 1, 32, &over); + assert(s == -1); + assert(!over); + s = int_add(0, (1ULL<<31), 32, &over); + assert((s & ((1ULL<<32)-1)) == (1ULL<<31)); + assert(!over); + s = int_sub(0, (1ULL<<31)-1, 32, &over); + assert((s & ((1ULL<<32)-1)) == (1ULL<<31)+1); + assert(!over); - s = int_add(-1, 0, 32, &over); assert(s == -1 && !over); - s = int_add(-1, 1, 32, &over); assert(s == 0 && !over); - s = int_sub(-1, -1, 32, &over); assert(s == 0 && !over); - s = int_sub(-1, (1ULL<<31)-1, 32, &over); assert((s & ((1ULL<<32)-1)) == (1ULL<<31) && !over); + s = int_add(-1, 0, 32, &over); + assert(s == -1); + assert(!over); + s = int_add(-1, 1, 32, &over); + assert(s == 0); + assert(!over); + s = int_sub(-1, -1, 32, &over); + assert(s == 0); + assert(!over); + s = int_sub(-1, (1ULL<<31)-1, 32, &over); + assert((s & ((1ULL<<32)-1)) == (1ULL<<31)); + assert(!over); } static void test_int64() { @@ -152,20 +204,42 @@ static void test_int64() { s = int_add(1, (1ULL<<63)-1, 64, &over); assert(over); s = int_add((1ULL<<63)-1, 1, 64, &over); assert(over); - s = int_sub(-1, (1ULL<<63), 64, &over); assert(s == (1ULL<<63)-1 && !over); + s = int_sub(-1, (1ULL<<63), 64, &over); + assert(s == (1ULL<<63)-1); + assert(!over); s = int_sub((1ULL<<63), 1, 64, &over); assert(over); - s = int_add(0, 0, 64, &over); assert(s == 0 && !over); - s = int_sub(0, 0, 64, &over); assert(s == 0 && !over); - s = int_add(0, -1, 64, &over); assert(s == -1 && !over); - s = int_sub(0, 1, 64, &over); assert(s == -1 && !over); - s = int_add(0, (1ULL<<63), 64, &over); assert(s == (int64_t)(1ULL<<63) && !over); - s = int_sub(0, (1ULL<<63)-1, 64, &over); assert(s == (int64_t)((1ULL<<63)+1) && !over); + s = int_add(0, 0, 64, &over); + assert(s == 0); + assert(!over); + s = int_sub(0, 0, 64, &over); + assert(s == 0); + assert(!over); + s = int_add(0, -1, 64, &over); + assert(s == -1); + assert(!over); + s = int_sub(0, 1, 64, &over); + assert(s == -1); + assert(!over); + s = int_add(0, (1ULL<<63), 64, &over); + assert(s == (int64_t)(1ULL<<63)); + assert(!over); + s = int_sub(0, (1ULL<<63)-1, 64, &over); + assert(s == (int64_t)((1ULL<<63)+1)); + assert(!over); - s = int_add(-1, 0, 64, &over); assert(s == -1 && !over); - s = int_add(-1, 1, 64, &over); assert(s == 0 && !over); - s = int_sub(-1, -1, 64, &over); assert(s == 0 && !over); - s = int_sub(-1, (1ULL<<63)-1, 64, &over); assert(s == (int64_t)(1ULL<<63) && !over); + s = int_add(-1, 0, 64, &over); + assert(s == -1); + assert(!over); + s = int_add(-1, 1, 64, &over); + assert(s == 0); + assert(!over); + s = int_sub(-1, -1, 64, &over); + assert(s == 0); + assert(!over); + s = int_sub(-1, (1ULL<<63)-1, 64, &over); + assert(s == (int64_t)(1ULL<<63)); + assert(!over); } static void test_int_sign(uint length_bits) { diff --git a/storage/tokudb/tests/math_test_uint.cc b/storage/tokudb/tests/math_test_uint.cc index 2fc8de8e093..2c5c9261c89 100644 --- a/storage/tokudb/tests/math_test_uint.cc +++ b/storage/tokudb/tests/math_test_uint.cc @@ -51,14 +51,18 @@ static void test_uint8() { m = x + y; if (m > (1ULL<<8)-1) assert(over); - else - assert(!over && n == (m % 256)); + else { + assert(!over); + assert(n == (m % 256)); + } n = uint_sub(x, y, 8, &over); m = x - y; if (m > x) assert(over); - else - assert(!over && n == (m % 256)); + else { + assert(!over); + assert(n == (m % 256)); + } } } } @@ -75,14 +79,18 @@ static void test_uint16() { m = x + y; if (m > (1ULL<<16)-1) assert(over); - else - assert(!over && n == (m % (1ULL<<16))); + else { + assert(!over); + assert(n == (m % (1ULL<<16))); + } n = uint_sub(x, y, 16, &over); m = x - y; if (m > x) assert(over); - else - assert(!over && n == (m % (1ULL<<16))); + else { + assert(!over); + assert(n == (m % (1ULL<<16))); + } } } } @@ -95,13 +103,23 @@ static void test_uint24() { s = uint_add((1ULL<<24)-1, (1ULL<<24)-1, 24, &over); assert(over); s = uint_add((1ULL<<24)-1, 1, 24, &over); assert(over); - s = uint_add((1ULL<<24)-1, 0, 24, &over); assert(!over && s == (1ULL<<24)-1); - s = uint_add(0, 1, 24, &over); assert(!over && s == 1); - s = uint_add(0, 0, 24, &over); assert(!over && s == 0); - s = uint_sub(0, 0, 24, &over); assert(!over && s == 0); + s = uint_add((1ULL<<24)-1, 0, 24, &over); + assert(!over); + assert(s == (1ULL<<24)-1); + s = uint_add(0, 1, 24, &over); + assert(!over); + assert(s == 1); + s = uint_add(0, 0, 24, &over); + assert(!over); + assert(s == 0); + s = uint_sub(0, 0, 24, &over); + assert(!over); + assert(s == 0); s = uint_sub(0, 1, 24, &over); assert(over); s = uint_sub(0, (1ULL<<24)-1, 24, &over); assert(over); - s = uint_sub((1ULL<<24)-1, (1ULL<<24)-1, 24, &over); assert(!over && s == 0); + s = uint_sub((1ULL<<24)-1, (1ULL<<24)-1, 24, &over); + assert(!over); + assert(s == 0); } static void test_uint32() { @@ -112,13 +130,23 @@ static void test_uint32() { s = uint_add((1ULL<<32)-1, (1ULL<<32)-1, 32, &over); assert(over); s = uint_add((1ULL<<32)-1, 1, 32, &over); assert(over); - s = uint_add((1ULL<<32)-1, 0, 32, &over); assert(!over && s == (1ULL<<32)-1); - s = uint_add(0, 1, 32, &over); assert(!over && s == 1); - s = uint_add(0, 0, 32, &over); assert(!over && s == 0); - s = uint_sub(0, 0, 32, &over); assert(!over && s == 0); + s = uint_add((1ULL<<32)-1, 0, 32, &over); + assert(!over); + assert(s == (1ULL<<32)-1); + s = uint_add(0, 1, 32, &over); + assert(!over); + assert(s == 1); + s = uint_add(0, 0, 32, &over); + assert(!over); + assert(s == 0); + s = uint_sub(0, 0, 32, &over); + assert(!over); + assert(s == 0); s = uint_sub(0, 1, 32, &over); assert(over); s = uint_sub(0, (1ULL<<32)-1, 32, &over); assert(over); - s = uint_sub((1ULL<<32)-1, (1ULL<<32)-1, 32, &over); assert(!over && s == 0); + s = uint_sub((1ULL<<32)-1, (1ULL<<32)-1, 32, &over); + assert(!over); + assert(s == 0); } static void test_uint64() { @@ -129,13 +157,23 @@ static void test_uint64() { s = uint_add(~0ULL, ~0ULL, 64, &over); assert(over); s = uint_add(~0ULL, 1, 64, &over); assert(over); - s = uint_add(~0ULL, 0, 64, &over); assert(!over && s == ~0ULL); - s = uint_add(0, 1, 64, &over); assert(!over && s == 1); - s = uint_add(0, 0, 64, &over); assert(!over && s == 0); - s = uint_sub(0, 0, 64, &over); assert(!over && s == 0); + s = uint_add(~0ULL, 0, 64, &over); + assert(!over); + assert(s == ~0ULL); + s = uint_add(0, 1, 64, &over); + assert(!over); + assert(s == 1); + s = uint_add(0, 0, 64, &over); + assert(!over); + assert(s == 0); + s = uint_sub(0, 0, 64, &over); + assert(!over); + assert(s == 0); s = uint_sub(0, 1, 64, &over); assert(over); s = uint_sub(0, ~0ULL, 64, &over); assert(over); - s = uint_sub(~0ULL, ~0ULL, 64, &over); assert(!over && s == 0); + s = uint_sub(~0ULL, ~0ULL, 64, &over); + assert(!over); + assert(s == 0); } int main() { diff --git a/storage/tokudb/tests/sint_test.cc b/storage/tokudb/tests/sint_test.cc index 9078ae87281..7823ee5a692 100644 --- a/storage/tokudb/tests/sint_test.cc +++ b/storage/tokudb/tests/sint_test.cc @@ -27,7 +27,6 @@ Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. #include #include #include -#include #include #include diff --git a/storage/tokudb/tests/tokudb_buffer_test.cc b/storage/tokudb/tests/tokudb_buffer_test.cc index a786cdf4592..7e296790d39 100644 --- a/storage/tokudb/tests/tokudb_buffer_test.cc +++ b/storage/tokudb/tests/tokudb_buffer_test.cc @@ -32,9 +32,13 @@ Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. static void test_null() { tokudb::buffer b; - assert(b.data() == NULL && b.size() == 0 && b.limit() == 0); + assert(b.data() == nullptr); + assert(b.size() == 0); + assert(b.limit() == 0); b.append(NULL, 0); - assert(b.data() == NULL && b.size() == 0 && b.limit() == 0); + assert(b.data() == nullptr); + assert(b.size() == 0); + assert(b.limit() == 0); } static void append_az(tokudb::buffer &b) { @@ -132,7 +136,8 @@ static void test_replace_grow() { } for (size_t i = 0; i < a.size()/2; i++) { unsigned char *cp = (unsigned char *) a.data() + 2*i; - assert(cp[0] == 'a'+i && cp[1] == 'a'+i); + assert(cp[0] == 'a'+i); + assert(cp[1] == 'a'+i); } } diff --git a/storage/tokudb/tests/uint_test.cc b/storage/tokudb/tests/uint_test.cc index b2c653b8fdd..e3aa1a6fe2f 100644 --- a/storage/tokudb/tests/uint_test.cc +++ b/storage/tokudb/tests/uint_test.cc @@ -27,7 +27,6 @@ Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. #include #include #include -#include #include #include diff --git a/storage/tokudb/tests/vlq_test.cc b/storage/tokudb/tests/vlq_test.cc index 80d797339b4..12b222f06c1 100644 --- a/storage/tokudb/tests/vlq_test.cc +++ b/storage/tokudb/tests/vlq_test.cc @@ -52,7 +52,8 @@ static void test_vlq_uint32_error(void) { in_s = tokudb::vlq_decode_ui(&n, b, 1); assert(in_s == 0); in_s = tokudb::vlq_decode_ui(&n, b, 2); - assert(in_s == 2 && n == 128); + assert(in_s == 2); + assert(n == 128); } static void test_80000000(void) { @@ -63,7 +64,8 @@ static void test_80000000(void) { out_s = tokudb::vlq_encode_ui(v, b, sizeof b); assert(out_s == 5); in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 5 && n == v); + assert(in_s == 5); + assert(n == v); } static void test_100000000(void) { @@ -74,7 +76,8 @@ static void test_100000000(void) { out_s = tokudb::vlq_encode_ui(v, b, sizeof b); assert(out_s == 5); in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 5 && n == v); + assert(in_s == 5); + assert(n == v); } int main(void) { diff --git a/storage/tokudb/tests/vlq_test_uint32.cc b/storage/tokudb/tests/vlq_test_uint32.cc index c5661b33ab5..3cc8af771a9 100644 --- a/storage/tokudb/tests/vlq_test_uint32.cc +++ b/storage/tokudb/tests/vlq_test_uint32.cc @@ -44,7 +44,8 @@ static void test_vlq_uint32(void) { assert(out_s == 1); uint32_t n; size_t in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 1 && n == v); + assert(in_s == 1); + assert(n == v); } printf("%u\n", 1<<7); @@ -54,7 +55,8 @@ static void test_vlq_uint32(void) { assert(out_s == 2); uint32_t n; size_t in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 2 && n == v); + assert(in_s == 2); + assert(n == v); } printf("%u\n", 1<<14); @@ -64,7 +66,8 @@ static void test_vlq_uint32(void) { assert(out_s == 3); uint32_t n; size_t in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 3 && n == v); + assert(in_s == 3); + assert(n == v); } printf("%u\n", 1<<21); @@ -74,7 +77,8 @@ static void test_vlq_uint32(void) { assert(out_s == 4); uint32_t n; size_t in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 4 && n == v); + assert(in_s == 4); + assert(n == v); } printf("%u\n", 1<<28); @@ -84,7 +88,8 @@ static void test_vlq_uint32(void) { assert(out_s == 5); uint32_t n; size_t in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 5 && n == v); + assert(in_s == 5); + assert(n == v); } } diff --git a/storage/tokudb/tests/vlq_test_uint64.cc b/storage/tokudb/tests/vlq_test_uint64.cc index a626db69487..697c597756c 100644 --- a/storage/tokudb/tests/vlq_test_uint64.cc +++ b/storage/tokudb/tests/vlq_test_uint64.cc @@ -46,7 +46,8 @@ static void test_vlq_uint64(uint64_t start, uint64_t stride) { assert(out_s == 1); uint64_t n; size_t in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 1 && n == v); + assert(in_s == 1); + assert(n == v); } printf("%u\n", 1<<7); @@ -56,7 +57,8 @@ static void test_vlq_uint64(uint64_t start, uint64_t stride) { assert(out_s == 2); uint64_t n; size_t in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 2 && n == v); + assert(in_s == 2); + assert(n == v); } printf("%u\n", 1<<14); @@ -66,7 +68,8 @@ static void test_vlq_uint64(uint64_t start, uint64_t stride) { assert(out_s == 3); uint64_t n; size_t in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 3 && n == v); + assert(in_s == 3); + assert(n == v); } printf("%u\n", 1<<21); @@ -76,7 +79,8 @@ static void test_vlq_uint64(uint64_t start, uint64_t stride) { assert(out_s == 4); uint64_t n; size_t in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 4 && n == v); + assert(in_s == 4); + assert(n == v); } printf("%u\n", 1<<28); @@ -90,7 +94,8 @@ static void test_vlq_uint64(uint64_t start, uint64_t stride) { assert(out_s == 5); uint64_t n; size_t in_s = tokudb::vlq_decode_ui(&n, b, out_s); - assert(in_s == 5 && n == v); + assert(in_s == 5); + assert(n == v); } } diff --git a/storage/tokudb/tokudb_buffer.h b/storage/tokudb/tokudb_buffer.h index 022f1b49643..1605543c378 100644 --- a/storage/tokudb/tokudb_buffer.h +++ b/storage/tokudb/tokudb_buffer.h @@ -134,8 +134,8 @@ public: char* data_offset = (char*)m_data + offset; if (new_s != old_s) { size_t n = m_size - (offset + old_s); - assert_always( - offset + new_s + n <= m_limit && offset + old_s + n <= m_limit); + assert_always(offset + new_s + n <= m_limit); + assert_always(offset + old_s + n <= m_limit); memmove(data_offset + new_s, data_offset + old_s, n); if (new_s > old_s) m_size += new_s - old_s; diff --git a/storage/tokudb/tokudb_math.h b/storage/tokudb/tokudb_math.h index 0338bf3871e..99cebd5b1d1 100644 --- a/storage/tokudb/tokudb_math.h +++ b/storage/tokudb/tokudb_math.h @@ -59,7 +59,8 @@ TOKUDB_UNUSED(static uint64_t uint_add( bool* over)); static uint64_t uint_add(uint64_t x, uint64_t y, uint length_bits, bool *over) { uint64_t mask = uint_mask(length_bits); - assert_always((x & ~mask) == 0 && (y & ~mask) == 0); + assert_always((x & ~mask) == 0); + assert_always((y & ~mask) == 0); uint64_t s = (x + y) & mask; *over = s < x; // check for overflow return s; @@ -75,7 +76,8 @@ TOKUDB_UNUSED(static uint64_t uint_sub( bool* over)); static uint64_t uint_sub(uint64_t x, uint64_t y, uint length_bits, bool *over) { uint64_t mask = uint_mask(length_bits); - assert_always((x & ~mask) == 0 && (y & ~mask) == 0); + assert_always((x & ~mask) == 0); + assert_always((y & ~mask) == 0); uint64_t s = (x - y) & mask; *over = s > x; // check for overflow return s; From b8eff8bce4505478dcb1981d344d917782c6e226 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 30 Oct 2019 13:23:15 +0300 Subject: [PATCH 54/68] avoid accessing TLS --- sql/sql_show.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c63b8b0f8a8..fbdb76e9e71 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7708,7 +7708,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL); field_count++; } - TMP_TABLE_PARAM *tmp_table_param = new TMP_TABLE_PARAM; + TMP_TABLE_PARAM *tmp_table_param = new (thd->mem_root) TMP_TABLE_PARAM; tmp_table_param->init(); tmp_table_param->table_charset= cs; tmp_table_param->field_count= field_count; From d1e6b0bcff0148f474e38002d5c1198726fe7970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Oct 2019 12:36:57 +0200 Subject: [PATCH 55/68] MDEV-20927 Duplicate key with auto increment Apply the changes to InnoDB and XtraDB that had been inadvertently skipped in the merge commit ae476868a5394041a00e75a29c7d45917e8dfae8 That merge failure sabotaged part of MDEV-20127: >Revert a problematic auto_increment_increment 'fix' from 2014. >This involves replacing the MDEV-8827 fix and in 10.1, >removing some WSREP instrumentation. The code changes were re-merged manually by executing the following: # Get the parent of the problematic merge. git checkout ae476868a5394041a00e75a29c7d45917e8dfae8^ # Perform the merge again. git merge ae476868a5394041a00e75a29c7d45917e8dfae8^2 # Get the conflict resolution from that merge. git checkout ae476868a5394041a00e75a29c7d45917e8dfae8 . # Note: Any changes to these files were removed (empty diff)! git diff HEAD storage/{innobase,xtradb}/handler/ha_innodb.cc # Apply the code changes: git diff cf40393471b10ca68cc1d2804c22ab9203900978^2..MERGE_HEAD \ storage/{innobase,xtradb}/handler/ha_innodb.cc| patch -p1 --- .../innodb/r/innodb-alter-autoinc.result | 6 +- .../suite/innodb/r/innodb-autoinc.result | 24 ++++---- mysql-test/suite/innodb/t/innodb-autoinc.test | 2 +- storage/innobase/handler/ha_innodb.cc | 58 +++++++++++-------- storage/xtradb/handler/ha_innodb.cc | 58 +++++++++++-------- 5 files changed, 84 insertions(+), 64 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-alter-autoinc.result b/mysql-test/suite/innodb/r/innodb-alter-autoinc.result index 82eb448fe45..c3ae453486a 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-autoinc.result +++ b/mysql-test/suite/innodb/r/innodb-alter-autoinc.result @@ -148,7 +148,7 @@ t1 CREATE TABLE `t1` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`), KEY `id` (`id`,`a`) -) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=latin1 +) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=latin1 INSERT INTO t1 SET a=123; INSERT INTO t1 VALUES(-123,-45); ALTER TABLE t1 AUTO_INCREMENT = 75; @@ -161,8 +161,8 @@ a id 123 55 347 60 33101 65 +123 70 123 75 -123 80 SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -170,5 +170,5 @@ t1 CREATE TABLE `t1` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`), KEY `id` (`id`,`a`) -) ENGINE=InnoDB AUTO_INCREMENT=85 DEFAULT CHARSET=latin1 +) ENGINE=InnoDB AUTO_INCREMENT=80 DEFAULT CHARSET=latin1 DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/innodb-autoinc.result b/mysql-test/suite/innodb/r/innodb-autoinc.result index 2c428b0ba1a..f2e2e087818 100644 --- a/mysql-test/suite/innodb/r/innodb-autoinc.result +++ b/mysql-test/suite/innodb/r/innodb-autoinc.result @@ -567,7 +567,7 @@ Variable_name Value auto_increment_increment 65535 auto_increment_offset 65535 INSERT INTO t1 VALUES (NULL),(NULL); -ERROR HY000: Failed to read auto-increment value from storage engine +ERROR 22003: Out of range value for column 'c1' at row 1 SELECT * FROM t1; c1 1 @@ -674,7 +674,7 @@ SELECT a,b FROM t; a b 1 S1 3 S2 -4 S2 +5 S2 # Client 1: Insert a record with auto_increment_increment=1 SET SESSION auto_increment_increment=1; SHOW CREATE TABLE t; @@ -683,14 +683,14 @@ t CREATE TABLE `t` ( `a` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `b` varchar(200) DEFAULT NULL, PRIMARY KEY (`a`) -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 INSERT INTO t(b) VALUES('S1'); SELECT a,b FROM t; a b 1 S1 3 S2 -4 S2 -5 S1 +5 S2 +6 S1 DROP TABLE t; # Autoincrement behaviour with mixed insert. CREATE TABLE t( @@ -728,22 +728,22 @@ t CREATE TABLE `t` ( `a` tinyint(4) NOT NULL AUTO_INCREMENT, `b` varchar(200) DEFAULT NULL, PRIMARY KEY (`a`) -) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=latin1 +) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=latin1 INSERT INTO t(b) VALUES('S4'); SELECT * FROM t; a b 1 S0 11 S1 -22 S3 -23 S4 28 S2 +31 S3 +32 S4 SHOW CREATE TABLE t; Table Create Table t CREATE TABLE `t` ( `a` tinyint(4) NOT NULL AUTO_INCREMENT, `b` varchar(200) DEFAULT NULL, PRIMARY KEY (`a`) -) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=latin1 +) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=latin1 DROP TABLE t; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=5; DROP TABLE IF EXISTS t1; @@ -784,7 +784,7 @@ t2 CREATE TABLE `t2` ( `n` int(10) unsigned NOT NULL, `o` enum('FALSE','TRUE') DEFAULT NULL, PRIMARY KEY (`m`) -) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=latin1 +) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=latin1 INSERT INTO t1 (b,c) SELECT n,o FROM t2 ; SHOW CREATE TABLE t1; Table Create Table @@ -1464,13 +1464,13 @@ SELECT * FROM t; i 1 301 -351 +601 SHOW CREATE TABLE t; Table Create Table t CREATE TABLE `t` ( `i` int(11) NOT NULL AUTO_INCREMENT, KEY `i` (`i`) -) ENGINE=InnoDB AUTO_INCREMENT=401 DEFAULT CHARSET=latin1 +) ENGINE=InnoDB AUTO_INCREMENT=651 DEFAULT CHARSET=latin1 DROP TABLE t; # # MDEV-14008 Assertion failing: `!is_set() || (m_status == DA_OK_BULK && is_bulk_op()) diff --git a/mysql-test/suite/innodb/t/innodb-autoinc.test b/mysql-test/suite/innodb/t/innodb-autoinc.test index 8b202f5db6b..b14d6db7f5d 100644 --- a/mysql-test/suite/innodb/t/innodb-autoinc.test +++ b/mysql-test/suite/innodb/t/innodb-autoinc.test @@ -349,7 +349,7 @@ INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976; SHOW VARIABLES LIKE "auto_inc%"; ---error 1467 +--error HA_ERR_AUTOINC_ERANGE INSERT INTO t1 VALUES (NULL),(NULL); SELECT * FROM t1; DROP TABLE t1; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index fd8f0d3787f..ed15c704373 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2000, 2019, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. Copyright (c) 2012, Facebook Inc. @@ -2588,11 +2588,10 @@ innobase_next_autoinc( if (next_value == 0) { ulonglong next; - if (current >= offset) { + if (current > offset) { next = (current - offset) / step; } else { - next = 0; - block -= step; + next = (offset - current) / step; } ut_a(max_value > next); @@ -16035,6 +16034,37 @@ ha_innobase::get_auto_increment( ut_ad(autoinc > 0); } + /** The following logic is needed to avoid duplicate key error + for autoincrement column. + + (1) InnoDB gives the current autoincrement value with respect + to increment and offset value. + + (2) Basically it does compute_next_insert_id() logic inside InnoDB + to avoid the current auto increment value changed by handler layer. + + (3) It is restricted only for insert operations. */ + + if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE + && autoinc < col_max_value) { + + ulonglong prev_auto_inc = autoinc; + + autoinc = ((autoinc - 1) + increment - offset)/ increment; + + autoinc = autoinc * increment + offset; + + /* If autoinc exceeds the col_max_value then reset + to old autoinc value. Because in case of non-strict + sql mode, boundary value is not considered as error. */ + + if (autoinc >= col_max_value) { + autoinc = prev_auto_inc; + } + + ut_ad(autoinc > 0); + } + /* Called for the first time ? */ if (trx->n_autoinc_rows == 0) { @@ -16072,26 +16102,6 @@ ha_innobase::get_auto_increment( current = *first_value; - if (prebuilt->autoinc_increment != increment) { - - WSREP_DEBUG("autoinc decrease: %llu -> %llu\n" - "THD: %ld, current: %llu, autoinc: %llu", - prebuilt->autoinc_increment, - increment, - thd_get_thread_id(ha_thd()), - current, autoinc); - if (!wsrep_on(ha_thd())) - { - current = autoinc - prebuilt->autoinc_increment; - current = innobase_next_autoinc( - current, 1, increment, offset, col_max_value); - } - - dict_table_autoinc_initialize(prebuilt->table, current); - - *first_value = current; - } - /* Compute the last value in the interval */ next_value = innobase_next_autoinc( current, *nb_reserved_values, increment, offset, diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 55e231ef770..ccaeadce932 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2000, 2019, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2013, 2018, MariaDB Corporation. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. @@ -2899,11 +2899,10 @@ innobase_next_autoinc( if (next_value == 0) { ulonglong next; - if (current >= offset) { + if (current > offset) { next = (current - offset) / step; } else { - next = 0; - block -= step; + next = (offset - current) / step; } ut_a(max_value > next); @@ -16673,6 +16672,37 @@ ha_innobase::get_auto_increment( ut_ad(autoinc > 0); } + /** The following logic is needed to avoid duplicate key error + for autoincrement column. + + (1) InnoDB gives the current autoincrement value with respect + to increment and offset value. + + (2) Basically it does compute_next_insert_id() logic inside InnoDB + to avoid the current auto increment value changed by handler layer. + + (3) It is restricted only for insert operations. */ + + if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE + && autoinc < col_max_value) { + + ulonglong prev_auto_inc = autoinc; + + autoinc = ((autoinc - 1) + increment - offset)/ increment; + + autoinc = autoinc * increment + offset; + + /* If autoinc exceeds the col_max_value then reset + to old autoinc value. Because in case of non-strict + sql mode, boundary value is not considered as error. */ + + if (autoinc >= col_max_value) { + autoinc = prev_auto_inc; + } + + ut_ad(autoinc > 0); + } + /* Called for the first time ? */ if (trx->n_autoinc_rows == 0) { @@ -16710,26 +16740,6 @@ ha_innobase::get_auto_increment( current = *first_value; - if (prebuilt->autoinc_increment != increment) { - - WSREP_DEBUG("autoinc decrease: %llu -> %llu\n" - "THD: %ld, current: %llu, autoinc: %llu", - prebuilt->autoinc_increment, - increment, - thd_get_thread_id(ha_thd()), - current, autoinc); - if (!wsrep_on(ha_thd())) - { - current = autoinc - prebuilt->autoinc_increment; - current = innobase_next_autoinc( - current, 1, increment, offset, col_max_value); - } - - dict_table_autoinc_initialize(prebuilt->table, current); - - *first_value = current; - } - /* Compute the last value in the interval */ next_value = innobase_next_autoinc( current, *nb_reserved_values, increment, offset, From d03a59c6ff3c07deff8b3067a97e8f126e294b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Oct 2019 11:56:05 +0200 Subject: [PATCH 56/68] XtraDB 5.6.45-86.1 --- .../sys_vars/r/sysvars_innodb,32bit,xtradb.rdiff | 2 +- .../suite/sys_vars/r/sysvars_innodb,xtradb.rdiff | 2 +- storage/xtradb/buf/buf0buf.cc | 3 ++- storage/xtradb/handler/ha_innodb.cc | 11 ++++++----- storage/xtradb/include/btr0sea.ic | 4 ++-- storage/xtradb/include/ha_prototypes.h | 2 +- storage/xtradb/include/sync0rw.ic | 3 ++- storage/xtradb/include/univ.i | 4 ++-- storage/xtradb/lock/lock0wait.cc | 1 + storage/xtradb/log/log0online.cc | 7 +++---- storage/xtradb/ut/ut0ut.cc | 1 - 11 files changed, 21 insertions(+), 19 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit,xtradb.rdiff b/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit,xtradb.rdiff index 8b8c69d05bf..ff3f5ba1d2c 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit,xtradb.rdiff +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit,xtradb.rdiff @@ -1215,7 +1215,7 @@ VARIABLE_NAME INNODB_VERSION SESSION_VALUE NULL -GLOBAL_VALUE 5.6.45 -+GLOBAL_VALUE 5.6.44-86.0 ++GLOBAL_VALUE 5.6.45-86.1 GLOBAL_VALUE_ORIGIN COMPILE-TIME DEFAULT_VALUE NULL VARIABLE_SCOPE GLOBAL diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb,xtradb.rdiff b/mysql-test/suite/sys_vars/r/sysvars_innodb,xtradb.rdiff index d5a5a0147f5..77e8fb638a1 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb,xtradb.rdiff +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb,xtradb.rdiff @@ -685,7 +685,7 @@ VARIABLE_NAME INNODB_VERSION SESSION_VALUE NULL -GLOBAL_VALUE 5.6.45 -+GLOBAL_VALUE 5.6.44-86.0 ++GLOBAL_VALUE 5.6.45-86.1 GLOBAL_VALUE_ORIGIN COMPILE-TIME DEFAULT_VALUE NULL VARIABLE_SCOPE GLOBAL diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index 09db5188245..6ddcc3521da 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -124,7 +124,8 @@ _increment_page_get_statistics(buf_block_t* block, trx_t* trx) byte block_hash_offset; ut_ad(block); - ut_ad(trx && trx->take_stats); + ut_ad(trx); + ut_ad(trx->take_stats); if (!trx->distinct_page_access_hash) { trx->distinct_page_access_hash diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index ccaeadce932..788f039f1c8 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -2136,12 +2136,13 @@ UNIV_INTERN ulong thd_flush_log_at_trx_commit( /*================================*/ - void* thd) + THD* thd) { /* THDVAR cannot be used in xtrabackup, plugin variables for innodb are not loaded, this makes xtrabackup crash when trying to use them. */ - return (thd || !IS_XTRABACKUP())? THDVAR((THD*)thd, flush_log_at_trx_commit) : FALSE; + return (thd || !IS_XTRABACKUP()) + ? THDVAR(thd, flush_log_at_trx_commit) : 0; } /********************************************************************//** @@ -19003,7 +19004,7 @@ innodb_sched_priority_master_update( push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WRONG_ARGUMENTS, "Failed to set the master thread " - "priority to %lu, " + "priority to %lu, " "the nice is %lu and the current priority is %lu", priority, nice, actual_priority); } @@ -21134,14 +21135,14 @@ static MYSQL_SYSVAR_BOOL(force_primary_key, "Do not allow to create table without primary key (off by default)", NULL, NULL, FALSE); -const char *corrupt_table_action_names[]= +static const char *corrupt_table_action_names[]= { "assert", /* 0 */ "warn", /* 1 */ "salvage", /* 2 */ NullS }; -TYPELIB corrupt_table_action_typelib= +static TYPELIB corrupt_table_action_typelib= { array_elements(corrupt_table_action_names) - 1, "corrupt_table_action_typelib", corrupt_table_action_names, NULL diff --git a/storage/xtradb/include/btr0sea.ic b/storage/xtradb/include/btr0sea.ic index 4838799e906..f7cff91f9d0 100644 --- a/storage/xtradb/include/btr0sea.ic +++ b/storage/xtradb/include/btr0sea.ic @@ -104,8 +104,8 @@ btr_search_get_latch( /*=================*/ const dict_index_t* index) /*!< in: index */ { - ut_ad(index->search_latch >= btr_search_latch_arr && - index->search_latch < btr_search_latch_arr + + ut_ad(index->search_latch >= btr_search_latch_arr); + ut_ad(index->search_latch < btr_search_latch_arr + btr_search_index_num); return(index->search_latch); diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h index 50b223d34f8..e5b545e0727 100644 --- a/storage/xtradb/include/ha_prototypes.h +++ b/storage/xtradb/include/ha_prototypes.h @@ -418,7 +418,7 @@ innobase_get_table_cache_size(void); ulong thd_flush_log_at_trx_commit( /*================================*/ - void* thd); + THD* thd); /**********************************************************************//** Get the current setting of the lower_case_table_names global parameter from diff --git a/storage/xtradb/include/sync0rw.ic b/storage/xtradb/include/sync0rw.ic index 075858bd3ce..125c4d90b24 100644 --- a/storage/xtradb/include/sync0rw.ic +++ b/storage/xtradb/include/sync0rw.ic @@ -453,7 +453,8 @@ rw_lock_higher_prio_waiters_exist( return(false); } - ut_ad(priority_lock && !high_priority); + ut_ad(priority_lock); + ut_ad(!high_priority); prio_rw_lock_t *prio_rw_lock = (prio_rw_lock_t *) lock; return prio_rw_lock->high_priority_wait_ex_waiter > 0 diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i index 69d5cbac5d1..011921d9a39 100644 --- a/storage/xtradb/include/univ.i +++ b/storage/xtradb/include/univ.i @@ -45,10 +45,10 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 6 -#define INNODB_VERSION_BUGFIX 44 +#define INNODB_VERSION_BUGFIX 45 #ifndef PERCONA_INNODB_VERSION -#define PERCONA_INNODB_VERSION 86.0 +#define PERCONA_INNODB_VERSION 86.1 #endif /* Enable UNIV_LOG_ARCHIVE in XtraDB */ diff --git a/storage/xtradb/lock/lock0wait.cc b/storage/xtradb/lock/lock0wait.cc index 3efc28967db..fe43ef3cc73 100644 --- a/storage/xtradb/lock/lock0wait.cc +++ b/storage/xtradb/lock/lock0wait.cc @@ -207,6 +207,7 @@ functions to get some info from THD. @param[in] trx requested trx @param[in] blocking blocking info array @param[in] blocking_count blocking info array size */ +static void print_lock_wait_timeout( const trx_t &trx, diff --git a/storage/xtradb/log/log0online.cc b/storage/xtradb/log/log0online.cc index 460fb19cf8a..601babc54a9 100644 --- a/storage/xtradb/log/log0online.cc +++ b/storage/xtradb/log/log0online.cc @@ -91,7 +91,7 @@ static const char* bmp_file_name_stem = "ib_modified_log_"; /** File name template for bitmap files. The 1st format tag is a directory name, the 2nd tag is the stem, the 3rd tag is a file sequence number, the 4th tag is the start LSN for the file. */ -static const char* bmp_file_name_template = "%s%s%lu_%llu.xdb"; +static const char* bmp_file_name_template = "%s%s%lu_" LSN_PF ".xdb"; /* On server startup with empty database srv_start_lsn == 0, in which case the first LSN of actual log records will be this. */ @@ -586,9 +586,8 @@ log_online_is_bitmap_file( return ((file_info->type == OS_FILE_TYPE_FILE || file_info->type == OS_FILE_TYPE_LINK) - && (sscanf(file_info->name, "%[a-z_]%lu_%llu.xdb", stem, - bitmap_file_seq_num, - (unsigned long long *)bitmap_file_start_lsn) == 3) + && (sscanf(file_info->name, "%[a-z_]%lu_" LSN_PF ".xdb", stem, + bitmap_file_seq_num, bitmap_file_start_lsn) == 3) && (!strcmp(stem, bmp_file_name_stem))); } diff --git a/storage/xtradb/ut/ut0ut.cc b/storage/xtradb/ut/ut0ut.cc index a9f24fcf18a..aa228a33bdc 100644 --- a/storage/xtradb/ut/ut0ut.cc +++ b/storage/xtradb/ut/ut0ut.cc @@ -40,7 +40,6 @@ Created 5/11/1994 Heikki Tuuri #include #ifndef UNIV_HOTBACKUP -# include "btr0types.h" # include "trx0trx.h" # include "ha_prototypes.h" # include "mysql_com.h" /* NAME_LEN */ From 73c864b5d16aec710a1686a83fb7e92e080a2f30 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 30 Oct 2019 12:25:07 +0100 Subject: [PATCH 57/68] Fix clang-cl build on Windows --- cmake/os/Windows.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index eb56f599eb4..dbb18a488c7 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -206,7 +206,7 @@ IF(MSVC) # Noisy warning C4800: 'type': forcing value to bool 'true' or 'false' (performance warning), # removed in VS2017 SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4800") - ELSE() + ELSEIF (NOT (CMAKE_CXX_COMPILER_ID MATCHES Clang)) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /d2OptimizeHugeFunctions") ENDIF() ENDIF() From 9277b6ec1ce8bc195a10b5deb11d65843adf8972 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 30 Oct 2019 14:38:18 +0100 Subject: [PATCH 58/68] Revert "MDEV-14448: Ctrl-C should not exit the client" This reverts commit 396313d301b3567aeadd04ae6a9322da2adc0a8b. --- client/mysql.cc | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 7329f2298ab..50d45696a5c 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1368,23 +1368,12 @@ sig_handler handle_sigint(int sig) char kill_buffer[40]; MYSQL *kill_mysql= NULL; - /* Terminate if we already tried interrupting. */ - if (interrupted_query == 2) + /* terminate if no query being executed, or we already tried interrupting */ + if (!executing_query || (interrupted_query == 2)) { tee_fprintf(stdout, "Ctrl-C -- exit!\n"); goto err; } - /* If no query being executed, don't exit. */ - if (!executing_query) - { - tee_fprintf(stdout, "Ctrl-C\n"); -#ifdef HAVE_READLINE - rl_on_new_line(); // Regenerate the prompt on a newline - rl_replace_line("", 0); // Clear the previous text - rl_redisplay(); -#endif - return; - } kill_mysql= mysql_init(kill_mysql); if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password, From 8fce180765b2ede9fb9f0f7ee6ffcda3386050bf Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 30 Oct 2019 09:50:52 +0100 Subject: [PATCH 59/68] MDEV-19432 Systemd service does not get re-enabled after upgrade following Fedora recommendations (see %systemd_post macro in FC29) let's do `systemctl preset` on the first installation of the server --- support-files/rpm/server-postin.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/support-files/rpm/server-postin.sh b/support-files/rpm/server-postin.sh index deb27c98ac1..71518423687 100644 --- a/support-files/rpm/server-postin.sh +++ b/support-files/rpm/server-postin.sh @@ -16,7 +16,8 @@ fi # Make MySQL start/shutdown automatically when the machine does it. if [ $1 = 1 ] ; then if [ -x /usr/bin/systemctl ] ; then - /usr/bin/systemctl daemon-reload >/dev/null 2>&1 + /usr/bin/systemctl daemon-reload >/dev/null 2>&1 || : + /usr/bin/systemctl preset mariadb.service >/dev/null 2>&1 || : elif [ -x /sbin/chkconfig ] ; then /sbin/chkconfig --add mysql fi From d6d621cec18251b55202bbd362315b3c1ed90181 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 30 Oct 2019 13:53:07 +0100 Subject: [PATCH 60/68] MDEV-18819 ALTER_COLUMN_VCOL is not set for generated stored columns --- .../innodb/r/alter_algorithm,INPLACE.rdiff | 14 ++++---------- .../innodb/r/alter_algorithm,INSTANT.rdiff | 13 ++++--------- .../innodb/r/alter_algorithm,NOCOPY.rdiff | 13 ++++--------- .../suite/innodb/r/alter_algorithm.result | 4 ---- .../innodb/r/innodb-alter-nullable.result | 19 ++++++++----------- .../suite/innodb/t/alter_algorithm.test | 4 ---- .../suite/innodb/t/innodb-alter-nullable.test | 3 --- sql/sql_table.cc | 2 +- 8 files changed, 21 insertions(+), 51 deletions(-) diff --git a/mysql-test/suite/innodb/r/alter_algorithm,INPLACE.rdiff b/mysql-test/suite/innodb/r/alter_algorithm,INPLACE.rdiff index a1fa20c2ba1..805ccdb563c 100644 --- a/mysql-test/suite/innodb/r/alter_algorithm,INPLACE.rdiff +++ b/mysql-test/suite/innodb/r/alter_algorithm,INPLACE.rdiff @@ -1,6 +1,6 @@ --- alter_algorithm.result +++ alter_algorithm.reject -@@ -7,44 +7,44 @@ +@@ -7,40 +7,40 @@ INSERT INTO t1(f1, f2, f3) VALUES(1, 1, 1); SELECT @@alter_algorithm; @@alter_algorithm @@ -18,12 +18,6 @@ -affected rows: 1 -info: Records: 1 Duplicates: 0 Warnings: 0 +affected rows: 0 -+info: Records: 0 Duplicates: 0 Warnings: 0 - # Make existing column NON-NULLABLE - ALTER TABLE t1 MODIFY f3 INT NOT NULL; --affected rows: 1 --info: Records: 1 Duplicates: 0 Warnings: 0 -+affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 # Drop Stored Column ALTER TABLE t1 DROP COLUMN f5; @@ -64,7 +58,7 @@ DROP TABLE t1; affected rows: 0 CREATE TABLE t1(f1 INT PRIMARY KEY, f2 INT NOT NULL, -@@ -57,22 +57,22 @@ +@@ -53,22 +53,22 @@ FOREIGN KEY fidx(f1) REFERENCES t1(f1))ENGINE=INNODB; INSERT INTO t1(f1, f2, f4, f5) VALUES(1, 2, 3, 4); ALTER TABLE t1 ADD INDEX idx1(f4), page_compressed=1; @@ -97,7 +91,7 @@ DROP TABLE t2, t1; affected rows: 0 CREATE TABLE t1(f1 INT NOT NULL, -@@ -85,27 +85,27 @@ +@@ -81,27 +81,27 @@ INSERT INTO t1(f1, f2) VALUES(1, 1); # Add column at the end of the table ALTER TABLE t1 ADD COLUMN f4 char(100) default 'BIG WALL'; @@ -135,7 +129,7 @@ # Column length varies ALTER TABLE t2 CHANGE f3 f3 VARCHAR(20); affected rows: 0 -@@ -113,12 +113,12 @@ +@@ -109,12 +109,12 @@ SET foreign_key_checks = 0; affected rows: 0 ALTER TABLE t3 ADD FOREIGN KEY fidx(f2) REFERENCES t2(f1); diff --git a/mysql-test/suite/innodb/r/alter_algorithm,INSTANT.rdiff b/mysql-test/suite/innodb/r/alter_algorithm,INSTANT.rdiff index 879bba43932..6d2ee160e46 100644 --- a/mysql-test/suite/innodb/r/alter_algorithm,INSTANT.rdiff +++ b/mysql-test/suite/innodb/r/alter_algorithm,INSTANT.rdiff @@ -1,6 +1,6 @@ --- alter_algorithm.result +++ alter_algorithm.reject -@@ -7,44 +7,35 @@ +@@ -7,40 +7,32 @@ INSERT INTO t1(f1, f2, f3) VALUES(1, 1, 1); SELECT @@alter_algorithm; @@alter_algorithm @@ -16,11 +16,6 @@ ALTER TABLE t1 MODIFY f2 INT; -affected rows: 1 -info: Records: 1 Duplicates: 0 Warnings: 0 -+Got one of the listed errors - # Make existing column NON-NULLABLE - ALTER TABLE t1 MODIFY f3 INT NOT NULL; --affected rows: 1 --info: Records: 1 Duplicates: 0 Warnings: 0 +Got one of the listed errors # Drop Stored Column ALTER TABLE t1 DROP COLUMN f5; @@ -55,7 +50,7 @@ DROP TABLE t1; affected rows: 0 CREATE TABLE t1(f1 INT PRIMARY KEY, f2 INT NOT NULL, -@@ -57,22 +48,17 @@ +@@ -53,22 +45,17 @@ FOREIGN KEY fidx(f1) REFERENCES t1(f1))ENGINE=INNODB; INSERT INTO t1(f1, f2, f4, f5) VALUES(1, 2, 3, 4); ALTER TABLE t1 ADD INDEX idx1(f4), page_compressed=1; @@ -83,7 +78,7 @@ DROP TABLE t2, t1; affected rows: 0 CREATE TABLE t1(f1 INT NOT NULL, -@@ -85,27 +71,27 @@ +@@ -81,27 +68,27 @@ INSERT INTO t1(f1, f2) VALUES(1, 1); # Add column at the end of the table ALTER TABLE t1 ADD COLUMN f4 char(100) default 'BIG WALL'; @@ -121,7 +116,7 @@ # Column length varies ALTER TABLE t2 CHANGE f3 f3 VARCHAR(20); affected rows: 0 -@@ -113,12 +99,12 @@ +@@ -109,12 +96,12 @@ SET foreign_key_checks = 0; affected rows: 0 ALTER TABLE t3 ADD FOREIGN KEY fidx(f2) REFERENCES t2(f1); diff --git a/mysql-test/suite/innodb/r/alter_algorithm,NOCOPY.rdiff b/mysql-test/suite/innodb/r/alter_algorithm,NOCOPY.rdiff index 6db0f2af347..c6ce83b5d9f 100644 --- a/mysql-test/suite/innodb/r/alter_algorithm,NOCOPY.rdiff +++ b/mysql-test/suite/innodb/r/alter_algorithm,NOCOPY.rdiff @@ -1,6 +1,6 @@ --- alter_algorithm.result +++ alter_algorithm.reject -@@ -7,44 +7,35 @@ +@@ -7,40 +7,32 @@ INSERT INTO t1(f1, f2, f3) VALUES(1, 1, 1); SELECT @@alter_algorithm; @@alter_algorithm @@ -16,11 +16,6 @@ ALTER TABLE t1 MODIFY f2 INT; -affected rows: 1 -info: Records: 1 Duplicates: 0 Warnings: 0 -+Got one of the listed errors - # Make existing column NON-NULLABLE - ALTER TABLE t1 MODIFY f3 INT NOT NULL; --affected rows: 1 --info: Records: 1 Duplicates: 0 Warnings: 0 +Got one of the listed errors # Drop Stored Column ALTER TABLE t1 DROP COLUMN f5; @@ -55,7 +50,7 @@ DROP TABLE t1; affected rows: 0 CREATE TABLE t1(f1 INT PRIMARY KEY, f2 INT NOT NULL, -@@ -57,22 +48,22 @@ +@@ -53,22 +45,22 @@ FOREIGN KEY fidx(f1) REFERENCES t1(f1))ENGINE=INNODB; INSERT INTO t1(f1, f2, f4, f5) VALUES(1, 2, 3, 4); ALTER TABLE t1 ADD INDEX idx1(f4), page_compressed=1; @@ -88,7 +83,7 @@ DROP TABLE t2, t1; affected rows: 0 CREATE TABLE t1(f1 INT NOT NULL, -@@ -85,27 +76,27 @@ +@@ -81,27 +73,27 @@ INSERT INTO t1(f1, f2) VALUES(1, 1); # Add column at the end of the table ALTER TABLE t1 ADD COLUMN f4 char(100) default 'BIG WALL'; @@ -126,7 +121,7 @@ # Column length varies ALTER TABLE t2 CHANGE f3 f3 VARCHAR(20); affected rows: 0 -@@ -113,12 +104,12 @@ +@@ -109,12 +101,12 @@ SET foreign_key_checks = 0; affected rows: 0 ALTER TABLE t3 ADD FOREIGN KEY fidx(f2) REFERENCES t2(f1); diff --git a/mysql-test/suite/innodb/r/alter_algorithm.result b/mysql-test/suite/innodb/r/alter_algorithm.result index 3d3a7e85444..bcfbe3355f9 100644 --- a/mysql-test/suite/innodb/r/alter_algorithm.result +++ b/mysql-test/suite/innodb/r/alter_algorithm.result @@ -17,10 +17,6 @@ info: Records: 1 Duplicates: 0 Warnings: 0 ALTER TABLE t1 MODIFY f2 INT; affected rows: 1 info: Records: 1 Duplicates: 0 Warnings: 0 -# Make existing column NON-NULLABLE -ALTER TABLE t1 MODIFY f3 INT NOT NULL; -affected rows: 1 -info: Records: 1 Duplicates: 0 Warnings: 0 # Drop Stored Column ALTER TABLE t1 DROP COLUMN f5; affected rows: 1 diff --git a/mysql-test/suite/innodb/r/innodb-alter-nullable.result b/mysql-test/suite/innodb/r/innodb-alter-nullable.result index 68ad6762335..1d481cf2bfe 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-nullable.result +++ b/mysql-test/suite/innodb/r/innodb-alter-nullable.result @@ -96,8 +96,8 @@ INSERT INTO t3 SET c=NULL; SET @old_sql_mode = @@sql_mode; SET sql_mode = ''; ALTER TABLE t1 MODIFY c INT NOT NULL; -affected rows: 0 -info: Records: 0 Duplicates: 0 Warnings: 1 +affected rows: 1 +info: Records: 1 Duplicates: 0 Warnings: 1 Warnings: Warning 1265 Data truncated for column 'c' at row 1 ALTER TABLE t2 MODIFY c INT NOT NULL; @@ -111,10 +111,9 @@ info: Records: 1 Duplicates: 0 Warnings: 1 Warnings: Warning 1265 Data truncated for column 'c' at row 1 SET sql_mode = @old_sql_mode; -# MDEV-18819 FIXME: Wrong result g=NULL SELECT * FROM t1; c g -0 NULL +0 0 SELECT * FROM t2; c v 0 0 @@ -137,8 +136,8 @@ INSERT INTO t1 SET c=NULL; INSERT INTO t2 SET c=NULL; INSERT INTO t3 SET c=NULL; ALTER IGNORE TABLE t1 MODIFY c INT NOT NULL; -affected rows: 0 -info: Records: 0 Duplicates: 0 Warnings: 1 +affected rows: 1 +info: Records: 1 Duplicates: 0 Warnings: 1 Warnings: Warning 1265 Data truncated for column 'c' at row 1 ALTER IGNORE TABLE t2 MODIFY c INT NOT NULL; @@ -151,10 +150,9 @@ affected rows: 1 info: Records: 1 Duplicates: 0 Warnings: 1 Warnings: Warning 1265 Data truncated for column 'c' at row 1 -# MDEV-18819 FIXME: Wrong result g=NULL SELECT * FROM t1; c g -0 NULL +0 0 SELECT * FROM t2; c v 0 0 @@ -186,12 +184,11 @@ UPDATE t1 SET c=0; UPDATE t2 SET c=0; UPDATE t3 SET c=0; ALTER TABLE t1 MODIFY c INT NOT NULL; -affected rows: 0 -info: Records: 0 Duplicates: 0 Warnings: 0 +affected rows: 1 +info: Records: 1 Duplicates: 0 Warnings: 0 ALTER TABLE t2 MODIFY c INT NOT NULL; affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 -# MDEV-18819 FIXME: This should not require ALGORITHM=COPY. ALTER TABLE t3 MODIFY c INT NOT NULL; affected rows: 1 info: Records: 1 Duplicates: 0 Warnings: 0 diff --git a/mysql-test/suite/innodb/t/alter_algorithm.test b/mysql-test/suite/innodb/t/alter_algorithm.test index 7cb706e865a..d410a15154d 100644 --- a/mysql-test/suite/innodb/t/alter_algorithm.test +++ b/mysql-test/suite/innodb/t/alter_algorithm.test @@ -31,10 +31,6 @@ ALTER TABLE t1 ADD COLUMN col1 INT NOT NULL,DROP PRIMARY KEY,ADD PRIMARY KEY(col --error $error_code ALTER TABLE t1 MODIFY f2 INT; ---echo # Make existing column NON-NULLABLE ---error $error_code -ALTER TABLE t1 MODIFY f3 INT NOT NULL; - --echo # Drop Stored Column --error $error_code ALTER TABLE t1 DROP COLUMN f5; diff --git a/mysql-test/suite/innodb/t/innodb-alter-nullable.test b/mysql-test/suite/innodb/t/innodb-alter-nullable.test index 9e6f5df2bc9..af13a12ab41 100644 --- a/mysql-test/suite/innodb/t/innodb-alter-nullable.test +++ b/mysql-test/suite/innodb/t/innodb-alter-nullable.test @@ -104,7 +104,6 @@ ALTER TABLE t2 MODIFY c INT NOT NULL; ALTER TABLE t3 MODIFY c INT NOT NULL; --disable_info SET sql_mode = @old_sql_mode; ---echo # MDEV-18819 FIXME: Wrong result g=NULL SELECT * FROM t1; SELECT * FROM t2; SELECT * FROM t3; @@ -123,7 +122,6 @@ ALTER IGNORE TABLE t1 MODIFY c INT NOT NULL; ALTER IGNORE TABLE t2 MODIFY c INT NOT NULL; ALTER IGNORE TABLE t3 MODIFY c INT NOT NULL; --disable_info ---echo # MDEV-18819 FIXME: Wrong result g=NULL SELECT * FROM t1; SELECT * FROM t2; SELECT * FROM t3; @@ -151,7 +149,6 @@ UPDATE t3 SET c=0; --enable_info ALTER TABLE t1 MODIFY c INT NOT NULL; ALTER TABLE t2 MODIFY c INT NOT NULL; ---echo # MDEV-18819 FIXME: This should not require ALGORITHM=COPY. ALTER TABLE t3 MODIFY c INT NOT NULL; --disable_info SELECT * FROM t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8eb0b078bd1..bb22e9a9f34 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6733,7 +6733,7 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar, } if (field->vcol_info->is_in_partitioning_expr() || - field->flags & PART_KEY_FLAG) + field->flags & PART_KEY_FLAG || field->stored_in_db()) { if (value_changes) ha_alter_info->handler_flags|= ALTER_COLUMN_VCOL; From baaf02a48b459e45714910d220a9379c6d38f875 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 30 Oct 2019 21:37:46 +0100 Subject: [PATCH 61/68] new CC 3.1 --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index c6403c4c847..947357354a9 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit c6403c4c847d94ed6b40d3fd128e729271867e75 +Subproject commit 947357354a92cbb7c15b1e9087d085fe65f75f5e From 5392b4a32c9da296f7b2e6a5b83e3bff6c24871e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 30 Oct 2019 19:31:26 +0100 Subject: [PATCH 62/68] MDEV-20354 All but last insert ignored in InnoDB tables when table locked mysql_insert() first opens all affected tables (which implicitly starts a transaction in InnoDB), then stat tables. A failure to open a stat table caused open_tables() to abort the current stmt transaction (trans_rollback_stmt()). So, from the server point of view the following ha_write_row()-s happened outside of a transactions, and the server didn't bother to commit them. The server has a mechanism to prevent a transaction being unexpectedly committed or rolled back in the middle of a statement - if an operation takes place _in a sub-statement_ it cannot change the transaction state. Operations on stat tables are exactly that - they are not allowed to change a transaction state. Put them in a sub-statement to make sure they don't. --- mysql-test/suite/innodb/r/stat_tables.result | 15 +++++++++++++++ mysql-test/suite/innodb/t/stat_tables.test | 17 +++++++++++++++++ sql/sql_class.h | 4 ++++ sql/sql_statistics.cc | 2 ++ 4 files changed, 38 insertions(+) create mode 100644 mysql-test/suite/innodb/r/stat_tables.result create mode 100644 mysql-test/suite/innodb/t/stat_tables.test diff --git a/mysql-test/suite/innodb/r/stat_tables.result b/mysql-test/suite/innodb/r/stat_tables.result new file mode 100644 index 00000000000..bb449570479 --- /dev/null +++ b/mysql-test/suite/innodb/r/stat_tables.result @@ -0,0 +1,15 @@ +rename table mysql.table_stats to mysql.table_stats_save; +flush tables; +set use_stat_tables= PREFERABLY; +create table t1 (a int) engine=InnoDB; +start transaction; +insert t1 values (1); +insert t1 values (2); +commit; +select * from t1; +a +1 +2 +drop table t1; +rename table mysql.table_stats_save to mysql.table_stats; +flush tables; diff --git a/mysql-test/suite/innodb/t/stat_tables.test b/mysql-test/suite/innodb/t/stat_tables.test new file mode 100644 index 00000000000..68344b3f425 --- /dev/null +++ b/mysql-test/suite/innodb/t/stat_tables.test @@ -0,0 +1,17 @@ +source include/have_innodb.inc; + +# +# MDEV-20354 All but last insert ignored in InnoDB tables when table locked +# +rename table mysql.table_stats to mysql.table_stats_save; +flush tables; +set use_stat_tables= PREFERABLY; +create table t1 (a int) engine=InnoDB; +start transaction; +insert t1 values (1); +insert t1 values (2); +commit; +select * from t1; +drop table t1; +rename table mysql.table_stats_save to mysql.table_stats; +flush tables; diff --git a/sql/sql_class.h b/sql/sql_class.h index 6c622648ac7..56bb9f45877 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1444,12 +1444,16 @@ public: /** @class Sub_statement_state @brief Used to save context when executing a function or trigger + + operations on stat tables aren't technically a sub-statement, but they are + similar in a sense that they cannot change the transaction status. */ /* Defines used for Sub_statement_state::in_sub_stmt */ #define SUB_STMT_TRIGGER 1 #define SUB_STMT_FUNCTION 2 +#define SUB_STMT_STAT_TABLES 4 class Sub_statement_state diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 4a1ed9cde4e..f002a5a5eab 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -268,7 +268,9 @@ inline int open_stat_tables(THD *thd, TABLE_LIST *tables, thd->push_internal_handler(&deh); init_table_list_for_stat_tables(tables, for_write); init_mdl_requests(tables); + thd->in_sub_stmt|= SUB_STMT_STAT_TABLES; rc= open_system_tables_for_read(thd, tables, backup); + thd->in_sub_stmt&= ~SUB_STMT_STAT_TABLES; thd->pop_internal_handler(); From 313855766f3ce608001d686553ef6e087a70d264 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 30 Oct 2019 19:42:16 +0100 Subject: [PATCH 63/68] cleanup * use compile_time_assert instead of DBUG_ASSERT * don't use thd->clear_error(), because * the error was already consumed by the error handler, so there is nothing to clear * it's dangerous to clear errors indiscriminately, if the error came from outside of read_statistics_for_tables() it must not be cleared --- sql/sql_statistics.cc | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index f002a5a5eab..11e2db9ae44 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -257,10 +257,8 @@ index_stat_def= {INDEX_STAT_N_FIELDS, index_stat_fields, 4, index_stat_pk_col}; Open all statistical tables and lock them */ -static -inline int open_stat_tables(THD *thd, TABLE_LIST *tables, - Open_tables_backup *backup, - bool for_write) +static int open_stat_tables(THD *thd, TABLE_LIST *tables, + Open_tables_backup *backup, bool for_write) { int rc; @@ -275,7 +273,7 @@ inline int open_stat_tables(THD *thd, TABLE_LIST *tables, /* If the number of tables changes, we should revise the check below. */ - DBUG_ASSERT(STATISTICS_TABLES == 3); + compile_time_assert(STATISTICS_TABLES == 3); if (!rc && (stat_table_intact.check(tables[TABLE_STAT].table, &table_stat_def) || @@ -3258,10 +3256,7 @@ int read_statistics_for_tables(THD *thd, TABLE_LIST *tables) DBUG_RETURN(0); if (open_stat_tables(thd, stat_tables, &open_tables_backup, FALSE)) - { - thd->clear_error(); DBUG_RETURN(1); - } for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) { From 2ba9a269df1c2321f6fa82ee6215c7ef06cf35e2 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Thu, 31 Oct 2019 06:13:38 +0100 Subject: [PATCH 64/68] new CC 3.1 due to typo in it --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index 947357354a9..980f2dbea65 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 947357354a92cbb7c15b1e9087d085fe65f75f5e +Subproject commit 980f2dbea6586091333057bb2994b18747466942 From 1bb857089fdcd3a08cb166cb6d75f3e1dbb76f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 31 Oct 2019 07:44:18 +0200 Subject: [PATCH 65/68] MDEV-20927: Remove duplicated code In commit d1e6b0bcff0148f474e38002d5c1198726fe7970 some code was supposed to be modified, but instead it got duplicated. Remove the duplicated copy. --- storage/innobase/handler/ha_innodb.cc | 31 --------------------------- storage/xtradb/handler/ha_innodb.cc | 31 --------------------------- 2 files changed, 62 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ed15c704373..4de2cdbeaec 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -16014,37 +16014,6 @@ ha_innobase::get_auto_increment( (3) It is restricted only for insert operations. */ - if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE - && autoinc < col_max_value) { - - ulonglong prev_auto_inc = autoinc; - - autoinc = ((autoinc - 1) + increment - offset)/ increment; - - autoinc = autoinc * increment + offset; - - /* If autoinc exceeds the col_max_value then reset - to old autoinc value. Because in case of non-strict - sql mode, boundary value is not considered as error. */ - - if (autoinc >= col_max_value) { - autoinc = prev_auto_inc; - } - - ut_ad(autoinc > 0); - } - - /** The following logic is needed to avoid duplicate key error - for autoincrement column. - - (1) InnoDB gives the current autoincrement value with respect - to increment and offset value. - - (2) Basically it does compute_next_insert_id() logic inside InnoDB - to avoid the current auto increment value changed by handler layer. - - (3) It is restricted only for insert operations. */ - if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE && autoinc < col_max_value) { diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 788f039f1c8..2aafb1a44ee 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -16653,37 +16653,6 @@ ha_innobase::get_auto_increment( (3) It is restricted only for insert operations. */ - if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE - && autoinc < col_max_value) { - - ulonglong prev_auto_inc = autoinc; - - autoinc = ((autoinc - 1) + increment - offset)/ increment; - - autoinc = autoinc * increment + offset; - - /* If autoinc exceeds the col_max_value then reset - to old autoinc value. Because in case of non-strict - sql mode, boundary value is not considered as error. */ - - if (autoinc >= col_max_value) { - autoinc = prev_auto_inc; - } - - ut_ad(autoinc > 0); - } - - /** The following logic is needed to avoid duplicate key error - for autoincrement column. - - (1) InnoDB gives the current autoincrement value with respect - to increment and offset value. - - (2) Basically it does compute_next_insert_id() logic inside InnoDB - to avoid the current auto increment value changed by handler layer. - - (3) It is restricted only for insert operations. */ - if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE && autoinc < col_max_value) { From 6dce6aecebe6ef78a14cb5c5c5daa8a355551e40 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 1 Nov 2019 09:39:43 +0400 Subject: [PATCH 66/68] MDEV-18244 Server crashes in ha_innobase::update_thd / ... / ha_partition::update_next_auto_inc_val. Partition table with the AUTO_INCREMENT column we ahve to check if the max value is properly loaded. So we need to open all tables in INSERT PARTITION statement if necessary. Also we need to check if some tables are pruned away and not count the max autoincrement in this case. --- mysql-test/main/partition_innodb.result | 24 ++++++++++++++++++++++++ mysql-test/main/partition_innodb.test | 20 ++++++++++++++++++++ sql/ha_partition.cc | 24 ++++++++++++++++-------- sql/ha_partition.h | 13 +++++++++++++ 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/mysql-test/main/partition_innodb.result b/mysql-test/main/partition_innodb.result index f3d24347ff9..5c63fcfbbc9 100644 --- a/mysql-test/main/partition_innodb.result +++ b/mysql-test/main/partition_innodb.result @@ -1028,5 +1028,29 @@ COUNT(*) 2 DROP TABLE t1; # +# MDEV-18244 Server crashes in ha_innobase::update_thd / ... / ha_partition::update_next_auto_inc_val +# +CREATE TABLE t1 (a INT) +ENGINE=InnoDB +PARTITION BY RANGE (a) ( +PARTITION p0 VALUES LESS THAN (6), +PARTITION pn VALUES LESS THAN MAXVALUE +); +INSERT INTO t1 VALUES (4),(5),(6); +ALTER TABLE t1 MODIFY a INT AUTO_INCREMENT PRIMARY KEY; +UPDATE t1 PARTITION (p0) SET a = 3 WHERE a = 5; +INSERT INTO t1 PARTITION(p0) VALUES (); +ERROR HY000: Found a row not matching the given partition set +INSERT INTO t1 PARTITION(p0) VALUES (-1); +INSERT INTO t1 VALUES (); +SELECT * FROM t1; +a +-1 +1 +3 +4 +6 +DROP TABLE t1; +# # End of 10.3 tests # diff --git a/mysql-test/main/partition_innodb.test b/mysql-test/main/partition_innodb.test index 629bc29e758..f7ce9b03a54 100644 --- a/mysql-test/main/partition_innodb.test +++ b/mysql-test/main/partition_innodb.test @@ -1105,6 +1105,26 @@ INSERT INTO t1 VALUES (1, 7, 8, 9), (2, NULL, NULL, NULL), (3, NULL, NULL, NULL) SELECT COUNT(*) FROM t1 WHERE x IS NULL AND y IS NULL AND z IS NULL; DROP TABLE t1; +--echo # +--echo # MDEV-18244 Server crashes in ha_innobase::update_thd / ... / ha_partition::update_next_auto_inc_val +--echo # + +CREATE TABLE t1 (a INT) + ENGINE=InnoDB + PARTITION BY RANGE (a) ( + PARTITION p0 VALUES LESS THAN (6), + PARTITION pn VALUES LESS THAN MAXVALUE + ); +INSERT INTO t1 VALUES (4),(5),(6); +ALTER TABLE t1 MODIFY a INT AUTO_INCREMENT PRIMARY KEY; +UPDATE t1 PARTITION (p0) SET a = 3 WHERE a = 5; +--error ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET +INSERT INTO t1 PARTITION(p0) VALUES (); +INSERT INTO t1 PARTITION(p0) VALUES (-1); +INSERT INTO t1 VALUES (); +SELECT * FROM t1; +DROP TABLE t1; + --echo # --echo # End of 10.3 tests --echo # diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 5a78249644d..ccda01de6b7 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3459,8 +3459,7 @@ bool ha_partition::init_partition_bitmaps() /* Open handler object - - SYNOPSIS +SYNOPSIS open() name Full path of table name mode Open mode flags @@ -3586,6 +3585,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) } else { + check_insert_autoincrement(); if (unlikely((error= open_read_partitions(name_buff, sizeof(name_buff))))) goto err_handler; m_num_locks= m_file_sample->lock_count(); @@ -4472,11 +4472,8 @@ exit: table->found_next_number_field->field_index)) { update_next_auto_inc_val(); - /* - The following call is safe as part_share->auto_inc_initialized - (tested in the call) is guaranteed to be set for update statements. - */ - set_auto_increment_if_higher(table->found_next_number_field); + if (part_share->auto_inc_initialized) + set_auto_increment_if_higher(table->found_next_number_field); } DBUG_RETURN(error); } @@ -8144,6 +8141,7 @@ int ha_partition::info(uint flag) if (flag & HA_STATUS_AUTO) { bool auto_inc_is_first_in_idx= (table_share->next_number_keypart == 0); + bool all_parts_opened= true; DBUG_PRINT("info", ("HA_STATUS_AUTO")); if (!table->found_next_number_field) stats.auto_increment_value= 0; @@ -8174,6 +8172,15 @@ int ha_partition::info(uint flag) ("checking all partitions for auto_increment_value")); do { + if (!bitmap_is_set(&m_opened_partitions, (uint)(file_array - m_file))) + { + /* + Some partitions aren't opened. + So we can't calculate the autoincrement. + */ + all_parts_opened= false; + break; + } file= *file_array; file->info(HA_STATUS_AUTO | no_lock_flag); set_if_bigger(auto_increment_value, @@ -8182,7 +8189,7 @@ int ha_partition::info(uint flag) DBUG_ASSERT(auto_increment_value); stats.auto_increment_value= auto_increment_value; - if (auto_inc_is_first_in_idx) + if (all_parts_opened && auto_inc_is_first_in_idx) { set_if_bigger(part_share->next_auto_inc_val, auto_increment_value); @@ -8485,6 +8492,7 @@ int ha_partition::change_partitions_to_open(List *partition_names) return 0; } + check_insert_autoincrement(); if (bitmap_cmp(&m_opened_partitions, &m_part_info->read_partitions) != 0) return 0; diff --git a/sql/ha_partition.h b/sql/ha_partition.h index d48947822b9..1085eca72cc 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1329,6 +1329,19 @@ private: unlock_auto_increment(); } + void check_insert_autoincrement() + { + /* + If we INSERT into the table having the AUTO_INCREMENT column, + we have to read all partitions for the next autoincrement value + unless we already did it. + */ + if (!part_share->auto_inc_initialized && + ha_thd()->lex->sql_command == SQLCOM_INSERT && + table->found_next_number_field) + bitmap_set_all(&m_part_info->read_partitions); + } + public: /* From 162f475c4be81dfbceed093ad03d114b4c69a3c0 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Fri, 1 Nov 2019 06:57:20 +0530 Subject: [PATCH 67/68] MDEV-20938 Double free of dict_foreign_t during instant ALTER TABLE innobase_drop_foreign_try(): Don't evict and reload the dict_foreign_t during instant ALTER TABLE if the FOREIGN KEY constraint is being dropped. The MDEV-19630 fix (commit 07b1a26c33b28812a4fd8c814de0fe7d943bbd6b) was incomplete, because it did not cover a case where the FOREIGN KEY constraint is being dropped. --- .../suite/innodb/r/instant_alter_bugs.result | 15 ++++++ .../suite/innodb/t/instant_alter_bugs.test | 19 ++++++- storage/innobase/handler/handler0alter.cc | 50 ++++++++++--------- 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/mysql-test/suite/innodb/r/instant_alter_bugs.result b/mysql-test/suite/innodb/r/instant_alter_bugs.result index 080395b0120..9e6c537cf7e 100644 --- a/mysql-test/suite/innodb/r/instant_alter_bugs.result +++ b/mysql-test/suite/innodb/r/instant_alter_bugs.result @@ -128,6 +128,10 @@ HANDLER h READ `PRIMARY` PREV WHERE 0; pk f1 f2 f3 f4 f5 f6 f7 f8 filler HANDLER h CLOSE; DROP TABLE t1; +# +# MDEV-19630 ALTER TABLE ... ADD COLUMN damages foreign keys +# which are pointed to the table being altered +# CREATE TABLE t1(f1 int not null, primary key(f1))engine=innodb; CREATE TABLE t2(f1 INT AUTO_INCREMENT NOT NULL, f2 INT NOT NULL, status ENUM ('a', 'b', 'c'), INDEX idx1(f2), @@ -154,3 +158,14 @@ t2 CREATE TABLE `t2` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ALTER TABLE t2 CHANGE status status VARCHAR(20) DEFAULT NULL; DROP TABLE t2, t1; +# +# MDEV-20938 Double free of dict_foreign_t during instant ALTER TABLE +# +CREATE TABLE t1 (id INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (a INT UNSIGNED PRIMARY KEY, b INT UNSIGNED UNIQUE, +FOREIGN KEY fk1 (b) REFERENCES t1 (id)) ENGINE=InnoDB; +ALTER TABLE t2 +DROP FOREIGN KEY fk1, +CHANGE b d INT UNSIGNED, +ADD c INT; +DROP TABLE t2, t1; diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test index bab102ebd7f..0edbb672584 100644 --- a/mysql-test/suite/innodb/t/instant_alter_bugs.test +++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test @@ -135,8 +135,10 @@ HANDLER h READ `PRIMARY` PREV WHERE 0; HANDLER h CLOSE; DROP TABLE t1; -# MDEV-19630 ALTER TABLE ... ADD COLUMN damages foreign keys which are pointed -# to the table being altered +--echo # +--echo # MDEV-19630 ALTER TABLE ... ADD COLUMN damages foreign keys +--echo # which are pointed to the table being altered +--echo # CREATE TABLE t1(f1 int not null, primary key(f1))engine=innodb; CREATE TABLE t2(f1 INT AUTO_INCREMENT NOT NULL, f2 INT NOT NULL, status ENUM ('a', 'b', 'c'), INDEX idx1(f2), @@ -154,3 +156,16 @@ DROP TABLE t2, t1; --let $datadir= `select @@datadir` --remove_file $datadir/test/load.data + +--echo # +--echo # MDEV-20938 Double free of dict_foreign_t during instant ALTER TABLE +--echo # + +CREATE TABLE t1 (id INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (a INT UNSIGNED PRIMARY KEY, b INT UNSIGNED UNIQUE, + FOREIGN KEY fk1 (b) REFERENCES t1 (id)) ENGINE=InnoDB; +ALTER TABLE t2 + DROP FOREIGN KEY fk1, + CHANGE b d INT UNSIGNED, + ADD c INT; +DROP TABLE t2, t1; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 1450624c0c2..7b7afa6d1df 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -7428,27 +7428,23 @@ innobase_drop_foreign_try( } /** Rename a column in the data dictionary tables. -@param[in] user_table InnoDB table that was being altered -@param[in] trx Data dictionary transaction +@param[in] ctx ALTER TABLE context +@param[in,out] trx Data dictionary transaction @param[in] table_name Table name in MySQL @param[in] nth_col 0-based index of the column @param[in] from old column name @param[in] to new column name -@param[in] new_clustered whether the table has been rebuilt -@param[in] evict_fk_cache Evict the fk info from cache @retval true Failure @retval false Success */ static MY_ATTRIBUTE((nonnull, warn_unused_result)) bool innobase_rename_column_try( - const dict_table_t* user_table, - trx_t* trx, - const char* table_name, - ulint nth_col, - const char* from, - const char* to, - bool new_clustered, - bool evict_fk_cache) + const ha_innobase_inplace_ctx& ctx, + trx_t* trx, + const char* table_name, + ulint nth_col, + const char* from, + const char* to) { pars_info_t* info; dberr_t error; @@ -7460,13 +7456,13 @@ innobase_rename_column_try( ut_ad(mutex_own(&dict_sys->mutex)); ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_X)); - if (new_clustered) { + if (ctx.need_rebuild()) { goto rename_foreign; } info = pars_info_create(); - pars_info_add_ull_literal(info, "tableid", user_table->id); + pars_info_add_ull_literal(info, "tableid", ctx.old_table->id); pars_info_add_int4_literal(info, "nth", nth_col); pars_info_add_str_literal(info, "new", to); @@ -7496,7 +7492,7 @@ err_exit: trx->op_info = "renaming column in SYS_FIELDS"; for (const dict_index_t* index = dict_table_get_first_index( - user_table); + ctx.old_table); index != NULL; index = dict_table_get_next_index(index)) { @@ -7549,8 +7545,8 @@ rename_foreign: std::set fk_evict; bool foreign_modified; - for (dict_foreign_set::const_iterator it = user_table->foreign_set.begin(); - it != user_table->foreign_set.end(); + for (dict_foreign_set::const_iterator it = ctx.old_table->foreign_set.begin(); + it != ctx.old_table->foreign_set.end(); ++it) { dict_foreign_t* foreign = *it; @@ -7563,6 +7559,14 @@ rename_foreign: continue; } + /* Ignore the foreign key rename if fk info + is being dropped. */ + if (innobase_dropping_foreign( + foreign, ctx.drop_fk, + ctx.num_to_drop_fk)) { + continue; + } + info = pars_info_create(); pars_info_add_str_literal(info, "id", foreign->id); @@ -7591,8 +7595,8 @@ rename_foreign: } for (dict_foreign_set::const_iterator it - = user_table->referenced_set.begin(); - it != user_table->referenced_set.end(); + = ctx.old_table->referenced_set.begin(); + it != ctx.old_table->referenced_set.end(); ++it) { foreign_modified = false; @@ -7633,7 +7637,7 @@ rename_foreign: } /* Reload the foreign key info for instant table too. */ - if (new_clustered || evict_fk_cache) { + if (ctx.need_rebuild() || ctx.is_instant()) { std::for_each(fk_evict.begin(), fk_evict.end(), dict_foreign_remove_from_cache); } @@ -7684,12 +7688,10 @@ innobase_rename_columns_try( : i - num_v; if (innobase_rename_column_try( - ctx->old_table, trx, table_name, + *ctx, trx, table_name, col_n, cf->field->field_name.str, - cf->field_name.str, - ctx->need_rebuild(), - ctx->is_instant())) { + cf->field_name.str)) { return(true); } goto processed_field; From 9c72963d2aef783cae652b5b8ac01f7aa2bcb43a Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 31 Oct 2019 19:44:29 +0300 Subject: [PATCH 68/68] MDEV-17171: RocksDB Tables do not have "Creation Date" Variant#5 of the patch: - take creation date from the .frm file, like InnoDB does - Update_time is in-memory only (like in InnoDB). --- storage/rocksdb/ha_rocksdb.cc | 37 +++++++ .../mysql-test/rocksdb/include/bulk_load.inc | 4 +- .../rocksdb/include/bulk_load_unsorted.inc | 4 +- .../mysql-test/rocksdb/r/bulk_load.result | 12 +-- .../rocksdb/r/bulk_load_rev_cf.result | 12 +-- .../r/bulk_load_rev_cf_and_data.result | 12 +-- .../rocksdb/r/bulk_load_rev_data.result | 12 +-- .../rocksdb/r/bulk_load_unsorted.result | 12 +-- .../rocksdb/r/bulk_load_unsorted_rev.result | 12 +-- .../mysql-test/rocksdb/r/issue255.result | 16 ++-- .../mysql-test/rocksdb/r/rocksdb.result | 6 +- .../rocksdb/r/show_table_status.result | 96 ++++++++++++++++++- .../rocksdb/r/truncate_table.result | 8 +- .../mysql-test/rocksdb/t/issue255.test | 17 ++-- .../rocksdb/mysql-test/rocksdb/t/rocksdb.test | 4 +- .../rocksdb/t/show_table_status.test | 91 +++++++++++++++++- .../mysql-test/rocksdb/t/truncate_table.test | 8 +- storage/rocksdb/rdb_datadic.cc | 20 ++++ storage/rocksdb/rdb_datadic.h | 17 +++- 19 files changed, 323 insertions(+), 77 deletions(-) diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc index fb3b7af67fb..f063d76f49c 100644 --- a/storage/rocksdb/ha_rocksdb.cc +++ b/storage/rocksdb/ha_rocksdb.cc @@ -2306,6 +2306,8 @@ class Rdb_transaction { bool m_is_delayed_snapshot = false; bool m_is_two_phase = false; + std::unordered_set modified_tables; + private: /* Number of write operations this transaction had when we took the last @@ -3001,6 +3003,26 @@ protected: virtual void start_tx() = 0; virtual void start_stmt() = 0; + protected: + // Non-virtual functions with actions to be done on transaction start and + // commit. + void on_commit() { + time_t tm; + tm = time(nullptr); + for (auto &it : modified_tables) { + it->update_time = tm; + } + modified_tables.clear(); + } + void on_rollback() { + modified_tables.clear(); + } + public: + // Inform the transaction that this table was modified + void log_table_write_op(Rdb_tbl_def *tbl) { + modified_tables.insert(tbl); + } + void set_initial_savepoint() { /* Set the initial savepoint. If the first statement in the transaction @@ -3185,7 +3207,9 @@ class Rdb_transaction_impl : public Rdb_transaction { goto error; } + on_commit(); error: + on_rollback(); /* Save the transaction object to be reused */ release_tx(); @@ -3201,6 +3225,7 @@ class Rdb_transaction_impl : public Rdb_transaction { public: void rollback() override { + on_rollback(); m_write_count = 0; m_insert_count = 0; m_update_count = 0; @@ -3522,7 +3547,9 @@ class Rdb_writebatch_impl : public Rdb_transaction { res = true; goto error; } + on_commit(); error: + on_rollback(); reset(); m_write_count = 0; @@ -3555,6 +3582,7 @@ class Rdb_writebatch_impl : public Rdb_transaction { } void rollback() override { + on_rollback(); m_write_count = 0; m_insert_count = 0; m_update_count = 0; @@ -10335,6 +10363,8 @@ int ha_rocksdb::update_write_row(const uchar *const old_data, row_info.tx->incr_insert_count(); } + row_info.tx->log_table_write_op(m_tbl_def); + if (do_bulk_commit(row_info.tx)) { DBUG_RETURN(HA_ERR_ROCKSDB_BULK_LOAD); } @@ -10814,6 +10844,7 @@ int ha_rocksdb::delete_row(const uchar *const buf) { } tx->incr_delete_count(); + tx->log_table_write_op(m_tbl_def); if (do_bulk_commit(tx)) { DBUG_RETURN(HA_ERR_ROCKSDB_BULK_LOAD); @@ -11008,6 +11039,12 @@ int ha_rocksdb::info(uint flag) { k->rec_per_key[j] = x; } } + + stats.create_time = m_tbl_def->get_creation_time(); + } + + if (flag & HA_STATUS_TIME) { + stats.update_time = m_tbl_def->update_time; } if (flag & HA_STATUS_ERRKEY) { diff --git a/storage/rocksdb/mysql-test/rocksdb/include/bulk_load.inc b/storage/rocksdb/mysql-test/rocksdb/include/bulk_load.inc index 29ec94188a2..3bb766d59b4 100644 --- a/storage/rocksdb/mysql-test/rocksdb/include/bulk_load.inc +++ b/storage/rocksdb/mysql-test/rocksdb/include/bulk_load.inc @@ -121,12 +121,12 @@ set rocksdb_bulk_load=0; --remove_file $file # Make sure row count index stats are correct ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # 13 # SHOW TABLE STATUS WHERE name LIKE 't%'; ANALYZE TABLE t1, t2, t3; ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # 13 # SHOW TABLE STATUS WHERE name LIKE 't%'; # Make sure all the data is there. diff --git a/storage/rocksdb/mysql-test/rocksdb/include/bulk_load_unsorted.inc b/storage/rocksdb/mysql-test/rocksdb/include/bulk_load_unsorted.inc index 46aea8f23b5..d6bee980fef 100644 --- a/storage/rocksdb/mysql-test/rocksdb/include/bulk_load_unsorted.inc +++ b/storage/rocksdb/mysql-test/rocksdb/include/bulk_load_unsorted.inc @@ -121,12 +121,12 @@ set rocksdb_bulk_load=0; --remove_file $file # Make sure row count index stats are correct ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # 13 # SHOW TABLE STATUS WHERE name LIKE 't%'; ANALYZE TABLE t1, t2, t3; ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # 13 # SHOW TABLE STATUS WHERE name LIKE 't%'; # Make sure all the data is there. diff --git a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load.result b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load.result index 889207040b6..98db48d772f 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load.result @@ -40,9 +40,9 @@ pk a b set rocksdb_bulk_load=0; SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL partitioned 0 N ANALYZE TABLE t1, t2, t3; Table Op Msg_type Msg_text test.t1 analyze status OK @@ -50,9 +50,9 @@ test.t2 analyze status OK test.t3 analyze status OK SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL partitioned 0 N select count(pk),count(a) from t1; count(pk) count(a) 2500000 2500000 diff --git a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_cf.result b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_cf.result index 2cf2bdb91a6..d894e2e371a 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_cf.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_cf.result @@ -40,9 +40,9 @@ pk a b set rocksdb_bulk_load=0; SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL partitioned 0 N ANALYZE TABLE t1, t2, t3; Table Op Msg_type Msg_text test.t1 analyze status OK @@ -50,9 +50,9 @@ test.t2 analyze status OK test.t3 analyze status OK SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL partitioned 0 N select count(pk),count(a) from t1; count(pk) count(a) 2500000 2500000 diff --git a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_cf_and_data.result b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_cf_and_data.result index 1d2497dc7e4..90402a87005 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_cf_and_data.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_cf_and_data.result @@ -40,9 +40,9 @@ pk a b set rocksdb_bulk_load=0; SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL partitioned 0 N ANALYZE TABLE t1, t2, t3; Table Op Msg_type Msg_text test.t1 analyze status OK @@ -50,9 +50,9 @@ test.t2 analyze status OK test.t3 analyze status OK SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL partitioned 0 N select count(pk),count(a) from t1; count(pk) count(a) 2500000 2500000 diff --git a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_data.result b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_data.result index 8b5576b8f5f..5a5a334a71f 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_data.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_rev_data.result @@ -40,9 +40,9 @@ pk a b set rocksdb_bulk_load=0; SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL partitioned 0 N ANALYZE TABLE t1, t2, t3; Table Op Msg_type Msg_text test.t1 analyze status OK @@ -50,9 +50,9 @@ test.t2 analyze status OK test.t3 analyze status OK SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_bin NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_bin NULL partitioned 0 N select count(pk),count(a) from t1; count(pk) count(a) 2500000 2500000 diff --git a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_unsorted.result b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_unsorted.result index e58950072bc..65b20296127 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_unsorted.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_unsorted.result @@ -72,9 +72,9 @@ LOAD DATA INFILE INTO TABLE t3; set rocksdb_bulk_load=0; SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL partitioned 0 N ANALYZE TABLE t1, t2, t3; Table Op Msg_type Msg_text test.t1 analyze status OK @@ -82,9 +82,9 @@ test.t2 analyze status OK test.t3 analyze status OK SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL partitioned 0 N select count(a),count(b) from t1; count(a) count(b) 2500000 2500000 diff --git a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_unsorted_rev.result b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_unsorted_rev.result index ca50d6f5a2b..aa97afb9b72 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_unsorted_rev.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/bulk_load_unsorted_rev.result @@ -72,9 +72,9 @@ LOAD DATA INFILE INTO TABLE t3; set rocksdb_bulk_load=0; SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL partitioned 0 N ANALYZE TABLE t1, t2, t3; Table Op Msg_type Msg_text test.t1 analyze status OK @@ -82,9 +82,9 @@ test.t2 analyze status OK test.t3 analyze status OK SHOW TABLE STATUS WHERE name LIKE 't%'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N -t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N -t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL partitioned 0 N +t1 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL 0 N +t2 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL 0 N +t3 ROCKSDB 10 Fixed 2500000 # # # # 0 NULL # # NULL latin1_swedish_ci NULL partitioned 0 N select count(a),count(b) from t1; count(a) count(b) 2500000 2500000 diff --git a/storage/rocksdb/mysql-test/rocksdb/r/issue255.result b/storage/rocksdb/mysql-test/rocksdb/r/issue255.result index d9b8f0e0851..840699ddaa1 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/issue255.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/issue255.result @@ -2,7 +2,7 @@ CREATE TABLE t1 (pk BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT); INSERT INTO t1 VALUES (5); SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB # Fixed # # # # # # 6 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB # Fixed # # # # # # 6 # # NULL latin1_swedish_ci NULL 0 N INSERT INTO t1 VALUES ('538647864786478647864'); Warnings: Warning 1264 Out of range value for column 'pk' at row 1 @@ -12,7 +12,7 @@ pk 9223372036854775807 SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 2 22 44 0 0 0 9223372036854775807 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB 10 Fixed 2 22 44 0 0 0 9223372036854775807 # # NULL latin1_swedish_ci NULL 0 N INSERT INTO t1 VALUES (); ERROR 23000: Duplicate entry '9223372036854775807' for key 'PRIMARY' SELECT * FROM t1; @@ -21,7 +21,7 @@ pk 9223372036854775807 SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB # Fixed # # # # # # 9223372036854775807 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB # Fixed # # # # # # 9223372036854775807 # # NULL latin1_swedish_ci NULL 0 N INSERT INTO t1 VALUES (); ERROR 23000: Duplicate entry '9223372036854775807' for key 'PRIMARY' SELECT * FROM t1; @@ -30,13 +30,13 @@ pk 9223372036854775807 SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB # Fixed # # # # # # 9223372036854775807 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB # Fixed # # # # # # 9223372036854775807 # # NULL latin1_swedish_ci NULL 0 N DROP TABLE t1; CREATE TABLE t1 (pk TINYINT NOT NULL PRIMARY KEY AUTO_INCREMENT); INSERT INTO t1 VALUES (5); SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB # Fixed # # # # # # 6 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB # Fixed # # # # # # 6 # # NULL latin1_swedish_ci NULL 0 N INSERT INTO t1 VALUES (1000); Warnings: Warning 1264 Out of range value for column 'pk' at row 1 @@ -46,7 +46,7 @@ pk 127 SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB # Fixed # # # # # # 127 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB # Fixed # # # # # # 127 # # NULL latin1_swedish_ci NULL 0 N INSERT INTO t1 VALUES (); ERROR 23000: Duplicate entry '127' for key 'PRIMARY' SELECT * FROM t1; @@ -55,7 +55,7 @@ pk 127 SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB # Fixed # # # # # # 127 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB # Fixed # # # # # # 127 # # NULL latin1_swedish_ci NULL 0 N INSERT INTO t1 VALUES (); ERROR 23000: Duplicate entry '127' for key 'PRIMARY' SELECT * FROM t1; @@ -64,5 +64,5 @@ pk 127 SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB # Fixed # # # # # # 127 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB # Fixed # # # # # # 127 # # NULL latin1_swedish_ci NULL 0 N DROP TABLE t1; diff --git a/storage/rocksdb/mysql-test/rocksdb/r/rocksdb.result b/storage/rocksdb/mysql-test/rocksdb/r/rocksdb.result index a25012239f8..e00872f2903 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/rocksdb.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/rocksdb.result @@ -1421,7 +1421,7 @@ create table t1 (i int primary key auto_increment) engine=RocksDB; insert into t1 values (null),(null); show table status like 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 1000 0 # 0 0 0 3 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB 10 Fixed 1000 0 # 0 0 0 3 # # NULL latin1_swedish_ci NULL 0 N drop table t1; # # Fix Issue #4: Crash when using pseudo-unique keys @@ -2594,7 +2594,7 @@ CREATE TABLE t1(a INT AUTO_INCREMENT KEY); INSERT INTO t1 VALUES(0),(-1),(0); SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 1000 0 0 0 0 0 3 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB 10 Fixed 1000 0 0 0 0 0 3 # # NULL latin1_swedish_ci NULL 0 N SELECT * FROM t1; a -1 @@ -2605,7 +2605,7 @@ CREATE TABLE t1(a INT AUTO_INCREMENT KEY); INSERT INTO t1 VALUES(0),(10),(0); SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 1000 0 0 0 0 0 12 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB 10 Fixed 1000 0 0 0 0 0 12 # # NULL latin1_swedish_ci NULL 0 N SELECT * FROM t1; a 1 diff --git a/storage/rocksdb/mysql-test/rocksdb/r/show_table_status.result b/storage/rocksdb/mysql-test/rocksdb/r/show_table_status.result index 572cac19f4a..ca373112c1c 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/show_table_status.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/show_table_status.result @@ -7,12 +7,12 @@ set global rocksdb_force_flush_memtable_now = true; CREATE TABLE t3 (a INT, b CHAR(8), pk INT PRIMARY KEY) ENGINE=rocksdb CHARACTER SET utf8; SHOW TABLE STATUS WHERE name IN ( 't1', 't2', 't3' ); Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed 1000 # # 0 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N -t2 ROCKSDB 10 Fixed 1000 # # 0 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N -t3 ROCKSDB 10 Fixed 1000 # # 0 0 0 NULL NULL NULL NULL utf8_general_ci NULL 0 N +t1 ROCKSDB 10 Fixed 1000 # # 0 0 0 NULL # # NULL latin1_swedish_ci NULL 0 N +t2 ROCKSDB 10 Fixed 1000 # # 0 0 0 NULL # # NULL latin1_swedish_ci NULL 0 N +t3 ROCKSDB 10 Fixed 1000 # # 0 0 0 NULL # # NULL utf8_general_ci NULL 0 N SHOW TABLE STATUS WHERE name LIKE 't2'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t2 ROCKSDB 10 Fixed 1000 # # 0 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL 0 N +t2 ROCKSDB 10 Fixed 1000 # # 0 0 0 NULL # # NULL latin1_swedish_ci NULL 0 N DROP TABLE t1, t2, t3; CREATE DATABASE `db_new..............................................end`; USE `db_new..............................................end`; @@ -22,3 +22,91 @@ SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.table_statistics WHERE T TABLE_SCHEMA db_new..............................................end TABLE_NAME t1_new..............................................end DROP DATABASE `db_new..............................................end`; +# +# MDEV-17171: Bug: RocksDB Tables do not have "Creation Date" +# +use test; +create table t1 (a int) engine=rocksdb; +select create_time is not null, update_time, check_time +from information_schema.tables where table_schema=database() and table_name='t1'; +create_time is not null update_time check_time +1 NULL NULL +insert into t1 values (1); +select create_time is not null, update_time is not null, check_time +from information_schema.tables where table_schema=database() and table_name='t1'; +create_time is not null update_time is not null check_time +1 1 NULL +flush tables; +select create_time is not null, update_time is not null, check_time +from information_schema.tables where table_schema=database() and table_name='t1'; +create_time is not null update_time is not null check_time +1 1 NULL +select create_time, update_time into @create_tm, @update_tm +from information_schema.tables +where table_schema=database() and table_name='t1'; +select sleep(3); +sleep(3) +0 +insert into t1 values (2); +select +create_time=@create_tm /* should not change */ , +timestampdiff(second, @update_tm, update_time) > 2, +check_time +from information_schema.tables +where table_schema=database() and table_name='t1'; +create_time=@create_tm 1 +timestampdiff(second, @update_tm, update_time) > 2 1 +check_time NULL +# +# Check how create_time survives ALTER TABLE. +# First, an ALTER TABLE that re-creates the table: +alter table t1 add b int; +select +create_time<>@create_tm /* should change */, +create_time IS NOT NULL, +update_time IS NULL +from information_schema.tables +where table_schema=database() and table_name='t1'; +create_time<>@create_tm 1 +create_time IS NOT NULL 1 +update_time IS NULL 1 +insert into t1 values (5,5); +select create_time, update_time into @create_tm, @update_tm +from information_schema.tables +where table_schema=database() and table_name='t1'; +# Then, an in-place ALTER TABLE: +alter table t1 add key (a); +select +create_time=@create_tm /* should not change */, +update_time +from information_schema.tables +where table_schema=database() and table_name='t1'; +create_time=@create_tm 1 +update_time NULL +# +# Check what is left after server restart +# +# Save t1's creation time +create table t2 as +select create_time +from information_schema.tables +where table_schema=database() and table_name='t1'; +select +create_time=(select create_time from t2) /* should change */, +update_time +from information_schema.tables +where table_schema=database() and table_name='t1'; +create_time=(select create_time from t2) 1 +update_time NULL +drop table t1, t2; +# +# Check how it works for partitioned tables +# +create table t1 (pk int primary key) partition by hash(pk) partitions 2; +insert into t1 values (1); +select create_time IS NOT NULL , update_time IS NOT NULL +from information_schema.tables +where table_schema=database() and table_name='t1'; +create_time IS NOT NULL 1 +update_time IS NOT NULL 1 +drop table t1; diff --git a/storage/rocksdb/mysql-test/rocksdb/r/truncate_table.result b/storage/rocksdb/mysql-test/rocksdb/r/truncate_table.result index 76d00d90420..47048677079 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/truncate_table.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/truncate_table.result @@ -9,19 +9,19 @@ DROP TABLE t1; CREATE TABLE t1 (a INT KEY AUTO_INCREMENT, c CHAR(8)) ENGINE=rocksdb; SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed # # # 0 0 0 1 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB 10 Fixed # # # 0 0 0 1 # # NULL latin1_swedish_ci NULL 0 N INSERT INTO t1 (c) VALUES ('a'),('b'),('c'); SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed # # # 0 0 0 4 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB 10 Fixed # # # 0 0 0 4 # # NULL latin1_swedish_ci NULL 0 N TRUNCATE TABLE t1; SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed # # # 0 0 0 1 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB 10 Fixed # # # 0 0 0 1 # # NULL latin1_swedish_ci NULL 0 N INSERT INTO t1 (c) VALUES ('d'); SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary -t1 ROCKSDB 10 Fixed # # # 0 0 0 2 NULL NULL NULL latin1_swedish_ci NULL 0 N +t1 ROCKSDB 10 Fixed # # # 0 0 0 2 # # NULL latin1_swedish_ci NULL 0 N SELECT a,c FROM t1; a c 1 d diff --git a/storage/rocksdb/mysql-test/rocksdb/t/issue255.test b/storage/rocksdb/mysql-test/rocksdb/t/issue255.test index 370dece0c6c..686f45b4056 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/issue255.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/issue255.test @@ -3,24 +3,25 @@ CREATE TABLE t1 (pk BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT); INSERT INTO t1 VALUES (5); ---replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # +--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; INSERT INTO t1 VALUES ('538647864786478647864'); ---replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # +--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # SELECT * FROM t1; +--replace_column 12 # 13 # SHOW TABLE STATUS LIKE 't1'; --error ER_DUP_ENTRY INSERT INTO t1 VALUES (); SELECT * FROM t1; ---replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # +--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; --error ER_DUP_ENTRY INSERT INTO t1 VALUES (); SELECT * FROM t1; ---replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # +--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; DROP TABLE t1; @@ -28,24 +29,24 @@ DROP TABLE t1; CREATE TABLE t1 (pk TINYINT NOT NULL PRIMARY KEY AUTO_INCREMENT); INSERT INTO t1 VALUES (5); ---replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # +--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; INSERT INTO t1 VALUES (1000); SELECT * FROM t1; ---replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # +--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; --error ER_DUP_ENTRY INSERT INTO t1 VALUES (); SELECT * FROM t1; ---replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # +--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; --error ER_DUP_ENTRY INSERT INTO t1 VALUES (); SELECT * FROM t1; ---replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # +--replace_column 3 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; DROP TABLE t1; diff --git a/storage/rocksdb/mysql-test/rocksdb/t/rocksdb.test b/storage/rocksdb/mysql-test/rocksdb/t/rocksdb.test index 96fe1a90bc9..84a9a5bbd5a 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/rocksdb.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/rocksdb.test @@ -1207,7 +1207,7 @@ drop table t1; create table t1 (i int primary key auto_increment) engine=RocksDB; insert into t1 values (null),(null); ---replace_column 7 # +--replace_column 7 # 12 # 13 # show table status like 't1'; drop table t1; @@ -1914,11 +1914,13 @@ DROP TABLE t1; # value is 4 while MyRocks will show it as 3. CREATE TABLE t1(a INT AUTO_INCREMENT KEY); INSERT INTO t1 VALUES(0),(-1),(0); +--replace_column 12 # 13 # SHOW TABLE STATUS LIKE 't1'; SELECT * FROM t1; DROP TABLE t1; CREATE TABLE t1(a INT AUTO_INCREMENT KEY); INSERT INTO t1 VALUES(0),(10),(0); +--replace_column 12 # 13 # SHOW TABLE STATUS LIKE 't1'; SELECT * FROM t1; DROP TABLE t1; diff --git a/storage/rocksdb/mysql-test/rocksdb/t/show_table_status.test b/storage/rocksdb/mysql-test/rocksdb/t/show_table_status.test index a293b9ee6b8..109301a8879 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/show_table_status.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/show_table_status.test @@ -1,4 +1,5 @@ --source include/have_rocksdb.inc +--source include/have_partition.inc --source include/not_windows.inc # decorated database names is too long, exceeded OS limits # @@ -25,7 +26,7 @@ set global rocksdb_force_flush_memtable_now = true; CREATE TABLE t3 (a INT, b CHAR(8), pk INT PRIMARY KEY) ENGINE=rocksdb CHARACTER SET utf8; ---replace_column 6 # 7 # +--replace_column 6 # 7 # 12 # 13 # SHOW TABLE STATUS WHERE name IN ( 't1', 't2', 't3' ); # Some statistics don't get updated as quickly. The Data_length and @@ -49,7 +50,7 @@ set global rocksdb_force_flush_memtable_now = true; # We expect the number of rows to be 10000. Data_len and Avg_row_len # may vary, depending on built-in compression library. ---replace_column 6 # 7 # +--replace_column 6 # 7 # 12 # 13 # SHOW TABLE STATUS WHERE name LIKE 't2'; DROP TABLE t1, t2, t3; @@ -63,3 +64,89 @@ CREATE TABLE `t1_new..............................................end`(a int) en INSERT INTO `t1_new..............................................end` VALUES (1); --query_vertical SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.table_statistics WHERE TABLE_NAME = 't1_new..............................................end' DROP DATABASE `db_new..............................................end`; +--echo # +--echo # MDEV-17171: Bug: RocksDB Tables do not have "Creation Date" +--echo # +use test; +create table t1 (a int) engine=rocksdb; + +select create_time is not null, update_time, check_time +from information_schema.tables where table_schema=database() and table_name='t1'; + +insert into t1 values (1); +select create_time is not null, update_time is not null, check_time +from information_schema.tables where table_schema=database() and table_name='t1'; + +flush tables; +select create_time is not null, update_time is not null, check_time +from information_schema.tables where table_schema=database() and table_name='t1'; + +select create_time, update_time into @create_tm, @update_tm +from information_schema.tables +where table_schema=database() and table_name='t1'; + +select sleep(3); +insert into t1 values (2); + +--vertical_results +select + create_time=@create_tm /* should not change */ , + timestampdiff(second, @update_tm, update_time) > 2, + check_time +from information_schema.tables +where table_schema=database() and table_name='t1'; + +--echo # +--echo # Check how create_time survives ALTER TABLE. +--echo # First, an ALTER TABLE that re-creates the table: +alter table t1 add b int; +select + create_time<>@create_tm /* should change */, + create_time IS NOT NULL, + update_time IS NULL +from information_schema.tables +where table_schema=database() and table_name='t1'; + +insert into t1 values (5,5); + +select create_time, update_time into @create_tm, @update_tm +from information_schema.tables +where table_schema=database() and table_name='t1'; + +--echo # Then, an in-place ALTER TABLE: +alter table t1 add key (a); + +select + create_time=@create_tm /* should not change */, + update_time +from information_schema.tables +where table_schema=database() and table_name='t1'; + +--echo # +--echo # Check what is left after server restart +--echo # + +--echo # Save t1's creation time +create table t2 as +select create_time +from information_schema.tables +where table_schema=database() and table_name='t1'; + +select + create_time=(select create_time from t2) /* should change */, + update_time +from information_schema.tables +where table_schema=database() and table_name='t1'; + +drop table t1, t2; + +--echo # +--echo # Check how it works for partitioned tables +--echo # +create table t1 (pk int primary key) partition by hash(pk) partitions 2; +insert into t1 values (1); + +select create_time IS NOT NULL , update_time IS NOT NULL +from information_schema.tables +where table_schema=database() and table_name='t1'; +drop table t1; diff --git a/storage/rocksdb/mysql-test/rocksdb/t/truncate_table.test b/storage/rocksdb/mysql-test/rocksdb/t/truncate_table.test index a61488654a3..1001eeb6cde 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/truncate_table.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/truncate_table.test @@ -29,22 +29,22 @@ DROP TABLE t1; CREATE TABLE t1 (a INT KEY AUTO_INCREMENT, c CHAR(8)) ENGINE=rocksdb; #--replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # ---replace_column 5 # 6 # 7 # +--replace_column 5 # 6 # 7 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; INSERT INTO t1 (c) VALUES ('a'),('b'),('c'); #--replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # ---replace_column 5 # 6 # 7 # +--replace_column 5 # 6 # 7 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; TRUNCATE TABLE t1; #--replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # ---replace_column 5 # 6 # 7 # +--replace_column 5 # 6 # 7 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; INSERT INTO t1 (c) VALUES ('d'); #--replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # ---replace_column 5 # 6 # 7 # +--replace_column 5 # 6 # 7 # 12 # 13 # SHOW TABLE STATUS LIKE 't1'; --sorted_result diff --git a/storage/rocksdb/rdb_datadic.cc b/storage/rocksdb/rdb_datadic.cc index e369c08dd51..0cefed77ac8 100644 --- a/storage/rocksdb/rdb_datadic.cc +++ b/storage/rocksdb/rdb_datadic.cc @@ -3592,6 +3592,26 @@ bool Rdb_tbl_def::put_dict(Rdb_dict_manager *const dict, return false; } +time_t Rdb_tbl_def::get_creation_time() { + time_t create_time = m_create_time; + + if (create_time == CREATE_TIME_UNKNOWN) { + // Read it from the .frm file. It's not a problem if several threads do this + // concurrently + char path[FN_REFLEN]; + snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home, + m_dbname.c_str(), m_tablename.c_str(), reg_ext); + unpack_filename(path,path); + MY_STAT f_stat; + if (my_stat(path, &f_stat, MYF(0))) + create_time = f_stat.st_ctime; + else + create_time = 0; // will be shown as SQL NULL + m_create_time = create_time; + } + return create_time; +} + // Length that each index flag takes inside the record. // Each index in the array maps to the enum INDEX_FLAG static const std::array index_flag_lengths = { diff --git a/storage/rocksdb/rdb_datadic.h b/storage/rocksdb/rdb_datadic.h index 0a3a747c633..d6cb242bd35 100644 --- a/storage/rocksdb/rdb_datadic.h +++ b/storage/rocksdb/rdb_datadic.h @@ -1092,22 +1092,28 @@ class Rdb_tbl_def { Rdb_tbl_def &operator=(const Rdb_tbl_def &) = delete; explicit Rdb_tbl_def(const std::string &name) - : m_key_descr_arr(nullptr), m_hidden_pk_val(0), m_auto_incr_val(0) { + : m_key_descr_arr(nullptr), m_hidden_pk_val(0), m_auto_incr_val(0), + m_create_time(CREATE_TIME_UNKNOWN) { set_name(name); } Rdb_tbl_def(const char *const name, const size_t len) - : m_key_descr_arr(nullptr), m_hidden_pk_val(0), m_auto_incr_val(0) { + : m_key_descr_arr(nullptr), m_hidden_pk_val(0), m_auto_incr_val(0), + m_create_time(CREATE_TIME_UNKNOWN) { set_name(std::string(name, len)); } explicit Rdb_tbl_def(const rocksdb::Slice &slice, const size_t pos = 0) - : m_key_descr_arr(nullptr), m_hidden_pk_val(0), m_auto_incr_val(0) { + : m_key_descr_arr(nullptr), m_hidden_pk_val(0), m_auto_incr_val(0), + m_create_time(CREATE_TIME_UNKNOWN) { set_name(std::string(slice.data() + pos, slice.size() - pos)); } ~Rdb_tbl_def(); + time_t get_creation_time(); + time_t update_time = 0; // in-memory only value, maintained right here + void check_and_set_read_free_rpl_table(); /* Number of indexes */ @@ -1133,6 +1139,11 @@ class Rdb_tbl_def { const std::string &base_tablename() const { return m_tablename; } const std::string &base_partition() const { return m_partition; } GL_INDEX_ID get_autoincr_gl_index_id(); + private: + const time_t CREATE_TIME_UNKNOWN= 1; + // CREATE_TIME_UNKNOWN means "didn't try to read, yet" + // 0 means "no data available" + std::atomic m_create_time; }; /*